aboutsummaryrefslogtreecommitdiffstats
path: root/programs/charon
diff options
context:
space:
mode:
authorMartin Willi <martin@strongswan.org>2006-04-28 07:14:48 +0000
committerMartin Willi <martin@strongswan.org>2006-04-28 07:14:48 +0000
commit997358a6c475c8886cce388ab325184a1ff733c9 (patch)
tree27a15790e030fc186d00cd710d2a3540f4defe69 /programs/charon
parent52923c9acb349adec3d1cc039e7a74c2e822da6e (diff)
downloadstrongswan-997358a6c475c8886cce388ab325184a1ff733c9.tar.bz2
strongswan-997358a6c475c8886cce388ab325184a1ff733c9.tar.xz
- import of strongswan-2.7.0
- applied patch for charon
Diffstat (limited to 'programs/charon')
-rw-r--r--programs/charon/Doxyfile220
-rw-r--r--programs/charon/Makefile99
-rw-r--r--programs/charon/charon.kdevelop105
-rw-r--r--programs/charon/charon/Makefile.charon25
-rw-r--r--programs/charon/charon/config/Makefile.config32
-rwxr-xr-xprograms/charon/charon/config/configuration.c112
-rwxr-xr-xprograms/charon/charon/config/configuration.h89
-rw-r--r--programs/charon/charon/config/connections/Makefile.connections24
-rw-r--r--programs/charon/charon/config/connections/connection.c367
-rw-r--r--programs/charon/charon/config/connections/connection.h283
-rwxr-xr-xprograms/charon/charon/config/connections/connection_store.h112
-rw-r--r--programs/charon/charon/config/connections/local_connection_store.c228
-rw-r--r--programs/charon/charon/config/connections/local_connection_store.h63
-rw-r--r--programs/charon/charon/config/credentials/Makefile.credentials20
-rwxr-xr-xprograms/charon/charon/config/credentials/credential_store.h91
-rw-r--r--programs/charon/charon/config/credentials/local_credential_store.c315
-rw-r--r--programs/charon/charon/config/credentials/local_credential_store.h84
-rw-r--r--programs/charon/charon/config/policies/Makefile.policies24
-rw-r--r--programs/charon/charon/config/policies/local_policy_store.c136
-rw-r--r--programs/charon/charon/config/policies/local_policy_store.h60
-rw-r--r--programs/charon/charon/config/policies/policy.c397
-rw-r--r--programs/charon/charon/config/policies/policy.h249
-rwxr-xr-xprograms/charon/charon/config/policies/policy_store.h76
-rw-r--r--programs/charon/charon/config/proposal.c642
-rw-r--r--programs/charon/charon/config/proposal.h269
-rw-r--r--programs/charon/charon/config/traffic_selector.c425
-rw-r--r--programs/charon/charon/config/traffic_selector.h258
-rw-r--r--programs/charon/charon/daemon.c390
-rw-r--r--programs/charon/charon/daemon.h324
-rw-r--r--programs/charon/charon/encoding/Makefile.encoding30
-rw-r--r--programs/charon/charon/encoding/generator.c1077
-rw-r--r--programs/charon/charon/encoding/generator.h101
-rw-r--r--programs/charon/charon/encoding/message.c1251
-rw-r--r--programs/charon/charon/encoding/message.h367
-rw-r--r--programs/charon/charon/encoding/parser.c1065
-rw-r--r--programs/charon/charon/encoding/parser.h95
-rw-r--r--programs/charon/charon/encoding/payloads/Makefile.payloads108
-rw-r--r--programs/charon/charon/encoding/payloads/auth_payload.c265
-rw-r--r--programs/charon/charon/encoding/payloads/auth_payload.h122
-rw-r--r--programs/charon/charon/encoding/payloads/cert_payload.c279
-rw-r--r--programs/charon/charon/encoding/payloads/cert_payload.h155
-rw-r--r--programs/charon/charon/encoding/payloads/certreq_payload.c259
-rw-r--r--programs/charon/charon/encoding/payloads/certreq_payload.h125
-rw-r--r--programs/charon/charon/encoding/payloads/configuration_attribute.c282
-rw-r--r--programs/charon/charon/encoding/payloads/configuration_attribute.h149
-rw-r--r--programs/charon/charon/encoding/payloads/cp_payload.c305
-rw-r--r--programs/charon/charon/encoding/payloads/cp_payload.h138
-rw-r--r--programs/charon/charon/encoding/payloads/delete_payload.c322
-rw-r--r--programs/charon/charon/encoding/payloads/delete_payload.h156
-rw-r--r--programs/charon/charon/encoding/payloads/eap_payload.c227
-rw-r--r--programs/charon/charon/encoding/payloads/eap_payload.h105
-rw-r--r--programs/charon/charon/encoding/payloads/encodings.c68
-rw-r--r--programs/charon/charon/encoding/payloads/encodings.h540
-rw-r--r--programs/charon/charon/encoding/payloads/encryption_payload.c702
-rw-r--r--programs/charon/charon/encoding/payloads/encryption_payload.h196
-rw-r--r--programs/charon/charon/encoding/payloads/id_payload.c320
-rw-r--r--programs/charon/charon/encoding/payloads/id_payload.h172
-rw-r--r--programs/charon/charon/encoding/payloads/ike_header.c408
-rw-r--r--programs/charon/charon/encoding/payloads/ike_header.h261
-rw-r--r--programs/charon/charon/encoding/payloads/ke_payload.c276
-rw-r--r--programs/charon/charon/encoding/payloads/ke_payload.h110
-rw-r--r--programs/charon/charon/encoding/payloads/nonce_payload.c241
-rw-r--r--programs/charon/charon/encoding/payloads/nonce_payload.h89
-rw-r--r--programs/charon/charon/encoding/payloads/notify_payload.c441
-rw-r--r--programs/charon/charon/encoding/payloads/notify_payload.h200
-rw-r--r--programs/charon/charon/encoding/payloads/payload.c131
-rw-r--r--programs/charon/charon/encoding/payloads/payload.h279
-rw-r--r--programs/charon/charon/encoding/payloads/proposal_substructure.c629
-rw-r--r--programs/charon/charon/encoding/payloads/proposal_substructure.h231
-rw-r--r--programs/charon/charon/encoding/payloads/sa_payload.c390
-rw-r--r--programs/charon/charon/encoding/payloads/sa_payload.h140
-rw-r--r--programs/charon/charon/encoding/payloads/traffic_selector_substructure.c374
-rw-r--r--programs/charon/charon/encoding/payloads/traffic_selector_substructure.h171
-rw-r--r--programs/charon/charon/encoding/payloads/transform_attribute.c333
-rw-r--r--programs/charon/charon/encoding/payloads/transform_attribute.h154
-rw-r--r--programs/charon/charon/encoding/payloads/transform_substructure.c485
-rw-r--r--programs/charon/charon/encoding/payloads/transform_substructure.h198
-rw-r--r--programs/charon/charon/encoding/payloads/ts_payload.c365
-rw-r--r--programs/charon/charon/encoding/payloads/ts_payload.h152
-rw-r--r--programs/charon/charon/encoding/payloads/unknown_payload.c207
-rw-r--r--programs/charon/charon/encoding/payloads/unknown_payload.h95
-rw-r--r--programs/charon/charon/encoding/payloads/vendor_id_payload.c227
-rw-r--r--programs/charon/charon/encoding/payloads/vendor_id_payload.h103
-rw-r--r--programs/charon/charon/network/Makefile.network24
-rw-r--r--programs/charon/charon/network/packet.c189
-rw-r--r--programs/charon/charon/network/packet.h135
-rw-r--r--programs/charon/charon/network/socket.c457
-rw-r--r--programs/charon/charon/network/socket.h128
-rw-r--r--programs/charon/charon/queues/Makefile.queues30
-rw-r--r--programs/charon/charon/queues/event_queue.c349
-rw-r--r--programs/charon/charon/queues/event_queue.h117
-rw-r--r--programs/charon/charon/queues/job_queue.c153
-rw-r--r--programs/charon/charon/queues/job_queue.h99
-rw-r--r--programs/charon/charon/queues/jobs/Makefile.jobs40
-rw-r--r--programs/charon/charon/queues/jobs/delete_established_ike_sa_job.c90
-rw-r--r--programs/charon/charon/queues/jobs/delete_established_ike_sa_job.h78
-rw-r--r--programs/charon/charon/queues/jobs/delete_half_open_ike_sa_job.c90
-rw-r--r--programs/charon/charon/queues/jobs/delete_half_open_ike_sa_job.h79
-rw-r--r--programs/charon/charon/queues/jobs/incoming_packet_job.c102
-rw-r--r--programs/charon/charon/queues/jobs/incoming_packet_job.h78
-rw-r--r--programs/charon/charon/queues/jobs/initiate_ike_sa_job.c101
-rw-r--r--programs/charon/charon/queues/jobs/initiate_ike_sa_job.h75
-rw-r--r--programs/charon/charon/queues/jobs/job.c34
-rw-r--r--programs/charon/charon/queues/jobs/job.h120
-rw-r--r--programs/charon/charon/queues/jobs/retransmit_request_job.c132
-rw-r--r--programs/charon/charon/queues/jobs/retransmit_request_job.h105
-rw-r--r--programs/charon/charon/queues/send_queue.c153
-rw-r--r--programs/charon/charon/queues/send_queue.h100
-rw-r--r--programs/charon/charon/sa/Makefile.sa37
-rw-r--r--programs/charon/charon/sa/authenticator.c405
-rw-r--r--programs/charon/charon/sa/authenticator.h138
-rw-r--r--programs/charon/charon/sa/child_sa.c590
-rw-r--r--programs/charon/charon/sa/child_sa.h149
-rw-r--r--programs/charon/charon/sa/ike_sa.c1199
-rw-r--r--programs/charon/charon/sa/ike_sa.h462
-rw-r--r--programs/charon/charon/sa/ike_sa_id.c185
-rw-r--r--programs/charon/charon/sa/ike_sa_id.h146
-rw-r--r--programs/charon/charon/sa/ike_sa_manager.c812
-rw-r--r--programs/charon/charon/sa/ike_sa_manager.h185
-rw-r--r--programs/charon/charon/sa/states/Makefile.states43
-rw-r--r--programs/charon/charon/sa/states/ike_auth_requested.c671
-rw-r--r--programs/charon/charon/sa/states/ike_auth_requested.h72
-rw-r--r--programs/charon/charon/sa/states/ike_sa_established.c239
-rw-r--r--programs/charon/charon/sa/states/ike_sa_established.h64
-rw-r--r--programs/charon/charon/sa/states/ike_sa_init_requested.c798
-rw-r--r--programs/charon/charon/sa/states/ike_sa_init_requested.h68
-rw-r--r--programs/charon/charon/sa/states/ike_sa_init_responded.c695
-rw-r--r--programs/charon/charon/sa/states/ike_sa_init_responded.h73
-rw-r--r--programs/charon/charon/sa/states/initiator_init.c360
-rw-r--r--programs/charon/charon/sa/states/initiator_init.h84
-rw-r--r--programs/charon/charon/sa/states/responder_init.c568
-rw-r--r--programs/charon/charon/sa/states/responder_init.h68
-rw-r--r--programs/charon/charon/sa/states/state.c37
-rw-r--r--programs/charon/charon/sa/states/state.h166
-rw-r--r--programs/charon/charon/threads/Makefile.threads39
-rw-r--r--programs/charon/charon/threads/kernel_interface.c729
-rw-r--r--programs/charon/charon/threads/kernel_interface.h185
-rw-r--r--programs/charon/charon/threads/receiver.c128
-rw-r--r--programs/charon/charon/threads/receiver.h67
-rw-r--r--programs/charon/charon/threads/scheduler.c124
-rw-r--r--programs/charon/charon/threads/scheduler.h67
-rw-r--r--programs/charon/charon/threads/sender.c126
-rw-r--r--programs/charon/charon/threads/sender.h63
-rwxr-xr-xprograms/charon/charon/threads/stroke_interface.c661
-rw-r--r--programs/charon/charon/threads/stroke_interface.h86
-rw-r--r--programs/charon/charon/threads/thread_pool.c623
-rw-r--r--programs/charon/charon/threads/thread_pool.h78
-rw-r--r--programs/charon/doc/Architecture.txt56
-rw-r--r--programs/charon/doc/Known-bugs.txt6
-rw-r--r--programs/charon/doc/Todo-list.txt49
-rw-r--r--programs/charon/lib/Makefile.lib31
-rw-r--r--programs/charon/lib/asn1/Makefile.asn129
-rw-r--r--programs/charon/lib/asn1/asn1.c738
-rw-r--r--programs/charon/lib/asn1/asn1.h137
-rw-r--r--programs/charon/lib/asn1/oid.c197
-rw-r--r--programs/charon/lib/asn1/oid.h80
-rw-r--r--programs/charon/lib/asn1/oid.pl127
-rw-r--r--programs/charon/lib/asn1/oid.txt184
-rwxr-xr-xprograms/charon/lib/asn1/pem.c343
-rwxr-xr-xprograms/charon/lib/asn1/pem.h25
-rw-r--r--programs/charon/lib/asn1/ttodata.c374
-rw-r--r--programs/charon/lib/asn1/ttodata.h30
-rw-r--r--programs/charon/lib/crypto/Makefile.transforms37
-rw-r--r--programs/charon/lib/crypto/crypters/Makefile.crypters23
-rw-r--r--programs/charon/lib/crypto/crypters/aes_cbc_crypter.c1627
-rw-r--r--programs/charon/lib/crypto/crypters/aes_cbc_crypter.h61
-rw-r--r--programs/charon/lib/crypto/crypters/crypter.c63
-rw-r--r--programs/charon/lib/crypto/crypters/crypter.h153
-rw-r--r--programs/charon/lib/crypto/diffie_hellman.c615
-rw-r--r--programs/charon/lib/crypto/diffie_hellman.h149
-rw-r--r--programs/charon/lib/crypto/hashers/Makefile.hashers27
-rw-r--r--programs/charon/lib/crypto/hashers/hasher.c60
-rw-r--r--programs/charon/lib/crypto/hashers/hasher.h147
-rw-r--r--programs/charon/lib/crypto/hashers/md5_hasher.c394
-rw-r--r--programs/charon/lib/crypto/hashers/md5_hasher.h60
-rw-r--r--programs/charon/lib/crypto/hashers/sha1_hasher.c269
-rw-r--r--programs/charon/lib/crypto/hashers/sha1_hasher.h60
-rw-r--r--programs/charon/lib/crypto/hmac.c209
-rw-r--r--programs/charon/lib/crypto/hmac.h118
-rw-r--r--programs/charon/lib/crypto/prf_plus.c157
-rw-r--r--programs/charon/lib/crypto/prf_plus.h93
-rw-r--r--programs/charon/lib/crypto/prfs/Makefile.prfs23
-rw-r--r--programs/charon/lib/crypto/prfs/hmac_prf.c117
-rw-r--r--programs/charon/lib/crypto/prfs/hmac_prf.h64
-rw-r--r--programs/charon/lib/crypto/prfs/prf.c67
-rw-r--r--programs/charon/lib/crypto/prfs/prf.h136
-rw-r--r--programs/charon/lib/crypto/rsa/Makefile.rsa23
-rw-r--r--programs/charon/lib/crypto/rsa/rsa_private_key.c772
-rw-r--r--programs/charon/lib/crypto/rsa/rsa_private_key.h185
-rw-r--r--programs/charon/lib/crypto/rsa/rsa_public_key.c458
-rw-r--r--programs/charon/lib/crypto/rsa/rsa_public_key.h153
-rw-r--r--programs/charon/lib/crypto/signers/Makefile.signers23
-rw-r--r--programs/charon/lib/crypto/signers/hmac_signer.c169
-rw-r--r--programs/charon/lib/crypto/signers/hmac_signer.h58
-rw-r--r--programs/charon/lib/crypto/signers/signer.c59
-rw-r--r--programs/charon/lib/crypto/signers/signer.h147
-rwxr-xr-xprograms/charon/lib/crypto/x509.c937
-rwxr-xr-xprograms/charon/lib/crypto/x509.h136
-rw-r--r--programs/charon/lib/definitions.c40
-rw-r--r--programs/charon/lib/definitions.h120
-rw-r--r--programs/charon/lib/library.c42
-rw-r--r--programs/charon/lib/library.h100
-rw-r--r--programs/charon/lib/types.c115
-rw-r--r--programs/charon/lib/types.h186
-rw-r--r--programs/charon/lib/utils/Makefile.utils47
-rw-r--r--programs/charon/lib/utils/host.c365
-rw-r--r--programs/charon/lib/utils/host.h225
-rw-r--r--programs/charon/lib/utils/identification.c1167
-rw-r--r--programs/charon/lib/utils/identification.h245
-rw-r--r--programs/charon/lib/utils/iterator.h153
-rw-r--r--programs/charon/lib/utils/leak_detective.c540
-rw-r--r--programs/charon/lib/utils/leak_detective.h50
-rw-r--r--programs/charon/lib/utils/linked_list.c727
-rw-r--r--programs/charon/lib/utils/linked_list.h203
-rw-r--r--programs/charon/lib/utils/logger.c342
-rw-r--r--programs/charon/lib/utils/logger.h198
-rw-r--r--programs/charon/lib/utils/logger_manager.c220
-rw-r--r--programs/charon/lib/utils/logger_manager.h160
-rw-r--r--programs/charon/lib/utils/randomizer.c164
-rw-r--r--programs/charon/lib/utils/randomizer.h110
-rw-r--r--programs/charon/lib/utils/tester.c256
-rw-r--r--programs/charon/lib/utils/tester.h148
-rw-r--r--programs/charon/patches/strongswan-2.7.0.patch874
-rw-r--r--programs/charon/scripts/alice-key.derbin0 -> 1190 bytes
-rw-r--r--programs/charon/scripts/alice.derbin0 -> 764 bytes
-rw-r--r--programs/charon/scripts/bob-key.derbin0 -> 1187 bytes
-rw-r--r--programs/charon/scripts/bob.derbin0 -> 759 bytes
-rw-r--r--programs/charon/scripts/complex1.derbin0 -> 934 bytes
-rw-r--r--programs/charon/scripts/complex2.derbin0 -> 956 bytes
-rwxr-xr-xprograms/charon/scripts/daemon-loop.sh13
-rwxr-xr-xprograms/charon/scripts/deleteline9
-rwxr-xr-xprograms/charon/scripts/replace9
-rwxr-xr-xprograms/charon/scripts/to-alice.sh27
-rwxr-xr-xprograms/charon/scripts/to-bob.sh27
-rw-r--r--programs/charon/stroke/Makefile.stroke17
-rw-r--r--programs/charon/stroke/stroke.c304
-rw-r--r--programs/charon/stroke/stroke.h91
-rw-r--r--programs/charon/testing/Makefile.testcases139
-rw-r--r--programs/charon/testing/aes_cbc_crypter_test.c201
-rw-r--r--programs/charon/testing/aes_cbc_crypter_test.h38
-rw-r--r--programs/charon/testing/certificate_test.c112
-rw-r--r--programs/charon/testing/certificate_test.h42
-rw-r--r--programs/charon/testing/child_sa_test.c101
-rw-r--r--programs/charon/testing/child_sa_test.h42
-rw-r--r--programs/charon/testing/connection_test.c82
-rw-r--r--programs/charon/testing/connection_test.h38
-rw-r--r--programs/charon/testing/diffie_hellman_test.c76
-rw-r--r--programs/charon/testing/diffie_hellman_test.h37
-rw-r--r--programs/charon/testing/encryption_payload_test.c139
-rw-r--r--programs/charon/testing/encryption_payload_test.h37
-rw-r--r--programs/charon/testing/event_queue_test.c143
-rw-r--r--programs/charon/testing/event_queue_test.h39
-rw-r--r--programs/charon/testing/generator_test.c1410
-rw-r--r--programs/charon/testing/generator_test.h183
-rw-r--r--programs/charon/testing/hasher_test.c170
-rw-r--r--programs/charon/testing/hasher_test.h49
-rw-r--r--programs/charon/testing/hmac_signer_test.c203
-rw-r--r--programs/charon/testing/hmac_signer_test.h46
-rw-r--r--programs/charon/testing/hmac_test.c408
-rw-r--r--programs/charon/testing/hmac_test.h49
-rw-r--r--programs/charon/testing/identification_test.c166
-rw-r--r--programs/charon/testing/identification_test.h37
-rw-r--r--programs/charon/testing/ike_sa_id_test.c84
-rw-r--r--programs/charon/testing/ike_sa_id_test.h40
-rw-r--r--programs/charon/testing/ike_sa_manager_test.c185
-rw-r--r--programs/charon/testing/ike_sa_manager_test.h39
-rw-r--r--programs/charon/testing/ike_sa_test.c56
-rw-r--r--programs/charon/testing/ike_sa_test.h37
-rw-r--r--programs/charon/testing/job_queue_test.c132
-rw-r--r--programs/charon/testing/job_queue_test.h40
-rw-r--r--programs/charon/testing/kernel_interface_test.c84
-rw-r--r--programs/charon/testing/kernel_interface_test.h38
-rw-r--r--programs/charon/testing/leak_detective_test.c79
-rw-r--r--programs/charon/testing/leak_detective_test.h38
-rw-r--r--programs/charon/testing/linked_list_test.c241
-rw-r--r--programs/charon/testing/linked_list_test.h74
-rw-r--r--programs/charon/testing/packet_test.c55
-rw-r--r--programs/charon/testing/packet_test.h37
-rw-r--r--programs/charon/testing/parser_test.c963
-rw-r--r--programs/charon/testing/parser_test.h170
-rw-r--r--programs/charon/testing/policy_test.c246
-rw-r--r--programs/charon/testing/policy_test.h42
-rw-r--r--programs/charon/testing/prf_plus_test.c145
-rw-r--r--programs/charon/testing/prf_plus_test.h38
-rw-r--r--programs/charon/testing/proposal_test.c98
-rw-r--r--programs/charon/testing/proposal_test.h42
-rw-r--r--programs/charon/testing/rsa_test.c226
-rw-r--r--programs/charon/testing/rsa_test.h41
-rw-r--r--programs/charon/testing/scheduler_test.c92
-rw-r--r--programs/charon/testing/scheduler_test.h37
-rw-r--r--programs/charon/testing/send_queue_test.c142
-rw-r--r--programs/charon/testing/send_queue_test.h40
-rw-r--r--programs/charon/testing/sender_test.c88
-rw-r--r--programs/charon/testing/sender_test.h37
-rw-r--r--programs/charon/testing/socket_test.c82
-rw-r--r--programs/charon/testing/socket_test.h38
-rw-r--r--programs/charon/testing/testcases.c263
-rw-r--r--programs/charon/testing/thread_pool_test.c41
-rw-r--r--programs/charon/testing/thread_pool_test.h37
299 files changed, 61241 insertions, 0 deletions
diff --git a/programs/charon/Doxyfile b/programs/charon/Doxyfile
new file mode 100644
index 000000000..5ee25a839
--- /dev/null
+++ b/programs/charon/Doxyfile
@@ -0,0 +1,220 @@
+# Doxyfile 1.4.1-KDevelop
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = "charon"
+PROJECT_NUMBER = 1.0
+OUTPUT_DIRECTORY = doc/api
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+USE_WINDOWS_ENCODING = NO
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF =
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = YES
+STRIP_FROM_PATH =
+STRIP_FROM_INC_PATH =
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = YES
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP = YES
+INHERIT_DOCS = YES
+DISTRIBUTE_GROUP_DOC = NO
+TAB_SIZE = 1
+ALIASES =
+OPTIMIZE_OUTPUT_FOR_C = NO
+OPTIMIZE_OUTPUT_JAVA = NO
+SUBGROUPING = YES
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL = NO
+EXTRACT_PRIVATE = NO
+EXTRACT_STATIC = NO
+EXTRACT_LOCAL_CLASSES = NO
+EXTRACT_LOCAL_METHODS = NO
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = YES
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = NO
+SORT_BY_SCOPE_NAME = NO
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = NO
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST = YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = YES
+SHOW_DIRECTORIES = NO
+FILE_VERSION_FILTER =
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_NO_PARAMDOC = NO
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = ./
+FILE_PATTERNS = *.h *.txt
+RECURSIVE = YES
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS =
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_PATTERNS =
+FILTER_SOURCE_FILES = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = NO
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = NO
+REFERENCED_BY_RELATION = NO
+REFERENCES_RELATION = NO
+VERBATIM_HEADERS = YES
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = NO
+COLS_IN_ALPHA_INDEX = 5
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT = .
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = YES
+ENUM_VALUES_PER_LINE = 1
+GENERATE_TREEVIEW = YES
+TREEVIEW_WIDTH = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = NO
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = NO
+USE_PDFLATEX = NO
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = YES
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = NO
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = YES
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED = LEAK_DETECTIVE
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = YES
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = NO
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+GROUP_GRAPHS = YES
+UML_LOOK = NO
+TEMPLATE_RELATIONS = NO
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+CALL_GRAPH = NO
+GRAPHICAL_HIERARCHY = YES
+DIRECTORY_GRAPH = YES
+DOT_IMAGE_FORMAT = png
+DOT_PATH =
+DOTFILE_DIRS =
+MAX_DOT_GRAPH_WIDTH = 1024
+MAX_DOT_GRAPH_HEIGHT = 1024
+MAX_DOT_GRAPH_DEPTH = 0
+DOT_TRANSPARENT = NO
+DOT_MULTI_TARGETS = NO
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = NO
diff --git a/programs/charon/Makefile b/programs/charon/Makefile
new file mode 100644
index 000000000..b69438b84
--- /dev/null
+++ b/programs/charon/Makefile
@@ -0,0 +1,99 @@
+# Copyright (C) 2005 Jan Hutter, Martin Willi
+# Hochschule fuer Technik Rapperswil
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+
+FREESWANSRCDIR=../..
+# include strongswan Makefile, if charon sits in its tree
+ifeq ($(shell ls $(FREESWANSRCDIR)/Makefile.inc 2>&1), ../../Makefile.inc)
+ include ${FREESWANSRCDIR}/Makefile.inc
+else
+# Defaults if not using strongswan defines
+ USE_LEAK_DETECTIVE?=false
+ INSTALL=install
+ INSTBINFLAGS=-b --suffix=.old
+ LIBEXECDIR=/usr/local/libexec/ipsec
+ SHAREDLIBDIR=/usr/local/lib
+endif
+
+
+BUILD_DIR= ./bin/
+
+BINNAMECHARON= $(BUILD_DIR)charon
+BINNAMESTROKE= $(BUILD_DIR)stroke
+BINNAMETEST= $(BUILD_DIR)run_tests
+BINNAMELIB= $(BUILD_DIR)libstrongswan.so
+
+MAIN_DIR= ./
+
+CFLAGS= -Icharon -Ilib -Istroke -fPIC -Wall -g
+ifeq ($(USE_LEAK_DETECTIVE),true)
+ CFLAGS+= -DLEAK_DETECTIVE
+endif
+
+# objects is extended by each included Makefile
+CHARON_OBJS=
+LIB_OBJS=
+TEST_OBJS=
+
+all : programs
+
+include $(MAIN_DIR)charon/Makefile.charon
+include $(MAIN_DIR)lib/Makefile.lib
+include $(MAIN_DIR)stroke/Makefile.stroke
+include $(MAIN_DIR)testing/Makefile.testcases
+
+programs : $(BINNAMECHARON) $(BINNAMESTROKE)
+
+test : $(BINNAMETEST)
+ LD_LIBRARY_PATH=$(BUILD_DIR) $(BINNAMETEST)
+
+run : $(BINNAMECHARON)
+ LD_LIBRARY_PATH=$(BUILD_DIR) $(BINNAMECHARON)
+
+apidoc :
+ doxygen Doxyfile
+
+build_dir:
+ mkdir -p $(BUILD_DIR)
+
+$(BINNAMELIB) : build_dir $(LIB_OBJS)
+ $(CC) -lpthread -ldl -lgmp -shared $(LIB_OBJS) -o $@
+
+$(BINNAMECHARON) : build_dir $(CHARON_OBJS) $(BINNAMELIB) $(BUILD_DIR)daemon.o
+ $(CC) -L./bin -lstrongswan $(CHARON_OBJS) $(BUILD_DIR)daemon.o -o $@
+
+$(BINNAMETEST) : build_dir $(CHARON_OBJS) $(TEST_OBJS) $(BINNAMELIB) $(BUILD_DIR)testcases.o
+ $(CC) -L./bin -lstrongswan $(LDFLAGS) $(CHARON_OBJS) $(TEST_OBJS) $(BUILD_DIR)testcases.o -o $@
+
+$(BINNAMESTROKE) : build_dir $(BINNAMELIB) $(BUILD_DIR)stroke.o
+ $(CC) $(LDFLAGS) $(CFLAGS) $(BUILD_DIR)stroke.o -o $@
+
+install : $(BINNAMECHARON) $(BINNAMESTROKE)
+ $(INSTALL) $(INSTBINFLAGS) $(BINNAMECHARON) $(BINNAMESTROKE) $(LIBEXECDIR)
+ $(INSTALL) $(INSTBINFLAGS) $(BINNAMELIB) $(SHAREDLIBDIR)
+
+install_file_list:
+ @echo $(LIBEXECDIR)/charon
+ @echo $(LIBEXECDIR)/stroke
+ @echo $(SHAREDLIBDIR)/libstrongswan.so
+
+clean :
+ rm -fR $(BUILD_DIR)
+
+cleanall: clean
+
+distclean: clean
+
+mostlyclean: clean
+
+realclean: clean
diff --git a/programs/charon/charon.kdevelop b/programs/charon/charon.kdevelop
new file mode 100644
index 000000000..270e815c4
--- /dev/null
+++ b/programs/charon/charon.kdevelop
@@ -0,0 +1,105 @@
+<?xml version = '1.0'?>
+<kdevelop>
+ <general>
+ <author>Martin Willi</author>
+ <email>martin@strongswan.org</email>
+ <version>$VERSION$</version>
+ <projectmanagement>KDevCustomProject</projectmanagement>
+ <primarylanguage>C</primarylanguage>
+ <ignoreparts/>
+ </general>
+ <kdevcustomproject>
+ <run>
+ <mainprogram>Source</mainprogram>
+ <directoryradio>executable</directoryradio>
+ </run>
+ <general>
+ <activedir/>
+ </general>
+ </kdevcustomproject>
+ <kdevdebugger>
+ <general>
+ <dbgshell/>
+ </general>
+ </kdevdebugger>
+ <kdevdoctreeview>
+ <ignoretocs>
+ <toc>ada</toc>
+ <toc>ada_bugs_gcc</toc>
+ <toc>bash</toc>
+ <toc>bash_bugs</toc>
+ <toc>clanlib</toc>
+ <toc>fortran_bugs_gcc</toc>
+ <toc>gnome1</toc>
+ <toc>gnustep</toc>
+ <toc>gtk</toc>
+ <toc>gtk_bugs</toc>
+ <toc>haskell</toc>
+ <toc>haskell_bugs_ghc</toc>
+ <toc>java_bugs_gcc</toc>
+ <toc>java_bugs_sun</toc>
+ <toc>kde2book</toc>
+ <toc>libstdc++</toc>
+ <toc>opengl</toc>
+ <toc>pascal_bugs_fp</toc>
+ <toc>php</toc>
+ <toc>php_bugs</toc>
+ <toc>perl</toc>
+ <toc>perl_bugs</toc>
+ <toc>python</toc>
+ <toc>python_bugs</toc>
+ <toc>qt-kdev3</toc>
+ <toc>ruby</toc>
+ <toc>ruby_bugs</toc>
+ <toc>sdl</toc>
+ <toc>stl</toc>
+ <toc>sw</toc>
+ <toc>w3c-dom-level2-html</toc>
+ <toc>w3c-svg</toc>
+ <toc>w3c-uaag10</toc>
+ <toc>wxwidgets_bugs</toc>
+ </ignoretocs>
+ <ignoreqt_xml>
+ <toc>Guide to the Qt Translation Tools</toc>
+ <toc>Qt Assistant Manual</toc>
+ <toc>Qt Designer Manual</toc>
+ <toc>Qt Reference Documentation</toc>
+ <toc>qmake User Guide</toc>
+ </ignoreqt_xml>
+ <ignoredoxygen>
+ <toc>KDE Libraries (Doxygen)</toc>
+ </ignoredoxygen>
+ </kdevdoctreeview>
+ <kdevfilecreate>
+ <filetypes/>
+ <useglobaltypes>
+ <type ext="c" />
+ <type ext="h" />
+ </useglobaltypes>
+ </kdevfilecreate>
+ <kdevcppsupport>
+ <references/>
+ <codecompletion>
+ <includeGlobalFunctions>true</includeGlobalFunctions>
+ <includeTypes>true</includeTypes>
+ <includeEnums>true</includeEnums>
+ <includeTypedefs>false</includeTypedefs>
+ <automaticCodeCompletion>true</automaticCodeCompletion>
+ <automaticArgumentsHint>true</automaticArgumentsHint>
+ <automaticHeaderCompletion>true</automaticHeaderCompletion>
+ <codeCompletionDelay>250</codeCompletionDelay>
+ <argumentsHintDelay>400</argumentsHintDelay>
+ <headerCompletionDelay>250</headerCompletionDelay>
+ </codecompletion>
+ </kdevcppsupport>
+ <kdevfileview>
+ <groups>
+ <hidenonprojectfiles>false</hidenonprojectfiles>
+ <hidenonlocation>false</hidenonlocation>
+ </groups>
+ <tree>
+ <hidepatterns>*.o,*.lo,CVS</hidepatterns>
+ <hidenonprojectfiles>false</hidenonprojectfiles>
+ </tree>
+ </kdevfileview>
+</kdevelop>
diff --git a/programs/charon/charon/Makefile.charon b/programs/charon/charon/Makefile.charon
new file mode 100644
index 000000000..336495db9
--- /dev/null
+++ b/programs/charon/charon/Makefile.charon
@@ -0,0 +1,25 @@
+# Copyright (C) 2006 Martin Willi
+# Hochschule fuer Technik Rapperswil
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+CHARON_DIR= $(MAIN_DIR)charon/
+
+$(BUILD_DIR)daemon.o : $(CHARON_DIR)daemon.c $(CHARON_DIR)daemon.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+
+include $(CHARON_DIR)network/Makefile.network
+include $(CHARON_DIR)config/Makefile.config
+include $(CHARON_DIR)encoding/Makefile.encoding
+include $(CHARON_DIR)queues/Makefile.queues
+include $(CHARON_DIR)sa/Makefile.sa
+include $(CHARON_DIR)threads/Makefile.threads \ No newline at end of file
diff --git a/programs/charon/charon/config/Makefile.config b/programs/charon/charon/config/Makefile.config
new file mode 100644
index 000000000..d4638b318
--- /dev/null
+++ b/programs/charon/charon/config/Makefile.config
@@ -0,0 +1,32 @@
+# Copyright (C) 2005 Jan Hutter, Martin Willi
+# Hochschule fuer Technik Rapperswil
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+
+CONFIG_DIR= $(CHARON_DIR)config/
+
+
+CHARON_OBJS+= $(BUILD_DIR)traffic_selector.o
+$(BUILD_DIR)traffic_selector.o : $(CONFIG_DIR)traffic_selector.c $(CONFIG_DIR)traffic_selector.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)proposal.o
+$(BUILD_DIR)proposal.o : $(CONFIG_DIR)proposal.c $(CONFIG_DIR)proposal.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)configuration.o
+$(BUILD_DIR)configuration.o : $(CONFIG_DIR)configuration.c $(CONFIG_DIR)configuration.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+include $(CONFIG_DIR)connections/Makefile.connections
+include $(CONFIG_DIR)credentials/Makefile.credentials
+include $(CONFIG_DIR)policies/Makefile.policies \ No newline at end of file
diff --git a/programs/charon/charon/config/configuration.c b/programs/charon/charon/config/configuration.c
new file mode 100755
index 000000000..eac1bd43a
--- /dev/null
+++ b/programs/charon/charon/config/configuration.c
@@ -0,0 +1,112 @@
+/**
+ * @file configuration.c
+ *
+ * @brief Implementation of configuration_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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stdlib.h>
+
+#include "configuration.h"
+
+#include <types.h>
+
+/**
+ * First retransmit timeout in milliseconds.
+ * Timeout value is increasing in each retransmit round.
+ */
+#define RETRANSMIT_TIMEOUT 3000
+
+/**
+ * Timeout in milliseconds after that a half open IKE_SA gets deleted.
+ */
+#define HALF_OPEN_IKE_SA_TIMEOUT 30000
+
+/**
+ * Max retransmit count.
+ * 0 for infinite. The max time a half open IKE_SA is alive is set by
+ * RETRANSMIT_TIMEOUT.
+ */
+#define MAX_RETRANSMIT_COUNT 0
+
+
+typedef struct private_configuration_t private_configuration_t;
+
+/**
+ * Private data of an configuration_t object.
+ */
+struct private_configuration_t {
+
+ /**
+ * Public part of configuration_t object.
+ */
+ configuration_t public;
+
+};
+
+/**
+ * Implementation of configuration_t.get_retransmit_timeout.
+ */
+static status_t get_retransmit_timeout (private_configuration_t *this, u_int32_t retransmit_count, u_int32_t *timeout)
+{
+ int new_timeout = RETRANSMIT_TIMEOUT, i;
+ if (retransmit_count > MAX_RETRANSMIT_COUNT && MAX_RETRANSMIT_COUNT != 0)
+ {
+ return FAILED;
+ }
+
+ for (i = 0; i < retransmit_count; i++)
+ {
+ new_timeout *= 2;
+ }
+
+ *timeout = new_timeout;
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of configuration_t.get_half_open_ike_sa_timeout.
+ */
+static u_int32_t get_half_open_ike_sa_timeout (private_configuration_t *this)
+{
+ return HALF_OPEN_IKE_SA_TIMEOUT;
+}
+
+/**
+ * Implementation of configuration_t.destroy.
+ */
+static void destroy(private_configuration_t *this)
+{
+ free(this);
+}
+
+/*
+ * Described in header-file
+ */
+configuration_t *configuration_create()
+{
+ private_configuration_t *this = malloc_thing(private_configuration_t);
+
+ /* public functions */
+ this->public.destroy = (void(*)(configuration_t*))destroy;
+ this->public.get_retransmit_timeout = (status_t (*) (configuration_t *, u_int32_t retransmit_count, u_int32_t *timeout))get_retransmit_timeout;
+ this->public.get_half_open_ike_sa_timeout = (u_int32_t (*) (configuration_t *)) get_half_open_ike_sa_timeout;
+
+ return (&this->public);
+}
diff --git a/programs/charon/charon/config/configuration.h b/programs/charon/charon/config/configuration.h
new file mode 100755
index 000000000..6b741f9fb
--- /dev/null
+++ b/programs/charon/charon/config/configuration.h
@@ -0,0 +1,89 @@
+/**
+ * @file configuration.h
+ *
+ * @brief Interface configuration_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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef CONFIGURATION_H_
+#define CONFIGURATION_H_
+
+#include <types.h>
+
+
+typedef struct configuration_t configuration_t;
+
+/**
+ * @brief The interface for various daemon related configs.
+ *
+ * @b Constructors:
+ * - configuration_create()
+ *
+ * @ingroup config
+ */
+struct configuration_t {
+
+ /**
+ * @brief Returns the retransmit timeout.
+ *
+ * The timeout values are managed by the configuration, so
+ * another backoff algorithm may be implemented here.
+ *
+ * @param this calling object
+ * @param retransmit_count number of times a message was retransmitted so far
+ * @param[out] timeout the new retransmit timeout in milliseconds
+ *
+ * @return
+ * - FAILED, if the message should not be retransmitted
+ * - SUCCESS
+ */
+ status_t (*get_retransmit_timeout) (configuration_t *this, u_int32_t retransmit_count, u_int32_t *timeout);
+
+ /**
+ * @brief Returns the timeout for an half open IKE_SA in ms.
+ *
+ * Half open means that the IKE_SA is still in one of the following states:
+ * - INITIATOR_INIT
+ * - RESPONDER_INIT
+ * - IKE_SA_INIT_REQUESTED
+ * - IKE_SA_INIT_RESPONDED
+ * - IKE_AUTH_REQUESTED
+ *
+ * @param this calling object
+ * @return timeout in milliseconds (ms)
+ */
+ u_int32_t (*get_half_open_ike_sa_timeout) (configuration_t *this);
+
+ /**
+ * @brief Destroys a configuration_t object.
+ *
+ * @param this calling object
+ */
+ void (*destroy) (configuration_t *this);
+};
+
+/**
+ * @brief Creates a configuration backend.
+ *
+ * @return static_configuration_t object
+ *
+ * @ingroup config
+ */
+configuration_t *configuration_create();
+
+#endif /*CONFIGURATION_H_*/
diff --git a/programs/charon/charon/config/connections/Makefile.connections b/programs/charon/charon/config/connections/Makefile.connections
new file mode 100644
index 000000000..8fbc983f6
--- /dev/null
+++ b/programs/charon/charon/config/connections/Makefile.connections
@@ -0,0 +1,24 @@
+# Copyright (C) 2006 Martin Willi
+# Hochschule fuer Technik Rapperswil
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+
+CONNECTIONS_DIR= $(CONFIG_DIR)connections/
+
+
+CHARON_OBJS+= $(BUILD_DIR)connection.o
+$(BUILD_DIR)connection.o : $(CONNECTIONS_DIR)connection.c $(CONNECTIONS_DIR)connection.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)local_connection_store.o
+$(BUILD_DIR)local_connection_store.o : $(CONNECTIONS_DIR)local_connection_store.c $(CONNECTIONS_DIR)local_connection_store.h
+ $(CC) $(CFLAGS) -c -o $@ $< \ No newline at end of file
diff --git a/programs/charon/charon/config/connections/connection.c b/programs/charon/charon/config/connections/connection.c
new file mode 100644
index 000000000..74e6762b4
--- /dev/null
+++ b/programs/charon/charon/config/connections/connection.c
@@ -0,0 +1,367 @@
+/**
+ * @file connection.c
+ *
+ * @brief Implementation of connection_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+
+#include "connection.h"
+
+#include <utils/linked_list.h>
+#include <utils/logger.h>
+
+/**
+ * String mappings for auth_method_t.
+ */
+mapping_t auth_method_m[] = {
+ {RSA_DIGITAL_SIGNATURE, "RSA"},
+ {SHARED_KEY_MESSAGE_INTEGRITY_CODE, "SHARED_KEY"},
+ {DSS_DIGITAL_SIGNATURE, "DSS"},
+ {MAPPING_END, NULL}
+};
+
+
+typedef struct private_connection_t private_connection_t;
+
+/**
+ * Private data of an connection_t object
+ */
+struct private_connection_t {
+
+ /**
+ * Public part
+ */
+ connection_t public;
+
+ /**
+ * Name of the connection
+ */
+ char *name;
+
+ /**
+ * ID of us
+ */
+ identification_t *my_id;
+
+ /**
+ * ID of remote peer
+ */
+ identification_t *other_id;
+
+ /**
+ * Host information of my host.
+ */
+ host_t *my_host;
+
+ /**
+ * Host information of other host.
+ */
+ host_t *other_host;
+
+ /**
+ * Method to use for own authentication data
+ */
+ auth_method_t auth_method;
+
+ /**
+ * Supported proposals
+ */
+ linked_list_t *proposals;
+};
+
+/**
+ * Implementation of connection_t.get_name.
+ */
+static char *get_name (private_connection_t *this)
+{
+ return this->name;
+}
+
+/**
+ * Implementation of connection_t.get_my_id.
+ */
+static identification_t *get_my_id (private_connection_t *this)
+{
+ return this->my_id;
+}
+
+/**
+ * Implementation of connection_t.get_other_id.
+ */
+static identification_t *get_other_id(private_connection_t *this)
+{
+ return this->other_id;
+}
+
+/**
+ * Implementation of connection_t.update_my_id
+ */
+static void update_my_id(private_connection_t *this, identification_t *my_id)
+{
+ this->my_id->destroy(this->my_id);
+ this->my_id = my_id;
+}
+
+/**
+ * Implementation of connection_t.update_other_id
+ */
+static void update_other_id(private_connection_t *this, identification_t *other_id)
+{
+ this->other_id->destroy(this->other_id);
+ this->other_id = other_id;
+}
+
+/**
+ * Implementation of connection_t.get_my_host.
+ */
+static host_t * get_my_host (private_connection_t *this)
+{
+ return this->my_host;
+}
+
+/**
+ * Implementation of connection_t.update_my_host.
+ */
+static void update_my_host(private_connection_t *this, host_t *my_host)
+{
+ this->my_host->destroy(this->my_host);
+ this->my_host = my_host;
+}
+
+/**
+ * Implementation of connection_t.update_other_host.
+ */
+static void update_other_host(private_connection_t *this, host_t *other_host)
+{
+ this->other_host->destroy(this->other_host);
+ this->other_host = other_host;
+}
+
+/**
+ * Implementation of connection_t.get_other_host.
+ */
+static host_t * get_other_host (private_connection_t *this)
+{
+ return this->other_host;
+}
+
+/**
+ * Implementation of connection_t.get_proposals.
+ */
+static linked_list_t* get_proposals (private_connection_t *this)
+{
+ return this->proposals;
+}
+
+/**
+ * Implementation of connection_t.select_proposal.
+ */
+static proposal_t *select_proposal(private_connection_t *this, linked_list_t *proposals)
+{
+ iterator_t *stored_iter, *supplied_iter;
+ proposal_t *stored, *supplied, *selected;
+
+ stored_iter = this->proposals->create_iterator(this->proposals, TRUE);
+ supplied_iter = proposals->create_iterator(proposals, TRUE);
+
+ /* compare all stored proposals with all supplied. Stored ones are preferred. */
+ while (stored_iter->has_next(stored_iter))
+ {
+ supplied_iter->reset(supplied_iter);
+ stored_iter->current(stored_iter, (void**)&stored);
+
+ while (supplied_iter->has_next(supplied_iter))
+ {
+ supplied_iter->current(supplied_iter, (void**)&supplied);
+ selected = stored->select(stored, supplied);
+ if (selected)
+ {
+ /* they match, return */
+ stored_iter->destroy(stored_iter);
+ supplied_iter->destroy(supplied_iter);
+ return selected;
+ }
+ }
+ }
+
+ /* no proposal match :-(, will result in a NO_PROPOSAL_CHOSEN... */
+ stored_iter->destroy(stored_iter);
+ supplied_iter->destroy(supplied_iter);
+
+ return NULL;
+}
+
+/**
+ * Implementation of connection_t.add_proposal.
+ */
+static void add_proposal (private_connection_t *this, proposal_t *proposal)
+{
+ this->proposals->insert_last(this->proposals, proposal);
+}
+
+/**
+ * Implementation of connection_t.auth_method_t.
+ */
+static auth_method_t get_auth_method(private_connection_t *this)
+{
+ return this->auth_method;
+}
+
+/**
+ * Implementation of connection_t.get_dh_group.
+ */
+static diffie_hellman_group_t get_dh_group(private_connection_t *this)
+{
+ iterator_t *iterator;
+ proposal_t *proposal;
+ algorithm_t *algo;
+
+ iterator = this->proposals->create_iterator(this->proposals, TRUE);
+ while (iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void**)&proposal);
+ proposal->get_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, &algo);
+ if (algo)
+ {
+ iterator->destroy(iterator);
+ return algo->algorithm;
+ }
+ }
+ iterator->destroy(iterator);
+ return MODP_UNDEFINED;
+}
+
+/**
+ * Implementation of connection_t.check_dh_group.
+ */
+static bool check_dh_group(private_connection_t *this, diffie_hellman_group_t dh_group)
+{
+ iterator_t *prop_iter, *alg_iter;
+ proposal_t *proposal;
+ algorithm_t *algo;
+
+ prop_iter = this->proposals->create_iterator(this->proposals, TRUE);
+ while (prop_iter->has_next(prop_iter))
+ {
+ prop_iter->current(prop_iter, (void**)&proposal);
+ alg_iter = proposal->create_algorithm_iterator(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP);
+ while (alg_iter->has_next(alg_iter))
+ {
+ alg_iter->current(alg_iter, (void**)&algo);
+ if (algo->algorithm == dh_group)
+ {
+ prop_iter->destroy(prop_iter);
+ alg_iter->destroy(alg_iter);
+ return TRUE;
+ }
+ }
+ }
+ prop_iter->destroy(prop_iter);
+ alg_iter->destroy(alg_iter);
+ return FALSE;
+}
+
+/**
+ * Implementation of connection_t.clone.
+ */
+static connection_t *clone(private_connection_t *this)
+{
+ iterator_t *iterator;
+ proposal_t *proposal;
+ private_connection_t *clone = (private_connection_t*)connection_create(
+ this->name,
+ this->my_host->clone(this->my_host),
+ this->other_host->clone(this->other_host),
+ this->my_id->clone(this->my_id),
+ this->other_id->clone(this->other_id),
+ this->auth_method);
+
+ /* clone all proposals */
+ iterator = this->proposals->create_iterator(this->proposals, TRUE);
+ while (iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void**)&proposal);
+ proposal = proposal->clone(proposal);
+ clone->proposals->insert_last(clone->proposals, (void*)proposal);
+ }
+ iterator->destroy(iterator);
+
+ return &clone->public;
+}
+
+/**
+ * Implementation of connection_t.destroy.
+ */
+static void destroy (private_connection_t *this)
+{
+ proposal_t *proposal;
+
+ while (this->proposals->remove_last(this->proposals, (void**)&proposal) == SUCCESS)
+ {
+ proposal->destroy(proposal);
+ }
+ this->proposals->destroy(this->proposals);
+
+ this->my_host->destroy(this->my_host);
+ this->other_host->destroy(this->other_host);
+ this->my_id->destroy(this->my_id);
+ this->other_id->destroy(this->other_id);
+ free(this->name);
+ free(this);
+}
+
+/**
+ * Described in header.
+ */
+connection_t * connection_create(char *name, host_t *my_host, host_t *other_host, identification_t *my_id, identification_t *other_id, auth_method_t auth_method)
+{
+ private_connection_t *this = malloc_thing(private_connection_t);
+
+ /* public functions */
+ this->public.get_name = (char*(*)(connection_t*))get_name;
+ this->public.get_my_id = (identification_t*(*)(connection_t*))get_my_id;
+ this->public.get_other_id = (identification_t*(*)(connection_t*))get_other_id;
+ this->public.get_my_host = (host_t*(*)(connection_t*))get_my_host;
+ this->public.update_my_host = (void(*)(connection_t*,host_t*))update_my_host;
+ this->public.update_other_host = (void(*)(connection_t*,host_t*))update_other_host;
+ this->public.update_my_id = (void(*)(connection_t*,identification_t*))update_my_id;
+ this->public.update_other_id = (void(*)(connection_t*,identification_t*))update_other_id;
+ this->public.get_other_host = (host_t*(*)(connection_t*))get_other_host;
+ this->public.get_proposals = (linked_list_t*(*)(connection_t*))get_proposals;
+ this->public.select_proposal = (proposal_t*(*)(connection_t*,linked_list_t*))select_proposal;
+ this->public.add_proposal = (void(*)(connection_t*, proposal_t*)) add_proposal;
+ this->public.get_auth_method = (auth_method_t(*)(connection_t*)) get_auth_method;
+ this->public.get_dh_group = (diffie_hellman_group_t(*)(connection_t*)) get_dh_group;
+ this->public.check_dh_group = (bool(*)(connection_t*,diffie_hellman_group_t)) check_dh_group;
+ this->public.clone = (connection_t*(*)(connection_t*))clone;
+ this->public.destroy = (void(*)(connection_t*))destroy;
+
+ /* private variables */
+ this->name = strdup(name);
+ this->my_host = my_host;
+ this->other_host = other_host;
+ this->my_id = my_id;
+ this->other_id = other_id;
+ this->auth_method = auth_method;
+
+ this->proposals = linked_list_create();
+
+ return (&this->public);
+}
diff --git a/programs/charon/charon/config/connections/connection.h b/programs/charon/charon/config/connections/connection.h
new file mode 100644
index 000000000..2cb3c20b8
--- /dev/null
+++ b/programs/charon/charon/config/connections/connection.h
@@ -0,0 +1,283 @@
+/**
+ * @file connection.h
+ *
+ * @brief Interface of connection_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef CONNECTION_H_
+#define CONNECTION_H_
+
+#include <types.h>
+#include <utils/host.h>
+#include <utils/linked_list.h>
+#include <utils/identification.h>
+#include <config/proposal.h>
+#include <crypto/diffie_hellman.h>
+
+
+typedef enum auth_method_t auth_method_t;
+
+/**
+ * AUTH Method to use.
+ *
+ * @ingroup config
+ */
+enum auth_method_t {
+ /**
+ * Computed as specified in section 2.15 of RFC using
+ * an RSA private key over a PKCS#1 padded hash.
+ */
+ RSA_DIGITAL_SIGNATURE = 1,
+
+ /**
+ * Computed as specified in section 2.15 of RFC using the
+ * shared key associated with the identity in the ID payload
+ * and the negotiated prf function
+ */
+ SHARED_KEY_MESSAGE_INTEGRITY_CODE = 2,
+
+ /**
+ * Computed as specified in section 2.15 of RFC using a
+ * DSS private key over a SHA-1 hash.
+ */
+ DSS_DIGITAL_SIGNATURE = 3,
+};
+
+/**
+ * string mappings for auth method.
+ *
+ * @ingroup config
+ */
+extern mapping_t auth_method_m[];
+
+
+typedef struct connection_t connection_t;
+
+/**
+ * @brief A connection_t defines the rules to set up an IKE_SA.
+ *
+ *
+ * @b Constructors:
+ * - connection_create()
+ *
+ * @ingroup config
+ */
+struct connection_t {
+
+ /**
+ * @brief Get my ID for this connection.
+ *
+ * Object is NOT getting cloned.
+ *
+ * @param this calling object
+ * @return host information as identification_t object
+ */
+ identification_t *(*get_my_id) (connection_t *this);
+
+ /**
+ * @brief Get others ID for this connection.
+ *
+ * Object is NOT getting cloned.
+ *
+ * @param this calling object
+ * @return host information as identification_t object
+ */
+ identification_t *(*get_other_id) (connection_t *this);
+
+ /**
+ * @brief Get my address as host_t object.
+ *
+ * Object is NOT getting cloned.
+ *
+ * @param this calling object
+ * @return host information as host_t object
+ */
+ host_t *(*get_my_host) (connection_t *this);
+
+ /**
+ * @brief Get others address as host_t object.
+ *
+ * Object is NOT getting cloned.
+ *
+ * @param this calling object
+ * @return host information as host_t object
+ */
+ host_t *(*get_other_host) (connection_t *this);
+
+ /**
+ * @brief Update address of my host.
+ *
+ * It may be necessary to uptdate own address, as it
+ * is set to the default route (0.0.0.0) in some cases.
+ * Old host is destroyed, new one NOT cloned.
+ *
+ * @param this calling object
+ * @param my_host new host to set as my_host
+ */
+ void (*update_my_host) (connection_t *this, host_t *my_host);
+
+ /**
+ * @brief Update address of remote host.
+ *
+ * It may be necessary to uptdate remote address, as a
+ * connection may define %any (0.0.0.0) or a subnet.
+ * Old host is destroyed, new one NOT cloned.
+ *
+ * @param this calling object
+ * @param my_host new host to set as other_host
+ */
+ void (*update_other_host) (connection_t *this, host_t *other_host);
+
+ /**
+ * @brief Update own ID.
+ *
+ * It may be necessary to uptdate own ID, as it
+ * is set to %any or to e.g. *@strongswan.org in
+ * some cases.
+ * Old ID is destroyed, new one NOT cloned.
+ *
+ * @param this calling object
+ * @param my_id new ID to set as my_id
+ */
+ void (*update_my_id) (connection_t *this, identification_t *my_id);
+
+ /**
+ * @brief Update others ID.
+ *
+ * It may be necessary to uptdate others ID, as it
+ * is set to %any or to e.g. *@strongswan.org in
+ * some cases.
+ * Old ID is destroyed, new one NOT cloned.
+ *
+ * @param this calling object
+ * @param other_id new ID to set as other_id
+ */
+ void (*update_other_id) (connection_t *this, identification_t *other_id);
+
+ /**
+ * @brief Returns a list of all supported proposals.
+ *
+ * Returned list is still owned by connection and MUST NOT
+ * modified or destroyed.
+ *
+ * @param this calling object
+ * @return list containing all the proposals
+ */
+ linked_list_t *(*get_proposals) (connection_t *this);
+
+ /**
+ * @brief 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) (connection_t *this, proposal_t *proposal);
+
+ /**
+ * @brief Select a proposed from suggested proposals.
+ *
+ * Returned proposal must be destroyed after usage.
+ *
+ * @param this calling object
+ * @param proposals list of proposals to select from
+ * @return selected proposal, or NULL if none matches.
+ */
+ proposal_t *(*select_proposal) (connection_t *this, linked_list_t *proposals);
+
+ /**
+ * @brief Get the authentication method to use
+ *
+ * @param this calling object
+ * @return authentication method
+ */
+ auth_method_t (*get_auth_method) (connection_t *this);
+
+ /**
+ * @brief Get the connection name.
+ *
+ * Name must not be freed, since it points to
+ * internal data.
+ *
+ * @param this calling object
+ * @return name of the connection
+ */
+ char* (*get_name) (connection_t *this);
+
+ /**
+ * @brief Get the DH group to use for connection initialization.
+ *
+ * @param this calling object
+ * @return dh group to use for initialization
+ */
+ diffie_hellman_group_t (*get_dh_group) (connection_t *this);
+
+ /**
+ * @brief Check if a suggested dh group is acceptable.
+ *
+ * If we guess a wrong DH group for IKE_SA_INIT, the other
+ * peer will send us a offer. But is this acceptable for us?
+ *
+ * @param this calling object
+ * @return TRUE if group acceptable
+ */
+ bool (*check_dh_group) (connection_t *this, diffie_hellman_group_t dh_group);
+
+ /**
+ * @brief Clone a connection_t object.
+ *
+ * @param this connection to clone
+ * @return clone of it
+ */
+ connection_t *(*clone) (connection_t *this);
+
+ /**
+ * @brief Destroys a connection_t object.
+ *
+ * @param this calling object
+ */
+ void (*destroy) (connection_t *this);
+};
+
+/**
+ * @brief Creates a connection_t object.
+ *
+ * Supplied hosts/IDs become owned by connection, so
+ * do not modify or destroy them after a call to
+ * connection_create(). Name gets cloned internally.
+ *
+ * @param name connection identifier
+ * @param my_host host_t representing local address
+ * @param other_host host_t representing remote address
+ * @param my_id identification_t for me
+ * @param other_id identification_t for other
+ * @param auth_method Authentication method to use for our(!) auth data
+ * @return connection_t object.
+ *
+ * @ingroup config
+ */
+connection_t * connection_create(char *name,
+ host_t *my_host, host_t *other_host,
+ identification_t *my_id,
+ identification_t *other_id,
+ auth_method_t auth_method);
+
+#endif /* CONNECTION_H_ */
diff --git a/programs/charon/charon/config/connections/connection_store.h b/programs/charon/charon/config/connections/connection_store.h
new file mode 100755
index 000000000..41fd58e42
--- /dev/null
+++ b/programs/charon/charon/config/connections/connection_store.h
@@ -0,0 +1,112 @@
+/**
+ * @file connection_store.h
+ *
+ * @brief Interface connection_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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef CONNECTION_STORE_H_
+#define CONNECTION_STORE_H_
+
+#include <types.h>
+#include <config/connections/connection.h>
+
+
+typedef struct connection_store_t connection_store_t;
+
+/**
+ * @brief The interface for a store of connection_t's.
+ *
+ * @b Constructors:
+ * - stroke_create()
+ *
+ * @ingroup config
+ */
+struct connection_store_t {
+
+ /**
+ * @brief Returns a connection definition identified by two IDs.
+ *
+ * This call is useful to get a connection which is identified by IDs
+ * rather than addresses, e.g. for connection setup on user request.
+ * The returned connection gets created/cloned and therefore must
+ * be destroyed after usage.
+ *
+ * @param this calling object
+ * @param my_id own ID of connection
+ * @param other_id others ID of connection
+ * @return
+ * - connection_t, if found
+ * - NULL otherwise
+ */
+ connection_t *(*get_connection_by_ids) (connection_store_t *this, identification_t *my_id, identification_t *other_id);
+
+ /**
+ * @brief Returns a connection definition identified by two hosts.
+ *
+ * This call is usefull to get a connection identified by addresses.
+ * It may be used after kernel request for traffic protection.
+ * The returned connection gets created/cloned and therefore must
+ * be destroyed after usage.
+ *
+ * @param this calling object
+ * @param my_id own address of connection
+ * @param other_id others address of connection
+ * @return
+ * - connection_t, if found
+ * - NULL otherwise
+ */
+ connection_t *(*get_connection_by_hosts) (connection_store_t *this, host_t *my_host, host_t *other_host);
+
+ /**
+ * @brief Returns a connection identified by its name.
+ *
+ * This call is usefull to get a connection identified its
+ * name, as on an connection setup.
+ *
+ * @param this calling object
+ * @param name name of the connection to get
+ * @return
+ * - connection_t, if found
+ * - NULL otherwise
+ */
+ connection_t *(*get_connection_by_name) (connection_store_t *this, char *name);
+
+ /**
+ * @brief Add a connection to the store.
+ *
+ * After a successful call, the connection is owned by the store and may
+ * not be manipulated nor destroyed.
+ *
+ * @param this calling object
+ * @param connection connection to add
+ * @return
+ * - SUCCESS, or
+ * - FAILED
+ */
+ status_t (*add_connection) (connection_store_t *this, connection_t *connection);
+
+ /**
+ * @brief Destroys a connection_store_t object.
+ *
+ * @param this calling object
+ */
+ void (*destroy) (connection_store_t *this);
+};
+
+#endif /* CONNECTION_STORE_H_ */
diff --git a/programs/charon/charon/config/connections/local_connection_store.c b/programs/charon/charon/config/connections/local_connection_store.c
new file mode 100644
index 000000000..3f07f0d21
--- /dev/null
+++ b/programs/charon/charon/config/connections/local_connection_store.c
@@ -0,0 +1,228 @@
+/**
+ * @file local_connection_store.c
+ *
+ * @brief Implementation of local_connection_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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+
+#include "local_connection_store.h"
+
+#include <utils/linked_list.h>
+#include <utils/logger_manager.h>
+
+
+typedef struct private_local_connection_store_t private_local_connection_store_t;
+
+/**
+ * Private data of an local_connection_store_t object
+ */
+struct private_local_connection_store_t {
+
+ /**
+ * Public part
+ */
+ local_connection_store_t public;
+
+ /**
+ * stored connection
+ */
+ linked_list_t *connections;
+
+ /**
+ * Assigned logger
+ */
+ logger_t *logger;
+};
+
+
+/**
+ * Implementation of connection_store_t.get_connection_by_hosts.
+ */
+static connection_t *get_connection_by_hosts(private_local_connection_store_t *this, host_t *my_host, host_t *other_host)
+{
+ iterator_t *iterator;
+ connection_t *current, *found = NULL;
+
+ this->logger->log(this->logger, CONTROL|LEVEL1, "getting config for hosts %s - %s",
+ my_host->get_address(my_host), other_host->get_address(other_host));
+
+ iterator = this->connections->create_iterator(this->connections, TRUE);
+ while (iterator->has_next(iterator))
+ {
+ host_t *config_my_host, *config_other_host;
+
+ iterator->current(iterator, (void**)&current);
+
+ config_my_host = current->get_my_host(current);
+ config_other_host = current->get_other_host(current);
+
+ /* first check if ip is equal */
+ if(config_other_host->ip_equals(config_other_host, other_host))
+ {
+ this->logger->log(this->logger, CONTROL|LEVEL2, "config entry with remote host %s",
+ config_other_host->get_address(config_other_host));
+ /* could be right one, check my_host for default route*/
+ if (config_my_host->is_default_route(config_my_host))
+ {
+ found = current->clone(current);
+ break;
+ }
+ /* check now if host informations are the same */
+ else if (config_my_host->ip_equals(config_my_host,my_host))
+ {
+ found = current->clone(current);
+ break;
+ }
+
+ }
+ /* Then check for wildcard hosts!
+ * TODO
+ * actually its only checked if other host with default route can be found! */
+ else if (config_other_host->is_default_route(config_other_host))
+ {
+ /* could be right one, check my_host for default route*/
+ if (config_my_host->is_default_route(config_my_host))
+ {
+ found = current->clone(current);
+ break;
+ }
+ /* check now if host informations are the same */
+ else if (config_my_host->ip_equals(config_my_host,my_host))
+ {
+ found = current->clone(current);
+ break;
+ }
+ }
+ }
+ iterator->destroy(iterator);
+
+ /* apply hosts as they are supplied since my_host may be %defaultroute, and other_host may be %any. */
+ if (found)
+ {
+ found->update_my_host(found, my_host->clone(my_host));
+ found->update_other_host(found, other_host->clone(other_host));
+ }
+
+ return found;
+}
+
+/**
+ * Implementation of connection_store_t.get_connection_by_ids.
+ */
+static connection_t *get_connection_by_ids(private_local_connection_store_t *this, identification_t *my_id, identification_t *other_id)
+{
+ iterator_t *iterator;
+ connection_t *current, *found = NULL;
+
+ this->logger->log(this->logger, CONTROL|LEVEL1, "getting config for ids %s - %s",
+ my_id->get_string(my_id), other_id->get_string(other_id));
+
+ iterator = this->connections->create_iterator(this->connections, TRUE);
+ while (iterator->has_next(iterator))
+ {
+ identification_t *config_my_id, *config_other_id;
+
+ iterator->current(iterator, (void**)&current);
+
+ config_my_id = current->get_my_id(current);
+ config_other_id = current->get_other_id(current);
+
+ /* first check if ids are equal
+ * TODO: Add wildcard checks */
+ if (config_other_id->equals(config_other_id, other_id) &&
+ config_my_id->equals(config_my_id, my_id))
+ {
+ this->logger->log(this->logger, CONTROL|LEVEL2, "config entry with remote id %s",
+ config_other_id->get_string(config_other_id));
+ found = current->clone(current);
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+
+ return found;
+}
+
+/**
+ * Implementation of connection_store_t.get_connection_by_name.
+ */
+static connection_t *get_connection_by_name(private_local_connection_store_t *this, char *name)
+{
+ iterator_t *iterator;
+ connection_t *current, *found = NULL;
+
+ iterator = this->connections->create_iterator(this->connections, TRUE);
+ while (iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void**)&current);
+ if (strcmp(name, current->get_name(current)) == 0)
+ {
+ found = current->clone(current);
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+
+ return found;
+}
+
+/**
+ * Implementation of connection_store_t.add_connection.
+ */
+static status_t add_connection(private_local_connection_store_t *this, connection_t *connection)
+{
+ this->connections->insert_last(this->connections, connection);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of connection_store_t.destroy.
+ */
+static void destroy (private_local_connection_store_t *this)
+{
+ connection_t *connection;
+
+ while (this->connections->remove_last(this->connections, (void**)&connection) == SUCCESS)
+ {
+ connection->destroy(connection);
+ }
+ this->connections->destroy(this->connections);
+ free(this);
+}
+
+/**
+ * Described in header.
+ */
+local_connection_store_t * local_connection_store_create()
+{
+ private_local_connection_store_t *this = malloc_thing(private_local_connection_store_t);
+
+ this->public.connection_store.get_connection_by_hosts = (connection_t*(*)(connection_store_t*,host_t*,host_t*))get_connection_by_hosts;
+ this->public.connection_store.get_connection_by_ids = (connection_t*(*)(connection_store_t*,identification_t*,identification_t*))get_connection_by_ids;
+ this->public.connection_store.get_connection_by_name = (connection_t*(*)(connection_store_t*,char*))get_connection_by_name;
+ this->public.connection_store.add_connection = (status_t(*)(connection_store_t*,connection_t*))add_connection;
+ this->public.connection_store.destroy = (void(*)(connection_store_t*))destroy;
+
+ /* private variables */
+ this->connections = linked_list_create();
+ this->logger = logger_manager->get_logger(logger_manager, CONFIG);
+
+ return (&this->public);
+}
diff --git a/programs/charon/charon/config/connections/local_connection_store.h b/programs/charon/charon/config/connections/local_connection_store.h
new file mode 100644
index 000000000..14a0a24ae
--- /dev/null
+++ b/programs/charon/charon/config/connections/local_connection_store.h
@@ -0,0 +1,63 @@
+/**
+ * @file local_connection_store.h
+ *
+ * @brief Interface of local_connection_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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef LOCAL_CONNECTION_H_
+#define LOCAL_CONNECTION_H_
+
+#include <types.h>
+#include <config/connections/connection_store.h>
+
+
+typedef struct local_connection_store_t local_connection_store_t;
+
+/**
+ * @brief A connection_store_t implementation using a simple connection list.
+ *
+ * The local_connection_store_t class implements the connection_store_t interface
+ * as simple as possible. connection_t's are stored in an in-memory list.
+ *
+ * @b Constructors:
+ * - local_connection_store_create()
+ *
+ * @todo Make thread-save first
+ * @todo Add remove_connection method
+ *
+ * @ingroup config
+ */
+struct local_connection_store_t {
+
+ /**
+ * Implements connection_store_t interface
+ */
+ connection_store_t connection_store;
+};
+
+/**
+ * @brief Creates a local_connection_store_t instance.
+ *
+ * @return connection store instance.
+ *
+ * @ingroup config
+ */
+local_connection_store_t * local_connection_store_create();
+
+#endif /* LOCAL_CONNECTION_H_ */
diff --git a/programs/charon/charon/config/credentials/Makefile.credentials b/programs/charon/charon/config/credentials/Makefile.credentials
new file mode 100644
index 000000000..720d56656
--- /dev/null
+++ b/programs/charon/charon/config/credentials/Makefile.credentials
@@ -0,0 +1,20 @@
+# Copyright (C) 2006 Martin Willi
+# Hochschule fuer Technik Rapperswil
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+
+CREDENTIALS_DIR= $(CONFIG_DIR)credentials/
+
+
+CHARON_OBJS+= $(BUILD_DIR)local_credential_store.o
+$(BUILD_DIR)local_credential_store.o : $(CREDENTIALS_DIR)local_credential_store.c $(CREDENTIALS_DIR)local_credential_store.h
+ $(CC) $(CFLAGS) -c -o $@ $<
diff --git a/programs/charon/charon/config/credentials/credential_store.h b/programs/charon/charon/config/credentials/credential_store.h
new file mode 100755
index 000000000..2339469c0
--- /dev/null
+++ b/programs/charon/charon/config/credentials/credential_store.h
@@ -0,0 +1,91 @@
+/**
+ * @file credential_store.h
+ *
+ * @brief Interface credential_store_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef CREDENTIAL_STORE_H_
+#define CREDENTIAL_STORE_H_
+
+#include <types.h>
+#include <crypto/rsa/rsa_private_key.h>
+#include <crypto/rsa/rsa_public_key.h>
+#include <utils/identification.h>
+
+
+typedef struct credential_store_t credential_store_t;
+
+/**
+ * @brief The interface for a credential_store backend.
+ *
+ * @b Constructors:
+ * - stroke_create()
+ *
+ * @ingroup config
+ */
+struct credential_store_t {
+
+ /**
+ * @brief Returns the preshared secret of a specific ID.
+ *
+ * The returned chunk must be destroyed by the caller after usage.
+ *
+ * @param this calling object
+ * @param identification identification_t object identifiying the secret.
+ * @param[out] preshared_secret the preshared secret will be written there.
+ * @return
+ * - NOT_FOUND if no preshared secrets for specific ID could be found
+ * - SUCCESS
+ *
+ * @todo We should use two IDs to query shared secrets, since we want to use different
+ * keys for different peers...
+ */
+ status_t (*get_shared_secret) (credential_store_t *this, identification_t *identification, chunk_t *preshared_secret);
+
+ /**
+ * @brief Returns the RSA public key of a specific ID.
+ *
+ * The returned rsa_public_key_t must be destroyed by the caller after usage.
+ *
+ * @param this calling object
+ * @param identification 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 *identification);
+
+ /**
+ * @brief Returns the RSA private key of a specific ID.
+ *
+ * The returned rsa_private_key_t must be destroyed by the caller after usage.
+ *
+ * @param this calling object
+ * @param identification identification_t object identifiying the key
+ * @return private key, or NULL if not found
+ */
+ rsa_private_key_t *(*get_rsa_private_key) (credential_store_t *this, identification_t *identification);
+
+ /**
+ * @brief Destroys a credential_store_t object.
+ *
+ * @param this calling object
+ */
+ void (*destroy) (credential_store_t *this);
+};
+
+#endif /*CREDENTIAL_STORE_H_*/
diff --git a/programs/charon/charon/config/credentials/local_credential_store.c b/programs/charon/charon/config/credentials/local_credential_store.c
new file mode 100644
index 000000000..dc6cb6c50
--- /dev/null
+++ b/programs/charon/charon/config/credentials/local_credential_store.c
@@ -0,0 +1,315 @@
+/**
+ * @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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <sys/stat.h>
+#include <dirent.h>
+
+#include "local_credential_store.h"
+
+#include <utils/linked_list.h>
+#include <utils/logger_manager.h>
+#include <crypto/x509.h>
+
+
+typedef struct key_entry_t key_entry_t;
+
+/**
+ * Private key with an associated ID to find it
+ */
+struct key_entry_t {
+
+ /**
+ * ID, as added
+ */
+ identification_t *id;
+
+ /**
+ * Associated rsa private key
+ */
+ rsa_private_key_t *key;
+};
+
+
+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 key_entry_t's with private keys
+ */
+ linked_list_t *private_keys;
+
+ /**
+ * list of x509 certificates with public keys
+ */
+ linked_list_t *certificates;
+
+ /**
+ * Assigned logger
+ */
+ logger_t *logger;
+};
+
+
+/**
+ * Implementation of credential_store_t.get_shared_secret.
+ */
+static status_t get_shared_secret(private_local_credential_store_t *this, identification_t *identification, chunk_t *preshared_secret)
+{
+ return FAILED;
+}
+
+/**
+ * Implementation of credential_store_t.get_rsa_public_key.
+ */
+static rsa_public_key_t * get_rsa_public_key(private_local_credential_store_t *this, identification_t *identification)
+{
+ x509_t *current;
+ rsa_public_key_t *found = NULL;
+ iterator_t *iterator;
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Looking for public key for %s",
+ identification->get_string(identification));
+ iterator = this->certificates->create_iterator(this->certificates, TRUE);
+ while (iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void**)&current);
+ identification_t *stored = current->get_subject(current);
+ this->logger->log(this->logger, CONTROL|LEVEL2, "there is one for %s",
+ stored->get_string(stored));
+ if (identification->equals(identification, stored))
+ {
+ found = current->get_public_key(current);
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ return found;
+}
+
+/**
+ * Implementation of credential_store_t.get_rsa_private_key.
+ */
+static rsa_private_key_t *get_rsa_private_key(private_local_credential_store_t *this, identification_t *identification)
+{
+ rsa_private_key_t *found = NULL;
+ key_entry_t *current;
+ iterator_t *iterator;
+
+ iterator = this->private_keys->create_iterator(this->private_keys, TRUE);
+ while (iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void**)&current);
+ if (identification->equals(identification, current->id))
+ {
+ found = current->key->clone(current->key);
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ return found;
+}
+
+/**
+ * Implements local_credential_store_t.load_private_keys
+ */
+static void load_certificates(private_local_credential_store_t *this, char *path)
+{
+ struct dirent* entry;
+ struct stat stb;
+ DIR* dir;
+ x509_t *cert;
+
+ dir = opendir(path);
+ if (dir == NULL) {
+ this->logger->log(this->logger, ERROR, "error opening certificate directory \"%s\"", path);
+ return;
+ }
+ while ((entry = readdir(dir)) != NULL)
+ {
+ char file[256];
+ 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)
+ {
+ cert = x509_create_from_file(file);
+ if (cert)
+ {
+ this->certificates->insert_last(this->certificates, (void*)cert);
+ this->logger->log(this->logger, CONTROL|LEVEL1, "loaded certificate \"%s\"", file);
+ }
+ else
+ {
+ this->logger->log(this->logger, ERROR, "certificate \"%s\" invalid, skipped", file);
+ }
+ }
+ }
+ closedir(dir);
+}
+
+/**
+ * Query the ID for a private key, by doing a lookup in the certificates
+ */
+static identification_t *get_id_for_private_key(private_local_credential_store_t *this, rsa_private_key_t *private_key)
+{
+ iterator_t *iterator;
+ x509_t *cert;
+ identification_t *found = NULL;
+ rsa_public_key_t *public_key;
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Getting ID for a private key...");
+
+ iterator = this->certificates->create_iterator(this->certificates, TRUE);
+ while (!found && iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void**)&cert);
+ public_key = cert->get_public_key(cert);
+ if (public_key)
+ {
+ if (private_key->belongs_to(private_key, public_key))
+ {
+ this->logger->log(this->logger, CONTROL|LEVEL2, "found a match");
+ found = cert->get_subject(cert);
+ found = found->clone(found);
+ }
+ else
+ {
+ this->logger->log(this->logger, CONTROL|LEVEL3, "this one did not match");
+ }
+ public_key->destroy(public_key);
+ }
+ }
+ iterator->destroy(iterator);
+ return found;
+}
+
+/**
+ * Implements local_credential_store_t.load_private_keys
+ */
+static void load_private_keys(private_local_credential_store_t *this, char *path)
+{
+ struct dirent* entry;
+ struct stat stb;
+ DIR* dir;
+ rsa_private_key_t *key;
+
+ dir = opendir(path);
+ if (dir == NULL) {
+ this->logger->log(this->logger, ERROR, "error opening private key directory \"%s\"", path);
+ return;
+ }
+ while ((entry = readdir(dir)) != NULL)
+ {
+ char file[256];
+ 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)
+ {
+ key = rsa_private_key_create_from_file(file, NULL);
+ if (key)
+ {
+ key_entry_t *entry;
+ identification_t *id = get_id_for_private_key(this, key);
+ if (!id)
+ {
+ this->logger->log(this->logger, ERROR,
+ "no certificate found for private key \"%s\", skipped", file);
+ key->destroy(key);
+ continue;
+ }
+ entry = malloc_thing(key_entry_t);
+ entry->key = key;
+ entry->id = id;
+ this->private_keys->insert_last(this->private_keys, (void*)entry);
+ this->logger->log(this->logger, CONTROL|LEVEL1, "loaded private key \"%s\"", file);
+ }
+ else
+ {
+ this->logger->log(this->logger, ERROR, "private key \"%s\" invalid, skipped", file);
+ }
+ }
+ }
+ closedir(dir);
+}
+
+/**
+ * Implementation of credential_store_t.destroy.
+ */
+static void destroy(private_local_credential_store_t *this)
+{
+ x509_t *certificate;
+ key_entry_t *key_entry;
+
+ while (this->certificates->remove_last(this->certificates, (void**)&certificate) == SUCCESS)
+ {
+ certificate->destroy(certificate);
+ }
+ this->certificates->destroy(this->certificates);
+ while (this->private_keys->remove_last(this->private_keys, (void**)&key_entry) == SUCCESS)
+ {
+ key_entry->id->destroy(key_entry->id);
+ key_entry->key->destroy(key_entry->key);
+ free(key_entry);
+ }
+ this->private_keys->destroy(this->private_keys);
+ free(this);
+}
+
+/**
+ * Described in header.
+ */
+local_credential_store_t * local_credential_store_create()
+{
+ private_local_credential_store_t *this = malloc_thing(private_local_credential_store_t);
+
+ this->public.credential_store.get_shared_secret = (status_t(*)(credential_store_t*,identification_t*,chunk_t*))get_shared_secret;
+ this->public.credential_store.get_rsa_private_key = (rsa_private_key_t*(*)(credential_store_t*,identification_t*))get_rsa_private_key;
+ this->public.credential_store.get_rsa_public_key = (rsa_public_key_t*(*)(credential_store_t*,identification_t*))get_rsa_public_key;
+ this->public.load_certificates = (void(*)(local_credential_store_t*,char*))load_certificates;
+ this->public.load_private_keys = (void(*)(local_credential_store_t*,char*))load_private_keys;
+ this->public.credential_store.destroy = (void(*)(credential_store_t*))destroy;
+
+ /* private variables */
+ this->private_keys = linked_list_create();
+ this->certificates = linked_list_create();
+ this->logger = logger_manager->get_logger(logger_manager, CONFIG);
+
+ return (&this->public);
+}
diff --git a/programs/charon/charon/config/credentials/local_credential_store.h b/programs/charon/charon/config/credentials/local_credential_store.h
new file mode 100644
index 000000000..ab9ef88d7
--- /dev/null
+++ b/programs/charon/charon/config/credentials/local_credential_store.h
@@ -0,0 +1,84 @@
+/**
+ * @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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef LOCAL_CREDENTIAL_H_
+#define LOCAL_CREDENTIAL_H_
+
+#include <types.h>
+#include <config/credentials/credential_store.h>
+
+
+typedef struct local_credential_store_t local_credential_store_t;
+
+/**
+ * @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 can be loaded
+ * from folders.
+ * Shared secret are not handled yet, so get_shared_secret always returns NOT_FOUND.
+ *
+ * @b Constructors:
+ * - local_credential_store_create()
+ *
+ * @ingroup config
+ */
+struct local_credential_store_t {
+
+ /**
+ * Implements credential_store_t interface
+ */
+ credential_store_t credential_store;
+
+ /**
+ * @brief Loads trusted certificates from a folder.
+ *
+ * Currently, all keys must be in binary DER format.
+ *
+ * @param this calling object
+ * @param path directory to load certificates from
+ */
+ void (*load_certificates) (local_credential_store_t *this, char *path);
+
+ /**
+ * @brief Loads RSA private keys from a folder.
+ *
+ * Currently, all keys must be unencrypted in binary DER format. Anything
+ * other gets ignored. Further, a certificate for the specific private
+ * key must already be loaded to get the ID from.
+ *
+ * @param this calling object
+ * @param path directory to load keys from
+ */
+ void (*load_private_keys) (local_credential_store_t *this, char *path);
+};
+
+/**
+ * @brief Creates a local_credential_store_t instance.
+ *
+ * @return credential store instance.
+ *
+ * @ingroup config
+ */
+local_credential_store_t *local_credential_store_create();
+
+#endif /* LOCAL_CREDENTIAL_H_ */
diff --git a/programs/charon/charon/config/policies/Makefile.policies b/programs/charon/charon/config/policies/Makefile.policies
new file mode 100644
index 000000000..e7ed8ab13
--- /dev/null
+++ b/programs/charon/charon/config/policies/Makefile.policies
@@ -0,0 +1,24 @@
+# Copyright (C) 2006 Martin Willi
+# Hochschule fuer Technik Rapperswil
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+
+POLICIES_DIR= $(CONFIG_DIR)policies/
+
+
+CHARON_OBJS+= $(BUILD_DIR)policy.o
+$(BUILD_DIR)policy.o : $(POLICIES_DIR)policy.c $(POLICIES_DIR)policy.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)local_policy_store.o
+$(BUILD_DIR)local_policy_store.o : $(POLICIES_DIR)local_policy_store.c $(POLICIES_DIR)local_policy_store.h
+ $(CC) $(CFLAGS) -c -o $@ $< \ No newline at end of file
diff --git a/programs/charon/charon/config/policies/local_policy_store.c b/programs/charon/charon/config/policies/local_policy_store.c
new file mode 100644
index 000000000..ae02357ea
--- /dev/null
+++ b/programs/charon/charon/config/policies/local_policy_store.c
@@ -0,0 +1,136 @@
+/**
+ * @file local_policy_store.c
+ *
+ * @brief Implementation of local_policy_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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "local_policy_store.h"
+
+#include <utils/linked_list.h>
+#include <utils/logger_manager.h>
+
+
+typedef struct private_local_policy_store_t private_local_policy_store_t;
+
+/**
+ * Private data of an local_policy_store_t object
+ */
+struct private_local_policy_store_t {
+
+ /**
+ * Public part
+ */
+ local_policy_store_t public;
+
+ /**
+ * list of policy_t's
+ */
+ linked_list_t *policies;
+
+ /**
+ * Assigned logger
+ */
+ logger_t *logger;
+};
+
+/**
+ * Implementation of policy_store_t.add_policy.
+ */
+static void add_policy(private_local_policy_store_t *this, policy_t *policy)
+{
+ this->policies->insert_last(this->policies, (void*)policy);
+}
+
+
+/**
+ * Implementation of policy_store_t.get_policy.
+ */
+static policy_t *get_policy(private_local_policy_store_t *this, identification_t *my_id, identification_t *other_id)
+{
+ iterator_t *iterator;
+ policy_t *current, *found = NULL;
+
+ this->logger->log(this->logger, CONTROL|LEVEL1, "Looking for policy for IDs %s - %s",
+ my_id ? my_id->get_string(my_id) : "%any",
+ other_id->get_string(other_id));
+ iterator = this->policies->create_iterator(this->policies, TRUE);
+ while (iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void **)&current);
+ identification_t *config_my_id = current->get_my_id(current);
+ identification_t *config_other_id = current->get_other_id(current);
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Found one for %s - %s",
+ config_my_id->get_string(config_my_id),
+ config_other_id->get_string(config_other_id));
+
+ /* check other host first */
+ if (other_id->belongs_to(other_id, config_other_id))
+ {
+ /* get it if my_id not specified */
+ if (my_id->belongs_to(my_id, config_my_id))
+ {
+ found = current->clone(current);
+ break;
+ }
+ }
+ }
+ iterator->destroy(iterator);
+
+ /* apply IDs as they are requsted, since they may be configured as %any or such */
+ if (found)
+ {
+ found->update_my_id(found, my_id->clone(my_id));
+ found->update_other_id(found, other_id->clone(other_id));
+ }
+ return found;
+}
+
+/**
+ * Implementation of policy_store_t.destroy.
+ */
+static void destroy(private_local_policy_store_t *this)
+{
+ policy_t *policy;
+
+ while (this->policies->remove_last(this->policies, (void**)&policy) == SUCCESS)
+ {
+ policy->destroy(policy);
+ }
+ this->policies->destroy(this->policies);
+ free(this);
+}
+
+/**
+ * Described in header.
+ */
+local_policy_store_t *local_policy_store_create()
+{
+ private_local_policy_store_t *this = malloc_thing(private_local_policy_store_t);
+
+ this->public.policy_store.add_policy = (void(*)(policy_store_t*,policy_t*))add_policy;
+ this->public.policy_store.get_policy = (policy_t*(*)(policy_store_t*,identification_t*,identification_t*))get_policy;
+ this->public.policy_store.destroy = (void(*)(policy_store_t*))destroy;
+
+ /* private variables */
+ this->policies = linked_list_create();
+ this->logger = logger_manager->get_logger(logger_manager, CONFIG);
+
+ return (&this->public);
+}
diff --git a/programs/charon/charon/config/policies/local_policy_store.h b/programs/charon/charon/config/policies/local_policy_store.h
new file mode 100644
index 000000000..7ab9e0efd
--- /dev/null
+++ b/programs/charon/charon/config/policies/local_policy_store.h
@@ -0,0 +1,60 @@
+/**
+ * @file local_policy_store.h
+ *
+ * @brief Interface of local_policy_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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef LOCAL_POLICY_STORE_H_
+#define LOCAL_POLICY_STORE_H_
+
+#include <types.h>
+#include <config/policies/policy_store.h>
+
+
+typedef struct local_policy_store_t local_policy_store_t;
+
+/**
+ * @brief A policy_store_t implementation using a simple policy lists.
+ *
+ * The local_policy_store_t class implements the policy_store_t interface
+ * as simple as possible. The policies are stored in a in-memory list.
+ *
+ * @b Constructors:
+ * - local_policy_store_create()
+ *
+ * @ingroup config
+ */
+struct local_policy_store_t {
+
+ /**
+ * Implements policy_store_t interface
+ */
+ policy_store_t policy_store;
+};
+
+/**
+ * @brief Creates a local_policy_store_t instance.
+ *
+ * @return policy store instance.
+ *
+ * @ingroup config
+ */
+local_policy_store_t *local_policy_store_create();
+
+#endif /* LOCAL_POLICY_STORE_H_ */
diff --git a/programs/charon/charon/config/policies/policy.c b/programs/charon/charon/config/policies/policy.c
new file mode 100644
index 000000000..cff87fc6b
--- /dev/null
+++ b/programs/charon/charon/config/policies/policy.c
@@ -0,0 +1,397 @@
+/**
+ * @file policy.c
+ *
+ * @brief Implementation of policy_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "policy.h"
+
+#include <utils/linked_list.h>
+#include <utils/identification.h>
+#include <utils/logger.h>
+
+typedef struct private_policy_t private_policy_t;
+
+/**
+ * Private data of an policy_t object
+ */
+struct private_policy_t {
+
+ /**
+ * Public part
+ */
+ policy_t public;
+
+ /**
+ * id to use to identify us
+ */
+ identification_t *my_id;
+
+ /**
+ * allowed id for other
+ */
+ identification_t *other_id;
+
+ /**
+ * list for all proposals
+ */
+ linked_list_t *proposals;
+
+ /**
+ * list for traffic selectors for my site
+ */
+ linked_list_t *my_ts;
+
+ /**
+ * list for traffic selectors for others site
+ */
+ linked_list_t *other_ts;
+
+ /**
+ * select_traffic_selectors for both
+ */
+ linked_list_t *(*select_traffic_selectors) (private_policy_t *,linked_list_t*,linked_list_t*);
+};
+
+/**
+ * Implementation of policy_t.get_my_id
+ */
+static identification_t *get_my_id(private_policy_t *this)
+{
+ return this->my_id;
+}
+
+/**
+ * Implementation of policy_t.get_other_id
+ */
+static identification_t *get_other_id(private_policy_t *this)
+{
+ return this->other_id;
+}
+
+/**
+ * Implementation of policy_t.update_my_id
+ */
+static void update_my_id(private_policy_t *this, identification_t *my_id)
+{
+ this->my_id->destroy(this->my_id);
+ this->my_id = my_id;
+}
+
+/**
+ * Implementation of policy_t.update_other_id
+ */
+static void update_other_id(private_policy_t *this, identification_t *other_id)
+{
+ this->other_id->destroy(this->other_id);
+ this->other_id = other_id;
+}
+
+/**
+ * Helper function which does the work for policy_t.update_my_ts and update_other_ts
+ */
+static void update_ts(linked_list_t* list, host_t *new_host)
+{
+ traffic_selector_t *ts;
+ iterator_t *iterator;
+
+ iterator = list->create_iterator(list, TRUE);
+ while (iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void**)&ts);
+ ts->update_address_range(ts, new_host);
+ }
+ iterator->destroy(iterator);
+}
+
+/**
+ * Implementation of policy_t.update_my_id
+ */
+static void update_my_ts(private_policy_t *this, host_t *my_host)
+{
+ update_ts(this->my_ts, my_host);
+}
+
+/**
+ * Implementation of policy_t.update_other_ts
+ */
+static void update_other_ts(private_policy_t *this, host_t *my_host)
+{
+ update_ts(this->other_ts, my_host);
+}
+
+/**
+ * Implementation of policy_t.get_my_traffic_selectors
+ */
+static linked_list_t *get_my_traffic_selectors(private_policy_t *this)
+{
+ return this->my_ts;
+}
+
+/**
+ * Implementation of policy_t.get_other_traffic_selectors
+ */
+static linked_list_t *get_other_traffic_selectors(private_policy_t *this, traffic_selector_t **traffic_selectors[])
+{
+ return this->other_ts;
+}
+
+/**
+ * Implementation of private_policy_t.select_my_traffic_selectors
+ */
+static linked_list_t *select_my_traffic_selectors(private_policy_t *this, linked_list_t *supplied)
+{
+ return this->select_traffic_selectors(this, this->my_ts, supplied);
+}
+
+/**
+ * Implementation of private_policy_t.select_other_traffic_selectors
+ */
+static linked_list_t *select_other_traffic_selectors(private_policy_t *this, linked_list_t *supplied)
+{
+ return this->select_traffic_selectors(this, this->other_ts, supplied);
+}
+/**
+ * Implementation of private_policy_t.select_traffic_selectors
+ */
+static linked_list_t *select_traffic_selectors(private_policy_t *this, linked_list_t *stored, linked_list_t *supplied)
+{
+ iterator_t *supplied_iter, *stored_iter;
+ traffic_selector_t *supplied_ts, *stored_ts, *selected_ts;
+ linked_list_t *selected = linked_list_create();
+
+
+ stored_iter = stored->create_iterator(stored, TRUE);
+ supplied_iter = supplied->create_iterator(supplied, TRUE);
+
+ /* iterate over all stored selectors */
+ while (stored_iter->has_next(stored_iter))
+ {
+ stored_iter->current(stored_iter, (void**)&stored_ts);
+
+ supplied_iter->reset(supplied_iter);
+ /* iterate over all supplied traffic selectors */
+ while (supplied_iter->has_next(supplied_iter))
+ {
+ supplied_iter->current(supplied_iter, (void**)&supplied_ts);
+
+ selected_ts = stored_ts->get_subset(stored_ts, supplied_ts);
+ if (selected_ts)
+ {
+ /* got a match, add to list */
+ selected->insert_last(selected, (void*)selected_ts);
+ }
+ }
+ }
+ stored_iter->destroy(stored_iter);
+ supplied_iter->destroy(supplied_iter);
+
+ return selected;
+}
+
+/**
+ * Implementation of policy_t.get_proposal_iterator
+ */
+static linked_list_t *get_proposals(private_policy_t *this)
+{
+ return this->proposals;
+}
+
+/**
+ * Implementation of policy_t.select_proposal
+ */
+static proposal_t *select_proposal(private_policy_t *this, linked_list_t *proposals)
+{
+ iterator_t *stored_iter, *supplied_iter;
+ proposal_t *stored, *supplied, *selected;
+
+ stored_iter = this->proposals->create_iterator(this->proposals, TRUE);
+ supplied_iter = proposals->create_iterator(proposals, TRUE);
+
+ /* compare all stored proposals with all supplied. Stored ones are preferred. */
+ while (stored_iter->has_next(stored_iter))
+ {
+ supplied_iter->reset(supplied_iter);
+ stored_iter->current(stored_iter, (void**)&stored);
+
+ while (supplied_iter->has_next(supplied_iter))
+ {
+ supplied_iter->current(supplied_iter, (void**)&supplied);
+ selected = stored->select(stored, supplied);
+ if (selected)
+ {
+ /* they match, return */
+ stored_iter->destroy(stored_iter);
+ supplied_iter->destroy(supplied_iter);
+ return selected;
+ }
+ }
+ }
+
+ /* no proposal match :-(, will result in a NO_PROPOSAL_CHOSEN... */
+ stored_iter->destroy(stored_iter);
+ supplied_iter->destroy(supplied_iter);
+
+ return NULL;
+}
+
+/**
+ * Implementation of policy_t.add_my_traffic_selector
+ */
+static void add_my_traffic_selector(private_policy_t *this, traffic_selector_t *traffic_selector)
+{
+ this->my_ts->insert_last(this->my_ts, (void*)traffic_selector);
+}
+
+/**
+ * Implementation of policy_t.add_other_traffic_selector
+ */
+static void add_other_traffic_selector(private_policy_t *this, traffic_selector_t *traffic_selector)
+{
+ this->other_ts->insert_last(this->other_ts, (void*)traffic_selector);
+}
+
+/**
+ * Implementation of policy_t.add_proposal
+ */
+static void add_proposal(private_policy_t *this, proposal_t *proposal)
+{
+ this->proposals->insert_last(this->proposals, (void*)proposal);
+}
+
+/**
+ * Implements policy_t.destroy.
+ */
+static status_t destroy(private_policy_t *this)
+{
+ proposal_t *proposal;
+ traffic_selector_t *traffic_selector;
+
+
+ /* delete proposals */
+ while(this->proposals->remove_last(this->proposals, (void**)&proposal) == SUCCESS)
+ {
+ proposal->destroy(proposal);
+ }
+ this->proposals->destroy(this->proposals);
+
+ /* delete traffic selectors */
+ while(this->my_ts->remove_last(this->my_ts, (void**)&traffic_selector) == SUCCESS)
+ {
+ traffic_selector->destroy(traffic_selector);
+ }
+ this->my_ts->destroy(this->my_ts);
+
+ /* delete traffic selectors */
+ while(this->other_ts->remove_last(this->other_ts, (void**)&traffic_selector) == SUCCESS)
+ {
+ traffic_selector->destroy(traffic_selector);
+ }
+ this->other_ts->destroy(this->other_ts);
+
+ /* delete ids */
+ this->my_id->destroy(this->my_id);
+ this->other_id->destroy(this->other_id);
+
+ free(this);
+ return SUCCESS;
+}
+
+/**
+ * Implements policy_t.clone.
+ */
+static policy_t *clone(private_policy_t *this)
+{
+ private_policy_t *clone = (private_policy_t*)policy_create(this->my_id->clone(this->my_id),
+ this->other_id->clone(this->other_id));
+ iterator_t *iterator;
+ proposal_t *proposal;
+ traffic_selector_t *ts;
+
+ /* clone all proposals */
+ iterator = this->proposals->create_iterator(this->proposals, TRUE);
+ while (iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void**)&proposal);
+ proposal = proposal->clone(proposal);
+ clone->proposals->insert_last(clone->proposals, (void*)proposal);
+ }
+ iterator->destroy(iterator);
+
+ /* clone all local traffic selectors */
+ iterator = this->my_ts->create_iterator(this->my_ts, TRUE);
+ while (iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void**)&ts);
+ ts = ts->clone(ts);
+ clone->my_ts->insert_last(clone->my_ts, (void*)ts);
+ }
+ iterator->destroy(iterator);
+
+ /* clone all remote traffic selectors */
+ iterator = this->other_ts->create_iterator(this->other_ts, TRUE);
+ while (iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void**)&ts);
+ ts = ts->clone(ts);
+ clone->other_ts->insert_last(clone->other_ts, (void*)ts);
+ }
+ iterator->destroy(iterator);
+
+ return &clone->public;
+}
+
+/*
+ * Described in header-file
+ */
+policy_t *policy_create(identification_t *my_id, identification_t *other_id)
+{
+ private_policy_t *this = malloc_thing(private_policy_t);
+
+ /* public functions */
+ this->public.get_my_id = (identification_t*(*)(policy_t*))get_my_id;
+ this->public.get_other_id = (identification_t*(*)(policy_t*))get_other_id;
+ this->public.update_my_id = (void(*)(policy_t*,identification_t*))update_my_id;
+ this->public.update_other_id = (void(*)(policy_t*,identification_t*))update_other_id;
+ this->public.update_my_ts = (void(*)(policy_t*,host_t*))update_my_ts;
+ this->public.update_other_ts = (void(*)(policy_t*,host_t*))update_other_ts;
+ this->public.get_my_traffic_selectors = (linked_list_t*(*)(policy_t*))get_my_traffic_selectors;
+ this->public.select_my_traffic_selectors = (linked_list_t*(*)(policy_t*,linked_list_t*))select_my_traffic_selectors;
+ this->public.get_other_traffic_selectors = (linked_list_t*(*)(policy_t*))get_other_traffic_selectors;
+ this->public.select_other_traffic_selectors = (linked_list_t*(*)(policy_t*,linked_list_t*))select_other_traffic_selectors;
+ this->public.get_proposals = (linked_list_t*(*)(policy_t*))get_proposals;
+ this->public.select_proposal = (proposal_t*(*)(policy_t*,linked_list_t*))select_proposal;
+ this->public.add_my_traffic_selector = (void(*)(policy_t*,traffic_selector_t*))add_my_traffic_selector;
+ this->public.add_other_traffic_selector = (void(*)(policy_t*,traffic_selector_t*))add_other_traffic_selector;
+ this->public.add_proposal = (void(*)(policy_t*,proposal_t*))add_proposal;
+ this->public.clone = (policy_t*(*)(policy_t*))clone;
+ this->public.destroy = (void(*)(policy_t*))destroy;
+
+ /* apply init values */
+ this->my_id = my_id;
+ this->other_id = other_id;
+
+ /* init private members*/
+ this->select_traffic_selectors = select_traffic_selectors;
+ this->proposals = linked_list_create();
+ this->my_ts = linked_list_create();
+ this->other_ts = linked_list_create();
+
+ return (&this->public);
+}
diff --git a/programs/charon/charon/config/policies/policy.h b/programs/charon/charon/config/policies/policy.h
new file mode 100644
index 000000000..78cda1e8b
--- /dev/null
+++ b/programs/charon/charon/config/policies/policy.h
@@ -0,0 +1,249 @@
+/**
+ * @file policy.h
+ *
+ * @brief Interface of policy_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef POLICY_H_
+#define POLICY_H_
+
+#include <types.h>
+#include <utils/identification.h>
+#include <config/traffic_selector.h>
+#include <config/proposal.h>
+#include <encoding/payloads/auth_payload.h>
+
+
+typedef struct policy_t policy_t;
+
+/**
+ * @brief A policy_t defines the policies to apply to CHILD_SAs.
+ *
+ * The given two IDs identify a policy. These rules define how
+ * child SAs may be set up and which traffic may be IPsec'ed.
+ *
+ * @b Constructors:
+ * - policy_create()
+ *
+ * @ingroup config
+ */
+struct policy_t {
+
+ /**
+ * @brief Get own id to use for identification.
+ *
+ * Returned object is not getting cloned.
+ *
+ * @param this calling object
+ * @return own id
+ */
+ identification_t *(*get_my_id) (policy_t *this);
+
+ /**
+ * @brief Get id of communication partner.
+ *
+ * Returned object is not getting cloned.
+ *
+ * @param this calling object
+ * @return other id
+ */
+ identification_t *(*get_other_id) (policy_t *this);
+
+ /**
+ * @brief Update own ID.
+ *
+ * It may be necessary to uptdate own ID, as it
+ * is set to %any or to e.g. *@strongswan.org in
+ * some cases.
+ * Old ID is destroyed, new one NOT cloned.
+ *
+ * @param this calling object
+ * @param my_id new ID to set as my_id
+ */
+ void (*update_my_id) (policy_t *this, identification_t *my_id);
+
+ /**
+ * @brief Update others ID.
+ *
+ * It may be necessary to uptdate others ID, as it
+ * is set to %any or to e.g. *@strongswan.org in
+ * some cases.
+ * Old ID is destroyed, new one NOT cloned.
+ *
+ * @param this calling object
+ * @param other_id new ID to set as other_id
+ */
+ void (*update_other_id) (policy_t *this, identification_t *other_id);
+
+ /**
+ * @brief Update own address in traffic selectors.
+ *
+ * Update own 0.0.0.0 address in traffic selectors
+ * with supplied one. The size of the subnet will be
+ * set to /32.
+ *
+ * @param this calling object
+ * @param my_host new address to set in traffic selectors
+ */
+ void (*update_my_ts) (policy_t *this, host_t *my_host);
+
+ /**
+ * @brief Update others address in traffic selectors.
+ *
+ * Update remote 0.0.0.0 address in traffic selectors
+ * with supplied one. The size of the subnet will be
+ * set to /32.
+ *
+ * @param this calling object
+ * @param other_host new address to set in traffic selectors
+ */
+ void (*update_other_ts) (policy_t *this, host_t *other_host);
+
+ /**
+ * @brief Get configured traffic selectors for our site.
+ *
+ * Returns a list with all traffic selectors for the local
+ * site. List and items MUST NOT be freed nor modified.
+ *
+ * @param this calling object
+ * @return list with traffic selectors
+ */
+ linked_list_t *(*get_my_traffic_selectors) (policy_t *this);
+
+ /**
+ * @brief Get configured traffic selectors for others site.
+ *
+ * Returns a list with all traffic selectors for the remote
+ * site. List and items MUST NOT be freed nor modified.
+ *
+ * @param this calling object
+ * @return list with traffic selectors
+ */
+ linked_list_t *(*get_other_traffic_selectors) (policy_t *this);
+
+ /**
+ * @brief Select traffic selectors from a supplied list for local site.
+ *
+ * Resulted list and traffic selectors must be destroyed after usage.
+ *
+ * @param this calling object
+ * @param supplied linked list with traffic selectors
+ * @return list containing the selected traffic selectors
+ */
+ linked_list_t *(*select_my_traffic_selectors) (policy_t *this, linked_list_t *supplied);
+
+ /**
+ * @brief Select traffic selectors from a supplied list for remote site.
+ *
+ * Resulted list and traffic selectors must be destroyed after usage.
+ *
+ * @param this calling object
+ * @param supplied linked list with traffic selectors
+ * @return list containing the selected traffic selectors
+ */
+ linked_list_t *(*select_other_traffic_selectors) (policy_t *this, linked_list_t *supplied);
+
+ /**
+ * @brief Get the list of internally stored proposals.
+ *
+ * Rembember: policy_t does store proposals for AH/ESP,
+ * IKE proposals are in the connection_t
+ *
+ * @warning List and Items are still owned by policy and MUST NOT
+ * be manipulated or freed!
+ *
+ * @param this calling object
+ * @return lists with proposals
+ */
+ linked_list_t *(*get_proposals) (policy_t *this);
+
+ /**
+ * @brief Select a proposal from a supplied list.
+ *
+ * @param this calling object
+ * @param proposals list from from wich proposals are selected
+ * @return selected proposal, or NULL if nothing matches
+ */
+ proposal_t *(*select_proposal) (policy_t *this, linked_list_t *proposals);
+
+ /**
+ * @brief Add a traffic selector to the list for local site.
+ *
+ * After add, proposal is owned by policy.
+ *
+ * @warning Do not add while other threads are reading.
+ *
+ * @param this calling object
+ * @param traffic_selector traffic_selector to add
+ */
+ void (*add_my_traffic_selector) (policy_t *this, traffic_selector_t *traffic_selector);
+
+ /**
+ * @brief Add a traffic selector to the list for remote site.
+ *
+ * After add, proposal is owned by policy.
+ *
+ * @warning Do not add while other threads are reading.
+ *
+ * @param this calling object
+ * @param traffic_selector traffic_selector to add
+ */
+ void (*add_other_traffic_selector) (policy_t *this, traffic_selector_t *traffic_selector);
+
+ /**
+ * @brief Add a proposal to the list.
+ *
+ * The proposals are stored by priority, first added
+ * is the most prefered.
+ *
+ * @warning Do not add while other threads are reading.
+ *
+ * @param this calling object
+ * @param proposal proposal to add
+ */
+ void (*add_proposal) (policy_t *this, proposal_t *proposal);
+
+ /**
+ * @brief Clone a policy.
+ *
+ * @param this policy to clone
+ * @return clone of it
+ */
+ policy_t *(*clone) (policy_t *this);
+
+ /**
+ * @brief Destroys the policy object
+ *
+ * @param this calling object
+ */
+ void (*destroy) (policy_t *this);
+};
+
+/**
+ * @brief Create a configuration object for IKE_AUTH and later.
+ *
+ * @param my_id identification_t for ourselves
+ * @param other_id identification_t for the remote guy
+ * @return policy_t object
+ *
+ * @ingroup config
+ */
+policy_t *policy_create(identification_t *my_id, identification_t *other_id);
+
+#endif /* POLICY_H_ */
diff --git a/programs/charon/charon/config/policies/policy_store.h b/programs/charon/charon/config/policies/policy_store.h
new file mode 100755
index 000000000..651dea634
--- /dev/null
+++ b/programs/charon/charon/config/policies/policy_store.h
@@ -0,0 +1,76 @@
+/**
+ * @file policy_store.h
+ *
+ * @brief Interface policy_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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef POLICY_STORE_H_
+#define POLICY_STORE_H_
+
+#include <types.h>
+#include <config/policies/policy.h>
+
+
+typedef struct policy_store_t policy_store_t;
+
+/**
+ * @brief The interface for a store of policy_t's.
+ *
+ * @b Constructors:
+ * - stroke_create()
+ *
+ * @ingroup config
+ */
+struct policy_store_t {
+
+ /**
+ * @brief Returns a policy identified by two IDs.
+ *
+ * The returned policy gets created/cloned and therefore must be
+ * destroyed by the caller.
+ *
+ * @param this calling object
+ * @param my_id own ID of the policy
+ * @param other_id others ID of the policy
+ * @return
+ * - matching policy_t, if found
+ * - NULL otherwise
+ */
+ policy_t *(*get_policy) (policy_store_t *this, identification_t *my_id, identification_t *other_id);
+
+ /**
+ * @brief Add a policy to the list.
+ *
+ * The policy is owned by the store after the call. Do
+ * not modify nor free.
+ *
+ * @param this calling object
+ * @param policy policy to add
+ */
+ void (*add_policy) (policy_store_t *this, policy_t *policy);
+
+ /**
+ * @brief Destroys a policy_store_t object.
+ *
+ * @param this calling object
+ */
+ void (*destroy) (policy_store_t *this);
+};
+
+#endif /*POLICY_STORE_H_*/
diff --git a/programs/charon/charon/config/proposal.c b/programs/charon/charon/config/proposal.c
new file mode 100644
index 000000000..cb71a756a
--- /dev/null
+++ b/programs/charon/charon/config/proposal.c
@@ -0,0 +1,642 @@
+/**
+ * @file proposal.c
+ *
+ * @brief Implementation of proposal_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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+
+#include "proposal.h"
+
+#include <utils/linked_list.h>
+#include <utils/identification.h>
+#include <utils/logger.h>
+
+
+/**
+ * String mappings for protocol_id_t.
+ */
+mapping_t protocol_id_m[] = {
+ {PROTO_NONE, "PROTO_NONE"},
+ {PROTO_IKE, "PROTO_IKE"},
+ {PROTO_AH, "PROTO_AH"},
+ {PROTO_ESP, "PROTO_ESP"},
+ {MAPPING_END, NULL}
+};
+
+/**
+ * String mappings for transform_type_t.
+ */
+mapping_t transform_type_m[] = {
+ {UNDEFINED_TRANSFORM_TYPE, "UNDEFINED_TRANSFORM_TYPE"},
+ {ENCRYPTION_ALGORITHM, "ENCRYPTION_ALGORITHM"},
+ {PSEUDO_RANDOM_FUNCTION, "PSEUDO_RANDOM_FUNCTION"},
+ {INTEGRITY_ALGORITHM, "INTEGRITY_ALGORITHM"},
+ {DIFFIE_HELLMAN_GROUP, "DIFFIE_HELLMAN_GROUP"},
+ {EXTENDED_SEQUENCE_NUMBERS, "EXTENDED_SEQUENCE_NUMBERS"},
+ {MAPPING_END, NULL}
+};
+
+/**
+ * String mappings for extended_sequence_numbers_t.
+ */
+mapping_t extended_sequence_numbers_m[] = {
+ {NO_EXT_SEQ_NUMBERS, "NO_EXT_SEQ_NUMBERS"},
+ {EXT_SEQ_NUMBERS, "EXT_SEQ_NUMBERS"},
+ {MAPPING_END, NULL}
+};
+
+
+typedef struct protocol_proposal_t protocol_proposal_t;
+
+/**
+ * substructure which holds all data algos for a specific protocol
+ */
+struct protocol_proposal_t {
+ /**
+ * protocol (ESP or AH)
+ */
+ protocol_id_t protocol;
+
+ /**
+ * priority ordered list of encryption algorithms
+ */
+ linked_list_t *encryption_algos;
+
+ /**
+ * priority ordered list of integrity algorithms
+ */
+ linked_list_t *integrity_algos;
+
+ /**
+ * priority ordered list of pseudo random functions
+ */
+ linked_list_t *prf_algos;
+
+ /**
+ * priority ordered list of dh groups
+ */
+ linked_list_t *dh_groups;
+
+ /**
+ * priority ordered list of extended sequence number flags
+ */
+ linked_list_t *esns;
+
+ /**
+ * senders SPI
+ */
+ chunk_t spi;
+};
+
+
+typedef struct private_proposal_t private_proposal_t;
+
+/**
+ * Private data of an proposal_t object
+ */
+struct private_proposal_t {
+
+ /**
+ * Public part
+ */
+ proposal_t public;
+
+ /**
+ * number of this proposal, as used in the payload
+ */
+ u_int8_t number;
+
+ /**
+ * list of protocol_proposal_t's
+ */
+ linked_list_t *protocol_proposals;
+};
+
+/**
+ * Look up a protocol_proposal, or create one if necessary...
+ */
+static protocol_proposal_t *get_protocol_proposal(private_proposal_t *this, protocol_id_t proto, bool create)
+{
+ protocol_proposal_t *proto_proposal = NULL, *current_proto_proposal;;
+ iterator_t *iterator;
+
+ /* find our protocol in the proposals */
+ iterator = this->protocol_proposals->create_iterator(this->protocol_proposals, TRUE);
+ while (iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void**)&current_proto_proposal);
+ if (current_proto_proposal->protocol == proto)
+ {
+ proto_proposal = current_proto_proposal;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+
+ if (!proto_proposal && create)
+ {
+ /* nope, create a new one */
+ proto_proposal = malloc_thing(protocol_proposal_t);
+ proto_proposal->protocol = proto;
+ proto_proposal->encryption_algos = linked_list_create();
+ proto_proposal->integrity_algos = linked_list_create();
+ proto_proposal->prf_algos = linked_list_create();
+ proto_proposal->dh_groups = linked_list_create();
+ proto_proposal->esns = linked_list_create();
+ if (proto == PROTO_IKE)
+ {
+ proto_proposal->spi.len = 8;
+ }
+ else
+ {
+ proto_proposal->spi.len = 4;
+ }
+ proto_proposal->spi.ptr = malloc(proto_proposal->spi.len);
+ /* add to the list */
+ this->protocol_proposals->insert_last(this->protocol_proposals, (void*)proto_proposal);
+ }
+ return proto_proposal;
+}
+
+/**
+ * Add algorithm/keysize to a algorithm list
+ */
+static void add_algo(linked_list_t *list, u_int8_t algo, size_t key_size)
+{
+ algorithm_t *algo_key = malloc_thing(algorithm_t);
+
+ algo_key->algorithm = algo;
+ algo_key->key_size = key_size;
+ list->insert_last(list, (void*)algo_key);
+}
+
+/**
+ * Implements proposal_t.add_algorithm
+ */
+static void add_algorithm(private_proposal_t *this, protocol_id_t proto, transform_type_t type, u_int16_t algo, size_t key_size)
+{
+ protocol_proposal_t *proto_proposal = get_protocol_proposal(this, proto, TRUE);
+
+ switch (type)
+ {
+ case ENCRYPTION_ALGORITHM:
+ add_algo(proto_proposal->encryption_algos, algo, key_size);
+ break;
+ case INTEGRITY_ALGORITHM:
+ add_algo(proto_proposal->integrity_algos, algo, key_size);
+ break;
+ case PSEUDO_RANDOM_FUNCTION:
+ add_algo(proto_proposal->prf_algos, algo, key_size);
+ break;
+ case DIFFIE_HELLMAN_GROUP:
+ add_algo(proto_proposal->dh_groups, algo, 0);
+ break;
+ case EXTENDED_SEQUENCE_NUMBERS:
+ add_algo(proto_proposal->esns, algo, 0);
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * Implements proposal_t.get_algorithm.
+ */
+static bool get_algorithm(private_proposal_t *this, protocol_id_t proto, transform_type_t type, algorithm_t** algo)
+{
+ linked_list_t * list;
+ protocol_proposal_t *proto_proposal = get_protocol_proposal(this, proto, FALSE);
+
+ if (proto_proposal == NULL)
+ {
+ return FALSE;
+ }
+ switch (type)
+ {
+ case ENCRYPTION_ALGORITHM:
+ list = proto_proposal->encryption_algos;
+ break;
+ case INTEGRITY_ALGORITHM:
+ list = proto_proposal->integrity_algos;
+ break;
+ case PSEUDO_RANDOM_FUNCTION:
+ list = proto_proposal->prf_algos;
+ break;
+ case DIFFIE_HELLMAN_GROUP:
+ list = proto_proposal->dh_groups;
+ break;
+ case EXTENDED_SEQUENCE_NUMBERS:
+ list = proto_proposal->esns;
+ break;
+ default:
+ return FALSE;
+ }
+ if (list->get_first(list, (void**)algo) != SUCCESS)
+ {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * Implements proposal_t.create_algorithm_iterator.
+ */
+static iterator_t *create_algorithm_iterator(private_proposal_t *this, protocol_id_t proto, transform_type_t type)
+{
+ protocol_proposal_t *proto_proposal = get_protocol_proposal(this, proto, FALSE);
+ if (proto_proposal == NULL)
+ {
+ return NULL;
+ }
+
+ switch (type)
+ {
+ case ENCRYPTION_ALGORITHM:
+ return proto_proposal->encryption_algos->create_iterator(proto_proposal->encryption_algos, TRUE);
+ case INTEGRITY_ALGORITHM:
+ return proto_proposal->integrity_algos->create_iterator(proto_proposal->integrity_algos, TRUE);
+ case PSEUDO_RANDOM_FUNCTION:
+ return proto_proposal->prf_algos->create_iterator(proto_proposal->prf_algos, TRUE);
+ case DIFFIE_HELLMAN_GROUP:
+ return proto_proposal->dh_groups->create_iterator(proto_proposal->dh_groups, TRUE);
+ case EXTENDED_SEQUENCE_NUMBERS:
+ return proto_proposal->esns->create_iterator(proto_proposal->esns, TRUE);
+ default:
+ break;
+ }
+ return NULL;
+}
+
+/**
+ * Find a matching alg/keysize in two linked lists
+ */
+static bool select_algo(linked_list_t *first, linked_list_t *second, bool *add, u_int16_t *alg, size_t *key_size)
+{
+ iterator_t *first_iter, *second_iter;
+ algorithm_t *first_alg, *second_alg;
+
+ /* if in both are zero algorithms specified, we HAVE a match */
+ if (first->get_count(first) == 0 && second->get_count(second) == 0)
+ {
+ *add = FALSE;
+ return TRUE;
+ }
+
+ first_iter = first->create_iterator(first, TRUE);
+ second_iter = second->create_iterator(second, TRUE);
+ /* compare algs, order of algs in "first" is preferred */
+ while (first_iter->has_next(first_iter))
+ {
+ first_iter->current(first_iter, (void**)&first_alg);
+ second_iter->reset(second_iter);
+ while (second_iter->has_next(second_iter))
+ {
+ second_iter->current(second_iter, (void**)&second_alg);
+ if (first_alg->algorithm == second_alg->algorithm &&
+ first_alg->key_size == second_alg->key_size)
+ {
+ /* ok, we have an algorithm */
+ *alg = first_alg->algorithm;
+ *key_size = first_alg->key_size;
+ *add = TRUE;
+ first_iter->destroy(first_iter);
+ second_iter->destroy(second_iter);
+ return TRUE;
+ }
+ }
+ }
+ /* no match in all comparisons */
+ first_iter->destroy(first_iter);
+ second_iter->destroy(second_iter);
+ return FALSE;
+}
+
+/**
+ * Implements proposal_t.select.
+ */
+static proposal_t *select_proposal(private_proposal_t *this, private_proposal_t *other)
+{
+ proposal_t *selected;
+ u_int16_t algo;
+ size_t key_size;
+ iterator_t *iterator;
+ protocol_proposal_t *this_prop, *other_prop;
+ protocol_id_t proto;
+ bool add;
+ u_int64_t spi;
+
+ /* empty proposal? no match */
+ if (this->protocol_proposals->get_count(this->protocol_proposals) == 0 ||
+ other->protocol_proposals->get_count(other->protocol_proposals) == 0)
+ {
+ return NULL;
+ }
+ /* they MUST have the same amount of protocols */
+ if (this->protocol_proposals->get_count(this->protocol_proposals) !=
+ other->protocol_proposals->get_count(other->protocol_proposals))
+ {
+ return NULL;
+ }
+
+ selected = proposal_create(this->number);
+
+ /* iterate over supplied proposals */
+ iterator = other->protocol_proposals->create_iterator(other->protocol_proposals, TRUE);
+ while (iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void**)&other_prop);
+ /* get the proposal with the same protocol */
+ proto = other_prop->protocol;
+ this_prop = get_protocol_proposal(this, proto, FALSE);
+
+ if (this_prop == NULL)
+ {
+ iterator->destroy(iterator);
+ selected->destroy(selected);
+ return NULL;
+ }
+
+ /* select encryption algorithm */
+ if (select_algo(this_prop->encryption_algos, other_prop->encryption_algos, &add, &algo, &key_size))
+ {
+ if (add)
+ {
+ selected->add_algorithm(selected, proto, ENCRYPTION_ALGORITHM, algo, key_size);
+ }
+ }
+ else
+ {
+ iterator->destroy(iterator);
+ selected->destroy(selected);
+ return NULL;
+ }
+ /* select integrity algorithm */
+ if (select_algo(this_prop->integrity_algos, other_prop->integrity_algos, &add, &algo, &key_size))
+ {
+ if (add)
+ {
+ selected->add_algorithm(selected, proto, INTEGRITY_ALGORITHM, algo, key_size);
+ }
+ }
+ else
+ {
+ iterator->destroy(iterator);
+ selected->destroy(selected);
+ return NULL;
+ }
+ /* select prf algorithm */
+ if (select_algo(this_prop->prf_algos, other_prop->prf_algos, &add, &algo, &key_size))
+ {
+ if (add)
+ {
+ selected->add_algorithm(selected, proto, PSEUDO_RANDOM_FUNCTION, algo, key_size);
+ }
+ }
+ else
+ {
+ iterator->destroy(iterator);
+ selected->destroy(selected);
+ return NULL;
+ }
+ /* select a DH-group */
+ if (select_algo(this_prop->dh_groups, other_prop->dh_groups, &add, &algo, &key_size))
+ {
+ if (add)
+ {
+ selected->add_algorithm(selected, proto, DIFFIE_HELLMAN_GROUP, algo, 0);
+ }
+ }
+ else
+ {
+ iterator->destroy(iterator);
+ selected->destroy(selected);
+ return NULL;
+ }
+ /* select if we use ESNs */
+ if (select_algo(this_prop->esns, other_prop->esns, &add, &algo, &key_size))
+ {
+ if (add)
+ {
+ selected->add_algorithm(selected, proto, EXTENDED_SEQUENCE_NUMBERS, algo, 0);
+ }
+ }
+ else
+ {
+ iterator->destroy(iterator);
+ selected->destroy(selected);
+ return NULL;
+ }
+ }
+ iterator->destroy(iterator);
+
+ /* apply spis from "other" */
+ spi = other->public.get_spi(&(other->public), PROTO_AH);
+ if (spi)
+ {
+ selected->set_spi(selected, PROTO_AH, spi);
+ }
+ spi = other->public.get_spi(&(other->public), PROTO_ESP);
+ if (spi)
+ {
+ selected->set_spi(selected, PROTO_ESP, spi);
+ }
+
+ /* everything matched, return new proposal */
+ return selected;
+}
+
+/**
+ * Implements proposal_t.get_number.
+ */
+static u_int8_t get_number(private_proposal_t *this)
+{
+ return this->number;
+}
+
+/**
+ * Implements proposal_t.get_protocols.
+ */
+static void get_protocols(private_proposal_t *this, protocol_id_t ids[2])
+{
+ iterator_t *iterator = this->protocol_proposals->create_iterator(this->protocol_proposals, TRUE);
+ u_int i = 0;
+
+ ids[0] = PROTO_NONE;
+ ids[1] = PROTO_NONE;
+ while (iterator->has_next(iterator))
+ {
+ protocol_proposal_t *proto_prop;
+ iterator->current(iterator, (void**)&proto_prop);
+ ids[i++] = proto_prop->protocol;
+ if (i>1)
+ {
+ /* should not happen, but who knows */
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+}
+
+/**
+ * Implements proposal_t.set_spi.
+ */
+static void set_spi(private_proposal_t *this, protocol_id_t proto, u_int64_t spi)
+{
+ protocol_proposal_t *proto_proposal = get_protocol_proposal(this, proto, FALSE);
+ if (proto_proposal)
+ {
+ if (proto == PROTO_AH || proto == PROTO_ESP)
+ {
+ *((u_int32_t*)proto_proposal->spi.ptr) = (u_int32_t)spi;
+ }
+ else
+ {
+ *((u_int64_t*)proto_proposal->spi.ptr) = spi;
+ }
+ }
+}
+
+/**
+ * Implements proposal_t.get_spi.
+ */
+static u_int64_t get_spi(private_proposal_t *this, protocol_id_t proto)
+{
+ protocol_proposal_t *proto_proposal = get_protocol_proposal(this, proto, FALSE);
+ if (proto_proposal)
+ {
+ if (proto == PROTO_AH || proto == PROTO_ESP)
+ {
+ return (u_int64_t)*((u_int32_t*)proto_proposal->spi.ptr);
+ }
+ else
+ {
+ return *((u_int64_t*)proto_proposal->spi.ptr);
+ }
+ }
+ return 0;
+}
+
+/**
+ * Clone a algorithm list
+ */
+static void clone_algo_list(linked_list_t *list, linked_list_t *clone_list)
+{
+ algorithm_t *algo, *clone_algo;
+ iterator_t *iterator = list->create_iterator(list, TRUE);
+ while (iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void**)&algo);
+ clone_algo = malloc_thing(algorithm_t);
+ memcpy(clone_algo, algo, sizeof(algorithm_t));
+ clone_list->insert_last(clone_list, (void*)clone_algo);
+ }
+ iterator->destroy(iterator);
+}
+
+/**
+ * Implements proposal_t.clone
+ */
+static proposal_t *clone(private_proposal_t *this)
+{
+ private_proposal_t *clone = (private_proposal_t*)proposal_create(this->number);
+
+ iterator_t *iterator = this->protocol_proposals->create_iterator(this->protocol_proposals, TRUE);
+ while (iterator->has_next(iterator))
+ {
+ protocol_proposal_t *proto_prop, *clone_proto_prop;
+ iterator->current(iterator, (void**)&proto_prop);
+
+ clone_proto_prop = get_protocol_proposal(clone, proto_prop->protocol, TRUE);
+ memcpy(clone_proto_prop->spi.ptr, proto_prop->spi.ptr, clone_proto_prop->spi.len);
+
+ clone_algo_list(proto_prop->encryption_algos, clone_proto_prop->encryption_algos);
+ clone_algo_list(proto_prop->integrity_algos, clone_proto_prop->integrity_algos);
+ clone_algo_list(proto_prop->prf_algos, clone_proto_prop->prf_algos);
+ clone_algo_list(proto_prop->dh_groups, clone_proto_prop->dh_groups);
+ clone_algo_list(proto_prop->esns, clone_proto_prop->esns);
+ }
+ iterator->destroy(iterator);
+
+ return &clone->public;
+}
+
+/**
+ * Frees all list items and destroys the list
+ */
+static void free_algo_list(linked_list_t *list)
+{
+ algorithm_t *algo;
+
+ while(list->get_count(list) > 0)
+ {
+ list->remove_last(list, (void**)&algo);
+ free(algo);
+ }
+ list->destroy(list);
+}
+
+/**
+ * Implements proposal_t.destroy.
+ */
+static void destroy(private_proposal_t *this)
+{
+ while(this->protocol_proposals->get_count(this->protocol_proposals) > 0)
+ {
+ protocol_proposal_t *proto_prop;
+ this->protocol_proposals->remove_last(this->protocol_proposals, (void**)&proto_prop);
+
+ free_algo_list(proto_prop->encryption_algos);
+ free_algo_list(proto_prop->integrity_algos);
+ free_algo_list(proto_prop->prf_algos);
+ free_algo_list(proto_prop->dh_groups);
+ free_algo_list(proto_prop->esns);
+
+ free(proto_prop->spi.ptr);
+ free(proto_prop);
+ }
+ this->protocol_proposals->destroy(this->protocol_proposals);
+
+ free(this);
+}
+
+/*
+ * Describtion in header-file
+ */
+proposal_t *proposal_create(u_int8_t number)
+{
+ private_proposal_t *this = malloc_thing(private_proposal_t);
+
+ this->public.add_algorithm = (void (*)(proposal_t*,protocol_id_t,transform_type_t,u_int16_t,size_t))add_algorithm;
+ this->public.create_algorithm_iterator = (iterator_t* (*)(proposal_t*,protocol_id_t,transform_type_t))create_algorithm_iterator;
+ this->public.get_algorithm = (bool (*)(proposal_t*,protocol_id_t,transform_type_t,algorithm_t**))get_algorithm;
+ this->public.select = (proposal_t* (*)(proposal_t*,proposal_t*))select_proposal;
+ this->public.get_number = (u_int8_t (*)(proposal_t*))get_number;
+ this->public.get_protocols = (void(*)(proposal_t *this, protocol_id_t ids[2]))get_protocols;
+ this->public.set_spi = (void(*)(proposal_t*,protocol_id_t,u_int64_t spi))set_spi;
+ this->public.get_spi = (u_int64_t(*)(proposal_t*,protocol_id_t))get_spi;
+ this->public.clone = (proposal_t*(*)(proposal_t*))clone;
+ this->public.destroy = (void(*)(proposal_t*))destroy;
+
+ /* init private members*/
+ this->number = number;
+ this->protocol_proposals = linked_list_create();
+
+ return (&this->public);
+}
diff --git a/programs/charon/charon/config/proposal.h b/programs/charon/charon/config/proposal.h
new file mode 100644
index 000000000..48e3ad8d5
--- /dev/null
+++ b/programs/charon/charon/config/proposal.h
@@ -0,0 +1,269 @@
+/**
+ * @file proposal.h
+ *
+ * @brief Interface of proposal_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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef PROPOSAL_H_
+#define PROPOSAL_H_
+
+#include <types.h>
+#include <utils/identification.h>
+#include <utils/linked_list.h>
+#include <utils/host.h>
+#include <crypto/crypters/crypter.h>
+#include <crypto/signers/signer.h>
+#include <crypto/diffie_hellman.h>
+#include <config/traffic_selector.h>
+
+
+typedef enum protocol_id_t protocol_id_t;
+
+/**
+ * Protocol ID of a proposal.
+ *
+ * @ingroup config
+ */
+enum protocol_id_t {
+ PROTO_NONE = 0,
+ PROTO_IKE = 1,
+ PROTO_AH = 2,
+ PROTO_ESP = 3,
+};
+
+/**
+ * String mappings for protocol_id_t.
+ *
+ * @ingroup config
+ */
+extern mapping_t protocol_id_m[];
+
+
+typedef enum transform_type_t transform_type_t;
+
+/**
+ * Type of a transform, as in IKEv2 RFC 3.3.2.
+ *
+ * @ingroup payloads
+ */
+enum transform_type_t {
+ UNDEFINED_TRANSFORM_TYPE = 241,
+ ENCRYPTION_ALGORITHM = 1,
+ PSEUDO_RANDOM_FUNCTION = 2,
+ INTEGRITY_ALGORITHM = 3,
+ DIFFIE_HELLMAN_GROUP = 4,
+ EXTENDED_SEQUENCE_NUMBERS = 5
+};
+
+/**
+ * String mappings for transform_type_t.
+ *
+ * @ingroup payloads
+ */
+extern mapping_t transform_type_m[];
+
+
+typedef enum extended_sequence_numbers_t extended_sequence_numbers_t;
+
+/**
+ * Extended sequence numbers, as in IKEv2 RFC 3.3.2.
+ *
+ * @ingroup payloads
+ */
+enum extended_sequence_numbers_t {
+ NO_EXT_SEQ_NUMBERS = 0,
+ EXT_SEQ_NUMBERS = 1
+};
+
+/**
+ * String mappings for extended_sequence_numbers_t.
+ *
+ * @ingroup payloads
+ */
+extern mapping_t extended_sequence_numbers_m[];
+
+
+typedef struct algorithm_t algorithm_t;
+
+/**
+ * Struct used to store different kinds of algorithms. The internal
+ * lists of algorithms contain such structures.
+ */
+struct algorithm_t {
+ /**
+ * Value from an encryption_algorithm_t/integrity_algorithm_t/...
+ */
+ u_int16_t algorithm;
+
+ /**
+ * the associated key size, or zero if not needed
+ */
+ u_int16_t key_size;
+};
+
+typedef struct proposal_t proposal_t;
+
+/**
+ * @brief Stores a set of algorithms used for an SA.
+ *
+ * A proposal stores algorithms for a specific
+ * protocol. It can store algorithms for more than
+ * one protocol (e.g. AH and ESP). Then the proposal
+ * means both protocols must be used.
+ * A proposal may contain more than one algorithm
+ * of the same kind. ONE of them can be selected.
+ *
+ * @warning This class is NOT thread-save!
+ *
+ * @b Constructors:
+ * - proposal_create()
+ *
+ * @ingroup config
+ */
+struct proposal_t {
+
+ /**
+ * @brief Add an algorithm to the proposal.
+ *
+ * The algorithms are stored by priority, first added
+ * is the most preferred.
+ * Key size is only needed for encryption algorithms
+ * with variable key size (such as AES). Must be set
+ * to zero if key size is not specified.
+ * The alg parameter accepts encryption_algorithm_t,
+ * integrity_algorithm_t, dh_group_number_t and
+ * extended_sequence_numbers_t.
+ *
+ * @warning Do not add while other threads are reading.
+ *
+ * @param this calling object
+ * @param proto desired protocol
+ * @param type kind of algorithm
+ * @param alg identifier for algorithm
+ * @param key_size key size to use
+ */
+ void (*add_algorithm) (proposal_t *this, protocol_id_t proto, transform_type_t type, u_int16_t alg, size_t key_size);
+
+ /**
+ * @brief Get an iterator over algorithms for a specifc protocol/algo type.
+ *
+ * @param this calling object
+ * @param proto desired protocol
+ * @param type kind of algorithm
+ * @return iterator over algorithms
+ */
+ iterator_t *(*create_algorithm_iterator) (proposal_t *this, protocol_id_t proto, transform_type_t type);
+
+ /**
+ * @brief Get the algorithm for a type to use.
+ *
+ * If there are multiple algorithms, only the first is returned.
+ * Result is still owned by proposal, do not modify!
+ *
+ * @param this calling object
+ * @param proto desired protocol
+ * @param type kind of algorithm
+ * @param[out] algo pointer which receives algorithm and key size
+ * @return TRUE if algorithm of this kind available
+ */
+ bool (*get_algorithm) (proposal_t *this, protocol_id_t proto, transform_type_t type, algorithm_t** algo);
+
+ /**
+ * @brief 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
+ */
+ proposal_t *(*select) (proposal_t *this, proposal_t *other);
+
+ /**
+ * @brief Get the number set on construction.
+ *
+ * @param this calling object
+ * @return number
+ */
+ u_int8_t (*get_number) (proposal_t *this);
+
+ /**
+ * @brief Get the protocol ids in the proposals.
+ *
+ * With AH and ESP, there could be two protocols in one
+ * proposal.
+ *
+ * @param this calling object
+ * @param ids array of protocol ids,
+ */
+ void (*get_protocols) (proposal_t *this, protocol_id_t ids[2]);
+
+ /**
+ * @brief Get the spi for a specific protocol.
+ *
+ * @param this calling object
+ * @param proto AH/ESP
+ * @return spi for proto
+ */
+ u_int64_t (*get_spi) (proposal_t *this, protocol_id_t proto);
+
+ /**
+ * @brief Set the spi for a specific protocol.
+ *
+ * @param this calling object
+ * @param proto AH/ESP
+ * @param spi spi to set for proto
+ */
+ void (*set_spi) (proposal_t *this, protocol_id_t proto, u_int64_t spi);
+
+ /**
+ * @brief Clone a proposal.
+ *
+ * @param this proposal to clone
+ * @return clone of it
+ */
+ proposal_t *(*clone) (proposal_t *this);
+
+ /**
+ * @brief Destroys the proposal object.
+ *
+ * @param this calling object
+ */
+ void (*destroy) (proposal_t *this);
+};
+
+/**
+ * @brief Create a child proposal for AH and/or ESP.
+ *
+ * Since the order of multiple proposals is important for
+ * key derivation, we must assign them numbers as they
+ * appear in the raw payload. Numbering starts at 1.
+ *
+ * @param number number of the proposal, as in the payload
+ * @return proposal_t object
+ *
+ * @ingroup config
+ */
+proposal_t *proposal_create(u_int8_t number);
+
+#endif /* PROPOSAL_H_ */
diff --git a/programs/charon/charon/config/traffic_selector.c b/programs/charon/charon/config/traffic_selector.c
new file mode 100644
index 000000000..81272659a
--- /dev/null
+++ b/programs/charon/charon/config/traffic_selector.c
@@ -0,0 +1,425 @@
+/**
+ * @file traffic_selector.c
+ *
+ * @brief Implementation of traffic_selector_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "traffic_selector.h"
+
+#include <utils/linked_list.h>
+#include <utils/identification.h>
+#include <arpa/inet.h>
+#include <string.h>
+
+typedef struct private_traffic_selector_t private_traffic_selector_t;
+
+/**
+ * Private data of an traffic_selector_t object
+ */
+struct private_traffic_selector_t {
+
+ /**
+ * Public part
+ */
+ traffic_selector_t public;
+
+ /**
+ * Type of address
+ */
+ ts_type_t type;
+
+ /**
+ * IP protocol (UDP, TCP, ICMP, ...)
+ */
+ u_int8_t protocol;
+
+ /**
+ * begin of address range, host order
+ */
+ union {
+ u_int32_t from_addr_ipv4;
+ };
+
+ /**
+ * end of address range, host order
+ */
+ union {
+ u_int32_t to_addr_ipv4;
+ };
+
+ /**
+ * begin of port range
+ */
+ u_int16_t from_port;
+
+ /**
+ * end of port range
+ */
+ u_int16_t to_port;
+};
+
+/**
+ * internal generic constructor
+ */
+static private_traffic_selector_t *traffic_selector_create(u_int8_t protocol, ts_type_t type, u_int16_t from_port, u_int16_t to_port);
+
+/**
+ * implements traffic_selector_t.get_subset
+ */
+static traffic_selector_t *get_subset(private_traffic_selector_t *this, private_traffic_selector_t *other)
+{
+ if ((this->type == TS_IPV4_ADDR_RANGE) &&
+ (other->type == TS_IPV4_ADDR_RANGE) &&
+ (this->protocol == other->protocol))
+ {
+ u_int32_t from_addr, to_addr;
+ u_int16_t from_port, to_port;
+ private_traffic_selector_t *new_ts;
+
+ /* calculate the maximum address range allowed for both */
+ from_addr = max(this->from_addr_ipv4, other->from_addr_ipv4);
+ to_addr = min(this->to_addr_ipv4, other->to_addr_ipv4);
+ if (from_addr > to_addr)
+ {
+ /* no match */
+ return NULL;
+ }
+
+ /* calculate the maximum port range allowed for both */
+ from_port = max(this->from_port, other->from_port);
+ to_port = min(this->to_port, other->to_port);
+ if (from_port > to_port)
+ {
+ /* no match */
+ return NULL;
+ }
+
+ /* got a match, return it */
+ new_ts = traffic_selector_create(this->protocol, this->type, from_port, to_port);
+ new_ts->from_addr_ipv4 = from_addr;
+ new_ts->to_addr_ipv4 = to_addr;
+ new_ts->type = TS_IPV4_ADDR_RANGE;
+ return &(new_ts->public);
+ }
+ return NULL;
+}
+
+/**
+ * Implements traffic_selector_t.get_from_address.
+ */
+static chunk_t get_from_address(private_traffic_selector_t *this)
+{
+ chunk_t from_addr = CHUNK_INITIALIZER;
+
+ switch (this->type)
+ {
+ case TS_IPV4_ADDR_RANGE:
+ {
+ u_int32_t network;
+ from_addr.len = sizeof(network);
+ from_addr.ptr = malloc(from_addr.len);
+ /* chunk must contain network order, convert! */
+ network = htonl(this->from_addr_ipv4);
+ memcpy(from_addr.ptr, &network, from_addr.len);
+ break;
+ }
+ case TS_IPV6_ADDR_RANGE:
+ {
+ break;
+ }
+ }
+ return from_addr;
+}
+
+/**
+ * Implements traffic_selector_t.get_to_address.
+ */
+static chunk_t get_to_address(private_traffic_selector_t *this)
+{
+ chunk_t to_addr = CHUNK_INITIALIZER;
+
+ switch (this->type)
+ {
+ case TS_IPV4_ADDR_RANGE:
+ {
+ u_int32_t network;
+ to_addr.len = sizeof(network);
+ to_addr.ptr = malloc(to_addr.len);
+ /* chunk must contain network order, convert! */
+ network = htonl(this->to_addr_ipv4);
+ memcpy(to_addr.ptr, &network, to_addr.len);
+ break;
+ }
+ case TS_IPV6_ADDR_RANGE:
+ {
+ break;
+ }
+ }
+ return to_addr;
+}
+
+/**
+ * Implements traffic_selector_t.get_from_port.
+ */
+static u_int16_t get_from_port(private_traffic_selector_t *this)
+{
+ return this->from_port;
+}
+
+/**
+ * Implements traffic_selector_t.get_to_port.
+ */
+static u_int16_t get_to_port(private_traffic_selector_t *this)
+{
+ return this->to_port;
+}
+
+/**
+ * Implements traffic_selector_t.get_type.
+ */
+static ts_type_t get_type(private_traffic_selector_t *this)
+{
+ return this->type;
+}
+
+/**
+ * Implements traffic_selector_t.get_protocol.
+ */
+static u_int8_t get_protocol(private_traffic_selector_t *this)
+{
+ return this->protocol;
+}
+
+/**
+ * Implements traffic_selector_t.get_netmask.
+ */
+static u_int8_t get_netmask(private_traffic_selector_t *this)
+{
+ switch (this->type)
+ {
+ case TS_IPV4_ADDR_RANGE:
+ {
+ u_int32_t from, to, bit;
+ from = htonl(this->from_addr_ipv4);
+ to = htonl(this->to_addr_ipv4);
+ for (bit = 0; bit < 32; bit++)
+ {
+ if ((1<<bit & from) != (1<<bit & to))
+ {
+ return bit;
+ }
+ }
+ return 32;
+ }
+ case TS_IPV6_ADDR_RANGE:
+ default:
+ {
+ return 0;
+ }
+ }
+}
+
+/**
+ * Implements traffic_selector_t.update_address_range.
+ */
+static void update_address_range(private_traffic_selector_t *this, host_t *host)
+{
+ if (host->get_family(host) == AF_INET &&
+ this->type == TS_IPV4_ADDR_RANGE)
+ {
+ if (this->from_addr_ipv4 == 0)
+ {
+ chunk_t from = host->get_address_as_chunk(host);
+ this->from_addr_ipv4 = ntohl(*((u_int32_t*)from.ptr));
+ this->to_addr_ipv4 = this->from_addr_ipv4;
+ chunk_free(&from);
+ }
+ }
+}
+
+/**
+ * Implements traffic_selector_t.clone.
+ */
+static traffic_selector_t *clone(private_traffic_selector_t *this)
+{
+ private_traffic_selector_t *clone = traffic_selector_create(this->protocol, this->type, this->from_port, this->to_port);
+ clone->type = this->type;
+ switch (clone->type)
+ {
+ case TS_IPV4_ADDR_RANGE:
+ {
+ clone->from_addr_ipv4 = this->from_addr_ipv4;
+ clone->to_addr_ipv4 = this->to_addr_ipv4;
+ return &(clone->public);
+ }
+ case TS_IPV6_ADDR_RANGE:
+ default:
+ {
+ free(this);
+ return NULL;
+ }
+ }
+}
+
+/**
+ * Implements traffic_selector_t.destroy.
+ */
+static void destroy(private_traffic_selector_t *this)
+{
+ free(this);
+}
+
+/*
+ * see header
+ */
+traffic_selector_t *traffic_selector_create_from_bytes(u_int8_t protocol, ts_type_t type, chunk_t from_addr, int16_t from_port, chunk_t to_addr, u_int16_t to_port)
+{
+ private_traffic_selector_t *this = traffic_selector_create(protocol, type, from_port, to_port);
+
+ this->type = type;
+ switch (type)
+ {
+ case TS_IPV4_ADDR_RANGE:
+ {
+ if (from_addr.len != 4 || to_addr.len != 4)
+ {
+ free(this);
+ return NULL;
+ }
+ /* chunk contains network order, convert! */
+ this->from_addr_ipv4 = ntohl(*((u_int32_t*)from_addr.ptr));
+ this->to_addr_ipv4 = ntohl(*((u_int32_t*)to_addr.ptr));
+ break;
+ }
+ case TS_IPV6_ADDR_RANGE:
+ default:
+ {
+ free(this);
+ return NULL;
+ }
+ }
+ return (&this->public);
+}
+
+/*
+ * see header
+ */
+traffic_selector_t *traffic_selector_create_from_subnet(host_t *net, u_int8_t netbits)
+{
+ private_traffic_selector_t *this = traffic_selector_create(0, 0, 0, 65535);
+
+ switch (net->get_family(net))
+ {
+ case AF_INET:
+ {
+ chunk_t from;
+
+ this->type = TS_IPV4_ADDR_RANGE;
+ from = net->get_address_as_chunk(net);
+ this->from_addr_ipv4 = ntohl(*((u_int32_t*)from.ptr));
+ if (this->from_addr_ipv4 == 0)
+ {
+ /* use /32 for 0.0.0.0 */
+ this->to_addr_ipv4 = 0xFFFFFF;
+ }
+ else
+ {
+ this->to_addr_ipv4 = this->from_addr_ipv4 | ((1 << (32 - netbits)) - 1);
+ }
+ chunk_free(&from);
+ break;
+ }
+ case AF_INET6:
+ default:
+ {
+ free(this);
+ return NULL;
+ }
+ }
+ return (&this->public);
+}
+
+/*
+ * see header
+ */
+traffic_selector_t *traffic_selector_create_from_string(u_int8_t protocol, ts_type_t type, char *from_addr, u_int16_t from_port, char *to_addr, u_int16_t to_port)
+{
+ private_traffic_selector_t *this = traffic_selector_create(protocol, type, from_port, to_port);
+
+ /* public functions */
+ this->public.get_subset = (traffic_selector_t*(*)(traffic_selector_t*,traffic_selector_t*))get_subset;
+ this->public.destroy = (void(*)(traffic_selector_t*))destroy;
+
+ this->type = type;
+ switch (type)
+ {
+ case TS_IPV4_ADDR_RANGE:
+ {
+ if (inet_aton(from_addr, (struct in_addr*)&(this->from_addr_ipv4)) == 0)
+ {
+ free(this);
+ return NULL;
+ }
+ if (inet_aton(to_addr, (struct in_addr*)&(this->to_addr_ipv4)) == 0)
+ {
+ free(this);
+ return NULL;
+ }
+ /* convert to host order, inet_aton has network order */
+ this->from_addr_ipv4 = ntohl(this->from_addr_ipv4);
+ this->to_addr_ipv4 = ntohl(this->to_addr_ipv4);
+ break;
+ }
+ case TS_IPV6_ADDR_RANGE:
+ {
+ free(this);
+ return NULL;
+ }
+ }
+
+ return (&this->public);
+}
+
+/*
+ * see declaration
+ */
+static private_traffic_selector_t *traffic_selector_create(u_int8_t protocol, ts_type_t type, u_int16_t from_port, u_int16_t to_port)
+{
+ private_traffic_selector_t *this = malloc_thing(private_traffic_selector_t);
+
+ /* public functions */
+ this->public.get_subset = (traffic_selector_t*(*)(traffic_selector_t*,traffic_selector_t*))get_subset;
+ this->public.get_from_address = (chunk_t(*)(traffic_selector_t*))get_from_address;
+ this->public.get_to_address = (chunk_t(*)(traffic_selector_t*))get_to_address;
+ this->public.get_from_port = (u_int16_t(*)(traffic_selector_t*))get_from_port;
+ this->public.get_to_port = (u_int16_t(*)(traffic_selector_t*))get_to_port;
+ this->public.get_type = (ts_type_t(*)(traffic_selector_t*))get_type;
+ this->public.get_protocol = (u_int8_t(*)(traffic_selector_t*))get_protocol;
+ this->public.get_netmask = (u_int8_t(*)(traffic_selector_t*))get_netmask;
+ this->public.update_address_range = (void(*)(traffic_selector_t*,host_t*))update_address_range;
+ this->public.clone = (traffic_selector_t*(*)(traffic_selector_t*))clone;
+ this->public.destroy = (void(*)(traffic_selector_t*))destroy;
+
+ this->from_port = from_port;
+ this->to_port = to_port;
+ this->protocol = protocol;
+ this->type = type;
+
+ return this;
+}
diff --git a/programs/charon/charon/config/traffic_selector.h b/programs/charon/charon/config/traffic_selector.h
new file mode 100644
index 000000000..5ac5bdeb1
--- /dev/null
+++ b/programs/charon/charon/config/traffic_selector.h
@@ -0,0 +1,258 @@
+/**
+ * @file traffic_selector.h
+ *
+ * @brief Interface of traffic_selector_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef TRAFFIC_SELECTOR_H_
+#define TRAFFIC_SELECTOR_H_
+
+#include <types.h>
+#include <utils/host.h>
+
+typedef enum ts_type_t ts_type_t;
+
+/**
+ * Traffic selector types.
+ *
+ * @ingroup config
+ */
+enum ts_type_t {
+
+ /**
+ * A range of IPv4 addresses, represented by two four (4) octet
+ * values. The first value is the beginning IPv4 address
+ * (inclusive) and the second value is the ending IPv4 address
+ * (inclusive). All addresses falling between the two specified
+ * addresses are considered to be within the list.
+ */
+ TS_IPV4_ADDR_RANGE = 7,
+
+ /**
+ * A range of IPv6 addresses, represented by two sixteen (16)
+ * octet values. The first value is the beginning IPv6 address
+ * (inclusive) and the second value is the ending IPv6 address
+ * (inclusive). All addresses falling between the two specified
+ * addresses are considered to be within the list.
+ */
+ TS_IPV6_ADDR_RANGE = 8
+};
+
+/**
+ * string mappings for ts_type_t
+ */
+extern mapping_t ts_type_m[];
+
+
+typedef struct traffic_selector_t traffic_selector_t;
+
+/**
+ * @brief 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
+ * 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
+ * @return
+ * - created subset of them
+ * - or NULL if no match between this and other
+ */
+ traffic_selector_t *(*get_subset) (traffic_selector_t *this, traffic_selector_t *other);
+
+ /**
+ * @brief 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.
+ *
+ * Data is in network order and represents the address.
+ * Size depends on protocol.
+ *
+ * Resulting chunk data is allocated and must be freed!
+ *
+ * @param this calling 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.
+ *
+ * Data is in network order and represents the address.
+ * Size depends on protocol.
+ *
+ * Resulting chunk data is allocated and must be freed!
+ *
+ * @param this calling object
+ * @return chunk containing the address
+ */
+ chunk_t (*get_to_address) (traffic_selector_t *this);
+
+ /**
+ * @brief Get starting port of this ts.
+ *
+ * Port is in host order, since the parser converts it.
+ * Size depends on protocol.
+ *
+ * @param this calling object
+ * @return port
+ */
+ u_int16_t (*get_from_port) (traffic_selector_t *this);
+
+ /**
+ * @brief Get ending port of this ts.
+ *
+ * Port is in host order, since the parser converts it.
+ * Size depends on protocol.
+ *
+ * @param this calling object
+ * @return port
+ */
+ u_int16_t (*get_to_port) (traffic_selector_t *this);
+
+ /**
+ * @brief Get the type of the traffic selector.
+ *
+ * @param this calling obect
+ * @return ts_type_t specifying the type
+ */
+ ts_type_t (*get_type) (traffic_selector_t *this);
+
+ /**
+ * @brief Get the protocol id of this ts.
+ *
+ * @param this calling obect
+ * @return protocol id
+ */
+ u_int8_t (*get_protocol) (traffic_selector_t *this);
+
+ /**
+ * @brief Get the netmask of the address range.
+ *
+ * Returns the number of bits associated to the subnet.
+ * (As the "24" in "192.168.0.0/24"). This is approximated
+ * if the address range is not a complete subnet! Since Linux
+ * does not support full IP address ranges (yet), we can't do this
+ * (much) better.
+ *
+ * @param this calling obect
+ * @return netmask as "bits for subnet"
+ */
+ u_int8_t (*get_netmask) (traffic_selector_t *this);
+
+ /**
+ * @brief Update the address of a traffic selector.
+ *
+ * Update the address range of a traffic selector,
+ * if the current address is 0.0.0.0. The new address range
+ * starts from the supplied address and also ends there
+ * (which means it is a one-host-address-range ;-).
+ *
+ * @param this calling obect
+ * @param host host_t specifying the address range
+ */
+ void (*update_address_range) (traffic_selector_t *this, host_t* host);
+
+ /**
+ * @brief Destroys the ts object
+ *
+ * @param this calling object
+ */
+ void (*destroy) (traffic_selector_t *this);
+};
+
+/**
+ * @brief 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
+ * @param from_addr start of address range as string
+ * @param from_port port number in host order
+ * @param to_addr end of address range as string
+ * @param to_port port number in host order
+ * @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, char *from_addr, u_int16_t from_port, char *to_addr, u_int16_t to_port);
+
+/**
+ * @brief 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
+ * don't have to convert twice.
+ *
+ * @param protocol protocol for this ts, such as TCP or UDP
+ * @param type type of following addresses, such as TS_IPV4_ADDR_RANGE
+ * @param from_address start of address range, network order
+ * @param from_port port number, host order
+ * @param to_address end of address range as string, network
+ * @param to_port port number, host order
+ * @return
+ * - traffic_selector_t object
+ * - NULL if invalid address input/protocol
+ *
+ * @ingroup config
+ */
+traffic_selector_t *traffic_selector_create_from_bytes(u_int8_t protocol, ts_type_t type, chunk_t from_address, int16_t from_port, chunk_t to_address, u_int16_t to_port);
+
+/**
+ * @brief 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
+ * all protocols, all ports and the address range specified by the
+ * subnet.
+ *
+ * @param net subnet to use
+ * @param netbits size of the subnet, as used in e.g. 192.168.0.0/24 notation
+ * @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);
+
+#endif /* TRAFFIC_SELECTOR_H_ */
diff --git a/programs/charon/charon/daemon.c b/programs/charon/charon/daemon.c
new file mode 100644
index 000000000..4b0ea54e8
--- /dev/null
+++ b/programs/charon/charon/daemon.c
@@ -0,0 +1,390 @@
+/**
+ * @file daemon.c
+ *
+ * @brief Implementation of daemon_t and main of IKEv2-Daemon.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stdio.h>
+#include <signal.h>
+#include <pthread.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <execinfo.h>
+#include <string.h>
+
+#include "daemon.h"
+
+#include <types.h>
+#include <config/connections/local_connection_store.h>
+#include <config/credentials/local_credential_store.h>
+#include <config/policies/local_policy_store.h>
+
+
+typedef struct private_daemon_t private_daemon_t;
+
+/**
+ * Private additions to daemon_t, contains threads and internal functions.
+ */
+struct private_daemon_t {
+ /**
+ * Public members of daemon_t.
+ */
+ daemon_t public;
+
+ /**
+ * A logger_t object assigned for daemon things.
+ */
+ logger_t *logger;
+
+ /**
+ * Signal set used for signal handling.
+ */
+ sigset_t signal_set;
+
+ /**
+ * The thread_id of main-thread.
+ */
+ pthread_t main_thread_id;
+
+ /**
+ * Main loop function.
+ *
+ * @param this calling object
+ */
+ void (*run) (private_daemon_t *this);
+
+ /**
+ * Initialize the daemon.
+ *
+ * @param this calling object
+ */
+ void (*initialize) (private_daemon_t *this);
+
+ /**
+ * Destroy the daemon.
+ *
+ * @param this calling object
+ */
+ void (*destroy) (private_daemon_t *this);
+};
+
+/**
+ * One and only instance of the daemon.
+ */
+daemon_t *charon;
+
+/**
+ * Implementation of private_daemon_t.run.
+ */
+static void run(private_daemon_t *this)
+{
+ /* reselect signals for this thread */
+ sigemptyset(&(this->signal_set));
+ sigaddset(&(this->signal_set), SIGINT);
+ sigaddset(&(this->signal_set), SIGHUP);
+ sigaddset(&(this->signal_set), SIGTERM);
+ pthread_sigmask(SIG_BLOCK, &(this->signal_set), 0);
+
+ while(TRUE)
+ {
+ int signal_number;
+ int error;
+
+ error = sigwait(&(this->signal_set), &signal_number);
+ if(error)
+ {
+ this->logger->log(this->logger, ERROR, "Error %d when waiting for signal", error);
+ return;
+ }
+ switch (signal_number)
+ {
+ case SIGHUP:
+ {
+ this->logger->log(this->logger, CONTROL, "Signal of type SIGHUP received. Do nothing");
+ break;
+ }
+ case SIGINT:
+ {
+ this->logger->log(this->logger, CONTROL, "Signal of type SIGINT received. Exit main loop");
+ return;
+ }
+ case SIGTERM:
+ this->logger->log(this->logger, CONTROL, "Signal of type SIGTERM received. Exit main loop");
+ return;
+ default:
+ {
+ this->logger->log(this->logger, CONTROL, "Unknown signal %d received. Do nothing", signal_number);
+ break;
+ }
+ }
+ }
+}
+
+/**
+ * Implementation of daemon_t.kill.
+ */
+static void kill_daemon(private_daemon_t *this, char *reason)
+{
+ /* we send SIGTERM, so the daemon can cleanly shut down */
+ this->logger->log(this->logger, CONTROL, "Killing daemon: %s", reason);
+ if (this->main_thread_id == pthread_self())
+ {
+ /* initialization failed, terminate daemon */
+ this->destroy(this);
+ unlink(PID_FILE);
+ exit(-1);
+ }
+ else
+ {
+ this->logger->log(this->logger, CONTROL, "sending SIGTERM to ourself", reason);
+ kill(0, SIGTERM);
+ /* thread must die, since he produced a ciritcal failure and can't continue */
+ pthread_exit(NULL);
+ }
+}
+
+/**
+ * Implementation of private_daemon_t.initialize.
+ */
+static void initialize(private_daemon_t *this)
+{
+ local_credential_store_t* cred_store;
+
+ this->public.configuration = configuration_create();
+ this->public.socket = socket_create(IKEV2_UDP_PORT);
+ this->public.ike_sa_manager = ike_sa_manager_create();
+ this->public.job_queue = job_queue_create();
+ this->public.event_queue = event_queue_create();
+ this->public.send_queue = send_queue_create();
+ this->public.connections = (connection_store_t*)local_connection_store_create();
+ this->public.policies = (policy_store_t*)local_policy_store_create();
+ this->public.credentials = (credential_store_t*)(cred_store = local_credential_store_create());
+
+ /* load keys & certs */
+ cred_store->load_certificates(cred_store, CERTIFICATE_DIR);
+ cred_store->load_private_keys(cred_store, PRIVATE_KEY_DIR);
+
+
+ /* start building threads, we are multi-threaded NOW */
+ this->public.stroke = stroke_create();
+ this->public.sender = sender_create();
+ this->public.receiver = receiver_create();
+ this->public.scheduler = scheduler_create();
+ this->public.kernel_interface = kernel_interface_create();
+ this->public.thread_pool = thread_pool_create(NUMBER_OF_WORKING_THREADS);
+}
+
+/**
+ * Destory all initiated objects
+ */
+static void destroy(private_daemon_t *this)
+{
+ if (this->public.ike_sa_manager != NULL)
+ {
+ this->public.ike_sa_manager->destroy(this->public.ike_sa_manager);
+ }
+ if (this->public.kernel_interface != NULL)
+ {
+ this->public.kernel_interface->destroy(this->public.kernel_interface);
+ }
+ if (this->public.receiver != NULL)
+ {
+ this->public.receiver->destroy(this->public.receiver);
+ }
+ if (this->public.scheduler != NULL)
+ {
+ this->public.scheduler->destroy(this->public.scheduler);
+ }
+ if (this->public.sender != NULL)
+ {
+ this->public.sender->destroy(this->public.sender);
+ }
+ if (this->public.thread_pool != NULL)
+ {
+ this->public.thread_pool->destroy(this->public.thread_pool);
+ }
+ if (this->public.job_queue != NULL)
+ {
+ this->public.job_queue->destroy(this->public.job_queue);
+ }
+ if (this->public.event_queue != NULL)
+ {
+ this->public.event_queue->destroy(this->public.event_queue);
+ }
+ if (this->public.send_queue != NULL)
+ {
+ this->public.send_queue->destroy(this->public.send_queue);
+ }
+ if (this->public.socket != NULL)
+ {
+ this->public.socket->destroy(this->public.socket);
+ }
+ if (this->public.configuration != NULL)
+ {
+ this->public.configuration->destroy(this->public.configuration);
+ }
+ if (this->public.credentials != NULL)
+ {
+ this->public.credentials->destroy(this->public.credentials);
+ }
+ if (this->public.connections != NULL)
+ {
+ this->public.connections->destroy(this->public.connections);
+ }
+ if (this->public.policies != NULL)
+ {
+ this->public.policies->destroy(this->public.policies);
+ }
+ if (this->public.stroke != NULL)
+ {
+ this->public.stroke->destroy(this->public.stroke);
+ }
+ free(this);
+}
+
+void signal_handler(int signal)
+{
+ void *array[20];
+ size_t size;
+ char **strings;
+ size_t i;
+ logger_t *logger;
+
+ size = backtrace(array, 20);
+ strings = backtrace_symbols(array, size);
+ logger = logger_manager->get_logger(logger_manager, DAEMON);
+
+ logger->log(logger, ERROR, "Thread %u received SIGSEGV. Dumping %d frames from stack:", pthread_self(), size);
+
+ for (i = 0; i < size; i++)
+ {
+ logger->log(logger, ERROR, " %s", strings[i]);
+ }
+ free (strings);
+ logger->log(logger, ERROR, "Killing ourself hard after SIGSEGV");
+ kill(getpid(), SIGKILL);
+}
+
+/**
+ * @brief Create the daemon.
+ *
+ * @return created daemon_t
+ */
+private_daemon_t *daemon_create()
+{
+ private_daemon_t *this = malloc_thing(private_daemon_t);
+ struct sigaction action;
+
+ /* assign methods */
+ this->run = run;
+ this->destroy = destroy;
+ this->initialize = initialize;
+ this->public.kill = (void (*) (daemon_t*,char*))kill_daemon;
+
+ /* NULL members for clean destruction */
+ this->public.socket = NULL;
+ this->public.ike_sa_manager = NULL;
+ this->public.job_queue = NULL;
+ this->public.event_queue = NULL;
+ this->public.send_queue = NULL;
+ this->public.configuration = NULL;
+ this->public.credentials = NULL;
+ this->public.connections = NULL;
+ this->public.policies = NULL;
+ this->public.sender= NULL;
+ this->public.receiver = NULL;
+ this->public.scheduler = NULL;
+ this->public.kernel_interface = NULL;
+ this->public.thread_pool = NULL;
+ this->public.stroke = NULL;
+
+ this->main_thread_id = pthread_self();
+
+ /* setup signal handling for all threads */
+ sigemptyset(&(this->signal_set));
+ sigaddset(&(this->signal_set), SIGSEGV);
+ sigaddset(&(this->signal_set), SIGINT);
+ sigaddset(&(this->signal_set), SIGHUP);
+ sigaddset(&(this->signal_set), SIGTERM);
+ pthread_sigmask(SIG_BLOCK, &(this->signal_set), 0);
+
+ /* setup SIGSEGV handler for all threads */
+ action.sa_handler = signal_handler;
+ action.sa_mask = this->signal_set;
+ action.sa_flags = 0;
+ if (sigaction(SIGSEGV, &action, NULL) == -1)
+ {
+ this->logger->log(this->logger, ERROR, "signal handler setup for SIGSEGV failed");
+ }
+ return this;
+}
+
+/**
+ * Main function, manages the daemon.
+ */
+int main(int argc, char *argv[])
+{
+ private_daemon_t *private_charon;
+ FILE *pid_file;
+ struct stat stb;
+ int i;
+
+ /* trivial argument parsing */
+ for (i = 1; i < argc; i++)
+ {
+ if (strcmp(argv[i], "--use-syslog") == 0)
+ {
+ logger_manager->set_output(logger_manager, ALL_LOGGERS, NULL);
+ }
+ }
+ private_charon = daemon_create();
+ charon = (daemon_t*)private_charon;
+
+ private_charon->logger = logger_manager->get_logger(logger_manager, DAEMON);
+
+ /* initialize daemon */
+ private_charon->initialize(private_charon);
+
+ /* check/setup PID file */
+ if (stat(PID_FILE, &stb) == 0)
+ {
+ private_charon->logger->log(private_charon->logger, ERROR,
+ "charon already running (\""PID_FILE"\" exists)");
+ private_charon->destroy(private_charon);
+ exit(-1);
+ }
+ pid_file = fopen(PID_FILE, "w");
+ if (pid_file)
+ {
+ fprintf(pid_file, "%d\n", getpid());
+ fclose(pid_file);
+ }
+
+ /* run daemon */
+ private_charon->run(private_charon);
+
+ /* normal termination, cleanup and exit */
+ private_charon->destroy(private_charon);
+ unlink(PID_FILE);
+
+ return 0;
+}
+
+
diff --git a/programs/charon/charon/daemon.h b/programs/charon/charon/daemon.h
new file mode 100644
index 000000000..5aee21fdb
--- /dev/null
+++ b/programs/charon/charon/daemon.h
@@ -0,0 +1,324 @@
+/**
+ * @file daemon.h
+ *
+ * @brief Interface of daemon_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef DAEMON_H_
+#define DAEMON_H_
+
+#include <threads/sender.h>
+#include <threads/receiver.h>
+#include <threads/scheduler.h>
+#include <threads/kernel_interface.h>
+#include <threads/thread_pool.h>
+#include <threads/stroke_interface.h>
+#include <network/socket.h>
+#include <sa/ike_sa_manager.h>
+#include <queues/send_queue.h>
+#include <queues/job_queue.h>
+#include <queues/event_queue.h>
+#include <utils/logger_manager.h>
+#include <config/configuration.h>
+#include <config/connections/connection_store.h>
+#include <config/policies/policy_store.h>
+#include <config/credentials/credential_store.h>
+
+/**
+ * @defgroup charon charon
+ *
+ * @brief IKEv2 keying daemon.
+ *
+ * @section Architecture
+ *
+ * All IKEv2 stuff is handled in charon. It uses a newer and more flexible
+ * architecture than pluto. Charon uses a thread-pool, which allows parallel
+ * execution SA-management. Beside the thread-pool, there are some special purpose
+ * threads which do their job for the common health of the daemon.
+ @verbatim
+ +------+
+ | E Q |
+ | v u |---+ +------+ +------+
+ | e e | | | | | IKE- |
+ | n u | +-----------+ | |--| SA |
+ | t e | | | | I M | +------+
+ +------------+ | - | | Scheduler | | K a |
+ | receiver | +------+ | | | E n | +------+
+ +----+-------+ +-----------+ | - a | | IKE- |
+ | | +------+ | | S g |--| SA |
+ +-------+--+ +-----| J Q |---+ +------------+ | A e | +------+
+ -| socket | | o u | | | | - r |
+ +-------+--+ | b e | | Thread- | | |
+ | | - u | | Pool | | |
+ +----+-------+ | e |------| |---| |
+ | sender | +------+ +------------+ +------+
+ +----+-------+
+ | +------+
+ | | S Q |
+ | | e u |
+ | | n e |
+ +------------| d u |
+ | - e |
+ +--+---+
+ @endverbatim
+ * The thread-pool is the heart of the architecture. It processes jobs from a
+ * (fully synchronized) job-queue. Mostly, a job is associated with a specific
+ * IKE SA. These IKE SAs are synchronized, only one thread can work one an IKE SA.
+ * This makes it unnecesary to use further synchronisation methods once a IKE SA
+ * is checked out. The (rather complex) synchronization of IKE SAs is completely
+ * done in the IKE SA manager.
+ * The sceduler is responsible for event firing. It waits until a event in the
+ * (fully synchronized) event-queue is ready for processing and pushes the event
+ * down to the job-queue. A thread form the pool will pick it up as quick as
+ * possible. Every thread can queue events or jobs. Furter, an event can place a
+ * packet in the send-queue. The sender thread waits for those packets and sends
+ * them over the wire, via the socket. The receiver does exactly the opposite of
+ * the sender. It waits on the socket, reads in packets an places them on the
+ * job-queue for further processing by a thread from the pool.
+ * There are even more threads, not drawn in the upper scheme. The stroke thread
+ * is responsible for reading and processessing commands from another process. The
+ * kernel interface thread handles communication from and to the kernel via a
+ * netlink socket. It waits for kernel events and processes them appropriately.
+ */
+
+/**
+ * @defgroup config config
+ *
+ * Classes implementing configuration related things.
+ *
+ * @ingroup charon
+ */
+
+/**
+ * @defgroup encoding encoding
+ *
+ * Classes used to encode and decode IKEv2 messages.
+ *
+ * @ingroup charon
+ */
+
+ /**
+ * @defgroup payloads payloads
+ *
+ * Classes representing specific IKEv2 payloads.
+ *
+ * @ingroup encoding
+ */
+
+/**
+ * @defgroup network network
+ *
+ * Classes for network relevant stuff.
+ *
+ * @ingroup charon
+ */
+
+/**
+ * @defgroup queues queues
+ *
+ * Different kind of queues
+ * (thread save lists).
+ *
+ * @ingroup charon
+ */
+
+/**
+ * @defgroup jobs jobs
+ *
+ * Jobs used in job queue and event queue.
+ *
+ * @ingroup queues
+ */
+
+/**
+ * @defgroup sa sa
+ *
+ * Security associations for IKE and IPSec,
+ * and some helper classes.
+ *
+ * @ingroup charon
+ */
+
+/**
+ * @defgroup states states
+ *
+ * Varius states in which an IKE SA can be.
+ *
+ * @ingroup sa
+ */
+
+/**
+ * @defgroup threads threads
+ *
+ * Threaded classes, which will do their job alone.
+ *
+ * @ingroup charon
+ */
+
+/**
+ * Name of the daemon.
+ *
+ * @ingroup charon
+ */
+#define DAEMON_NAME "charon"
+
+/**
+ * @brief Number of threads in the thread pool.
+ *
+ * There are several other threads, this defines
+ * only the number of threads in thread_pool_t.
+ *
+ * @ingroup charon
+ */
+#define NUMBER_OF_WORKING_THREADS 4
+
+/**
+ * UDP Port on which the daemon will listen for incoming traffic.
+ *
+ * @ingroup charon
+ */
+#define IKEV2_UDP_PORT 500
+
+/**
+ * PID file, in which charon stores its process id
+ *
+ * @ingroup charon
+ */
+#define PID_FILE "/var/run/charon.pid"
+
+/**
+ * Directory of IPsec relevant files
+ *
+ * @ingroup charon
+ */
+#define IPSEC_DIR "/etc/ipsec.d"
+
+/**
+ * Directory for private keys
+ *
+ * @ingroup charon
+ */
+#define PRIVATE_KEY_DIR IPSEC_DIR "/private"
+
+/**
+ * Directory for trusted certificates
+ *
+ * @ingroup charon
+ */
+#define CERTIFICATE_DIR IPSEC_DIR "/certs"
+
+
+typedef struct daemon_t daemon_t;
+
+/**
+ * @brief Main class of daemon, contains some globals.
+ *
+ * @ingroup charon
+ */
+struct daemon_t {
+ /**
+ * A socket_t instance.
+ */
+ socket_t *socket;
+
+ /**
+ * A send_queue_t instance.
+ */
+ send_queue_t *send_queue;
+
+ /**
+ * A job_queue_t instance.
+ */
+ job_queue_t *job_queue;
+
+ /**
+ * A event_queue_t instance.
+ */
+ event_queue_t *event_queue;
+
+ /**
+ * A ike_sa_manager_t instance.
+ */
+ ike_sa_manager_t *ike_sa_manager;
+
+ /**
+ * A configuration_t instance.
+ */
+ configuration_t *configuration;
+
+ /**
+ * A connection_store_t instance.
+ */
+ connection_store_t *connections;
+
+ /**
+ * A policy_store_t instance.
+ */
+ policy_store_t *policies;
+
+ /**
+ * A credential_store_t instance.
+ */
+ credential_store_t *credentials;
+
+ /**
+ * The Sender-Thread.
+ */
+ sender_t *sender;
+
+ /**
+ * The Receiver-Thread.
+ */
+ receiver_t *receiver;
+
+ /**
+ * The Scheduler-Thread.
+ */
+ scheduler_t *scheduler;
+
+ /**
+ * The Thread pool managing the worker threads.
+ */
+ thread_pool_t *thread_pool;
+
+ /**
+ * Kernel Interface to communicate with kernel
+ */
+ kernel_interface_t *kernel_interface;
+
+ /**
+ * IPC interface, as whack in pluto
+ */
+ stroke_t *stroke;
+
+ /**
+ * @brief 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);
+};
+
+/**
+ * The one and only instance of the daemon.
+ */
+extern daemon_t *charon;
+
+#endif /*DAEMON_H_*/
diff --git a/programs/charon/charon/encoding/Makefile.encoding b/programs/charon/charon/encoding/Makefile.encoding
new file mode 100644
index 000000000..ccdb42f79
--- /dev/null
+++ b/programs/charon/charon/encoding/Makefile.encoding
@@ -0,0 +1,30 @@
+# Copyright (C) 2005 Jan Hutter, Martin Willi
+# Hochschule fuer Technik Rapperswil
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+
+ENCODING_DIR= $(CHARON_DIR)encoding/
+
+CHARON_OBJS+= $(BUILD_DIR)generator.o
+$(BUILD_DIR)generator.o : $(ENCODING_DIR)generator.c $(ENCODING_DIR)generator.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)parser.o
+$(BUILD_DIR)parser.o : $(ENCODING_DIR)parser.c $(ENCODING_DIR)parser.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)message.o
+$(BUILD_DIR)message.o : $(ENCODING_DIR)message.c $(ENCODING_DIR)message.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+
+include $(ENCODING_DIR)payloads/Makefile.payloads \ No newline at end of file
diff --git a/programs/charon/charon/encoding/generator.c b/programs/charon/charon/encoding/generator.c
new file mode 100644
index 000000000..ba12190dd
--- /dev/null
+++ b/programs/charon/charon/encoding/generator.c
@@ -0,0 +1,1077 @@
+/**
+ * @file generator.c
+ *
+ * @brief Implementation of generator_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+
+
+#include "generator.h"
+
+#include <types.h>
+#include <daemon.h>
+#include <utils/linked_list.h>
+#include <utils/logger_manager.h>
+#include <encoding/payloads/payload.h>
+#include <encoding/payloads/proposal_substructure.h>
+#include <encoding/payloads/transform_substructure.h>
+#include <encoding/payloads/sa_payload.h>
+#include <encoding/payloads/ke_payload.h>
+#include <encoding/payloads/notify_payload.h>
+#include <encoding/payloads/nonce_payload.h>
+#include <encoding/payloads/id_payload.h>
+#include <encoding/payloads/auth_payload.h>
+#include <encoding/payloads/cert_payload.h>
+#include <encoding/payloads/certreq_payload.h>
+#include <encoding/payloads/ts_payload.h>
+#include <encoding/payloads/delete_payload.h>
+#include <encoding/payloads/vendor_id_payload.h>
+#include <encoding/payloads/cp_payload.h>
+#include <encoding/payloads/configuration_attribute.h>
+#include <encoding/payloads/eap_payload.h>
+
+
+typedef struct private_generator_t private_generator_t;
+
+/**
+ * Private part of a generator_t object.
+ */
+struct private_generator_t {
+ /**
+ * Public part of a generator_t object.
+ */
+ generator_t public;
+
+ /**
+ * Generates a U_INT-Field type and writes it to buffer.
+ *
+ * @param this private_generator_t object
+ * @param int_type type of U_INT field (U_INT_4, U_INT_8, etc.)
+ * ATTRIBUTE_TYPE is also generated in this function
+ * @param offset offset of value in data struct
+ * @param generator_contexts generator_contexts_t object where the context is written or read from
+ * @return
+ * - SUCCESS
+ * - FAILED if allignment is wrong
+ */
+ void (*generate_u_int_type) (private_generator_t *this,encoding_type_t int_type,u_int32_t offset);
+
+ /**
+ * Get size of current buffer in bytes.
+ *
+ * @param this private_generator_t object
+ * @return Size of buffer in bytes
+ */
+ size_t (*get_current_buffer_size) (private_generator_t *this);
+
+ /**
+ * Get free space of current buffer in bytes.
+ *
+ * @param this private_generator_t object
+ * @return space in buffer in bytes
+ */
+ size_t (*get_current_buffer_space) (private_generator_t *this);
+
+ /**
+ * Get length of data in buffer (in bytes).
+ *
+ * @param this private_generator_t object
+ * @return length of data in bytes
+ */
+ size_t (*get_current_data_length) (private_generator_t *this);
+
+ /**
+ * Get current offset in buffer (in bytes).
+ *
+ * @param this private_generator_t object
+ * @return offset in bytes
+ */
+ u_int32_t (*get_current_buffer_offset) (private_generator_t *this);
+
+ /**
+ * Generates a RESERVED BIT field or a RESERVED BYTE field and writes
+ * it to the buffer.
+ *
+ * @param this private_generator_t object
+ * @param generator_contexts generator_contexts_t object where the context is written or read from
+ * @param bits number of bits to generate
+ */
+ void (*generate_reserved_field) (private_generator_t *this,int bits);
+
+ /**
+ * Generates a FLAG field.
+ *
+ * @param this private_generator_t object
+ * @param generator_contexts generator_contexts_t object where the context is written or read from
+ * @param offset offset of flag value in data struct
+ */
+ void (*generate_flag) (private_generator_t *this,u_int32_t offset);
+
+ /**
+ * Writes the current buffer content into a chunk_t.
+ *
+ * Memory of specific chunk_t gets allocated.
+ *
+ * @param this calling private_generator_t object
+ * @param data pointer of chunk_t to write to
+ */
+ void (*write_chunk) (private_generator_t *this,chunk_t *data);
+
+ /**
+ * Generates a bytestream from a chunk_t.
+ *
+ * @param this private_generator_t object
+ * @param offset offset of chunk_t value in data struct
+ */
+ void (*generate_from_chunk) (private_generator_t *this,u_int32_t offset);
+
+ /**
+ * Makes sure enough space is available in buffer to store amount of bits.
+ *
+ * If buffer is to small to hold the specific amount of bits it
+ * is increased using reallocation function of allocator.
+ *
+ * @param this calling private_generator_t object
+ * @param bits number of bits to make available in buffer
+ */
+ void (*make_space_available) (private_generator_t *this,size_t bits);
+
+ /**
+ * Writes a specific amount of byte into the buffer.
+ *
+ * If buffer is to small to hold the specific amount of bytes it
+ * is increased.
+ *
+ * @param this calling private_generator_t object
+ * @param bytes pointer to bytes to write
+ * @param number_of_bytes number of bytes to write into buffer
+ */
+ void (*write_bytes_to_buffer) (private_generator_t *this,void * bytes,size_t number_of_bytes);
+
+
+ /**
+ * Writes a specific amount of byte into the buffer at a specific offset.
+ *
+ * @warning buffer size is not check to hold the data if offset is to large.
+ *
+ * @param this calling private_generator_t object
+ * @param bytes pointer to bytes to write
+ * @param number_of_bytes number of bytes to write into buffer
+ * @param offset offset to write the data into
+ */
+ void (*write_bytes_to_buffer_at_offset) (private_generator_t *this,void * bytes,size_t number_of_bytes,u_int32_t offset);
+
+ /**
+ * Buffer used to generate the data into.
+ */
+ u_int8_t *buffer;
+
+ /**
+ * Current write position in buffer (one byte aligned).
+ */
+ u_int8_t *out_position;
+
+ /**
+ * Position of last byte in buffer.
+ */
+ u_int8_t *roof_position;
+
+ /**
+ * Current bit writing to in current byte (between 0 and 7).
+ */
+ size_t current_bit;
+
+ /**
+ * Associated data struct to read informations from.
+ */
+ void * data_struct;
+
+ /*
+ * Last payload length position offset in the buffer.
+ */
+ u_int32_t last_payload_length_position_offset;
+
+ /**
+ * Offset of the header length field in the buffer.
+ */
+ u_int32_t header_length_position_offset;
+
+ /**
+ * Last SPI size.
+ */
+ u_int8_t last_spi_size;
+
+ /*
+ * Attribute format of the last generated transform attribute.
+ *
+ * Used to check if a variable value field is used or not for
+ * the transform attribute value.
+ */
+ bool attribute_format;
+
+ /*
+ * Depending on the value of attribute_format this field is used
+ * to hold the length of the transform attribute in bytes.
+ */
+ u_int16_t attribute_length;
+
+ /**
+ * Associated Logger.
+ */
+ logger_t *logger;
+};
+
+/**
+ * Implementation of private_generator_t.get_current_buffer_size.
+ */
+static size_t get_current_buffer_size (private_generator_t *this)
+{
+ return ((this->roof_position) - (this->buffer));
+}
+
+/**
+ * Implementation of private_generator_t.get_current_buffer_space.
+ */
+static size_t get_current_buffer_space (private_generator_t *this)
+{
+ /* we know, one byte more */
+ size_t space = (this->roof_position) - (this->out_position);
+ return (space);
+}
+
+/**
+ * Implementation of private_generator_t.get_current_data_length.
+ */
+static size_t get_current_data_length (private_generator_t *this)
+{
+ return (this->out_position - this->buffer);
+}
+
+/**
+ * Implementation of private_generator_t.get_current_buffer_offset.
+ */
+static u_int32_t get_current_buffer_offset (private_generator_t *this)
+{
+ return (this->out_position - this->buffer);
+}
+
+/**
+ * Implementation of private_generator_t.generate_u_int_type.
+ */
+static void generate_u_int_type (private_generator_t *this,encoding_type_t int_type,u_int32_t offset)
+{
+ size_t number_of_bits = 0;
+
+ /* find out number of bits of each U_INT type to check for enough space
+ in buffer */
+ switch (int_type)
+ {
+ case U_INT_4:
+ number_of_bits = 4;
+ break;
+ case TS_TYPE:
+ case U_INT_8:
+ number_of_bits = 8;
+ break;
+ case U_INT_16:
+ case CONFIGURATION_ATTRIBUTE_LENGTH:
+ number_of_bits = 16;
+ break;
+ case U_INT_32:
+ number_of_bits = 32;
+ break;
+ case U_INT_64:
+ number_of_bits = 64;
+ break;
+ case ATTRIBUTE_TYPE:
+ number_of_bits = 15;
+ break;
+ case IKE_SPI:
+ number_of_bits = 64;
+ break;
+
+ default:
+ this->logger->log(this->logger, ERROR, "U_INT Type %s is not supported",
+ mapping_find(encoding_type_m,int_type));
+
+ return;
+ }
+ /* U_INT Types of multiple then 8 bits must be aligned */
+ if (((number_of_bits % 8) == 0) && (this->current_bit != 0))
+ {
+ this->logger->log(this->logger, ERROR, "U_INT Type %s is not 8 Bit aligned",
+ mapping_find(encoding_type_m,int_type));
+ /* current bit has to be zero for values multiple of 8 bits */
+ return;
+ }
+
+ /* make sure enough space is available in buffer */
+ this->make_space_available(this,number_of_bits);
+ /* now handle each u int type differently */
+ switch (int_type)
+ {
+ case U_INT_4:
+ {
+ if (this->current_bit == 0)
+ {
+ /* highval of current byte in buffer has to be set to the new value*/
+ u_int8_t high_val = *((u_int8_t *)(this->data_struct + offset)) << 4;
+ /* lowval in buffer is not changed */
+ u_int8_t low_val = *(this->out_position) & 0x0F;
+ /* highval is set, low_val is not changed */
+ *(this->out_position) = high_val | low_val;
+ this->logger->log(this->logger, RAW|LEVEL2, " => %d", *(this->out_position));
+ /* write position is not changed, just bit position is moved */
+ this->current_bit = 4;
+ }
+ else if (this->current_bit == 4)
+ {
+ /* highval in buffer is not changed */
+ u_int high_val = *(this->out_position) & 0xF0;
+ /* lowval of current byte in buffer has to be set to the new value*/
+ u_int low_val = *((u_int8_t *)(this->data_struct + offset)) & 0x0F;
+ *(this->out_position) = high_val | low_val;
+ this->logger->log(this->logger, RAW|LEVEL2, " => %d", *(this->out_position));
+ this->out_position++;
+ this->current_bit = 0;
+
+ }
+ else
+ {
+ this->logger->log(this->logger, ERROR, "U_INT_4 Type is not 4 Bit aligned");
+ /* 4 Bit integers must have a 4 bit alignment */
+ return;
+ };
+ break;
+ }
+ case TS_TYPE:
+ case U_INT_8:
+ {
+ /* 8 bit values are written as they are */
+ *this->out_position = *((u_int8_t *)(this->data_struct + offset));
+ this->logger->log(this->logger, RAW|LEVEL2, " => %d", *(this->out_position));
+ this->out_position++;
+ break;
+
+ }
+ case ATTRIBUTE_TYPE:
+ {
+ /* attribute type must not change first bit uf current byte ! */
+ if (this->current_bit != 1)
+ {
+ this->logger->log(this->logger, ERROR, "ATTRIBUTE FORMAT flag is not set");
+ /* first bit has to be set! */
+ return;
+ }
+ /* get value of attribute format flag */
+ u_int8_t attribute_format_flag = *(this->out_position) & 0x80;
+ /* get attribute type value as 16 bit integer*/
+ u_int16_t int16_val = htons(*((u_int16_t*)(this->data_struct + offset)));
+ /* last bit must be unset */
+ int16_val = int16_val & 0xFF7F;
+
+ int16_val = int16_val | attribute_format_flag;
+ this->logger->log(this->logger, RAW|LEVEL2, " => %d", int16_val);
+ /* write bytes to buffer (set bit is overwritten)*/
+ this->write_bytes_to_buffer(this,&int16_val,sizeof(u_int16_t));
+ this->current_bit = 0;
+ break;
+
+ }
+ case U_INT_16:
+ case CONFIGURATION_ATTRIBUTE_LENGTH:
+ {
+ u_int16_t int16_val = htons(*((u_int16_t*)(this->data_struct + offset)));
+ this->logger->log_bytes(this->logger, RAW|LEVEL2, " =>", (void*)&int16_val, sizeof(int16_val));
+ this->write_bytes_to_buffer(this,&int16_val,sizeof(u_int16_t));
+ break;
+ }
+ case U_INT_32:
+ {
+ u_int32_t int32_val = htonl(*((u_int32_t*)(this->data_struct + offset)));
+ this->logger->log_bytes(this->logger, RAW|LEVEL2, " =>", (void*)&int32_val, sizeof(int32_val));
+ this->write_bytes_to_buffer(this,&int32_val,sizeof(u_int32_t));
+ break;
+ }
+ case U_INT_64:
+ {
+ /* 64 bit integers are written as two 32 bit integers */
+ u_int32_t int32_val_low = htonl(*((u_int32_t*)(this->data_struct + offset)));
+ u_int32_t int32_val_high = htonl(*((u_int32_t*)(this->data_struct + offset) + 1));
+ this->logger->log_bytes(this->logger, RAW|LEVEL2, " => (low)", (void*)&int32_val_low, sizeof(int32_val_low));
+ this->logger->log_bytes(this->logger, RAW|LEVEL2, " => (high)", (void*)&int32_val_high, sizeof(int32_val_high));
+ /* TODO add support for big endian machines */
+ this->write_bytes_to_buffer(this,&int32_val_high,sizeof(u_int32_t));
+ this->write_bytes_to_buffer(this,&int32_val_low,sizeof(u_int32_t));
+ break;
+ }
+
+ case IKE_SPI:
+ {
+ /* 64 bit are written as they come :-) */
+ this->write_bytes_to_buffer(this,(this->data_struct + offset),sizeof(u_int64_t));
+ this->logger->log_bytes(this->logger, RAW|LEVEL2, " =>", (void*)(this->data_struct + offset), sizeof(u_int64_t));
+ break;
+ }
+ default:
+ {
+ this->logger->log(this->logger, ERROR, "U_INT Type %s is not supported", mapping_find(encoding_type_m,int_type));
+ return;
+ }
+ }
+}
+
+/**
+ * Implementation of private_generator_t.generate_reserved_field.
+ */
+static void generate_reserved_field(private_generator_t *this,int bits)
+{
+ /* only one bit or 8 bit fields are supported */
+ if ((bits != 1) && (bits != 8))
+ {
+ this->logger->log(this->logger, ERROR, "Reserved field of %d bits cannot be generated", bits);
+ return ;
+ }
+ /* make sure enough space is available in buffer */
+ this->make_space_available(this,bits);
+
+ if (bits == 1)
+ {
+ /* one bit processing */
+ u_int8_t reserved_bit = ~(1 << (7 - this->current_bit));
+ *(this->out_position) = *(this->out_position) & reserved_bit;
+ if (this->current_bit == 0)
+ {
+ /* memory must be zero */
+ *(this->out_position) = 0x00;
+ }
+
+
+ this->current_bit++;
+ if (this->current_bit >= 8)
+ {
+ this->current_bit = this->current_bit % 8;
+ this->out_position++;
+ }
+ }
+ else
+ {
+ /* one byte processing*/
+ if (this->current_bit > 0)
+ {
+ this->logger->log(this->logger, ERROR,
+ "Reserved field cannot be written cause allignement of current bit is %d",
+ this->current_bit);
+ return;
+ }
+ *(this->out_position) = 0x00;
+ this->out_position++;
+ }
+}
+
+/**
+ * Implementation of private_generator_t.generate_flag.
+ */
+static void generate_flag (private_generator_t *this,u_int32_t offset)
+{
+ /* value of current flag */
+ u_int8_t flag_value;
+ /* position of flag in current byte */
+ u_int8_t flag;
+
+ /* if the value in the data_struct is TRUE, flag_value is set to 1, 0 otherwise */
+ flag_value = (*((bool *) (this->data_struct + offset))) ? 1 : 0;
+ /* get flag position */
+ flag = (flag_value << (7 - this->current_bit));
+
+ /* make sure one bit is available in buffer */
+ this->make_space_available(this,1);
+ if (this->current_bit == 0)
+ {
+ /* memory must be zero */
+ *(this->out_position) = 0x00;
+ }
+
+ *(this->out_position) = *(this->out_position) | flag;
+
+
+ this->logger->log(this->logger, RAW|LEVEL2, " => %d", *(this->out_position));
+
+ this->current_bit++;
+ if (this->current_bit >= 8)
+ {
+ this->current_bit = this->current_bit % 8;
+ this->out_position++;
+ }
+}
+
+/**
+ * Implementation of private_generator_t.generate_from_chunk.
+ */
+static void generate_from_chunk (private_generator_t *this,u_int32_t offset)
+{
+ if (this->current_bit != 0)
+ {
+ this->logger->log(this->logger, ERROR, "can not generate a chunk at Bitpos %d", this->current_bit);
+ return ;
+ }
+
+ /* position in buffer */
+ chunk_t *attribute_value = (chunk_t *)(this->data_struct + offset);
+
+ this->logger->log_chunk(this->logger, RAW|LEVEL2, " =>", *attribute_value);
+
+ /* use write_bytes_to_buffer function to do the job */
+ this->write_bytes_to_buffer(this,attribute_value->ptr,attribute_value->len);
+}
+
+/**
+ * Implementation of private_generator_t.make_space_available.
+ */
+static void make_space_available (private_generator_t *this, size_t bits)
+{
+ while (((this->get_current_buffer_space(this) * 8) - this->current_bit) < bits)
+ {
+ /* must increase buffer */
+ size_t old_buffer_size = this->get_current_buffer_size(this);
+ size_t new_buffer_size = old_buffer_size + GENERATOR_DATA_BUFFER_INCREASE_VALUE;
+ size_t out_position_offset = ((this->out_position) - (this->buffer));
+
+ this->logger->log(this->logger, CONTROL|LEVEL3, "increased gen buffer from %d to %d byte",
+ old_buffer_size, new_buffer_size);
+
+ /* Reallocate space for new buffer */
+ this->buffer = realloc(this->buffer,new_buffer_size);
+
+ this->out_position = (this->buffer + out_position_offset);
+ this->roof_position = (this->buffer + new_buffer_size);
+ }
+}
+
+/**
+ * Implementation of private_generator_t.write_bytes_to_buffer.
+ */
+static void write_bytes_to_buffer (private_generator_t *this,void * bytes, size_t number_of_bytes)
+{
+ int i;
+ u_int8_t *read_position = (u_int8_t *) bytes;
+
+ this->make_space_available(this,number_of_bytes * 8);
+
+ for (i = 0; i < number_of_bytes; i++)
+ {
+ *(this->out_position) = *(read_position);
+ read_position++;
+ this->out_position++;
+ }
+}
+
+/**
+ * Implementation of private_generator_t.write_bytes_to_buffer_at_offset.
+ */
+static void write_bytes_to_buffer_at_offset (private_generator_t *this,void * bytes,size_t number_of_bytes,u_int32_t offset)
+{
+ int i;
+ u_int8_t *read_position = (u_int8_t *) bytes;
+ u_int8_t *write_position;
+ u_int32_t free_space_after_offset = (this->get_current_buffer_size(this) - offset);
+
+ /* check first if enough space for new data is available */
+ if (number_of_bytes > free_space_after_offset)
+ {
+ this->make_space_available(this,(number_of_bytes - free_space_after_offset) * 8);
+ }
+
+ write_position = this->buffer + offset;
+ for (i = 0; i < number_of_bytes; i++)
+ {
+ *(write_position) = *(read_position);
+ read_position++;
+ write_position++;
+ }
+}
+
+/**
+ * Implementation of private_generator_t.write_to_chunk.
+ */
+static void write_to_chunk (private_generator_t *this,chunk_t *data)
+{
+ size_t data_length = this->get_current_data_length(this);
+ u_int32_t header_length_field = data_length;
+
+ /* write length into header length field */
+ if (this->header_length_position_offset > 0)
+ {
+ u_int32_t int32_val = htonl(header_length_field);
+ this->write_bytes_to_buffer_at_offset(this,&int32_val,sizeof(u_int32_t),this->header_length_position_offset);
+ }
+
+ if (this->current_bit > 0)
+ data_length++;
+ data->ptr = malloc(data_length);
+ memcpy(data->ptr,this->buffer,data_length);
+ data->len = data_length;
+
+ this->logger->log_chunk(this->logger, RAW|LEVEL3, "generated data of this generator", *data);
+}
+
+/**
+ * Implementation of private_generator_t.generate_payload.
+ */
+static void generate_payload (private_generator_t *this,payload_t *payload)
+{
+ int i;
+ this->data_struct = payload;
+ size_t rule_count;
+ encoding_rule_t *rules;
+ payload_type_t payload_type;
+ u_int8_t *payload_start;
+
+ /* get payload type */
+ payload_type = payload->get_type(payload);
+ /* spi size has to get reseted */
+ this->last_spi_size = 0;
+
+ payload_start = this->out_position;
+
+ this->logger->log(this->logger, CONTROL|LEVEL1, "generating payload of type %s",
+ mapping_find(payload_type_m,payload_type));
+
+ /* each payload has its own encoding rules */
+ payload->get_encoding_rules(payload,&rules,&rule_count);
+
+ for (i = 0; i < rule_count;i++)
+ {
+ this->logger->log(this->logger, CONTROL|LEVEL2, " generating rule %d %s",
+ i, mapping_find(encoding_type_m,rules[i].type));
+ switch (rules[i].type)
+ {
+ /* all u int values, IKE_SPI,TS_TYPE and ATTRIBUTE_TYPE are generated in generate_u_int_type */
+ case U_INT_4:
+ case U_INT_8:
+ case U_INT_16:
+ case U_INT_32:
+ case U_INT_64:
+ case IKE_SPI:
+ case TS_TYPE:
+ case ATTRIBUTE_TYPE:
+ case CONFIGURATION_ATTRIBUTE_LENGTH:
+ {
+ this->generate_u_int_type(this,rules[i].type,rules[i].offset);
+ break;
+ }
+ case RESERVED_BIT:
+ {
+ this->generate_reserved_field(this,1);
+ break;
+ }
+ case RESERVED_BYTE:
+ {
+ this->generate_reserved_field(this,8);
+ break;
+ }
+ case FLAG:
+ {
+ this->generate_flag(this,rules[i].offset);
+ break;
+ }
+ case PAYLOAD_LENGTH:
+ {
+ /* position of payload lenght field is temporary stored */
+ this->last_payload_length_position_offset = this->get_current_buffer_offset(this);
+ /* payload length is generated like an U_INT_16 */
+ this->generate_u_int_type(this,U_INT_16,rules[i].offset);
+ break;
+ }
+ case HEADER_LENGTH:
+ {
+ /* position of header length field is temporary stored */
+ this->header_length_position_offset = this->get_current_buffer_offset(this);
+ /* header length is generated like an U_INT_32 */
+ this->generate_u_int_type(this,U_INT_32,rules[i].offset);
+ break;
+ }
+ case SPI_SIZE:
+ /* spi size is handled as 8 bit unsigned integer */
+ this->generate_u_int_type(this,U_INT_8,rules[i].offset);
+ /* last spi size is temporary stored */
+ this->last_spi_size = *((u_int8_t *)(this->data_struct + rules[i].offset));
+ break;
+ case ADDRESS:
+ {
+ /* the Address value is generated from chunk */
+ this->generate_from_chunk(this,rules[i].offset);
+ break;
+ }
+ case SPI:
+ {
+ /* the SPI value is generated from chunk */
+ this->generate_from_chunk(this,rules[i].offset);
+ break;
+ }
+ case KEY_EXCHANGE_DATA:
+ case NOTIFICATION_DATA:
+ case NONCE_DATA:
+ case ID_DATA:
+ case AUTH_DATA:
+ case CERT_DATA:
+ case CERTREQ_DATA:
+ case SPIS:
+ case CONFIGURATION_ATTRIBUTE_VALUE:
+ case VID_DATA:
+ case EAP_MESSAGE:
+ {
+ u_int32_t payload_length_position_offset;
+ u_int16_t length_of_payload;
+ u_int16_t header_length = 0;
+ u_int16_t length_in_network_order;
+
+ switch(rules[i].type)
+ {
+ case KEY_EXCHANGE_DATA:
+ header_length = KE_PAYLOAD_HEADER_LENGTH;
+ break;
+ case NOTIFICATION_DATA:
+ header_length = NOTIFY_PAYLOAD_HEADER_LENGTH + this->last_spi_size ;
+ break;
+ case NONCE_DATA:
+ header_length = NONCE_PAYLOAD_HEADER_LENGTH;
+ break;
+ case ID_DATA:
+ header_length = ID_PAYLOAD_HEADER_LENGTH;
+ break;
+ case AUTH_DATA:
+ header_length = AUTH_PAYLOAD_HEADER_LENGTH;
+ break;
+ case CERT_DATA:
+ header_length = CERT_PAYLOAD_HEADER_LENGTH;
+ break;
+ case CERTREQ_DATA:
+ header_length = CERTREQ_PAYLOAD_HEADER_LENGTH;
+ break;
+ case SPIS:
+ header_length = DELETE_PAYLOAD_HEADER_LENGTH;
+ break;
+ case VID_DATA:
+ header_length = VENDOR_ID_PAYLOAD_HEADER_LENGTH;
+ break;
+ case CONFIGURATION_ATTRIBUTE_VALUE:
+ header_length = CONFIGURATION_ATTRIBUTE_HEADER_LENGTH;
+ break;
+ case EAP_MESSAGE:
+ header_length = EAP_PAYLOAD_HEADER_LENGTH;
+ break;
+ default:
+ break;
+ }
+
+ /* the data value is generated from chunk */
+ this->generate_from_chunk(this,rules[i].offset);
+
+ payload_length_position_offset = this->last_payload_length_position_offset;
+
+
+ /* Length of payload is calculated */
+ length_of_payload = header_length + ((chunk_t *)(this->data_struct + rules[i].offset))->len;
+
+ length_in_network_order = htons(length_of_payload);
+ this->write_bytes_to_buffer_at_offset(this,&length_in_network_order,sizeof(u_int16_t),payload_length_position_offset);
+ break;
+ }
+ case PROPOSALS:
+ {
+ /* before iterative generate the transforms, store the current payload length position */
+ u_int32_t payload_length_position_offset = this->last_payload_length_position_offset;
+ /* Length of SA_PAYLOAD is calculated */
+ u_int16_t length_of_sa_payload = SA_PAYLOAD_HEADER_LENGTH;
+ u_int16_t int16_val;
+ /* proposals are stored in a linked list and so accessed */
+ linked_list_t *proposals = *((linked_list_t **)(this->data_struct + rules[i].offset));
+
+ iterator_t *iterator;
+ /* create forward iterator */
+ iterator = proposals->create_iterator(proposals,TRUE);
+ /* every proposal is processed (iterative call )*/
+ while (iterator->has_next(iterator))
+ {
+ payload_t *current_proposal;
+ u_int32_t before_generate_position_offset;
+ u_int32_t after_generate_position_offset;
+
+ iterator->current(iterator,(void **)&current_proposal);
+
+ before_generate_position_offset = this->get_current_buffer_offset(this);
+ this->public.generate_payload(&(this->public),current_proposal);
+ after_generate_position_offset = this->get_current_buffer_offset(this);
+
+ /* increase size of transform */
+ length_of_sa_payload += (after_generate_position_offset - before_generate_position_offset);
+ }
+ iterator->destroy(iterator);
+
+ int16_val = htons(length_of_sa_payload);
+ this->write_bytes_to_buffer_at_offset(this,&int16_val,sizeof(u_int16_t),payload_length_position_offset);
+ break;
+ }
+ case TRANSFORMS:
+ {
+ /* before iterative generate the transforms, store the current length position */
+ u_int32_t payload_length_position_offset = this->last_payload_length_position_offset;
+ u_int16_t length_of_proposal = PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH + this->last_spi_size;
+ u_int16_t int16_val;
+ linked_list_t *transforms = *((linked_list_t **)(this->data_struct + rules[i].offset));
+ iterator_t *iterator;
+
+ /* create forward iterator */
+ iterator = transforms->create_iterator(transforms,TRUE);
+ while (iterator->has_next(iterator))
+ {
+ payload_t *current_transform;
+ u_int32_t before_generate_position_offset;
+ u_int32_t after_generate_position_offset;
+
+ iterator->current(iterator,(void **)&current_transform);
+
+ before_generate_position_offset = this->get_current_buffer_offset(this);
+ this->public.generate_payload(&(this->public),current_transform);
+ after_generate_position_offset = this->get_current_buffer_offset(this);
+
+ /* increase size of transform */
+ length_of_proposal += (after_generate_position_offset - before_generate_position_offset);
+ }
+
+ iterator->destroy(iterator);
+
+ int16_val = htons(length_of_proposal);
+ this->write_bytes_to_buffer_at_offset(this,&int16_val,sizeof(u_int16_t),payload_length_position_offset);
+
+ break;
+ }
+ case TRANSFORM_ATTRIBUTES:
+ {
+ /* before iterative generate the transform attributes, store the current length position */
+ u_int32_t transform_length_position_offset = this->last_payload_length_position_offset;
+
+ u_int16_t length_of_transform = TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH;
+ u_int16_t int16_val;
+ linked_list_t *transform_attributes =*((linked_list_t **)(this->data_struct + rules[i].offset));
+
+ iterator_t *iterator;
+ /* create forward iterator */
+ iterator = transform_attributes->create_iterator(transform_attributes,TRUE);
+ while (iterator->has_next(iterator))
+ {
+ payload_t *current_attribute;
+ u_int32_t before_generate_position_offset;
+ u_int32_t after_generate_position_offset;
+
+ iterator->current(iterator,(void **)&current_attribute);
+
+ before_generate_position_offset = this->get_current_buffer_offset(this);
+ this->public.generate_payload(&(this->public),current_attribute);
+ after_generate_position_offset = this->get_current_buffer_offset(this);
+
+ /* increase size of transform */
+ length_of_transform += (after_generate_position_offset - before_generate_position_offset);
+ }
+
+ iterator->destroy(iterator);
+
+ int16_val = htons(length_of_transform);
+ this->write_bytes_to_buffer_at_offset(this,&int16_val,sizeof(u_int16_t),transform_length_position_offset);
+
+ break;
+ }
+ case CONFIGURATION_ATTRIBUTES:
+ {
+ /* before iterative generate the configuration attributes, store the current length position */
+ u_int32_t configurations_length_position_offset = this->last_payload_length_position_offset;
+
+ u_int16_t length_of_configurations = CP_PAYLOAD_HEADER_LENGTH;
+ u_int16_t int16_val;
+ linked_list_t *configuration_attributes =*((linked_list_t **)(this->data_struct + rules[i].offset));
+
+ iterator_t *iterator;
+ /* create forward iterator */
+ iterator = configuration_attributes->create_iterator(configuration_attributes,TRUE);
+ while (iterator->has_next(iterator))
+ {
+ payload_t *current_attribute;
+ u_int32_t before_generate_position_offset;
+ u_int32_t after_generate_position_offset;
+
+ iterator->current(iterator,(void **)&current_attribute);
+
+ before_generate_position_offset = this->get_current_buffer_offset(this);
+ this->public.generate_payload(&(this->public),current_attribute);
+ after_generate_position_offset = this->get_current_buffer_offset(this);
+
+ /* increase size of transform */
+ length_of_configurations += (after_generate_position_offset - before_generate_position_offset);
+ }
+
+ iterator->destroy(iterator);
+
+ int16_val = htons(length_of_configurations);
+ this->write_bytes_to_buffer_at_offset(this,&int16_val,sizeof(u_int16_t),configurations_length_position_offset);
+
+ break;
+ }
+ case ATTRIBUTE_FORMAT:
+ {
+ this->generate_flag(this,rules[i].offset);
+ /* Attribute format is a flag which is stored in context*/
+ this->attribute_format = *((bool *) (this->data_struct + rules[i].offset));
+ break;
+ }
+
+ case ATTRIBUTE_LENGTH_OR_VALUE:
+ {
+ if (this->attribute_format == FALSE)
+ {
+ this->generate_u_int_type(this,U_INT_16,rules[i].offset);
+ /* this field hold the length of the attribute */
+ this->attribute_length = *((u_int16_t *)(this->data_struct + rules[i].offset));
+ }
+ else
+ {
+ this->generate_u_int_type(this,U_INT_16,rules[i].offset);
+ }
+ break;
+ }
+ case ATTRIBUTE_VALUE:
+ {
+ if (this->attribute_format == FALSE)
+ {
+ this->logger->log(this->logger, CONTROL|LEVEL3, "attribute value has not fixed size");
+ /* the attribute value is generated */
+ this->generate_from_chunk(this,rules[i].offset);
+ }
+ break;
+ }
+ case TRAFFIC_SELECTORS:
+ {
+ /* before iterative generate the traffic_selectors, store the current payload length position */
+ u_int32_t payload_length_position_offset = this->last_payload_length_position_offset;
+ /* Length of SA_PAYLOAD is calculated */
+ u_int16_t length_of_ts_payload = TS_PAYLOAD_HEADER_LENGTH;
+ u_int16_t int16_val;
+ /* traffic selectors are stored in a linked list and so accessed */
+ linked_list_t *traffic_selectors = *((linked_list_t **)(this->data_struct + rules[i].offset));
+
+ iterator_t *iterator;
+ /* create forward iterator */
+ iterator = traffic_selectors->create_iterator(traffic_selectors,TRUE);
+ /* every proposal is processed (iterative call )*/
+ while (iterator->has_next(iterator))
+ {
+ payload_t *current_traffic_selector_substructure;
+ u_int32_t before_generate_position_offset;
+ u_int32_t after_generate_position_offset;
+
+ iterator->current(iterator,(void **)&current_traffic_selector_substructure);
+
+ before_generate_position_offset = this->get_current_buffer_offset(this);
+ this->public.generate_payload(&(this->public),current_traffic_selector_substructure);
+ after_generate_position_offset = this->get_current_buffer_offset(this);
+
+ /* increase size of transform */
+ length_of_ts_payload += (after_generate_position_offset - before_generate_position_offset);
+ }
+ iterator->destroy(iterator);
+
+ int16_val = htons(length_of_ts_payload);
+ this->write_bytes_to_buffer_at_offset(this,&int16_val,sizeof(u_int16_t),payload_length_position_offset);
+ break;
+ }
+
+ case ENCRYPTED_DATA:
+ {
+ this->generate_from_chunk(this, rules[i].offset);
+ break;
+ }
+ default:
+ this->logger->log(this->logger, ERROR, "field type %s is not supported",
+ mapping_find(encoding_type_m,rules[i].type));
+ return;
+ }
+ }
+ this->logger->log(this->logger, CONTROL|LEVEL2, "generating %s payload finished.",
+ mapping_find(payload_type_m, payload_type));
+ this->logger->log_bytes(this->logger, RAW|LEVEL3, "generated data for this payload",
+ payload_start, this->out_position-payload_start);
+}
+
+/**
+ * Implementation of generator_t.destroy.
+ */
+static status_t destroy(private_generator_t *this)
+{
+ free(this->buffer);
+ free(this);
+ return SUCCESS;
+}
+
+/*
+ * Described in header
+ */
+generator_t *generator_create()
+{
+ private_generator_t *this;
+
+ this = malloc_thing(private_generator_t);
+
+ /* initiate public functions */
+ this->public.generate_payload = (void(*)(generator_t*, payload_t *)) generate_payload;
+ this->public.destroy = (void(*)(generator_t*)) destroy;
+ this->public.write_to_chunk = (void (*) (generator_t *,chunk_t *)) write_to_chunk;
+
+
+ /* initiate private functions */
+ this->get_current_buffer_size = get_current_buffer_size;
+ this->get_current_buffer_space = get_current_buffer_space;
+ this->get_current_data_length = get_current_data_length;
+ this->get_current_buffer_offset = get_current_buffer_offset;
+ this->generate_u_int_type = generate_u_int_type;
+ this->generate_reserved_field = generate_reserved_field;
+ this->generate_flag = generate_flag;
+ this->generate_from_chunk = generate_from_chunk;
+ this->make_space_available = make_space_available;
+ this->write_bytes_to_buffer = write_bytes_to_buffer;
+ this->write_bytes_to_buffer_at_offset = write_bytes_to_buffer_at_offset;
+
+
+ /* allocate memory for buffer */
+ this->buffer = malloc(GENERATOR_DATA_BUFFER_SIZE);
+
+ /* initiate private variables */
+ this->out_position = this->buffer;
+ this->roof_position = this->buffer + GENERATOR_DATA_BUFFER_SIZE;
+ this->data_struct = NULL;
+ this->current_bit = 0;
+ this->last_payload_length_position_offset = 0;
+ this->header_length_position_offset = 0;
+ this->logger = logger_manager->get_logger(logger_manager, GENERATOR);
+
+ return &(this->public);
+}
diff --git a/programs/charon/charon/encoding/generator.h b/programs/charon/charon/encoding/generator.h
new file mode 100644
index 000000000..717d32b73
--- /dev/null
+++ b/programs/charon/charon/encoding/generator.h
@@ -0,0 +1,101 @@
+/**
+ * @file generator.h
+ *
+ * @brief Interface of generator_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef GENERATOR_H_
+#define GENERATOR_H_
+
+#include <types.h>
+#include <encoding/payloads/encodings.h>
+#include <encoding/payloads/payload.h>
+
+/**
+ * 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
+
+
+typedef struct generator_t generator_t;
+
+/**
+ * @brief A generator_t class used to generate IKEv2 payloads.
+ *
+ * After creation, multiple payloads can be generated with the generate_payload
+ * method. The generated bytes are appended. After all payloads are added,
+ * the write_to_chunk method writes out all generated data since
+ * the creation of the generator. After that, the generator must be destroyed.
+ * The generater uses a set of encoding rules, which it can get from
+ * the supplied payload. With this rules, the generater can generate
+ * the payload and all substructures automatically.
+ *
+ * @b Constructor:
+ * - generator_create()
+ *
+ * @ingroup encoding
+ */
+struct generator_t {
+
+ /**
+ * @brief 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
+ */
+ void (*generate_payload) (generator_t *this,payload_t *payload);
+
+ /**
+ * @brief Writes all generated data of the generator to a chunk.
+ *
+ * @param this generator_t object
+ * @param[out] 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
+ */
+ void (*destroy) (generator_t *this);
+};
+
+/**
+ * @brief Constructor to create a generator.
+ *
+ * @return generator_t object.
+ *
+ * @ingroup encoding
+ */
+generator_t *generator_create();
+
+#endif /*GENERATOR_H_*/
diff --git a/programs/charon/charon/encoding/message.c b/programs/charon/charon/encoding/message.c
new file mode 100644
index 000000000..a57315272
--- /dev/null
+++ b/programs/charon/charon/encoding/message.c
@@ -0,0 +1,1251 @@
+/**
+ * @file message.c
+ *
+ * @brief Implementation of message_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stdlib.h>
+
+#include "message.h"
+
+#include <types.h>
+#include <daemon.h>
+#include <sa/ike_sa_id.h>
+#include <encoding/generator.h>
+#include <encoding/parser.h>
+#include <utils/linked_list.h>
+#include <utils/logger_manager.h>
+#include <encoding/payloads/encodings.h>
+#include <encoding/payloads/payload.h>
+#include <encoding/payloads/encryption_payload.h>
+#include <encoding/payloads/unknown_payload.h>
+
+/**
+ * Max number of notify payloads per IKEv2 Message
+ */
+#define MAX_NOTIFY_PAYLOADS 10
+
+
+typedef struct payload_rule_t payload_rule_t;
+
+/**
+ * A payload rule defines the rules for a payload
+ * in a specific message rule. It defines if and how
+ * many times a payload must/can occur in a message
+ * and if it must be encrypted.
+ */
+struct payload_rule_t {
+ /**
+ * Payload type.
+ */
+ payload_type_t payload_type;
+
+ /**
+ * Minimal occurence of this payload.
+ */
+ size_t min_occurence;
+
+ /**
+ * Max occurence of this payload.
+ */
+ size_t max_occurence;
+
+ /**
+ * TRUE if payload must be encrypted
+ */
+ bool encrypted;
+
+ /**
+ * If this payload occurs, the message rule is
+ * fullfilled in any case. This applies e.g. to
+ * notify_payloads.
+ */
+ bool sufficient;
+};
+
+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.
+ *
+ */
+struct message_rule_t {
+ /**
+ * Type of message.
+ */
+ exchange_type_t exchange_type;
+
+ /**
+ * Is message a request or response.
+ */
+ bool is_request;
+
+ /**
+ * Message contains encrypted content.
+ */
+ bool encrypted_content;
+
+ /**
+ * Number of payload rules which will follow
+ */
+ size_t payload_rule_count;
+
+ /**
+ * Pointer to first payload rule
+ */
+ payload_rule_t *payload_rules;
+};
+
+/**
+ * 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},
+};
+
+/**
+ * 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},
+};
+
+/**
+ * Message rule for IKE_AUTH from initiator.
+ */
+static payload_rule_t ike_auth_i_payload_rules[] = {
+ {NOTIFY,0,MAX_NOTIFY_PAYLOADS,TRUE,FALSE},
+ {ID_INITIATOR,1,1,TRUE,FALSE},
+ {CERTIFICATE,0,1,TRUE,FALSE},
+ {CERTIFICATE_REQUEST,0,1,TRUE,FALSE},
+ {ID_RESPONDER,0,1,TRUE,FALSE},
+ {AUTHENTICATION,1,1,TRUE,FALSE},
+ {SECURITY_ASSOCIATION,1,1,TRUE,FALSE},
+ {TRAFFIC_SELECTOR_INITIATOR,1,1,TRUE,FALSE},
+ {TRAFFIC_SELECTOR_RESPONDER,1,1,TRUE,FALSE},
+ {CONFIGURATION,0,1,TRUE,FALSE},
+};
+
+/**
+ * Message rule for IKE_AUTH from responder.
+ */
+static payload_rule_t ike_auth_r_payload_rules[] = {
+ {NOTIFY,0,MAX_NOTIFY_PAYLOADS,TRUE,TRUE},
+ {CERTIFICATE,0,1,TRUE,FALSE},
+ {ID_RESPONDER,1,1,TRUE,FALSE},
+ {AUTHENTICATION,1,1,TRUE,FALSE},
+ {SECURITY_ASSOCIATION,1,1,TRUE,FALSE},
+ {TRAFFIC_SELECTOR_INITIATOR,1,1,TRUE,FALSE},
+ {TRAFFIC_SELECTOR_RESPONDER,1,1,TRUE,FALSE},
+ {CONFIGURATION,0,1,TRUE,FALSE},
+};
+
+
+/**
+ * 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},
+
+};
+
+/**
+ * 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},
+};
+
+
+/**
+ * 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}
+};
+
+
+typedef struct private_message_t private_message_t;
+
+/**
+ * Private data of an message_t object.
+ */
+struct private_message_t {
+
+ /**
+ * Public part of a message_t object.
+ */
+ message_t public;
+
+ /**
+ * Minor version of message.
+ */
+ u_int8_t major_version;
+
+ /**
+ * Major version of message.
+ */
+ u_int8_t minor_version;
+
+ /**
+ * First Payload in message.
+ */
+ payload_type_t first_payload;
+
+ /**
+ * Assigned exchange type.
+ */
+ exchange_type_t exchange_type;
+
+ /**
+ * TRUE if message is a request, FALSE if a reply.
+ */
+ bool is_request;
+
+ /**
+ * Message ID of this message.
+ */
+ u_int32_t message_id;
+
+ /**
+ * ID of assigned IKE_SA.
+ */
+ ike_sa_id_t *ike_sa_id;
+
+ /**
+ * Assigned UDP packet, stores incoming packet or last generated one.
+ */
+ packet_t *packet;
+
+ /**
+ * Linked List where payload data are stored in.
+ */
+ linked_list_t *payloads;
+
+ /**
+ * Assigned parser to parse Header and Body of this message.
+ */
+ parser_t *parser;
+
+ /**
+ * The message rule for this message instance
+ */
+ message_rule_t *message_rule;
+
+ /**
+ * Assigned logger.
+ */
+ logger_t *logger;
+
+ /**
+ * Sets the private message_rule member to the rule which
+ * applies to this message. Must be called before get_payload_rule().
+ *
+ * @param this calling object
+ * @return
+ * - SUCCESS
+ * - NOT_FOUND if no message rule applies to this message.
+ */
+ status_t (*set_message_rule) (private_message_t *this);
+
+ /**
+ * Gets the payload_rule_t for a specific message_rule_t and payload type.
+ *
+ * @param this calling object
+ * @param payload_type payload type
+ * @param[out] payload_rule returned payload_rule_t
+ * @return
+ * - SUCCESS
+ * - NOT_FOUND if payload not defined in current message rule
+ * - INVALID_STATE if message rule is not set via set_message_rule()
+ */
+ status_t (*get_payload_rule) (private_message_t *this, payload_type_t payload_type, payload_rule_t **payload_rule);
+
+ /**
+ * Encrypts all payloads which has to get encrypted.
+ *
+ * Can also be called with messages not containing encrypted content.
+ *
+ * @param this calling object
+ * @param crypter crypter_t object
+ * @param signer signer_t object
+ * @return
+ * - SUCCESS
+ * - INVALID_STATE if no crypter/signer supplied but needed
+ */
+ status_t (*encrypt_payloads) (private_message_t *this,crypter_t *crypter, signer_t* signer);
+
+ /**
+ * Decrypts encrypted contents, and checks if a payload is encrypted if it has to be.
+ *
+ * @param this calling object
+ * @param crypter crypter_t object
+ * @param signer signer_t object
+ * @return
+ * - SUCCESS
+ * - FAILED if decryption not successfull
+ * - INVALID_STATE if no crypter/signer supplied but needed
+ */
+ status_t (*decrypt_payloads) (private_message_t *this,crypter_t *crypter, signer_t* signer);
+
+ /**
+ * Verifies the message. Checks for payloads count.
+ *
+ * @param calling object
+ * @return
+ * - SUCCESS if message valid, or
+ * - FAILED if message does not align with message rules.
+ */
+ status_t (*verify) (private_message_t *this);
+};
+
+/**
+ * Implementation of private_message_t.set_message_rule.
+ */
+static status_t set_message_rule(private_message_t *this)
+{
+ int i;
+
+ for (i = 0; i < (sizeof(message_rules) / sizeof(message_rule_t)); i++)
+ {
+ if ((this->exchange_type == message_rules[i].exchange_type) &&
+ (this->is_request == message_rules[i].is_request))
+ {
+ /* found rule for given exchange_type*/
+ this->message_rule = &(message_rules[i]);
+ return SUCCESS;
+ }
+ }
+ this->message_rule = NULL;
+ return NOT_FOUND;
+}
+
+/**
+ * Implementation of private_message_t.get_payload_rule.
+ */
+static status_t get_payload_rule(private_message_t *this, payload_type_t payload_type, payload_rule_t **payload_rule)
+{
+ int i;
+
+ for (i = 0; i < this->message_rule->payload_rule_count;i++)
+ {
+ if (this->message_rule->payload_rules[i].payload_type == payload_type)
+ {
+ *payload_rule = &(this->message_rule->payload_rules[i]);
+ return SUCCESS;
+ }
+ }
+
+ *payload_rule = NULL;
+ return NOT_FOUND;
+}
+
+/**
+ * Implementation of message_t.set_ike_sa_id.
+ */
+static void set_ike_sa_id (private_message_t *this,ike_sa_id_t *ike_sa_id)
+{
+ this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
+}
+
+/**
+ * Implementation of message_t.get_ike_sa_id.
+ */
+static status_t get_ike_sa_id (private_message_t *this,ike_sa_id_t **ike_sa_id)
+{
+ if (this->ike_sa_id == NULL)
+ {
+ return FAILED;
+ }
+ *ike_sa_id = this->ike_sa_id->clone(this->ike_sa_id);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of message_t.set_message_id.
+ */
+static void set_message_id (private_message_t *this,u_int32_t message_id)
+{
+ this->message_id = message_id;
+}
+
+/**
+ * Implementation of message_t.get_message_id.
+ */
+static u_int32_t get_message_id (private_message_t *this)
+{
+ return this->message_id;
+}
+
+/**
+ * Implementation of message_t.get_responder_spi.
+ */
+static u_int64_t get_responder_spi (private_message_t *this)
+{
+ return (this->ike_sa_id->get_responder_spi(this->ike_sa_id));
+}
+
+/**
+ * Implementation of message_t.set_major_version.
+ */
+static void set_major_version (private_message_t *this,u_int8_t major_version)
+{
+ this->major_version = major_version;
+}
+
+
+/**
+ * Implementation of message_t.set_major_version.
+ */
+static u_int8_t get_major_version (private_message_t *this)
+{
+ return this->major_version;
+}
+
+/**
+ * Implementation of message_t.set_minor_version.
+ */
+static void set_minor_version (private_message_t *this,u_int8_t minor_version)
+{
+ this->minor_version = minor_version;
+}
+
+/**
+ * Implementation of message_t.get_minor_version.
+ */
+static u_int8_t get_minor_version (private_message_t *this)
+{
+ return this->minor_version;
+}
+
+/**
+ * Implementation of message_t.set_exchange_type.
+ */
+static void set_exchange_type (private_message_t *this,exchange_type_t exchange_type)
+{
+ this->exchange_type = exchange_type;
+}
+
+/**
+ * Implementation of message_t.get_exchange_type.
+ */
+static exchange_type_t get_exchange_type (private_message_t *this)
+{
+ return this->exchange_type;
+}
+
+/**
+ * Implementation of message_t.set_request.
+ */
+static void set_request (private_message_t *this,bool request)
+{
+ this->is_request = request;
+}
+
+/**
+ * Implementation of message_t.get_request.
+ */
+static exchange_type_t get_request (private_message_t *this)
+{
+ return this->is_request;
+}
+
+/**
+ * Implementation of message_t.add_payload.
+ */
+static void add_payload(private_message_t *this, payload_t *payload)
+{
+ payload_t *last_payload;
+ if (this->payloads->get_count(this->payloads) > 0)
+ {
+ this->payloads->get_last(this->payloads,(void **) &last_payload);
+ last_payload->set_next_type(last_payload, payload->get_type(payload));
+ }
+ else
+ {
+ this->first_payload = payload->get_type(payload);
+ }
+ payload->set_next_type(payload, NO_PAYLOAD);
+ this->payloads->insert_last(this->payloads, (void*)payload);
+
+ this->logger->log(this->logger, CONTROL|LEVEL1, "Added payload of type %s to message",
+ mapping_find(payload_type_m, payload->get_type(payload)));
+}
+
+/**
+ * Implementation of message_t.set_source.
+ */
+static void set_source(private_message_t *this, host_t *host)
+{
+ this->packet->set_source(this->packet, host);
+}
+
+/**
+ * Implementation of message_t.set_destination.
+ */
+static void set_destination(private_message_t *this, host_t *host)
+{
+
+ this->packet->set_destination(this->packet, host);
+}
+
+/**
+ * Implementation of message_t.get_source.
+ */
+static host_t* get_source(private_message_t *this)
+{
+ return this->packet->get_source(this->packet);
+}
+
+/**
+ * Implementation of message_t.get_destination.
+ */
+static host_t * get_destination(private_message_t *this)
+{
+ return this->packet->get_destination(this->packet);
+}
+
+/**
+ * Implementation of message_t.get_destination.
+ */
+static iterator_t *get_payload_iterator(private_message_t *this)
+{
+ return this->payloads->create_iterator(this->payloads, TRUE);
+}
+
+
+/**
+ * Implementation of message_t.generate.
+ */
+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;
+ payload_t *payload, *next_payload;
+ iterator_t *iterator;
+ status_t status;
+ chunk_t packet_data;
+
+ this->logger->log(this->logger, CONTROL, "Generating message of type %s, contains %d payloads",
+ mapping_find(exchange_type_m,this->exchange_type),
+ this->payloads->get_count(this->payloads));
+
+ if (this->exchange_type == EXCHANGE_TYPE_UNDEFINED)
+ {
+ this->logger->log(this->logger, ERROR | LEVEL1, "Exchange type %s is not defined",
+ mapping_find(exchange_type_m,this->exchange_type));
+ return INVALID_STATE;
+ }
+
+ if (this->packet->get_source(this->packet) == NULL ||
+ this->packet->get_destination(this->packet) == NULL)
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1, "%s not defined",
+ !this->packet->get_source(this->packet) ? "source" : "destination");
+ return INVALID_STATE;
+ }
+
+ /* set the rules for this messge */
+ status = this->set_message_rule(this);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, ERROR, "No message rules specified for a %s %s",
+ mapping_find(exchange_type_m,this->exchange_type),
+ this->is_request ? "request" : "response");
+ return NOT_SUPPORTED;
+ }
+
+
+ /* going to encrypt all content which have to be encrypted */
+ status = this->encrypt_payloads(this, crypter, signer);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, ERROR | LEVEL1, "Could not encrypt payloads");
+ return status;
+ }
+
+ /* build ike header */
+ ike_header = ike_header_create();
+
+ ike_header->set_exchange_type(ike_header, this->exchange_type);
+ ike_header->set_message_id(ike_header, this->message_id);
+ ike_header->set_response_flag(ike_header, !this->is_request);
+ ike_header->set_initiator_flag(ike_header, this->ike_sa_id->is_initiator(this->ike_sa_id));
+ ike_header->set_initiator_spi(ike_header, this->ike_sa_id->get_initiator_spi(this->ike_sa_id));
+ ike_header->set_responder_spi(ike_header, this->ike_sa_id->get_responder_spi(this->ike_sa_id));
+
+ generator = generator_create();
+
+ payload = (payload_t*)ike_header;
+
+
+ /* generate every payload expect last one, this is doen later*/
+ iterator = this->payloads->create_iterator(this->payloads, TRUE);
+ while(iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void**)&next_payload);
+ payload->set_next_type(payload, next_payload->get_type(next_payload));
+ generator->generate_payload(generator, payload);
+ payload = next_payload;
+ }
+ iterator->destroy(iterator);
+
+ /* last payload has no next payload*/
+ payload->set_next_type(payload, NO_PAYLOAD);
+
+ generator->generate_payload(generator, payload);
+
+ ike_header->destroy(ike_header);
+
+ /* build packet */
+ generator->write_to_chunk(generator, &packet_data);
+ generator->destroy(generator);
+
+ /* if last payload is of type encrypted, integrity checksum if necessary */
+ if (payload->get_type(payload) == ENCRYPTED)
+ {
+ this->logger->log(this->logger, CONTROL | LEVEL1, "Build signature on whole message");
+ encryption_payload_t *encryption_payload = (encryption_payload_t*)payload;
+ status = encryption_payload->build_signature(encryption_payload, packet_data);
+ if (status != SUCCESS)
+ {
+ return status;
+ }
+ }
+
+ this->packet->set_data(this->packet, packet_data);
+
+ /* clone packet for caller */
+ *packet = this->packet->clone(this->packet);
+
+ this->logger->log(this->logger, CONTROL|LEVEL1, "Message of type %s generated successfully",
+ mapping_find(exchange_type_m,this->exchange_type));
+ return SUCCESS;
+}
+
+/**
+ * Implementation of message_t.get_packet.
+ */
+static packet_t *get_packet (private_message_t *this)
+{
+ return this->packet->clone(this->packet);
+}
+
+/**
+ * Implementation of message_t.get_packet_data.
+ */
+static chunk_t get_packet_data (private_message_t *this)
+{
+ return chunk_clone(this->packet->get_data(this->packet));
+}
+
+/**
+ * Implementation of message_t.parse_header.
+ */
+static status_t parse_header(private_message_t *this)
+{
+ ike_header_t *ike_header;
+ status_t status;
+
+
+ this->logger->log(this->logger, CONTROL|LEVEL1, "parsing Header of message");
+
+ this->parser->reset_context(this->parser);
+ status = this->parser->parse_payload(this->parser,HEADER,(payload_t **) &ike_header);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, ERROR | LEVEL1, "Header could not be parsed");
+ return status;
+
+ }
+
+ /* verify payload */
+ status = ike_header->payload_interface.verify(&(ike_header->payload_interface));
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, ERROR | LEVEL1, "Header verification failed");
+ ike_header->destroy(ike_header);
+ return status;
+ }
+
+ if (this->ike_sa_id != NULL)
+ {
+ this->ike_sa_id->destroy(this->ike_sa_id);
+ }
+
+ this->ike_sa_id = ike_sa_id_create(ike_header->get_initiator_spi(ike_header),
+ ike_header->get_responder_spi(ike_header),
+ ike_header->get_initiator_flag(ike_header));
+
+ this->exchange_type = ike_header->get_exchange_type(ike_header);
+ this->message_id = ike_header->get_message_id(ike_header);
+ this->is_request = (!(ike_header->get_response_flag(ike_header)));
+ this->major_version = ike_header->get_maj_version(ike_header);
+ this->minor_version = ike_header->get_min_version(ike_header);
+ this->first_payload = ike_header->payload_interface.get_next_type(&(ike_header->payload_interface));
+
+ this->logger->log(this->logger, CONTROL, "Parsed a %s %s",
+ mapping_find(exchange_type_m, this->exchange_type),
+ this->is_request ? "request" : "response");
+
+ ike_header->destroy(ike_header);
+
+ /* get the rules for this messge */
+ status = this->set_message_rule(this);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, ERROR, "No message rules specified for a %s %s",
+ mapping_find(exchange_type_m,this->exchange_type),
+ this->is_request ? "request" : "response");
+ }
+
+ return status;
+}
+
+/**
+ * Implementation of message_t.parse_body.
+ */
+static status_t parse_body(private_message_t *this, crypter_t *crypter, signer_t *signer)
+{
+ status_t status = SUCCESS;
+ payload_type_t current_payload_type;
+
+ current_payload_type = this->first_payload;
+
+ this->logger->log(this->logger, CONTROL|LEVEL1, "Parsing body of message, first payload is %s",
+ mapping_find(payload_type_m, current_payload_type));
+
+ /* parse payload for payload, while there are more available */
+ while ((current_payload_type != NO_PAYLOAD))
+ {
+ payload_t *current_payload;
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Start parsing a %s payload",
+ mapping_find(payload_type_m, current_payload_type));
+
+ /* parse current payload */
+ status = this->parser->parse_payload(this->parser,current_payload_type,(payload_t **) &current_payload);
+
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, ERROR, "Payload type %s could not be parsed",
+ mapping_find(payload_type_m,current_payload_type));
+ return status;
+ }
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Verify payload of type %s",
+ mapping_find(payload_type_m, current_payload_type));
+
+ /* verify it, stop parsig if its invalid */
+ status = current_payload->verify(current_payload);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, ERROR, "%s payload verification failed",
+ mapping_find(payload_type_m,current_payload_type));
+ current_payload->destroy(current_payload);
+ status = VERIFY_ERROR;
+ return status;
+ }
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "%s payload verified. Adding to payload list",
+ mapping_find(payload_type_m, current_payload_type));
+ this->payloads->insert_last(this->payloads,current_payload);
+
+ /* an encryption payload is the last one, so STOP here. decryption is done later */
+ if (current_payload_type == ENCRYPTED)
+ {
+ this->logger->log(this->logger, CONTROL|LEVEL2, "%s payload found. Stop parsing",
+ mapping_find(payload_type_m, current_payload_type));
+ break;
+ }
+
+ /* get next payload type */
+ current_payload_type = current_payload->get_next_type(current_payload);
+ }
+
+ if (current_payload_type == ENCRYPTED)
+ status = this->decrypt_payloads(this,crypter,signer);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, ERROR, "Could not decrypt payloads");
+ return status;
+ }
+
+ status = this->verify(this);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, ERROR, "Verification of message failed");
+ }
+
+ this->logger->log(this->logger, CONTROL, "Message %s %s contains %d payloads",
+ mapping_find(exchange_type_m, this->exchange_type),
+ this->is_request ? "request" : "response",
+ this->payloads->get_count(this->payloads));
+
+ return status;
+}
+
+/**
+ * Implementation of private_message_t.verify.
+ */
+static status_t verify(private_message_t *this)
+{
+ int i;
+ iterator_t *iterator;
+ size_t total_found_payloads = 0;
+
+ this->logger->log(this->logger, CONTROL|LEVEL1, "Verifying message structure");
+
+ iterator = this->payloads->create_iterator(this->payloads,TRUE);
+ /* check for payloads with wrong count*/
+ for (i = 0; i < this->message_rule->payload_rule_count;i++)
+ {
+ size_t found_payloads = 0;
+
+ /* check all payloads for specific rule */
+ iterator->reset(iterator);
+
+ while(iterator->has_next(iterator))
+ {
+ payload_t *current_payload;
+ payload_type_t current_payload_type;
+
+ iterator->current(iterator,(void **)&current_payload);
+ current_payload_type = current_payload->get_type(current_payload);
+
+ if (current_payload_type == UNKNOWN_PAYLOAD)
+ {
+ /* unknown payloads are ignored, IF they are not critical */
+ unknown_payload_t *unknown_payload = (unknown_payload_t*)current_payload;
+ if (unknown_payload->is_critical(unknown_payload))
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1, "%s (%d) is not supported, but its critical!",
+ mapping_find(payload_type_m, current_payload_type), current_payload_type);
+ iterator->destroy(iterator);
+ return NOT_SUPPORTED;
+ }
+ }
+ else if (current_payload_type == this->message_rule->payload_rules[i].payload_type)
+ {
+ found_payloads++;
+ total_found_payloads++;
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Found payload of type %s",
+ mapping_find(payload_type_m, this->message_rule->payload_rules[i].payload_type));
+
+ /* as soon as ohe payload occures more then specified, the verification fails */
+ if (found_payloads > this->message_rule->payload_rules[i].max_occurence)
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1, "Payload of type %s more than %d times (%d) occured in current message",
+ mapping_find(payload_type_m, current_payload_type),
+ this->message_rule->payload_rules[i].max_occurence, found_payloads);
+ iterator->destroy(iterator);
+ return FAILED;
+ }
+ }
+ }
+
+ if (found_payloads < this->message_rule->payload_rules[i].min_occurence)
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1, "Payload of type %s not occured %d times (%d)",
+ mapping_find(payload_type_m, this->message_rule->payload_rules[i].payload_type),
+ this->message_rule->payload_rules[i].min_occurence, found_payloads);
+ iterator->destroy(iterator);
+ return FAILED;
+ }
+ if ((this->message_rule->payload_rules[i].sufficient) && (this->payloads->get_count(this->payloads) == total_found_payloads))
+ {
+ iterator->destroy(iterator);
+ return SUCCESS;
+ }
+ }
+ iterator->destroy(iterator);
+ return SUCCESS;
+}
+
+
+/**
+ * Implementation of private_message_t.decrypt_and_verify_payloads.
+ */
+static status_t decrypt_payloads(private_message_t *this,crypter_t *crypter, signer_t* signer)
+{
+ bool current_payload_was_encrypted = FALSE;
+ payload_t *previous_payload = NULL;
+ int payload_number = 1;
+ iterator_t *iterator;
+ status_t status;
+
+ iterator = this->payloads->create_iterator(this->payloads,TRUE);
+
+ /* process each payload and decrypt a encryption payload */
+ while(iterator->has_next(iterator))
+ {
+ payload_rule_t *payload_rule;
+ payload_type_t current_payload_type;
+ payload_t *current_payload;
+
+ /* get current payload */
+ iterator->current(iterator,(void **)&current_payload);
+
+ /* needed to check */
+ current_payload_type = current_payload->get_type(current_payload);
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Process payload of type %s",
+ mapping_find(payload_type_m,current_payload_type));
+
+ if (current_payload_type == ENCRYPTED)
+ {
+ encryption_payload_t *encryption_payload;
+ payload_t *current_encrypted_payload;
+
+ encryption_payload = (encryption_payload_t*)current_payload;
+
+ this->logger->log(this->logger, CONTROL | LEVEL2, "Found an encryption payload");
+
+ if (payload_number != this->payloads->get_count(this->payloads))
+ {
+ /* encrypted payload is not last one */
+ this->logger->log(this->logger, ERROR | LEVEL1, "Encrypted payload is not last payload");
+ iterator->destroy(iterator);
+ return FAILED;
+ }
+ /* decrypt */
+ encryption_payload->set_transforms(encryption_payload, crypter, signer);
+ this->logger->log(this->logger, CONTROL | LEVEL1, "Verify signature of encryption payload");
+ status = encryption_payload->verify_signature(encryption_payload, this->packet->get_data(this->packet));
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, ERROR | LEVEL1, "encryption payload signature invalid");
+ iterator->destroy(iterator);
+ return status;
+ }
+ this->logger->log(this->logger, CONTROL | LEVEL2, "Decrypt content of encryption payload");
+ status = encryption_payload->decrypt(encryption_payload);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, ERROR | LEVEL1, "Encrypted payload could not be decrypted and parsed: %s",
+ mapping_find(status_m, status));
+ iterator->destroy(iterator);
+ return status;
+ }
+
+ /* needed later to find out if a payload was encrypted */
+ current_payload_was_encrypted = TRUE;
+
+ /* check if there are payloads contained in the encryption payload */
+ if (encryption_payload->get_payload_count(encryption_payload) == 0)
+ {
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Encrypted payload is empty");
+ /* remove the encryption payload, is not needed anymore */
+ iterator->remove(iterator);
+ /* encrypted payload contains no other payload */
+ current_payload_type = NO_PAYLOAD;
+ }
+ else
+ {
+ /* encryption_payload is replaced with first payload contained in encryption_payload */
+ encryption_payload->remove_first_payload(encryption_payload, &current_encrypted_payload);
+ iterator->replace(iterator,NULL,(void *) current_encrypted_payload);
+ current_payload_type = current_encrypted_payload->get_type(current_encrypted_payload);
+ }
+
+ /* is the current paylad the first in the message? */
+ if (previous_payload == NULL)
+ {
+ /* yes, set the first payload type of the message to the current type */
+ this->first_payload = current_payload_type;
+ }
+ else
+ {
+ /* no, set the next_type of the previous payload to the current type */
+ previous_payload->set_next_type(previous_payload, current_payload_type);
+ }
+
+ /* all encrypted payloads are added to the payload list */
+ while (encryption_payload->get_payload_count(encryption_payload) > 0)
+ {
+ encryption_payload->remove_first_payload(encryption_payload, &current_encrypted_payload);
+ this->logger->log(this->logger, CONTROL | LEVEL1, "Insert unencrypted payload of type %s at end of list.",
+ mapping_find(payload_type_m,current_encrypted_payload->get_type(current_encrypted_payload)));
+ this->payloads->insert_last(this->payloads,current_encrypted_payload);
+ }
+
+ /* encryption payload is processed, payloads are moved. Destroy it. */
+ encryption_payload->destroy(encryption_payload);
+ }
+
+ /* we allow unknown payloads of any type and don't bother if it was encrypted. Not our problem. */
+ if (current_payload_type != UNKNOWN_PAYLOAD)
+ {
+ /* get the ruleset for found payload */
+ status = this->get_payload_rule(this, current_payload_type, &payload_rule);
+ if (status != SUCCESS)
+ {
+ /* payload is not allowed */
+ this->logger->log(this->logger, ERROR | LEVEL1, "Payload type %s not allowed",mapping_find(payload_type_m,current_payload_type));
+ iterator->destroy(iterator);
+ return status;
+ }
+
+ /* check if the payload was encrypted, and if it should been have encrypted */
+ if (payload_rule->encrypted != current_payload_was_encrypted)
+ {
+ /* payload was not encrypted, but should have been. or vice-versa */
+ this->logger->log(this->logger, ERROR | LEVEL1, "Payload type %s should be %s!",
+ mapping_find(payload_type_m,current_payload_type),
+ (payload_rule->encrypted) ? "encrypted" : "not encrypted");
+ iterator->destroy(iterator);
+ return FAILED;
+ }
+ }
+ /* advance to the next payload */
+ payload_number++;
+ /* is stored to set next payload in case of found encryption payload */
+ previous_payload = current_payload;
+ }
+ iterator->destroy(iterator);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of private_message_t.encrypt_payloads.
+ */
+static status_t encrypt_payloads (private_message_t *this,crypter_t *crypter, signer_t* signer)
+{
+ encryption_payload_t *encryption_payload = NULL;
+ status_t status;
+ linked_list_t *all_payloads;
+
+ if (!this->message_rule->encrypted_content)
+ {
+ this->logger->log(this->logger, CONTROL | LEVEL1, "Message doesn't have to be encrypted");
+ /* message contains no content to encrypt */
+ return SUCCESS;
+ }
+
+ this->logger->log(this->logger, CONTROL | LEVEL2, "Copy all payloads to a temporary list");
+ all_payloads = linked_list_create();
+
+ /* first copy all payloads in a temporary list */
+ while (this->payloads->get_count(this->payloads) > 0)
+ {
+ void *current_payload;
+ this->payloads->remove_first(this->payloads,&current_payload);
+ all_payloads->insert_last(all_payloads,current_payload);
+ }
+
+ encryption_payload = encryption_payload_create();
+
+ this->logger->log(this->logger, CONTROL | LEVEL2, "Check each payloads if they have to get encrypted");
+ while (all_payloads->get_count(all_payloads) > 0)
+ {
+ payload_rule_t *payload_rule;
+ payload_t *current_payload;
+ bool to_encrypt = FALSE;
+
+ all_payloads->remove_first(all_payloads,(void **)&current_payload);
+ this->logger->log(this->logger, CONTROL | LEVEL3, "Get rule for payload %s",
+ mapping_find(payload_type_m,current_payload->get_type(current_payload)));
+
+ status = this->get_payload_rule(this,current_payload->get_type(current_payload),&payload_rule);
+ /* for payload types which are not found in supported payload list, it is presumed
+ * that they don't have to be encrypted */
+ if ((status == SUCCESS) && (payload_rule->encrypted))
+ {
+ this->logger->log(this->logger, CONTROL | LEVEL2, "Payload %s has to get encrypted",
+ mapping_find(payload_type_m,current_payload->get_type(current_payload)));
+ to_encrypt = TRUE;
+ }
+ else if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, CONTROL | LEVEL2, "Payload %s not defined for exchange type %s. Handle it anyway",
+ mapping_find(payload_type_m,current_payload->get_type(current_payload)),
+ mapping_find(exchange_type_m,this->exchange_type));
+ }
+
+ if (to_encrypt)
+ {
+ this->logger->log(this->logger, CONTROL | LEVEL2, "Insert payload %s to encryption payload",
+ mapping_find(payload_type_m,current_payload->get_type(current_payload)));
+
+ encryption_payload->add_payload(encryption_payload,current_payload);
+ }
+ else
+ {
+ this->logger->log(this->logger, CONTROL | LEVEL2, "Insert payload %s as payload wich does not have to be encrypted",
+ mapping_find(payload_type_m,current_payload->get_type(current_payload)));
+ this->public.add_payload(&(this->public), (payload_t*)encryption_payload);
+ }
+ }
+
+ status = SUCCESS;
+ this->logger->log(this->logger, CONTROL | LEVEL2, "Set transforms for encryption payload ");
+ encryption_payload->set_transforms(encryption_payload,crypter,signer);
+ this->logger->log(this->logger, CONTROL | LEVEL1, "Encrypt all payloads of encrypted payload");
+ status = encryption_payload->encrypt(encryption_payload);
+ this->logger->log(this->logger, CONTROL | LEVEL2, "Add encrypted payload to payload list");
+ this->public.add_payload(&(this->public), (payload_t*)encryption_payload);
+
+ all_payloads->destroy(all_payloads);
+
+ return status;
+}
+
+
+/**
+ * Implementation of message_t.destroy.
+ */
+static void destroy (private_message_t *this)
+{
+ iterator_t *iterator;
+
+ this->logger->log(this->logger, CONTROL|LEVEL3, "Going to destroy message_t object");
+
+ this->packet->destroy(this->packet);
+
+ if (this->ike_sa_id != NULL)
+ {
+ this->ike_sa_id->destroy(this->ike_sa_id);
+ }
+
+ iterator = this->payloads->create_iterator(this->payloads, TRUE);
+ while (iterator->has_next(iterator))
+ {
+ payload_t *payload;
+ iterator->current(iterator, (void**)&payload);
+ this->logger->log(this->logger, CONTROL|LEVEL3, "Destroying payload of type %s",
+ mapping_find(payload_type_m, payload->get_type(payload)));
+ payload->destroy(payload);
+ }
+ iterator->destroy(iterator);
+ this->payloads->destroy(this->payloads);
+ this->parser->destroy(this->parser);
+
+ free(this);
+}
+
+/*
+ * Described in Header-File
+ */
+message_t *message_create_from_packet(packet_t *packet)
+{
+ private_message_t *this = malloc_thing(private_message_t);
+
+ /* public functions */
+ this->public.set_major_version = (void(*)(message_t*, u_int8_t))set_major_version;
+ this->public.get_major_version = (u_int8_t(*)(message_t*))get_major_version;
+ this->public.set_minor_version = (void(*)(message_t*, u_int8_t))set_minor_version;
+ this->public.get_minor_version = (u_int8_t(*)(message_t*))get_minor_version;
+ this->public.set_message_id = (void(*)(message_t*, u_int32_t))set_message_id;
+ this->public.get_message_id = (u_int32_t(*)(message_t*))get_message_id;
+ this->public.get_responder_spi = (u_int64_t(*)(message_t*))get_responder_spi;
+ this->public.set_ike_sa_id = (void(*)(message_t*, ike_sa_id_t *))set_ike_sa_id;
+ this->public.get_ike_sa_id = (status_t(*)(message_t*, ike_sa_id_t **))get_ike_sa_id;
+ this->public.set_exchange_type = (void(*)(message_t*, exchange_type_t))set_exchange_type;
+ this->public.get_exchange_type = (exchange_type_t(*)(message_t*))get_exchange_type;
+ this->public.set_request = (void(*)(message_t*, bool))set_request;
+ this->public.get_request = (bool(*)(message_t*))get_request;
+ this->public.add_payload = (void(*)(message_t*,payload_t*))add_payload;
+ this->public.generate = (status_t (*) (message_t *,crypter_t*,signer_t*,packet_t**)) generate;
+ this->public.set_source = (void (*) (message_t*,host_t*)) set_source;
+ this->public.get_source = (host_t * (*) (message_t*)) get_source;
+ this->public.set_destination = (void (*) (message_t*,host_t*)) set_destination;
+ this->public.get_destination = (host_t * (*) (message_t*)) get_destination;
+ this->public.get_payload_iterator = (iterator_t * (*) (message_t *)) get_payload_iterator;
+ this->public.parse_header = (status_t (*) (message_t *)) parse_header;
+ this->public.parse_body = (status_t (*) (message_t *,crypter_t*,signer_t*)) parse_body;
+ this->public.get_packet = (packet_t * (*) (message_t*)) get_packet;
+ this->public.get_packet_data = (chunk_t (*) (message_t *this)) get_packet_data;
+ this->public.destroy = (void(*)(message_t*))destroy;
+
+ /* private values */
+ this->exchange_type = EXCHANGE_TYPE_UNDEFINED;
+ this->is_request = TRUE;
+ this->ike_sa_id = NULL;
+ this->first_payload = NO_PAYLOAD;
+ this->message_id = 0;
+
+ /* private functions */
+ this->set_message_rule = set_message_rule;
+ this->get_payload_rule = get_payload_rule;
+ this->encrypt_payloads = encrypt_payloads;
+ this->decrypt_payloads = decrypt_payloads;
+ this->verify = verify;
+
+ /* private values */
+ if (packet == NULL)
+ {
+ packet = packet_create();
+ }
+ this->message_rule = NULL;
+ this->packet = packet;
+ this->payloads = linked_list_create();
+
+ /* parser is created from data of packet */
+ this->parser = parser_create(this->packet->get_data(this->packet));
+
+ this->logger = logger_manager->get_logger(logger_manager, MESSAGE);
+
+ return (&this->public);
+}
+
+/*
+ * Described in Header.
+ */
+message_t *message_create()
+{
+ return message_create_from_packet(NULL);
+}
+
+/*
+ * Described in Header.
+ */
+message_t *message_create_notify_reply(host_t *source, host_t *destination, exchange_type_t exchange_type, bool original_initiator,ike_sa_id_t *ike_sa_id,notify_message_type_t notify_type)
+{
+ message_t *message = message_create_from_packet(NULL);
+ notify_payload_t *payload;
+
+ message->set_source(message, source->clone(source));
+ message->set_destination(message, destination->clone(destination));
+ message->set_exchange_type(message, exchange_type);
+ message->set_request(message, FALSE);
+ message->set_message_id(message,0);
+ message->set_ike_sa_id(message, ike_sa_id);
+
+ payload = notify_payload_create_from_protocol_and_type(PROTO_IKE, notify_type);
+ message->add_payload(message,(payload_t *) payload);
+
+ return message;
+}
diff --git a/programs/charon/charon/encoding/message.h b/programs/charon/charon/encoding/message.h
new file mode 100644
index 000000000..e3a72f439
--- /dev/null
+++ b/programs/charon/charon/encoding/message.h
@@ -0,0 +1,367 @@
+/**
+ * @file message.h
+ *
+ * @brief Interface of message_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef MESSAGE_H_
+#define MESSAGE_H_
+
+#include <types.h>
+#include <sa/ike_sa_id.h>
+#include <network/packet.h>
+#include <encoding/payloads/ike_header.h>
+#include <encoding/payloads/notify_payload.h>
+#include <utils/linked_list.h>
+#include <crypto/crypters/crypter.h>
+#include <crypto/signers/signer.h>
+
+
+typedef struct message_t message_t;
+
+/**
+ * @brief 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.
+ *
+ * @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.
+ *
+ * @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.
+ *
+ * @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.
+ *
+ * @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.
+ *
+ * @param this message_t object
+ * @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.
+ *
+ * @param this message_t object
+ * @return message_id type of the message
+ */
+ u_int32_t (*get_message_id) (message_t *this);
+
+ /**
+ * @brief 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.
+ *
+ * @warning ike_sa_id gets cloned internaly and
+ * so can be destroyed afterwards.
+ *
+ * @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.
+ *
+ * @warning The returned ike_sa_id is a clone of the internal one.
+ * So it has to be destroyed by the caller.
+ *
+ * @param this message_t object
+ * @param ike_sa_id pointer to ike_sa_id pointer which will be set
+ * @return
+ * - SUCCESS
+ * - FAILED if no ike_sa_id is set
+ */
+ status_t (*get_ike_sa_id) (message_t *this,ike_sa_id_t **ike_sa_id);
+
+ /**
+ * @brief 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.
+ *
+ * @param this message_t object
+ * @return exchange type of the message
+ */
+ exchange_type_t (*get_exchange_type) (message_t *this);
+
+ /**
+ * @brief Sets the request flag.
+ *
+ * @param this message_t object
+ * @param original_initiator TRUE if message is a request, FALSE if it is a reply
+ */
+ void (*set_request) (message_t *this,bool request);
+
+ /**
+ * @brief 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.
+ *
+ * If the payload must be encrypted is not specified here. Encryption
+ * of payloads is evaluated via internal rules for the messages and
+ * is done before generation. The order of payloads may change, since
+ * all payloads to encrypt are added to the encryption payload, which is
+ * always the last one.
+ *
+ * @param this message_t object
+ * @param payload payload to append
+ */
+ void (*add_payload) (message_t *this, payload_t *payload);
+
+ /**
+ * @brief 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
+ * - FAILED if consistence check of header failed
+ */
+ status_t (*parse_header) (message_t *this);
+
+ /**
+ * @brief Parses body of message.
+ *
+ * The body gets not only parsed, but rather it gets verified.
+ * All payloads are verified if they are allowed to exist in the message
+ * of this type and if their own structure is ok.
+ * If there are encrypted payloads, they get decrypted via the supplied
+ * crypter. Also the message integrity gets verified with the supplied
+ * signer.
+ * Crypter/signer can be omitted (by passing NULL) when no encryption
+ * payload is expected.
+ *
+ * @param this message_t object
+ * @param crypter crypter to decrypt encryption payloads
+ * @param signer signer to verifiy a message with an encryption payload
+ * @return
+ * - SUCCESS if header could be parsed
+ * - NOT_SUPPORTED if ciritcal unknown payloads found
+ * - FAILED if message type is not suppported!
+ * - PARSE_ERROR if corrupted/invalid data found
+ * - VERIFY_ERROR if verification of some payload failed
+ * - INVALID_STATE if crypter/signer not supplied, but needed
+ */
+ status_t (*parse_body) (message_t *this, crypter_t *crypter, signer_t *signer);
+
+ /**
+ * @brief Generates the UDP packet of specific message.
+ *
+ * Payloads which must be encrypted are generated first and added to
+ * an encryption payload. This encryption payload will get encrypted via
+ * the supplied crypter. Then all other payloads and the header get generated.
+ * After that, the checksum is added to the encryption payload over the full
+ * message.
+ * Crypter/signer can be omitted (by passing NULL) when no encryption
+ * payload is expected.
+ *
+ * @param this message_t object
+ * @param crypter crypter to use when a payload must be encrypted
+ * @param signer signer to build a mac
+ * @return
+ * - SUCCESS if packet could be generated
+ * - INVALID_STATE if exchange type is currently not set
+ * - NOT_FOUND if no rules found for message generation
+ * - INVALID_STATE if crypter/signer not supplied but needed.
+ */
+ status_t (*generate) (message_t *this, crypter_t *crypter, signer_t *signer, packet_t **packet);
+
+ /**
+ * @brief 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.
+ *
+ * @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.
+ *
+ * @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.
+ *
+ * @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.
+ *
+ * @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);
+
+ /**
+ * 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);
+
+ /**
+ * 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
+ */
+ void (*destroy) (message_t *this);
+};
+
+/**
+ * @brief 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
+ * Call message_t.parse_header afterwards.
+ *
+ * @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.
+ *
+ * - 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();
+
+/**
+ * @brief Creates an message_t object of type reply containing a notify payload.
+ *
+ * @return message_t object
+ *
+ * @ingroup encoding
+ */
+message_t *message_create_notify_reply(host_t *source, host_t *destination, exchange_type_t exchange_type, bool original_initiator,ike_sa_id_t *ike_sa_id,notify_message_type_t notify_type);
+
+#endif /*MESSAGE_H_*/
diff --git a/programs/charon/charon/encoding/parser.c b/programs/charon/charon/encoding/parser.c
new file mode 100644
index 000000000..a589e9bde
--- /dev/null
+++ b/programs/charon/charon/encoding/parser.c
@@ -0,0 +1,1065 @@
+/**
+ * @file parser.c
+ *
+ * @brief Implementation of parser_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stdlib.h>
+#include <arpa/inet.h>
+#include <string.h>
+
+#include "parser.h"
+
+#include <types.h>
+#include <definitions.h>
+#include <daemon.h>
+#include <utils/logger.h>
+#include <utils/linked_list.h>
+#include <encoding/payloads/encodings.h>
+#include <encoding/payloads/payload.h>
+#include <encoding/payloads/sa_payload.h>
+#include <encoding/payloads/proposal_substructure.h>
+#include <encoding/payloads/transform_substructure.h>
+#include <encoding/payloads/transform_attribute.h>
+#include <encoding/payloads/ke_payload.h>
+#include <encoding/payloads/nonce_payload.h>
+#include <encoding/payloads/id_payload.h>
+#include <encoding/payloads/notify_payload.h>
+#include <encoding/payloads/encryption_payload.h>
+#include <encoding/payloads/auth_payload.h>
+#include <encoding/payloads/cert_payload.h>
+#include <encoding/payloads/certreq_payload.h>
+#include <encoding/payloads/ts_payload.h>
+#include <encoding/payloads/delete_payload.h>
+#include <encoding/payloads/vendor_id_payload.h>
+#include <encoding/payloads/cp_payload.h>
+#include <encoding/payloads/configuration_attribute.h>
+#include <encoding/payloads/eap_payload.h>
+#include <encoding/payloads/unknown_payload.h>
+
+
+typedef struct private_parser_t private_parser_t;
+
+/**
+ * Private data stored in a context.
+ *
+ * Contains pointers and counters to store current state.
+ */
+struct private_parser_t {
+ /**
+ * Public members, see parser_t.
+ */
+ parser_t public;
+
+ /**
+ * @brief Parse a 4-Bit unsigned integer from the current parsing position.
+ *
+ * @param this parser_t object
+ * @param rule_number number of current rule
+ * @param[out] output_pos pointer where to write the parsed result
+ * @return
+ * - SUCCESS or
+ * - PARSE_ERROR when not successful
+ */
+ 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.
+ *
+ * @param this parser_t object
+ * @param rule_number number of current rule
+ * @param[out] output_pos pointer where to write the parsed result
+ * @return
+ * - SUCCESS or
+ * - PARSE_ERROR when not successful
+ */
+ 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.
+ *
+ * This is a special case used for ATTRIBUTE_TYPE.
+ * Big-/Little-endian conversion is done here.
+ *
+ * @param this parser_t object
+ * @param rule_number number of current rule
+ * @param[out] output_pos pointer where to write the parsed result
+ * @return
+ * - SUCCESS or
+ * - PARSE_ERROR when not successful
+ */
+ 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.
+ *
+ * Big-/Little-endian conversion is done here.
+ *
+ * @param this parser_t object
+ * @param rule_number number of current rule
+ * @param[out] output_pos pointer where to write the parsed result
+ * @return
+ * - SUCCESS or
+ * - PARSE_ERROR when not successful
+ */
+ 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.
+ *
+ * Big-/Little-endian conversion is done here.
+ *
+ * @param this parser_t object
+ * @param rule_number number of current rule
+ * @param[out] output_pos pointer where to write the parsed result
+ * @return
+ * - SUCCESS or
+ * - PARSE_ERROR when not successful
+ */
+ 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.
+ *
+ * @todo add support for big-endian machines.
+ *
+ * @param this parser_t object
+ * @param rule_number number of current rule
+ * @param[out] output_pos pointer where to write the parsed result
+ * @return
+ * - SUCCESS or
+ * - PARSE_ERROR when not successful
+ */
+ 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
+ *
+ * @param this parser_t object
+ * @param rule_number number of current rule
+ * @param[out] output_pos pointer where to write the parsed result
+ * @param bytes number of bytes to parse
+ * @return
+ * - SUCCESS or
+ * - PARSE_ERROR when not successful
+ */
+ 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
+ *
+ * @param this parser_t object
+ * @param rule_number number of current rule
+ * @param[out] output_pos pointer where to write the parsed result
+ * @return
+ * - SUCCESS or
+ * - PARSE_ERROR when not successful
+ */
+ status_t (*parse_bit) (private_parser_t *this, int rule_number, bool *output_pos);
+
+ /**
+ * @brief Parse substructures in a list
+ *
+ * This function calls the parser recursivly to parse contained substructures
+ * in a linked_list_t. The list must already be created. Payload defines
+ * the type of the substructures. parsing is continued until the specified length
+ * is completely parsed.
+ *
+ * @param this parser_t object
+ * @param rule_number number of current rule
+ * @param[out] output_pos pointer of a linked_list where substructures are added
+ * @param payload_type type of the contained substructures to parse
+ * @param length number of bytes to parse in this list
+ * @return
+ * - SUCCESS or
+ * - PARSE_ERROR when not successful
+ */
+ 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.
+ *
+ * This function clones length number of bytes to output_pos, without
+ * modifiyng them. Space will be allocated and must be freed by caller.
+ *
+ * @param this parser_t object
+ * @param rule_number number of current rule
+ * @param[out] output_pos pointer of a chunk which will point to the allocated data
+ * @param length number of bytes to clone
+ * @return
+ * - SUCCESS or
+ * - PARSE_ERROR when not successful
+ */
+ status_t (*parse_chunk) (private_parser_t *this, int rule_number, chunk_t *output_pos, size_t length);
+
+ /**
+ * Current bit for reading in input data.
+ */
+ u_int8_t bit_pos;
+
+ /**
+ * Current byte for reading in input data.
+ */
+ u_int8_t *byte_pos;
+
+ /**
+ * Input data to parse.
+ */
+ u_int8_t *input;
+
+ /**
+ * Roof of input, used for length-checking.
+ */
+ u_int8_t *input_roof;
+
+ /**
+ * Set of encoding rules for this parsing session.
+ */
+ encoding_rule_t *rules;
+
+ /**
+ * Assigned logger_t object.
+ */
+ logger_t *logger;
+};
+
+/**
+ * Implementation of private_parser_t.parse_uint4.
+ */
+static status_t parse_uint4(private_parser_t *this, int rule_number, u_int8_t *output_pos)
+{
+ if (this->byte_pos + sizeof(u_int8_t) > this->input_roof)
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1, " not enough input to parse rule %d %s",
+ rule_number, mapping_find(encoding_type_m,
+ this->rules[rule_number].type));
+ return PARSE_ERROR;
+ }
+ switch (this->bit_pos)
+ {
+ case 0:
+ /* caller interested in result ? */
+ if (output_pos != NULL)
+ {
+ *output_pos = *(this->byte_pos) >> 4;
+ }
+ this->bit_pos = 4;
+ break;
+ case 4:
+ /* caller interested in result ? */
+ if (output_pos != NULL)
+ {
+ *output_pos = *(this->byte_pos) & 0x0F;
+ }
+ this->bit_pos = 0;
+ this->byte_pos++;
+ break;
+ default:
+ this->logger->log(this->logger, ERROR, " found rule %d %s on bitpos %d",
+ rule_number, mapping_find(encoding_type_m,
+ this->rules[rule_number].type), this->bit_pos);
+ return PARSE_ERROR;
+ }
+
+ if (output_pos != NULL)
+ {
+ this->logger->log(this->logger, RAW|LEVEL2, " => %d", *output_pos);
+ }
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of private_parser_t.parse_uint8.
+ */
+static status_t parse_uint8(private_parser_t *this, int rule_number, u_int8_t *output_pos)
+{
+ if (this->byte_pos + sizeof(u_int8_t) > this->input_roof)
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1, " not enough input to parse rule %d %s",
+ rule_number, mapping_find(encoding_type_m,
+ this->rules[rule_number].type));
+ return PARSE_ERROR;
+ }
+ if (this->bit_pos)
+ {
+ this->logger->log(this->logger, ERROR, " found rule %d %s on bitpos %d",
+ rule_number, mapping_find(encoding_type_m,
+ this->rules[rule_number].type), this->bit_pos);
+ return PARSE_ERROR;
+ }
+
+ /* caller interested in result ? */
+ if (output_pos != NULL)
+ {
+ *output_pos = *(this->byte_pos);
+ this->logger->log(this->logger, RAW|LEVEL2, " => %d", *output_pos);
+ }
+ this->byte_pos++;
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of private_parser_t.parse_uint15.
+ */
+static status_t parse_uint15(private_parser_t *this, int rule_number, u_int16_t *output_pos)
+{
+ if (this->byte_pos + sizeof(u_int16_t) > this->input_roof)
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1, " not enough input to parse rule %d %s",
+ rule_number, mapping_find(encoding_type_m,
+ this->rules[rule_number].type));
+ return PARSE_ERROR;
+ }
+ if (this->bit_pos != 1)
+ {
+ this->logger->log(this->logger, ERROR, " found rule %d %s on bitpos %d",
+ rule_number, mapping_find(encoding_type_m, this->rules[rule_number].type),
+ this->bit_pos);
+ return PARSE_ERROR;
+ }
+ /* caller interested in result ? */
+ if (output_pos != NULL)
+ {
+ *output_pos = ntohs(*((u_int16_t*)this->byte_pos)) & ~0x8000;
+ this->logger->log(this->logger, RAW|LEVEL2, " => %d", *output_pos);
+ }
+ this->byte_pos += 2;
+ this->bit_pos = 0;
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of private_parser_t.parse_uint16.
+ */
+static status_t parse_uint16(private_parser_t *this, int rule_number, u_int16_t *output_pos)
+{
+ if (this->byte_pos + sizeof(u_int16_t) > this->input_roof)
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1, " not enough input to parse rule %d %s",
+ rule_number, mapping_find(encoding_type_m, this->rules[rule_number].type));
+ return PARSE_ERROR;
+ }
+ if (this->bit_pos)
+ {
+ this->logger->log(this->logger, ERROR, " found rule %d %s on bitpos %d",
+ rule_number, mapping_find(encoding_type_m, this->rules[rule_number].type),
+ this->bit_pos);
+ return PARSE_ERROR;
+ }
+ /* caller interested in result ? */
+ if (output_pos != NULL)
+ {
+ *output_pos = ntohs(*((u_int16_t*)this->byte_pos));
+
+ this->logger->log(this->logger, RAW|LEVEL2, " => %d", *output_pos);
+ }
+ this->byte_pos += 2;
+
+ return SUCCESS;
+}
+/**
+ * Implementation of private_parser_t.parse_uint32.
+ */
+static status_t parse_uint32(private_parser_t *this, int rule_number, u_int32_t *output_pos)
+{
+ if (this->byte_pos + sizeof(u_int32_t) > this->input_roof)
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1, " not enough input to parse rule %d %s",
+ rule_number, mapping_find(encoding_type_m, this->rules[rule_number].type));
+ return PARSE_ERROR;
+ }
+ if (this->bit_pos)
+ {
+ this->logger->log(this->logger, ERROR, " found rule %d %s on bitpos %d",
+ rule_number, mapping_find(encoding_type_m, this->rules[rule_number].type),
+ this->bit_pos);
+ return PARSE_ERROR;
+ }
+ /* caller interested in result ? */
+ if (output_pos != NULL)
+ {
+ *output_pos = ntohl(*((u_int32_t*)this->byte_pos));
+
+ this->logger->log(this->logger, RAW|LEVEL2, " => %d", *output_pos);
+ }
+ this->byte_pos += 4;
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of private_parser_t.parse_uint64.
+ */
+static status_t parse_uint64(private_parser_t *this, int rule_number, u_int64_t *output_pos)
+{
+ if (this->byte_pos + sizeof(u_int64_t) > this->input_roof)
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1, " not enough input to parse rule %d %s",
+ rule_number, mapping_find(encoding_type_m, this->rules[rule_number].type));
+ return PARSE_ERROR;
+ }
+ if (this->bit_pos)
+ {
+ this->logger->log(this->logger, ERROR, " found rule %d %s on bitpos %d",
+ rule_number, mapping_find(encoding_type_m, this->rules[rule_number].type),
+ this->bit_pos);
+ return PARSE_ERROR;
+ }
+ /* caller interested in result ? */
+ if (output_pos != NULL)
+ {
+ /* assuming little endian host order */
+ *(output_pos + 1) = ntohl(*((u_int32_t*)this->byte_pos));
+ *output_pos = ntohl(*(((u_int32_t*)this->byte_pos) + 1));
+
+ this->logger->log_bytes(this->logger, RAW|LEVEL2, " =>", (void*)output_pos, 8);
+ }
+ this->byte_pos += 8;
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of private_parser_t.parse_bytes.
+ */
+static status_t parse_bytes (private_parser_t *this, int rule_number, u_int8_t *output_pos,size_t bytes)
+{
+ if (this->byte_pos + bytes > this->input_roof)
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1, " not enough input to parse rule %d %s",
+ rule_number, mapping_find(encoding_type_m, this->rules[rule_number].type));
+ return PARSE_ERROR;
+ }
+ if (this->bit_pos)
+ {
+ this->logger->log(this->logger, ERROR, " found rule %d %s on bitpos %d",
+ rule_number, mapping_find(encoding_type_m, this->rules[rule_number].type),
+ this->bit_pos);
+ return PARSE_ERROR;
+ }
+
+ /* caller interested in result ? */
+ if (output_pos != NULL)
+ {
+ memcpy(output_pos,this->byte_pos,bytes);
+
+ this->logger->log_bytes(this->logger, RAW|LEVEL2, " =>", (void*)output_pos, bytes);
+ }
+ this->byte_pos += bytes;
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of private_parser_t.parse_bit.
+ */
+static status_t parse_bit(private_parser_t *this, int rule_number, bool *output_pos)
+{
+ if (this->byte_pos + sizeof(u_int8_t) > this->input_roof)
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1, " not enough input to parse rule %d %s",
+ rule_number, mapping_find(encoding_type_m, this->rules[rule_number].type));
+ return PARSE_ERROR;
+ }
+ /* caller interested in result ? */
+ if (output_pos != NULL)
+ {
+ u_int8_t mask;
+ mask = 0x01 << (7 - this->bit_pos);
+ *output_pos = *this->byte_pos & mask;
+
+ if (*output_pos)
+ {
+ /* set to a "clean", comparable true */
+ *output_pos = TRUE;
+ }
+
+ this->logger->log(this->logger, RAW|LEVEL2, " => %d", *output_pos);
+ }
+ this->bit_pos = (this->bit_pos + 1) % 8;
+ if (this->bit_pos == 0)
+ {
+ this->byte_pos++;
+ }
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of private_parser_t.parse_list.
+ */
+static status_t parse_list(private_parser_t *this, int rule_number, linked_list_t **output_pos, payload_type_t payload_type, size_t length)
+{
+ linked_list_t * list = *output_pos;
+
+ if (length < 0)
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1, " invalid length for rule %d %s",
+ rule_number, mapping_find(encoding_type_m, this->rules[rule_number].type));
+ return PARSE_ERROR;
+ }
+
+ if (this->bit_pos)
+ {
+ this->logger->log(this->logger, ERROR, " found rule %d %s on bitpos %d",
+ rule_number, mapping_find(encoding_type_m, this->rules[rule_number].type), this->bit_pos);
+ return PARSE_ERROR;
+ }
+
+ while (length > 0)
+ {
+ u_int8_t *pos_before = this->byte_pos;
+ payload_t *payload;
+ status_t status;
+ this->logger->log(this->logger, CONTROL|LEVEL1, " %d bytes left, parsing recursivly %s",
+ length, mapping_find(payload_type_m, payload_type));
+ status = this->public.parse_payload((parser_t*)this, payload_type, &payload);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, ERROR, " parsing of a %s substructure failed",
+ mapping_find(payload_type_m, payload_type));
+ return status;
+ }
+ list->insert_last(list, payload);
+ length -= this->byte_pos - pos_before;
+ }
+ *output_pos = list;
+ return SUCCESS;
+}
+
+/**
+ * Implementation of private_parser_t.parse_chunk.
+ */
+static status_t parse_chunk(private_parser_t *this, int rule_number, chunk_t *output_pos, size_t length)
+{
+ if (this->byte_pos + length > this->input_roof)
+ {
+ this->logger->log(this->logger, ERROR, " not enough input (%d bytes) to parse rule %d %s",
+ length, rule_number, mapping_find(encoding_type_m, this->rules[rule_number].type));
+ return PARSE_ERROR;
+ }
+ if (this->bit_pos)
+ {
+ this->logger->log(this->logger, ERROR, " found rule %d %s on bitpos %d",
+ rule_number, mapping_find(encoding_type_m, this->rules[rule_number].type), this->bit_pos);
+ return PARSE_ERROR;
+ }
+ if (output_pos != NULL)
+ {
+ output_pos->len = length;
+ output_pos->ptr = malloc(length);
+ memcpy(output_pos->ptr, this->byte_pos, length);
+ }
+ this->byte_pos += length;
+ this->logger->log_bytes(this->logger, RAW|LEVEL2, " =>", (void*)output_pos->ptr, length);
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of parser_t.parse_payload.
+ */
+static status_t parse_payload(private_parser_t *this, payload_type_t payload_type, payload_t **payload)
+{
+ payload_t *pld;
+ void *output;
+ size_t rule_count, payload_length, spi_size, attribute_length;
+ u_int16_t ts_type;
+ bool attribute_format;
+ int rule_number;
+ encoding_rule_t *rule;
+
+ /* create instance of the payload to parse */
+ pld = payload_create(payload_type);
+
+ this->logger->log(this->logger, CONTROL|LEVEL1, "parsing %s payload, %d bytes left",
+ mapping_find(payload_type_m, payload_type),
+ this->input_roof-this->byte_pos);
+
+ this->logger->log_bytes(this->logger, RAW|LEVEL3, "parsing payload from", this->byte_pos,
+ this->input_roof-this->byte_pos);
+
+ if (pld->get_type(pld) == UNKNOWN_PAYLOAD)
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1, " payload type %d is unknown, handling as %s",
+ payload_type, mapping_find(payload_type_m, UNKNOWN_PAYLOAD));
+ }
+
+ /* base pointer for output, avoids casting in every rule */
+ output = pld;
+
+ /* parse the payload with its own rulse */
+ pld->get_encoding_rules(pld, &(this->rules), &rule_count);
+ for (rule_number = 0; rule_number < rule_count; rule_number++)
+ {
+ rule = &(this->rules[rule_number]);
+ this->logger->log(this->logger, CONTROL|LEVEL2, " parsing rule %d %s",
+ rule_number, mapping_find(encoding_type_m, rule->type));
+ switch (rule->type)
+ {
+ case U_INT_4:
+ {
+ if (this->parse_uint4(this, rule_number, output + rule->offset) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ break;
+ }
+ case U_INT_8:
+ {
+ if (this->parse_uint8(this, rule_number, output + rule->offset) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ break;
+ }
+ case U_INT_16:
+ {
+ if (this->parse_uint16(this, rule_number, output + rule->offset) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ break;
+ }
+ case U_INT_32:
+ {
+ if (this->parse_uint32(this, rule_number, output + rule->offset) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ break;
+ }
+ case U_INT_64:
+ {
+ if (this->parse_uint64(this, rule_number, output + rule->offset) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ break;
+ }
+ case IKE_SPI:
+ {
+ if (this->parse_bytes(this, rule_number, output + rule->offset,8) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ break;
+ }
+ case RESERVED_BIT:
+ {
+ if (this->parse_bit(this, rule_number, NULL) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ break;
+ }
+ case RESERVED_BYTE:
+ {
+ if (this->parse_uint8(this, rule_number, NULL) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ break;
+ }
+ case FLAG:
+ {
+ if (this->parse_bit(this, rule_number, output + rule->offset) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ break;
+ }
+ case PAYLOAD_LENGTH:
+ {
+ if (this->parse_uint16(this, rule_number, output + rule->offset) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ payload_length = *(u_int16_t*)(output + rule->offset);
+ break;
+ }
+ case HEADER_LENGTH:
+ {
+ if (this->parse_uint32(this, rule_number, output + rule->offset) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ break;
+ }
+ case SPI_SIZE:
+ {
+ if (this->parse_uint8(this, rule_number, output + rule->offset) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ spi_size = *(u_int8_t*)(output + rule->offset);
+ break;
+ }
+ case SPI:
+ {
+ if (this->parse_chunk(this, rule_number, output + rule->offset, spi_size) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ break;
+ }
+ case PROPOSALS:
+ {
+ size_t proposals_length = payload_length - SA_PAYLOAD_HEADER_LENGTH;
+ if (this->parse_list(this, rule_number, output + rule->offset, PROPOSAL_SUBSTRUCTURE, proposals_length) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ break;
+ }
+ case TRANSFORMS:
+ {
+ size_t transforms_length = payload_length - spi_size - PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH;
+ if (this->parse_list(this, rule_number, output + rule->offset, TRANSFORM_SUBSTRUCTURE, transforms_length) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ break;
+ }
+ case TRANSFORM_ATTRIBUTES:
+ {
+ size_t transform_a_length = payload_length - TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH;
+ if (this->parse_list(this, rule_number, output + rule->offset, TRANSFORM_ATTRIBUTE, transform_a_length) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ break;
+ }
+ case CONFIGURATION_ATTRIBUTES:
+ {
+ size_t configuration_attributes_length = payload_length - CP_PAYLOAD_HEADER_LENGTH;
+ if (this->parse_list(this, rule_number, output + rule->offset, CONFIGURATION_ATTRIBUTE, configuration_attributes_length) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ break;
+ }
+ case ATTRIBUTE_FORMAT:
+ {
+ if (this->parse_bit(this, rule_number, output + rule->offset) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ attribute_format = *(bool*)(output + rule->offset);
+ break;
+ }
+ case ATTRIBUTE_TYPE:
+ {
+ if (this->parse_uint15(this, rule_number, output + rule->offset) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ attribute_format = *(bool*)(output + rule->offset);
+ break;
+ }
+ case CONFIGURATION_ATTRIBUTE_LENGTH:
+ {
+ if (this->parse_uint16(this, rule_number, output + rule->offset) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ attribute_length = *(u_int16_t*)(output + rule->offset);
+ break;
+ }
+ case ATTRIBUTE_LENGTH_OR_VALUE:
+ {
+ if (this->parse_uint16(this, rule_number, output + rule->offset) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ attribute_length = *(u_int16_t*)(output + rule->offset);
+ break;
+ }
+ case ATTRIBUTE_VALUE:
+ {
+ if (attribute_format == FALSE)
+ {
+ if (this->parse_chunk(this, rule_number, output + rule->offset, attribute_length) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ }
+ break;
+ }
+ case NONCE_DATA:
+ {
+ size_t nonce_length = payload_length - NONCE_PAYLOAD_HEADER_LENGTH;
+ if (this->parse_chunk(this, rule_number, output + rule->offset, nonce_length) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ break;
+ }
+ case ID_DATA:
+ {
+ size_t data_length = payload_length - ID_PAYLOAD_HEADER_LENGTH;
+ if (this->parse_chunk(this, rule_number, output + rule->offset, data_length) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ break;
+ }
+ case AUTH_DATA:
+ {
+ size_t data_length = payload_length - AUTH_PAYLOAD_HEADER_LENGTH;
+ if (this->parse_chunk(this, rule_number, output + rule->offset, data_length) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ break;
+ }
+ case CERT_DATA:
+ {
+ size_t data_length = payload_length - CERT_PAYLOAD_HEADER_LENGTH;
+ if (this->parse_chunk(this, rule_number, output + rule->offset, data_length) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ break;
+ }
+ case CERTREQ_DATA:
+ {
+ size_t data_length = payload_length - CERTREQ_PAYLOAD_HEADER_LENGTH;
+ if (this->parse_chunk(this, rule_number, output + rule->offset, data_length) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ break;
+ }
+ case EAP_MESSAGE:
+ {
+ size_t data_length = payload_length - EAP_PAYLOAD_HEADER_LENGTH;
+ if (this->parse_chunk(this, rule_number, output + rule->offset, data_length) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ break;
+ }
+ case SPIS:
+ {
+ size_t data_length = payload_length - DELETE_PAYLOAD_HEADER_LENGTH;
+ if (this->parse_chunk(this, rule_number, output + rule->offset, data_length) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ break;
+ }
+ case VID_DATA:
+ {
+ size_t data_length = payload_length - VENDOR_ID_PAYLOAD_HEADER_LENGTH;
+ if (this->parse_chunk(this, rule_number, output + rule->offset, data_length) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ break;
+ }
+ case CONFIGURATION_ATTRIBUTE_VALUE:
+ {
+ size_t data_length = attribute_length;
+ if (this->parse_chunk(this, rule_number, output + rule->offset, data_length) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ break;
+ }
+ case KEY_EXCHANGE_DATA:
+ {
+ size_t keydata_length = payload_length - KE_PAYLOAD_HEADER_LENGTH;
+ if (this->parse_chunk(this, rule_number, output + rule->offset, keydata_length) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ break;
+ }
+ case NOTIFICATION_DATA:
+ {
+ size_t notify_length = payload_length - NOTIFY_PAYLOAD_HEADER_LENGTH - spi_size;
+ if (this->parse_chunk(this, rule_number, output + rule->offset, notify_length) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ break;
+ }
+ case ENCRYPTED_DATA:
+ {
+ size_t data_length = payload_length - ENCRYPTION_PAYLOAD_HEADER_LENGTH;
+ if (this->parse_chunk(this, rule_number, output + rule->offset, data_length) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ break;
+ }
+ case TS_TYPE:
+ {
+ if (this->parse_uint8(this, rule_number, output + rule->offset) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ ts_type = *(u_int8_t*)(output + rule->offset);
+ break;
+ }
+ case ADDRESS:
+ {
+ size_t address_length = (ts_type == TS_IPV4_ADDR_RANGE) ? 4 : 16;
+ if (this->parse_chunk(this, rule_number, output + rule->offset,address_length) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ break;
+ }
+ case TRAFFIC_SELECTORS:
+ {
+ size_t traffic_selectors_length = payload_length - TS_PAYLOAD_HEADER_LENGTH;
+ if (this->parse_list(this, rule_number, output + rule->offset, TRAFFIC_SELECTOR_SUBSTRUCTURE, traffic_selectors_length) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ break;
+ }
+ case UNKNOWN_PAYLOAD:
+ {
+ size_t unknown_payload_data_length = payload_length - UNKNOWN_PAYLOAD_HEADER_LENGTH;
+ if (this->parse_chunk(this, rule_number, output + rule->offset, unknown_payload_data_length) != SUCCESS)
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ break;
+ }
+ default:
+ {
+ this->logger->log(this->logger, ERROR, " no rule to parse rule %d %s (%d)", rule_number, mapping_find(encoding_type_m, rule->type), rule->type);
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ }
+ /* process next rulue */
+ rule++;
+ }
+
+ *payload = pld;
+ this->logger->log(this->logger, CONTROL|LEVEL2, "parsing %s payload finished.",
+ mapping_find(payload_type_m, payload_type));
+ return SUCCESS;
+}
+
+/**
+ * Implementation of parser_t.get_remaining_byte_count.
+ */
+static int get_remaining_byte_count (private_parser_t *this)
+{
+ int count = (this->input_roof - this->byte_pos);
+ return count;
+}
+
+/**
+ * Implementation of parser_t.reset_context.
+ */
+static void reset_context (private_parser_t *this)
+{
+ this->byte_pos = this->input;
+ this->bit_pos = 0;
+}
+
+/**
+ * Implementation of parser_t.destroy.
+ */
+static void destroy(private_parser_t *this)
+{
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+parser_t *parser_create(chunk_t data)
+{
+ private_parser_t *this = malloc_thing(private_parser_t);
+
+ this->logger = logger_manager->get_logger(logger_manager, PARSER);
+
+ this->public.parse_payload = (status_t(*)(parser_t*,payload_type_t,payload_t**)) parse_payload;
+ this->public.reset_context = (void(*)(parser_t*)) reset_context;
+ this->public.get_remaining_byte_count = (int (*) (parser_t *))get_remaining_byte_count;
+ this->public.destroy = (void(*)(parser_t*)) destroy;
+
+ this->parse_uint4 = parse_uint4;
+ this->parse_uint8 = parse_uint8;
+ this->parse_uint15 = parse_uint15;
+ this->parse_uint16 = parse_uint16;
+ this->parse_uint32 = parse_uint32;
+ this->parse_uint64 = parse_uint64;
+ this->parse_bytes = parse_bytes;
+ this->parse_bit = parse_bit;
+ this->parse_list = parse_list;
+ this->parse_chunk = parse_chunk;
+
+ this->input = data.ptr;
+ this->byte_pos = data.ptr;
+ this->bit_pos = 0;
+ this->input_roof = data.ptr + data.len;
+
+ return (parser_t*)this;
+}
+
diff --git a/programs/charon/charon/encoding/parser.h b/programs/charon/charon/encoding/parser.h
new file mode 100644
index 000000000..216fac9b7
--- /dev/null
+++ b/programs/charon/charon/encoding/parser.h
@@ -0,0 +1,95 @@
+/**
+ * @file parser.h
+ *
+ * @brief Interface of parser_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef PARSER_H_
+#define PARSER_H_
+
+#include <types.h>
+#include <encoding/payloads/encodings.h>
+#include <encoding/payloads/payload.h>
+
+
+typedef struct parser_t parser_t;
+
+/**
+ * @brief 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.
+ *
+ * @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
+ * @return
+ * - SUCCESSFUL if succeeded,
+ * - PARSE_ERROR if corrupted/invalid data found
+ */
+ status_t (*parse_payload) (parser_t *this, payload_type_t payload_type, payload_t **payload);
+
+ /**
+ * Gets the remaining byte count which is not currently parsed.
+ *
+ * @param parser parser_t object
+ */
+ int (*get_remaining_byte_count) (parser_t *this);
+
+ /**
+ * @brief Resets the current parser context.
+ *
+ * @param parser parser_t object
+ */
+ void (*reset_context) (parser_t *this);
+
+ /**
+ * @brief Destroys a parser_t object.
+ *
+ * @param parser 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
+ *
+ * @ingroup encoding
+ */
+parser_t *parser_create(chunk_t data);
+
+#endif /*PARSER_H_*/
diff --git a/programs/charon/charon/encoding/payloads/Makefile.payloads b/programs/charon/charon/encoding/payloads/Makefile.payloads
new file mode 100644
index 000000000..61d920907
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/Makefile.payloads
@@ -0,0 +1,108 @@
+# Copyright (C) 2005 Jan Hutter, Martin Willi
+# Hochschule fuer Technik Rapperswil
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+
+PAYLOADS_DIR= $(ENCODING_DIR)payloads/
+
+CHARON_OBJS+= $(BUILD_DIR)encodings.o
+$(BUILD_DIR)encodings.o : $(PAYLOADS_DIR)encodings.c $(PAYLOADS_DIR)encodings.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)ike_header.o
+$(BUILD_DIR)ike_header.o : $(PAYLOADS_DIR)ike_header.c $(PAYLOADS_DIR)ike_header.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)ke_payload.o
+$(BUILD_DIR)ke_payload.o : $(PAYLOADS_DIR)ke_payload.c $(PAYLOADS_DIR)ke_payload.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)nonce_payload.o
+$(BUILD_DIR)nonce_payload.o : $(PAYLOADS_DIR)nonce_payload.c $(PAYLOADS_DIR)nonce_payload.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)notify_payload.o
+$(BUILD_DIR)notify_payload.o : $(PAYLOADS_DIR)notify_payload.c $(PAYLOADS_DIR)notify_payload.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)id_payload.o
+$(BUILD_DIR)id_payload.o : $(PAYLOADS_DIR)id_payload.c $(PAYLOADS_DIR)id_payload.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)auth_payload.o
+$(BUILD_DIR)auth_payload.o : $(PAYLOADS_DIR)auth_payload.c $(PAYLOADS_DIR)auth_payload.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)cert_payload.o
+$(BUILD_DIR)cert_payload.o : $(PAYLOADS_DIR)cert_payload.c $(PAYLOADS_DIR)cert_payload.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)certreq_payload.o
+$(BUILD_DIR)certreq_payload.o : $(PAYLOADS_DIR)certreq_payload.c $(PAYLOADS_DIR)certreq_payload.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)delete_payload.o
+$(BUILD_DIR)delete_payload.o : $(PAYLOADS_DIR)delete_payload.c $(PAYLOADS_DIR)delete_payload.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)vendor_id_payload.o
+$(BUILD_DIR)vendor_id_payload.o : $(PAYLOADS_DIR)vendor_id_payload.c $(PAYLOADS_DIR)vendor_id_payload.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)cp_payload.o
+$(BUILD_DIR)cp_payload.o : $(PAYLOADS_DIR)cp_payload.c $(PAYLOADS_DIR)cp_payload.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)configuration_attribute.o
+$(BUILD_DIR)configuration_attribute.o : $(PAYLOADS_DIR)configuration_attribute.c $(PAYLOADS_DIR)configuration_attribute.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)eap_payload.o
+$(BUILD_DIR)eap_payload.o : $(PAYLOADS_DIR)eap_payload.c $(PAYLOADS_DIR)eap_payload.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)unknown_payload.o
+$(BUILD_DIR)unknown_payload.o : $(PAYLOADS_DIR)unknown_payload.c $(PAYLOADS_DIR)unknown_payload.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)ts_payload.o
+$(BUILD_DIR)ts_payload.o : $(PAYLOADS_DIR)ts_payload.c $(PAYLOADS_DIR)ts_payload.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)traffic_selector_substructure.o
+$(BUILD_DIR)traffic_selector_substructure.o : $(PAYLOADS_DIR)traffic_selector_substructure.c $(PAYLOADS_DIR)traffic_selector_substructure.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)payload.o
+$(BUILD_DIR)payload.o : $(PAYLOADS_DIR)payload.c $(PAYLOADS_DIR)payload.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)proposal_substructure.o
+$(BUILD_DIR)proposal_substructure.o : $(PAYLOADS_DIR)proposal_substructure.c $(PAYLOADS_DIR)proposal_substructure.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)sa_payload.o
+$(BUILD_DIR)sa_payload.o : $(PAYLOADS_DIR)sa_payload.c $(PAYLOADS_DIR)sa_payload.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)transform_attribute.o
+$(BUILD_DIR)transform_attribute.o : $(PAYLOADS_DIR)transform_attribute.c $(PAYLOADS_DIR)transform_attribute.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)transform_substructure.o
+$(BUILD_DIR)transform_substructure.o : $(PAYLOADS_DIR)transform_substructure.c $(PAYLOADS_DIR)transform_substructure.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)encryption_payload.o
+$(BUILD_DIR)encryption_payload.o : $(PAYLOADS_DIR)encryption_payload.c $(PAYLOADS_DIR)encryption_payload.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
diff --git a/programs/charon/charon/encoding/payloads/auth_payload.c b/programs/charon/charon/encoding/payloads/auth_payload.c
new file mode 100644
index 000000000..cc7c4bfb1
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/auth_payload.c
@@ -0,0 +1,265 @@
+/**
+ * @file auth_payload.h
+ *
+ * @brief Implementation of auth_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "auth_payload.h"
+
+#include <encoding/payloads/encodings.h>
+
+
+typedef struct private_auth_payload_t private_auth_payload_t;
+
+/**
+ * Private data of an auth_payload_t object.
+ *
+ */
+struct private_auth_payload_t {
+
+ /**
+ * Public auth_payload_t interface.
+ */
+ auth_payload_t public;
+
+ /**
+ * Next payload type.
+ */
+ u_int8_t next_payload;
+
+ /**
+ * Critical flag.
+ */
+ bool critical;
+
+ /**
+ * Length of this payload.
+ */
+ u_int16_t payload_length;
+
+ /**
+ * Method of the AUTH Data.
+ */
+ u_int8_t auth_method;
+
+ /**
+ * The contained auth data value.
+ */
+ chunk_t auth_data;
+};
+
+/**
+ * Encoding rules to parse or generate a AUTH payload
+ *
+ * The defined offsets are the positions in a object of type
+ * private_auth_payload_t.
+ *
+ */
+encoding_rule_t auth_payload_encodings[] = {
+ /* 1 Byte next payload type, stored in the field next_payload */
+ { U_INT_8, offsetof(private_auth_payload_t, next_payload) },
+ /* the critical bit */
+ { FLAG, offsetof(private_auth_payload_t, critical) },
+ /* 7 Bit reserved bits, nowhere stored */
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ /* Length of the whole payload*/
+ { PAYLOAD_LENGTH, offsetof(private_auth_payload_t, payload_length)},
+ /* 1 Byte AUTH type*/
+ { U_INT_8, offsetof(private_auth_payload_t, auth_method) },
+ /* 3 reserved bytes */
+ { RESERVED_BYTE, 0 },
+ { RESERVED_BYTE, 0 },
+ { RESERVED_BYTE, 0 },
+ /* some auth data bytes, length is defined in PAYLOAD_LENGTH */
+ { AUTH_DATA, offsetof(private_auth_payload_t, auth_data) }
+};
+
+/*
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Next Payload !C! RESERVED ! Payload Length !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Auth Method ! RESERVED !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! !
+ ~ Authentication Data ~
+ ! !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+/**
+ * Implementation of payload_t.verify.
+ */
+static status_t verify(private_auth_payload_t *this)
+{
+ if ((this->auth_method == 0) ||
+ ((this->auth_method >= 4) && (this->auth_method <= 200)))
+ {
+ /* reserved IDs */
+ return FAILED;
+ }
+ return SUCCESS;
+}
+
+/**
+ * Implementation of auth_payload_t.get_encoding_rules.
+ */
+static void get_encoding_rules(private_auth_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
+{
+ *rules = auth_payload_encodings;
+ *rule_count = sizeof(auth_payload_encodings) / sizeof(encoding_rule_t);
+}
+
+/**
+ * Implementation of payload_t.get_type.
+ */
+static payload_type_t get_payload_type(private_auth_payload_t *this)
+{
+ return AUTHENTICATION;
+}
+
+/**
+ * Implementation of payload_t.get_next_type.
+ */
+static payload_type_t get_next_type(private_auth_payload_t *this)
+{
+ return (this->next_payload);
+}
+
+/**
+ * Implementation of payload_t.set_next_type.
+ */
+static void set_next_type(private_auth_payload_t *this,payload_type_t type)
+{
+ this->next_payload = type;
+}
+
+/**
+ * Implementation of payload_t.get_length.
+ */
+static size_t get_length(private_auth_payload_t *this)
+{
+ return this->payload_length;
+}
+
+/**
+ * Implementation of auth_payload_t.set_auth_method.
+ */
+static void set_auth_method (private_auth_payload_t *this, auth_method_t method)
+{
+ this->auth_method = method;
+}
+
+/**
+ * Implementation of auth_payload_t.get_auth_method.
+ */
+static auth_method_t get_auth_method (private_auth_payload_t *this)
+{
+ return (this->auth_method);
+}
+
+/**
+ * Implementation of auth_payload_t.set_data.
+ */
+static void set_data (private_auth_payload_t *this, chunk_t data)
+{
+ if (this->auth_data.ptr != NULL)
+ {
+ chunk_free(&(this->auth_data));
+ }
+ this->auth_data.ptr = clalloc(data.ptr,data.len);
+ this->auth_data.len = data.len;
+ this->payload_length = AUTH_PAYLOAD_HEADER_LENGTH + this->auth_data.len;
+}
+
+/**
+ * Implementation of auth_payload_t.get_data.
+ */
+static chunk_t get_data (private_auth_payload_t *this)
+{
+ return (this->auth_data);
+}
+
+/**
+ * Implementation of auth_payload_t.get_data_clone.
+ */
+static chunk_t get_data_clone (private_auth_payload_t *this)
+{
+ chunk_t cloned_data;
+ if (this->auth_data.ptr == NULL)
+ {
+ return (this->auth_data);
+ }
+ cloned_data.ptr = clalloc(this->auth_data.ptr,this->auth_data.len);
+ cloned_data.len = this->auth_data.len;
+ return cloned_data;
+}
+
+/**
+ * Implementation of payload_t.destroy and auth_payload_t.destroy.
+ */
+static void destroy(private_auth_payload_t *this)
+{
+ if (this->auth_data.ptr != NULL)
+ {
+ chunk_free(&(this->auth_data));
+ }
+
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+auth_payload_t *auth_payload_create()
+{
+ private_auth_payload_t *this = malloc_thing(private_auth_payload_t);
+
+ /* interface functions */
+ this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
+ this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
+ this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
+ this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
+ this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
+ this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_payload_type;
+ this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
+
+ /* public functions */
+ this->public.destroy = (void (*) (auth_payload_t *)) destroy;
+ this->public.set_auth_method = (void (*) (auth_payload_t *,auth_method_t)) set_auth_method;
+ this->public.get_auth_method = (auth_method_t (*) (auth_payload_t *)) get_auth_method;
+ this->public.set_data = (void (*) (auth_payload_t *,chunk_t)) set_data;
+ this->public.get_data_clone = (chunk_t (*) (auth_payload_t *)) get_data_clone;
+ this->public.get_data = (chunk_t (*) (auth_payload_t *)) get_data;
+
+ /* private variables */
+ this->critical = FALSE;
+ this->next_payload = NO_PAYLOAD;
+ this->payload_length =AUTH_PAYLOAD_HEADER_LENGTH;
+ this->auth_data = CHUNK_INITIALIZER;
+
+ return (&(this->public));
+}
diff --git a/programs/charon/charon/encoding/payloads/auth_payload.h b/programs/charon/charon/encoding/payloads/auth_payload.h
new file mode 100644
index 000000000..e099cdfef
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/auth_payload.h
@@ -0,0 +1,122 @@
+/**
+ * @file auth_payload.h
+ *
+ * @brief Interface of auth_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#ifndef AUTH_PAYLOAD_H_
+#define AUTH_PAYLOAD_H_
+
+#include <types.h>
+#include <encoding/payloads/payload.h>
+#include <config/connections/connection.h>
+
+/**
+ * Length of a auth payload without the auth data in bytes.
+ *
+ * @ingroup payloads
+ */
+#define AUTH_PAYLOAD_HEADER_LENGTH 8
+
+
+typedef struct auth_payload_t auth_payload_t;
+
+/**
+ * @brief 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 {
+
+ /**
+ * The payload_t interface.
+ */
+ payload_t payload_interface;
+
+ /**
+ * @brief 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.
+ *
+ * @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.
+ *
+ * Data are getting 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.
+ *
+ * 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.
+ *
+ * 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
+ */
+ void (*destroy) (auth_payload_t *this);
+};
+
+/**
+ * @brief Creates an empty auth_payload_t object.
+ *
+ * @return auth_payload_t object
+ *
+ * @ingroup payloads
+ */
+auth_payload_t *auth_payload_create();
+
+
+#endif /* AUTH_PAYLOAD_H_ */
diff --git a/programs/charon/charon/encoding/payloads/cert_payload.c b/programs/charon/charon/encoding/payloads/cert_payload.c
new file mode 100644
index 000000000..146d42eda
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/cert_payload.c
@@ -0,0 +1,279 @@
+/**
+ * @file cert_payload.c
+ *
+ * @brief Implementation of cert_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stddef.h>
+
+#include "cert_payload.h"
+
+
+/**
+ * String mappings for cert_encoding_t.
+ */
+mapping_t cert_encoding_m[] = {
+ {PKCS7_WRAPPED_X509_CERTIFICATE, "PKCS7_WRAPPED_X509_CERTIFICATE"},
+ {PGP_CERTIFICATE, "PGP_CERTIFICATE"},
+ {DNS_SIGNED_KEY, "DNS_SIGNED_KEY"},
+ {X509_CERTIFICATE_SIGNATURE, "X509_CERTIFICATE_SIGNATURE"},
+ {KERBEROS_TOKEN, "KERBEROS_TOKEN"},
+ {CERTIFICATE_REVOCATION_LIST, "CERTIFICATE_REVOCATION_LIST"},
+ {AUTHORITY_REVOCATION_LIST, "AUTHORITY_REVOCATION_LIST"},
+ {SPKI_CERTIFICATE, "SPKI_CERTIFICATE"},
+ {X509_CERTIFICATE_ATTRIBUTE, "X509_CERTIFICATE_ATTRIBUTE"},
+ {RAW_SA_KEY, "RAW_SA_KEY"},
+ {HASH_AND_URL_X509_CERTIFICATE, "HASH_AND_URL_X509_CERTIFICATE"},
+ {HASH_AND_URL_X509_BUNDLE, "HASH_AND_URL_X509_BUNDLE"},
+ {MAPPING_END, NULL}
+};
+
+
+typedef struct private_cert_payload_t private_cert_payload_t;
+
+/**
+ * Private data of an cert_payload_t object.
+ *
+ */
+struct private_cert_payload_t {
+ /**
+ * Public cert_payload_t interface.
+ */
+ cert_payload_t public;
+
+ /**
+ * Next payload type.
+ */
+ u_int8_t next_payload;
+
+ /**
+ * Critical flag.
+ */
+ bool critical;
+
+ /**
+ * Length of this payload.
+ */
+ u_int16_t payload_length;
+
+ /**
+ * Encoding of the CERT Data.
+ */
+ u_int8_t cert_encoding;
+
+ /**
+ * The contained cert data value.
+ */
+ chunk_t cert_data;
+};
+
+/**
+ * Encoding rules to parse or generate a CERT payload
+ *
+ * The defined offsets are the positions in a object of type
+ * private_cert_payload_t.
+ *
+ */
+encoding_rule_t cert_payload_encodings[] = {
+ /* 1 Byte next payload type, stored in the field next_payload */
+ { U_INT_8, offsetof(private_cert_payload_t, next_payload) },
+ /* the critical bit */
+ { FLAG, offsetof(private_cert_payload_t, critical) },
+ /* 7 Bit reserved bits, nowhere stored */
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ /* Length of the whole payload*/
+ { PAYLOAD_LENGTH, offsetof(private_cert_payload_t, payload_length)},
+ /* 1 Byte CERT type*/
+ { U_INT_8, offsetof(private_cert_payload_t, cert_encoding) },
+ /* some cert data bytes, length is defined in PAYLOAD_LENGTH */
+ { CERT_DATA, offsetof(private_cert_payload_t, cert_data) }
+};
+
+/*
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Next Payload !C! RESERVED ! Payload Length !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Cert Encoding ! !
+ +-+-+-+-+-+-+-+-+ !
+ ~ Certificate Data ~
+ ! !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+/**
+ * Implementation of payload_t.verify.
+ */
+static status_t verify(private_cert_payload_t *this)
+{
+ if ((this->cert_encoding == 0) ||
+ ((this->cert_encoding >= 14) && (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)
+{
+ *rules = cert_payload_encodings;
+ *rule_count = sizeof(cert_payload_encodings) / sizeof(encoding_rule_t);
+}
+
+/**
+ * Implementation of payload_t.get_type.
+ */
+static payload_type_t get_payload_type(private_cert_payload_t *this)
+{
+ return CERTIFICATE;
+}
+
+/**
+ * Implementation of payload_t.get_next_type.
+ */
+static payload_type_t get_next_type(private_cert_payload_t *this)
+{
+ return (this->next_payload);
+}
+
+/**
+ * Implementation of payload_t.set_next_type.
+ */
+static void set_next_type(private_cert_payload_t *this,payload_type_t type)
+{
+ this->next_payload = type;
+}
+
+/**
+ * Implementation of payload_t.get_length.
+ */
+static size_t get_length(private_cert_payload_t *this)
+{
+ return this->payload_length;
+}
+
+/**
+ * Implementation of cert_payload_t.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.
+ */
+static void set_data (private_cert_payload_t *this, chunk_t data)
+{
+ 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)
+ {
+ return (this->cert_data);
+ }
+ cloned_data.ptr = clalloc(this->cert_data.ptr,this->cert_data.len);
+ cloned_data.len = this->cert_data.len;
+ return cloned_data;
+}
+
+/**
+ * Implementation of payload_t.destroy and cert_payload_t.destroy.
+ */
+static void destroy(private_cert_payload_t *this)
+{
+ if (this->cert_data.ptr != NULL)
+ {
+ chunk_free(&(this->cert_data));
+ }
+
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+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;
+ this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
+ this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
+ this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_payload_type;
+ this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
+
+ /* public functions */
+ this->public.destroy = (void (*) (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;
+
+ /* private variables */
+ this->critical = FALSE;
+ this->next_payload = NO_PAYLOAD;
+ this->payload_length =CERT_PAYLOAD_HEADER_LENGTH;
+ this->cert_data = CHUNK_INITIALIZER;
+
+ return (&(this->public));
+}
diff --git a/programs/charon/charon/encoding/payloads/cert_payload.h b/programs/charon/charon/encoding/payloads/cert_payload.h
new file mode 100644
index 000000000..9148cfd31
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/cert_payload.h
@@ -0,0 +1,155 @@
+/**
+ * @file cert_payload.h
+ *
+ * @brief Interface of cert_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef CERT_PAYLOAD_H_
+#define CERT_PAYLOAD_H_
+
+#include <types.h>
+#include <encoding/payloads/payload.h>
+
+/**
+ * Length of a cert payload without the cert data in bytes.
+ *
+ * @ingroup payloads
+ */
+#define CERT_PAYLOAD_HEADER_LENGTH 5
+
+
+typedef enum cert_encoding_t cert_encoding_t;
+
+/**
+ * @brief Certificate encoding, as described in IKEv2 RFC section 3.6
+ *
+ * @ingroup payloads
+ */
+enum cert_encoding_t {
+ PKCS7_WRAPPED_X509_CERTIFICATE = 1,
+ PGP_CERTIFICATE = 2,
+ DNS_SIGNED_KEY = 3,
+ X509_CERTIFICATE_SIGNATURE = 4,
+ KERBEROS_TOKEN = 6,
+ CERTIFICATE_REVOCATION_LIST = 7,
+ AUTHORITY_REVOCATION_LIST = 8,
+ SPKI_CERTIFICATE = 9,
+ X509_CERTIFICATE_ATTRIBUTE = 10,
+ RAW_SA_KEY = 11,
+ HASH_AND_URL_X509_CERTIFICATE = 12,
+ HASH_AND_URL_X509_BUNDLE = 13
+};
+
+/**
+ * string mappings for cert_encoding_t.
+ *
+ * @ingroup payloads
+ */
+extern mapping_t cert_encoding_m[];
+
+
+typedef struct cert_payload_t cert_payload_t;
+
+/**
+ * @brief 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 {
+
+ /**
+ * 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.
+ *
+ * @param this calling cert_payload_t object
+ * @return CERT data as chunk_t
+ */
+ chunk_t (*get_data_clone) (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
+ */
+ void (*destroy) (cert_payload_t *this);
+};
+
+/**
+ * @brief Creates an empty cert_payload_t object.
+ *
+ * @return cert_payload_t object
+ *
+ * @ingroup payloads
+ */
+cert_payload_t *cert_payload_create();
+
+
+#endif /* CERT_PAYLOAD_H_ */
diff --git a/programs/charon/charon/encoding/payloads/certreq_payload.c b/programs/charon/charon/encoding/payloads/certreq_payload.c
new file mode 100644
index 000000000..cdab82be4
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/certreq_payload.c
@@ -0,0 +1,259 @@
+/**
+ * @file certreq_payload.c
+ *
+ * @brief Implementation of certreq_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stddef.h>
+
+#include "certreq_payload.h"
+
+
+typedef struct private_certreq_payload_t private_certreq_payload_t;
+
+/**
+ * Private data of an certreq_payload_t object.
+ *
+ */
+struct private_certreq_payload_t {
+ /**
+ * Public certreq_payload_t interface.
+ */
+ certreq_payload_t public;
+
+ /**
+ * Next payload type.
+ */
+ u_int8_t next_payload;
+
+ /**
+ * Critical flag.
+ */
+ bool critical;
+
+ /**
+ * Length of this payload.
+ */
+ u_int16_t payload_length;
+
+ /**
+ * Encoding of the CERT Data.
+ */
+ u_int8_t cert_encoding;
+
+ /**
+ * The contained certreq data value.
+ */
+ chunk_t certreq_data;
+};
+
+/**
+ * Encoding rules to parse or generate a CERTREQ payload
+ *
+ * The defined offsets are the positions in a object of type
+ * private_certreq_payload_t.
+ *
+ */
+encoding_rule_t certreq_payload_encodings[] = {
+ /* 1 Byte next payload type, stored in the field next_payload */
+ { U_INT_8, offsetof(private_certreq_payload_t, next_payload) },
+ /* the critical bit */
+ { FLAG, offsetof(private_certreq_payload_t, critical) },
+ /* 7 Bit reserved bits, nowhere stored */
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ /* Length of the whole payload*/
+ { PAYLOAD_LENGTH, offsetof(private_certreq_payload_t, payload_length)},
+ /* 1 Byte CERTREQ type*/
+ { U_INT_8, offsetof(private_certreq_payload_t, cert_encoding)},
+ /* some certreq data bytes, length is defined in PAYLOAD_LENGTH */
+ { CERTREQ_DATA, offsetof(private_certreq_payload_t, certreq_data)}
+};
+
+/*
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Next Payload !C! RESERVED ! Payload Length !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Cert Encoding ! !
+ +-+-+-+-+-+-+-+-+ !
+ ~ Certification Authority ~
+ ! !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+/**
+ * Implementation of payload_t.verify.
+ */
+static status_t verify(private_certreq_payload_t *this)
+{
+ if ((this->cert_encoding == 0) ||
+ ((this->cert_encoding >= 14) && (this->cert_encoding <= 200)))
+ {
+ /* reserved IDs */
+ return FAILED;
+ }
+ return SUCCESS;
+}
+
+/**
+ * Implementation of certreq_payload_t.get_encoding_rules.
+ */
+static void get_encoding_rules(private_certreq_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
+{
+ *rules = certreq_payload_encodings;
+ *rule_count = sizeof(certreq_payload_encodings) / sizeof(encoding_rule_t);
+}
+
+/**
+ * Implementation of payload_t.get_type.
+ */
+static payload_type_t get_payload_type(private_certreq_payload_t *this)
+{
+ return CERTIFICATE_REQUEST;
+}
+
+/**
+ * Implementation of payload_t.get_next_type.
+ */
+static payload_type_t get_next_type(private_certreq_payload_t *this)
+{
+ return (this->next_payload);
+}
+
+/**
+ * Implementation of payload_t.set_next_type.
+ */
+static void set_next_type(private_certreq_payload_t *this,payload_type_t type)
+{
+ this->next_payload = type;
+}
+
+/**
+ * Implementation of payload_t.get_length.
+ */
+static size_t get_length(private_certreq_payload_t *this)
+{
+ return this->payload_length;
+}
+
+/**
+ * Implementation of certreq_payload_t.set_cert_encoding.
+ */
+static void set_cert_encoding (private_certreq_payload_t *this, cert_encoding_t encoding)
+{
+ this->cert_encoding = encoding;
+}
+
+/**
+ * Implementation of certreq_payload_t.get_cert_encoding.
+ */
+static cert_encoding_t get_cert_encoding (private_certreq_payload_t *this)
+{
+ return (this->cert_encoding);
+}
+
+/**
+ * Implementation of certreq_payload_t.set_data.
+ */
+static void set_data (private_certreq_payload_t *this, chunk_t data)
+{
+ if (this->certreq_data.ptr != NULL)
+ {
+ chunk_free(&(this->certreq_data));
+ }
+ 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;
+}
+
+/**
+ * Implementation of certreq_payload_t.get_data.
+ */
+static chunk_t get_data (private_certreq_payload_t *this)
+{
+ return (this->certreq_data);
+}
+
+/**
+ * Implementation of certreq_payload_t.get_data_clone.
+ */
+static chunk_t get_data_clone (private_certreq_payload_t *this)
+{
+ chunk_t cloned_data;
+ if (this->certreq_data.ptr == NULL)
+ {
+ return (this->certreq_data);
+ }
+ cloned_data.ptr = clalloc(this->certreq_data.ptr,this->certreq_data.len);
+ cloned_data.len = this->certreq_data.len;
+ return cloned_data;
+}
+
+/**
+ * Implementation of payload_t.destroy and certreq_payload_t.destroy.
+ */
+static void destroy(private_certreq_payload_t *this)
+{
+ if (this->certreq_data.ptr != NULL)
+ {
+ chunk_free(&(this->certreq_data));
+ }
+
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+certreq_payload_t *certreq_payload_create()
+{
+ private_certreq_payload_t *this = malloc_thing(private_certreq_payload_t);
+
+ /* interface functions */
+ this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
+ this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
+ this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
+ this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
+ this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
+ this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_payload_type;
+ this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
+
+ /* public functions */
+ this->public.destroy = (void (*) (certreq_payload_t *)) destroy;
+ this->public.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;
+
+ /* private variables */
+ this->critical = FALSE;
+ this->next_payload = NO_PAYLOAD;
+ this->payload_length =CERTREQ_PAYLOAD_HEADER_LENGTH;
+ this->certreq_data = CHUNK_INITIALIZER;
+
+ return (&(this->public));
+}
diff --git a/programs/charon/charon/encoding/payloads/certreq_payload.h b/programs/charon/charon/encoding/payloads/certreq_payload.h
new file mode 100644
index 000000000..3e88e7ffe
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/certreq_payload.h
@@ -0,0 +1,125 @@
+/**
+ * @file certreq_payload.h
+ *
+ * @brief Interface of certreq_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef CERTREQ_PAYLOAD_H_
+#define CERTREQ_PAYLOAD_H_
+
+#include <types.h>
+#include <encoding/payloads/payload.h>
+#include <encoding/payloads/cert_payload.h>
+
+/**
+ * Length of a CERTREQ payload without the CERTREQ data in bytes.
+ *
+ * @ingroup payloads
+ */
+#define CERTREQ_PAYLOAD_HEADER_LENGTH 5
+
+
+typedef struct certreq_payload_t certreq_payload_t;
+
+/**
+ * @brief 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 {
+ /**
+ * The payload_t interface.
+ */
+ 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.
+ *
+ * @param this calling certreq_payload_t object
+ * @param data CERTREQ data as chunk_t
+ */
+ void (*set_data) (certreq_payload_t *this, chunk_t data);
+
+ /**
+ * @brief Get the CERTREQ data.
+ *
+ * Returned data are a copy of the internal one.
+ *
+ * @param this calling certreq_payload_t object
+ * @return CERTREQ data as chunk_t
+ */
+ chunk_t (*get_data_clone) (certreq_payload_t *this);
+
+ /**
+ * @brief Get the CERTREQ data.
+ *
+ * Returned data are NOT copied.
+ *
+ * @param this calling certreq_payload_t object
+ * @return CERTREQ data as chunk_t
+ */
+ chunk_t (*get_data) (certreq_payload_t *this);
+
+ /**
+ * @brief Destroys an certreq_payload_t object.
+ *
+ * @param this certreq_payload_t object to destroy
+ */
+ void (*destroy) (certreq_payload_t *this);
+};
+
+/**
+ * @brief Creates an empty certreq_payload_t object.
+ *
+ * @return certreq_payload_t object
+ *
+ * @ingroup payloads
+ */
+certreq_payload_t *certreq_payload_create();
+
+
+#endif /* CERTREQ_PAYLOAD_H_ */
diff --git a/programs/charon/charon/encoding/payloads/configuration_attribute.c b/programs/charon/charon/encoding/payloads/configuration_attribute.c
new file mode 100644
index 000000000..489d7f372
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/configuration_attribute.c
@@ -0,0 +1,282 @@
+/**
+ * @file configuration_attribute.c
+ *
+ * @brief Implementation of configuration_attribute_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stddef.h>
+
+#include "configuration_attribute.h"
+
+#include <encoding/payloads/encodings.h>
+#include <types.h>
+
+
+typedef struct private_configuration_attribute_t private_configuration_attribute_t;
+
+/**
+ * Private data of an configuration_attribute_t object.
+ *
+ */
+struct private_configuration_attribute_t {
+ /**
+ * Public configuration_attribute_t interface.
+ */
+ configuration_attribute_t public;
+
+ /**
+ * Type of the attribute.
+ */
+ u_int16_t attribute_type;
+
+ /**
+ * Length of the attribute.
+ */
+ u_int16_t attribute_length;
+
+
+ /**
+ * Attribute value as chunk.
+ */
+ chunk_t attribute_value;
+};
+
+/**
+ * String mappings for configuration_attribute_type_t.
+ */
+mapping_t configuration_attribute_type_m[] = {
+ {INTERNAL_IP4_ADDRESS, "INTERNAL_IP4_ADDRESS"},
+ {INTERNAL_IP4_NETMASK, "INTERNAL_IP4_NETMASK"},
+ {INTERNAL_IP4_DNS, "INTERNAL_IP4_DNS"},
+ {INTERNAL_IP4_NBNS, "INTERNAL_IP4_NBNS"},
+ {INTERNAL_ADDRESS_EXPIRY, "INTERNAL_ADDRESS_EXPIRY"},
+ {INTERNAL_IP4_DHCP, "INTERNAL_IP4_DHCP"},
+ {APPLICATION_VERSION, "APPLICATION_VERSION"},
+ {INTERNAL_IP6_ADDRESS, "INTERNAL_IP6_ADDRESS"},
+ {INTERNAL_IP6_DNS, "INTERNAL_IP6_DNS"},
+ {INTERNAL_IP6_NBNS, "INTERNAL_IP6_NBNS"},
+ {INTERNAL_IP6_DHCP, "INTERNAL_IP6_DHCP"},
+ {INTERNAL_IP4_SUBNET, "INTERNAL_IP4_SUBNET"},
+ {SUPPORTED_ATTRIBUTES, "SUPPORTED_ATTRIBUTES"},
+ {INTERNAL_IP6_SUBNET, "INTERNAL_IP6_SUBNET"},
+ {MAPPING_END, NULL}
+};
+
+
+/**
+ * Encoding rules to parse or generate a configuration attribute.
+ *
+ * The defined offsets are the positions in a object of type
+ * private_configuration_attribute_t.
+ *
+ */
+encoding_rule_t configuration_attribute_encodings[] = {
+
+ { RESERVED_BIT, 0 },
+ /* type of the attribute as 15 bit unsigned integer */
+ { ATTRIBUTE_TYPE, offsetof(private_configuration_attribute_t, attribute_type) },
+ /* Length of attribute value */
+ { CONFIGURATION_ATTRIBUTE_LENGTH, offsetof(private_configuration_attribute_t, attribute_length)},
+ /* Value of attribute if attribute format flag is zero */
+ { CONFIGURATION_ATTRIBUTE_VALUE, offsetof(private_configuration_attribute_t, attribute_value)}
+};
+
+/*
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ !R| Attribute Type ! Length |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ ~ Value ~
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+/**
+ * Implementation of payload_t.verify.
+ */
+static status_t verify(private_configuration_attribute_t *this)
+{
+ switch (this->attribute_type)
+ {
+ case INTERNAL_IP4_ADDRESS:
+ case INTERNAL_IP4_NETMASK:
+ case INTERNAL_IP4_DNS:
+ case INTERNAL_IP4_NBNS:
+ case INTERNAL_ADDRESS_EXPIRY:
+ case INTERNAL_IP4_DHCP:
+ case APPLICATION_VERSION:
+ case INTERNAL_IP6_ADDRESS:
+ case INTERNAL_IP6_DNS:
+ case INTERNAL_IP6_NBNS:
+ case INTERNAL_IP6_DHCP:
+ case INTERNAL_IP4_SUBNET:
+ case SUPPORTED_ATTRIBUTES:
+ case INTERNAL_IP6_SUBNET:
+ {
+ /* Attribute types are not checked in here */
+ break;
+ }
+ default:
+ return FAILED;
+ }
+
+ if (this->attribute_length != this->attribute_value.len)
+ {
+ return FAILED;
+ }
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of payload_t.get_encoding_rules.
+ */
+static void get_encoding_rules(private_configuration_attribute_t *this, encoding_rule_t **rules, size_t *rule_count)
+{
+ *rules = configuration_attribute_encodings;
+ *rule_count = sizeof(configuration_attribute_encodings) / sizeof(encoding_rule_t);
+}
+
+/**
+ * Implementation of payload_t.get_type.
+ */
+static payload_type_t get_type(private_configuration_attribute_t *this)
+{
+ return CONFIGURATION_ATTRIBUTE;
+}
+
+/**
+ * Implementation of payload_t.get_next_type.
+ */
+static payload_type_t get_next_type(private_configuration_attribute_t *this)
+{
+ return (NO_PAYLOAD);
+}
+
+/**
+ * Implementation of payload_t.set_next_type.
+ */
+static void set_next_type(private_configuration_attribute_t *this,payload_type_t type)
+{
+}
+
+/**
+ * Implementation of configuration_attribute_t.get_length.
+ */
+static size_t get_length(private_configuration_attribute_t *this)
+{
+ return (this->attribute_value.len + CONFIGURATION_ATTRIBUTE_HEADER_LENGTH);
+}
+
+/**
+ * Implementation of configuration_attribute_t.set_value.
+ */
+static void set_value(private_configuration_attribute_t *this, chunk_t value)
+{
+ if (this->attribute_value.ptr != NULL)
+ {
+ /* free existing value */
+ chunk_free(&(this->attribute_value));
+ }
+
+ this->attribute_value.ptr = clalloc(value.ptr,value.len);
+ this->attribute_value.len = value.len;
+
+ this->attribute_length = this->attribute_value.len;
+}
+
+/**
+ * Implementation of configuration_attribute_t.get_value.
+ */
+static chunk_t get_value (private_configuration_attribute_t *this)
+{
+ return this->attribute_value;
+}
+
+
+/**
+ * Implementation of configuration_attribute_t.set_attribute_type.
+ */
+static void set_attribute_type (private_configuration_attribute_t *this, u_int16_t type)
+{
+ this->attribute_type = type & 0x7FFF;
+}
+
+/**
+ * Implementation of configuration_attribute_t.get_attribute_type.
+ */
+static u_int16_t get_attribute_type (private_configuration_attribute_t *this)
+{
+ return this->attribute_type;
+}
+
+/**
+ * Implementation of configuration_attribute_t.get_attribute_length.
+ */
+static u_int16_t get_attribute_length (private_configuration_attribute_t *this)
+{
+ return this->attribute_length;
+}
+
+
+/**
+ * Implementation of configuration_attribute_t.destroy and payload_t.destroy.
+ */
+static void destroy(private_configuration_attribute_t *this)
+{
+ if (this->attribute_value.ptr != NULL)
+ {
+ free(this->attribute_value.ptr);
+ }
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+configuration_attribute_t *configuration_attribute_create()
+{
+ private_configuration_attribute_t *this = malloc_thing(private_configuration_attribute_t);
+
+ /* payload interface */
+ this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
+ this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
+ this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
+ this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
+ this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
+ this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_type;
+ this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
+
+ /* public functions */
+ this->public.set_value = (void (*) (configuration_attribute_t *,chunk_t)) set_value;
+ this->public.get_value = (chunk_t (*) (configuration_attribute_t *)) get_value;
+ this->public.set_attribute_type = (void (*) (configuration_attribute_t *,u_int16_t type)) set_attribute_type;
+ this->public.get_attribute_type = (u_int16_t (*) (configuration_attribute_t *)) get_attribute_type;
+ this->public.get_attribute_length = (u_int16_t (*) (configuration_attribute_t *)) get_attribute_length;
+ this->public.destroy = (void (*) (configuration_attribute_t *)) destroy;
+
+ /* set default values of the fields */
+ this->attribute_type = 0;
+ this->attribute_value = CHUNK_INITIALIZER;
+ this->attribute_length = 0;
+
+ return (&(this->public));
+}
diff --git a/programs/charon/charon/encoding/payloads/configuration_attribute.h b/programs/charon/charon/encoding/payloads/configuration_attribute.h
new file mode 100644
index 000000000..5b6b4f473
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/configuration_attribute.h
@@ -0,0 +1,149 @@
+/**
+ * @file configuration_attribute.h
+ *
+ * @brief Interface of configuration_attribute_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef CONFIGURATION_ATTRIBUTE_H_
+#define CONFIGURATION_ATTRIBUTE_H_
+
+#include <types.h>
+#include <encoding/payloads/payload.h>
+
+
+
+/**
+ * Configuration attribute header length in bytes.
+ *
+ * @ingroup payloads
+ */
+#define CONFIGURATION_ATTRIBUTE_HEADER_LENGTH 4
+
+
+typedef enum configuration_attribute_type_t configuration_attribute_type_t;
+
+/**
+ * Type of the attribute, as in IKEv2 RFC 3.15.1.
+ *
+ * @ingroup payloads
+ */
+enum configuration_attribute_type_t {
+ INTERNAL_IP4_ADDRESS = 1,
+ INTERNAL_IP4_NETMASK = 2,
+ INTERNAL_IP4_DNS = 3,
+ INTERNAL_IP4_NBNS = 4,
+ INTERNAL_ADDRESS_EXPIRY = 5,
+ INTERNAL_IP4_DHCP = 6,
+ APPLICATION_VERSION = 7,
+ INTERNAL_IP6_ADDRESS = 8,
+ INTERNAL_IP6_DNS = 10,
+ INTERNAL_IP6_NBNS = 11,
+ INTERNAL_IP6_DHCP = 12,
+ INTERNAL_IP4_SUBNET = 13,
+ SUPPORTED_ATTRIBUTES = 14,
+ INTERNAL_IP6_SUBNET = 15
+};
+
+/**
+ * String mappings for configuration_attribute_type_t.
+ *
+ * @ingroup payloads
+ */
+extern mapping_t configuration_attribute_type_m[];
+
+typedef struct configuration_attribute_t configuration_attribute_t;
+
+/**
+ * @brief 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 {
+ /**
+ * The payload_t interface.
+ */
+ payload_t payload_interface;
+
+ /**
+ * @brief 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.
+ *
+ * @warning 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.
+ *
+ * @param this calling configuration_attribute_t object
+ * @param type type to set (most significant bit is set to zero)
+ */
+ void (*set_attribute_type) (configuration_attribute_t *this, u_int16_t type);
+
+ /**
+ * @brief get the type of the attribute.
+ *
+ * @param this calling configuration_attribute_t object
+ * @return type of the value
+ */
+ u_int16_t (*get_attribute_type) (configuration_attribute_t *this);
+
+ /**
+ * @brief get the length of an attribute.
+ *
+ * @param this calling configuration_attribute_t object
+ * @return type of the value
+ */
+ u_int16_t (*get_attribute_length) (configuration_attribute_t *this);
+
+ /**
+ * @brief Destroys an configuration_attribute_t object.
+ *
+ * @param this configuration_attribute_t object to destroy
+ */
+ void (*destroy) (configuration_attribute_t *this);
+};
+
+/**
+ * @brief Creates an empty configuration_attribute_t object.
+ *
+ * @return created configuration_attribute_t object
+ *
+ * @ingroup payloads
+ */
+configuration_attribute_t *configuration_attribute_create();
+
+#endif /* CONFIGURATION_ATTRIBUTE_H_*/
diff --git a/programs/charon/charon/encoding/payloads/cp_payload.c b/programs/charon/charon/encoding/payloads/cp_payload.c
new file mode 100644
index 000000000..583488382
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/cp_payload.c
@@ -0,0 +1,305 @@
+/**
+ * @file cp_payload.c
+ *
+ * @brief Implementation of cp_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stddef.h>
+
+#include "cp_payload.h"
+
+#include <encoding/payloads/encodings.h>
+#include <utils/linked_list.h>
+
+
+/**
+ * String mappings for config_type_t.
+ */
+mapping_t config_type_m[] = {
+ {CFG_REQUEST, "CFG_REQUEST"},
+ {CFG_REPLY, "CFG_REPLY"},
+ {CFG_SET, "CFG_SET"},
+ {CFG_ACK, "CFG_ACK"},
+ {MAPPING_END, NULL}
+};
+
+
+typedef struct private_cp_payload_t private_cp_payload_t;
+
+/**
+ * Private data of an cp_payload_t object.
+ *
+ */
+struct private_cp_payload_t {
+ /**
+ * Public cp_payload_t interface.
+ */
+ cp_payload_t public;
+
+ /**
+ * Next payload type.
+ */
+ u_int8_t next_payload;
+
+ /**
+ * Critical flag.
+ */
+ bool critical;
+
+ /**
+ * Length of this payload.
+ */
+ u_int16_t payload_length;
+
+ /**
+ * Configuration Attributes in this payload are stored in a linked_list_t.
+ */
+ linked_list_t * attributes;
+
+ /**
+ * Config Type.
+ */
+ u_int8_t config_type;
+
+ /**
+ * @brief Computes the length of this payload.
+ *
+ * @param this calling private_cp_payload_t object
+ */
+ void (*compute_length) (private_cp_payload_t *this);
+};
+
+/**
+ * Encoding rules to parse or generate a IKEv2-CP Payload
+ *
+ * The defined offsets are the positions in a object of type
+ * private_cp_payload_t.
+ *
+ */
+encoding_rule_t cp_payload_encodings[] = {
+ /* 1 Byte next payload type, stored in the field next_payload */
+ { U_INT_8, offsetof(private_cp_payload_t, next_payload) },
+ /* the critical bit */
+ { FLAG, offsetof(private_cp_payload_t, critical) },
+ /* 7 Bit reserved bits, nowhere stored */
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ /* Length of the whole CP payload*/
+ { PAYLOAD_LENGTH, offsetof(private_cp_payload_t, payload_length) },
+ /* Proposals are stored in a proposal substructure,
+ offset points to a linked_list_t pointer */
+ { U_INT_8, offsetof(private_cp_payload_t, config_type) },
+ { RESERVED_BYTE,0 },
+ { RESERVED_BYTE,0 },
+ { RESERVED_BYTE,0 },
+ { CONFIGURATION_ATTRIBUTES, offsetof(private_cp_payload_t, attributes) }
+};
+
+/*
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Next Payload !C! RESERVED ! Payload Length !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! CFG Type ! RESERVED !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! !
+ ~ Configuration Attributes ~
+ ! !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+/**
+ * Implementation of payload_t.verify.
+ */
+static status_t verify(private_cp_payload_t *this)
+{
+ status_t status = SUCCESS;
+ iterator_t *iterator;
+
+ iterator = this->attributes->create_iterator(this->attributes,TRUE);
+
+ while(iterator->has_next(iterator))
+ {
+ configuration_attribute_t *attribute;
+ iterator->current(iterator,(void **)&attribute);
+ status = attribute->payload_interface.verify(&(attribute->payload_interface));
+ if (status != SUCCESS)
+ {
+ break;
+ }
+ }
+
+ iterator->destroy(iterator);
+ return status;
+}
+
+/**
+ * Implementation of payload_t.get_encoding_rules.
+ */
+static void get_encoding_rules(private_cp_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
+{
+ *rules = cp_payload_encodings;
+ *rule_count = sizeof(cp_payload_encodings) / sizeof(encoding_rule_t);
+}
+
+/**
+ * Implementation of payload_t.get_type.
+ */
+static payload_type_t get_type(private_cp_payload_t *this)
+{
+ return CONFIGURATION;
+}
+
+/**
+ * Implementation of payload_t.get_next_type.
+ */
+static payload_type_t get_next_type(private_cp_payload_t *this)
+{
+ return (this->next_payload);
+}
+
+/**
+ * Implementation of payload_t.set_next_type.
+ */
+static void set_next_type(private_cp_payload_t *this,payload_type_t type)
+{
+ this->next_payload = type;
+}
+
+/**
+ * Implementation of payload_t.get_length.
+ */
+static size_t get_length(private_cp_payload_t *this)
+{
+ this->compute_length(this);
+ return this->payload_length;
+}
+
+/**
+ * Implementation of cp_payload_t.create_configuration_attribute_iterator.
+ */
+static iterator_t *create_configuration_attribute_iterator (private_cp_payload_t *this,bool forward)
+{
+ return this->attributes->create_iterator(this->attributes,forward);
+}
+
+/**
+ * Implementation of cp_payload_t.add_proposal_substructure.
+ */
+static void add_configuration_attribute (private_cp_payload_t *this,configuration_attribute_t *attribute)
+{
+ this->attributes->insert_last(this->attributes,(void *) attribute);
+ this->compute_length(this);
+}
+
+/**
+ * Implementation of cp_payload_t.set_config_type.
+ */
+static void set_config_type (private_cp_payload_t *this,config_type_t config_type)
+{
+ this->config_type = config_type;
+}
+
+/**
+ * Implementation of cp_payload_t.get_config_type.
+ */
+static config_type_t get_config_type (private_cp_payload_t *this)
+{
+ return this->config_type;
+}
+
+/**
+ * Implementation of private_cp_payload_t.compute_length.
+ */
+static void compute_length (private_cp_payload_t *this)
+{
+ iterator_t *iterator;
+ size_t length = CP_PAYLOAD_HEADER_LENGTH;
+ iterator = this->attributes->create_iterator(this->attributes,TRUE);
+ while (iterator->has_next(iterator))
+ {
+ payload_t *current_attribute;
+ iterator->current(iterator,(void **) &current_attribute);
+ length += current_attribute->get_length(current_attribute);
+ }
+ iterator->destroy(iterator);
+
+ this->payload_length = length;
+}
+
+/**
+ * Implementation of payload_t.destroy and cp_payload_t.destroy.
+ */
+static status_t destroy(private_cp_payload_t *this)
+{
+ /* all attributes are getting destroyed */
+ while (this->attributes->get_count(this->attributes) > 0)
+ {
+ configuration_attribute_t *current_attribute;
+ this->attributes->remove_last(this->attributes,(void **)&current_attribute);
+ current_attribute->destroy(current_attribute);
+ }
+ this->attributes->destroy(this->attributes);
+
+ free(this);
+
+ return SUCCESS;
+}
+
+/*
+ * Described in header.
+ */
+cp_payload_t *cp_payload_create()
+{
+ private_cp_payload_t *this = malloc_thing(private_cp_payload_t);
+
+ /* public interface */
+ this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
+ this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
+ this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
+ this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
+ this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
+ this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_type;
+ this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
+
+ /* public functions */
+ this->public.create_configuration_attribute_iterator = (iterator_t* (*) (cp_payload_t *,bool)) create_configuration_attribute_iterator;
+ this->public.add_configuration_attribute = (void (*) (cp_payload_t *,configuration_attribute_t *)) add_configuration_attribute;
+ this->public.set_config_type = (void (*) (cp_payload_t *, config_type_t)) set_config_type;
+ this->public.get_config_type = (config_type_t (*) (cp_payload_t *)) get_config_type;
+ this->public.destroy = (void (*) (cp_payload_t *)) destroy;
+
+
+ /* private functions */
+ this->compute_length = compute_length;
+
+ /* set default values of the fields */
+ this->critical = FALSE;
+ this->next_payload = NO_PAYLOAD;
+ this->payload_length = CP_PAYLOAD_HEADER_LENGTH;
+
+ this->attributes = linked_list_create();
+ return (&(this->public));
+}
diff --git a/programs/charon/charon/encoding/payloads/cp_payload.h b/programs/charon/charon/encoding/payloads/cp_payload.h
new file mode 100644
index 000000000..eb8076446
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/cp_payload.h
@@ -0,0 +1,138 @@
+/**
+ * @file cp_payload.h
+ *
+ * @brief Interface of cp_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef CP_PAYLOAD_H_
+#define CP_PAYLOAD_H_
+
+#include <types.h>
+#include <encoding/payloads/payload.h>
+#include <encoding/payloads/configuration_attribute.h>
+#include <utils/linked_list.h>
+
+/**
+ * CP_PAYLOAD length in bytes without any proposal substructure.
+ *
+ * @ingroup payloads
+ */
+#define CP_PAYLOAD_HEADER_LENGTH 8
+
+
+typedef enum config_type_t config_type_t;
+
+/**
+ * Config Type of an Configuration Payload.
+ *
+ * @ingroup payloads
+ */
+enum config_type_t {
+ CFG_REQUEST = 1,
+ CFG_REPLY = 2,
+ CFG_SET = 3,
+ CFG_ACK = 4,
+};
+
+/**
+ * string mappings for config_type_t.
+ *
+ * @ingroup payloads
+ */
+extern mapping_t config_type_m[];
+
+
+typedef struct cp_payload_t cp_payload_t;
+
+/**
+ * @brief 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 {
+ /**
+ * The payload_t interface.
+ */
+ payload_t payload_interface;
+
+ /**
+ * @brief Creates an iterator of stored configuration_attribute_t objects.
+ *
+ * @warning The created iterator has to get destroyed by the caller!
+ *
+ * @warning 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
+ * @param[in] forward iterator direction (TRUE: front to end)
+ * @return created iterator_t object
+ */
+ iterator_t *(*create_configuration_attribute_iterator) (cp_payload_t *this, bool forward);
+
+ /**
+ * @brief Adds a configuration_attribute_t object to this object.
+ *
+ * @warning 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.
+ *
+ * @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.
+ *
+ * @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
+ */
+ void (*destroy) (cp_payload_t *this);
+};
+
+/**
+ * @brief Creates an empty cp_payload_t object
+ *
+ * @return cp_payload_t object
+ *
+ * @ingroup payloads
+ */
+cp_payload_t *cp_payload_create();
+
+#endif /*CP_PAYLOAD_H_*/
diff --git a/programs/charon/charon/encoding/payloads/delete_payload.c b/programs/charon/charon/encoding/payloads/delete_payload.c
new file mode 100644
index 000000000..28e78800f
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/delete_payload.c
@@ -0,0 +1,322 @@
+/**
+ * @file delete_payload.c
+ *
+ * @brief Implementation of delete_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stddef.h>
+
+#include "delete_payload.h"
+
+
+typedef struct private_delete_payload_t private_delete_payload_t;
+
+/**
+ * Private data of an delete_payload_t object.
+ *
+ */
+struct private_delete_payload_t {
+ /**
+ * Public delete_payload_t interface.
+ */
+ delete_payload_t public;
+
+ /**
+ * Next payload type.
+ */
+ u_int8_t next_payload;
+
+ /**
+ * Critical flag.
+ */
+ bool critical;
+
+ /**
+ * Length of this payload.
+ */
+ u_int16_t payload_length;
+
+ /**
+ * Protocol ID.
+ */
+ u_int8_t protocol_id;
+
+ /**
+ * SPI Size.
+ */
+ u_int8_t spi_size;
+
+ /**
+ * Number of SPI's.
+ */
+ u_int16_t spi_count;
+
+ /**
+ * The contained SPI's.
+ */
+ chunk_t spis;
+};
+
+/**
+ * Encoding rules to parse or generate a DELETE payload
+ *
+ * The defined offsets are the positions in a object of type
+ * private_delete_payload_t.
+ *
+ */
+encoding_rule_t delete_payload_encodings[] = {
+ /* 1 Byte next payload type, stored in the field next_payload */
+ { U_INT_8, offsetof(private_delete_payload_t, next_payload) },
+ /* the critical bit */
+ { FLAG, offsetof(private_delete_payload_t, critical) },
+ /* 7 Bit reserved bits, nowhere stored */
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ /* Length of the whole payload*/
+ { PAYLOAD_LENGTH, offsetof(private_delete_payload_t, payload_length)},
+ { U_INT_8, offsetof(private_delete_payload_t, protocol_id) },
+ { U_INT_8, offsetof(private_delete_payload_t, spi_size) },
+ { U_INT_16, offsetof(private_delete_payload_t, spi_count) },
+ /* some delete data bytes, length is defined in PAYLOAD_LENGTH */
+ { SPIS, offsetof(private_delete_payload_t, spis) }
+};
+
+/*
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Next Payload !C! RESERVED ! Payload Length !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Protocol ID ! SPI Size ! # of SPIs !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! !
+ ~ Security Parameter Index(es) (SPI) ~
+ ! !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+/**
+ * Implementation of payload_t.verify.
+ */
+static status_t verify(private_delete_payload_t *this)
+{
+ if ((this->protocol_id == 0) ||
+ (this->protocol_id > 3))
+ {
+ /* reserved IDs */
+ return FAILED;
+ }
+ if (this->spis.len != (this->spi_count * this->spi_size))
+ {
+ return FAILED;
+ }
+ if ((this->protocol_id == PROTO_IKE) && (this->spis.len != 0))
+ {
+ /* IKE deletion has no spi assigned! */
+ return FAILED;
+ }
+
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of delete_payload_t.get_encoding_rules.
+ */
+static void get_encoding_rules(private_delete_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
+{
+ *rules = delete_payload_encodings;
+ *rule_count = sizeof(delete_payload_encodings) / sizeof(encoding_rule_t);
+}
+
+/**
+ * Implementation of payload_t.get_type.
+ */
+static payload_type_t get_payload_type(private_delete_payload_t *this)
+{
+ return DELETE;
+}
+
+/**
+ * Implementation of payload_t.get_next_type.
+ */
+static payload_type_t get_next_type(private_delete_payload_t *this)
+{
+ return (this->next_payload);
+}
+
+/**
+ * Implementation of payload_t.set_next_type.
+ */
+static void set_next_type(private_delete_payload_t *this,payload_type_t type)
+{
+ this->next_payload = type;
+}
+
+/**
+ * Implementation of payload_t.get_length.
+ */
+static size_t get_length(private_delete_payload_t *this)
+{
+ return this->payload_length;
+}
+
+/**
+ * Implementation of delete_payload_t.set_protocol_id.
+ */
+static void set_protocol_id (private_delete_payload_t *this, protocol_id_t protocol_id)
+{
+ this->protocol_id = protocol_id;
+}
+
+/**
+ * Implementation of delete_payload_t.get_protocol_id.
+ */
+static protocol_id_t get_protocol_id (private_delete_payload_t *this)
+{
+ return (this->protocol_id);
+}
+
+/**
+ * Implementation of delete_payload_t.set_spi_size.
+ */
+static void set_spi_size (private_delete_payload_t *this, u_int8_t spi_size)
+{
+ this->spi_size = spi_size;
+}
+
+/**
+ * Implementation of delete_payload_t.get_spi_size.
+ */
+static u_int8_t get_spi_size (private_delete_payload_t *this)
+{
+ return (this->spi_size);
+}
+
+/**
+ * Implementation of delete_payload_t.set_spi_count.
+ */
+static void set_spi_count (private_delete_payload_t *this, u_int16_t spi_count)
+{
+ this->spi_count = spi_count;
+}
+
+/**
+ * Implementation of delete_payload_t.get_spi_count.
+ */
+static u_int16_t get_spi_count (private_delete_payload_t *this)
+{
+ return (this->spi_count);
+}
+
+
+/**
+ * Implementation of delete_payload_t.set_spis.
+ */
+static void set_spis (private_delete_payload_t *this, chunk_t spis)
+{
+ if (this->spis.ptr != NULL)
+ {
+ chunk_free(&(this->spis));
+ }
+ this->spis.ptr = clalloc(spis.ptr,spis.len);
+ this->spis.len = spis.len;
+ this->payload_length = DELETE_PAYLOAD_HEADER_LENGTH + this->spis.len;
+}
+
+/**
+ * Implementation of delete_payload_t.get_spis.
+ */
+static chunk_t get_spis (private_delete_payload_t *this)
+{
+ return (this->spis);
+}
+
+/**
+ * Implementation of delete_payload_t.get_spis_clone.
+ */
+static chunk_t get_spis_clone (private_delete_payload_t *this)
+{
+ chunk_t cloned_spis;
+ if (this->spis.ptr == NULL)
+ {
+ return (this->spis);
+ }
+ cloned_spis.ptr = clalloc(this->spis.ptr,this->spis.len);
+ cloned_spis.len = this->spis.len;
+ return cloned_spis;
+}
+
+/**
+ * Implementation of payload_t.destroy and delete_payload_t.destroy.
+ */
+static void destroy(private_delete_payload_t *this)
+{
+ if (this->spis.ptr != NULL)
+ {
+ chunk_free(&(this->spis));
+ }
+
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+delete_payload_t *delete_payload_create()
+{
+ private_delete_payload_t *this = malloc_thing(private_delete_payload_t);
+
+ /* interface functions */
+ this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
+ this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
+ this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
+ this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
+ this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
+ this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_payload_type;
+ this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
+
+ /* public functions */
+ this->public.destroy = (void (*) (delete_payload_t *)) destroy;
+ this->public.set_protocol_id = (void (*) (delete_payload_t *,protocol_id_t)) set_protocol_id;
+ this->public.get_protocol_id = (protocol_id_t (*) (delete_payload_t *)) get_protocol_id;
+ this->public.set_spi_size = (void (*) (delete_payload_t *,u_int8_t)) set_spi_size;
+ this->public.get_spi_size = (u_int8_t (*) (delete_payload_t *)) get_spi_size;
+ this->public.set_spi_count = (void (*) (delete_payload_t *,u_int16_t)) set_spi_count;
+ this->public.get_spi_count = (u_int16_t (*) (delete_payload_t *)) get_spi_count;
+ this->public.set_spis = (void (*) (delete_payload_t *,chunk_t)) set_spis;
+ this->public.get_spis_clone = (chunk_t (*) (delete_payload_t *)) get_spis_clone;
+ this->public.get_spis = (chunk_t (*) (delete_payload_t *)) get_spis;
+
+ /* private variables */
+ this->critical = FALSE;
+ this->next_payload = NO_PAYLOAD;
+ this->payload_length =DELETE_PAYLOAD_HEADER_LENGTH;
+ this->protocol_id = PROTO_NONE;
+ this->spi_size = 0;
+ this->spi_count = 0;
+ this->spis = CHUNK_INITIALIZER;
+
+ return (&(this->public));
+}
diff --git a/programs/charon/charon/encoding/payloads/delete_payload.h b/programs/charon/charon/encoding/payloads/delete_payload.h
new file mode 100644
index 000000000..71a6317d4
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/delete_payload.h
@@ -0,0 +1,156 @@
+/**
+ * @file delete_payload.h
+ *
+ * @brief Interface of delete_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef DELETE_PAYLOAD_H_
+#define DELETE_PAYLOAD_H_
+
+#include <types.h>
+#include <encoding/payloads/payload.h>
+#include <encoding/payloads/proposal_substructure.h>
+
+/**
+ * Length of a delete payload without the SPI in bytes.
+ *
+ * @ingroup payloads
+ */
+#define DELETE_PAYLOAD_HEADER_LENGTH 8
+
+
+
+typedef struct delete_payload_t delete_payload_t;
+
+/**
+ * @brief 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 {
+ /**
+ * The payload_t interface.
+ */
+ payload_t payload_interface;
+
+ /**
+ * @brief Set the protocol ID.
+ *
+ * @param this calling delete_payload_t object
+ * @param protocol_id protocol ID
+ */
+ void (*set_protocol_id) (delete_payload_t *this, protocol_id_t protocol_id);
+
+ /**
+ * @brief 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 Set the SPI size.
+ *
+ *
+ * @param this calling delete_payload_t object
+ * @param spi_size SPI size
+ */
+ void (*set_spi_size) (delete_payload_t *this, u_int8_t spi_size);
+
+ /**
+ * @brief Get the SPI size.
+ *
+ * @param this calling delete_payload_t object
+ * @return SPI size
+ */
+ u_int8_t (*get_spi_size) (delete_payload_t *this);
+
+ /**
+ * @brief Set the SPI count.
+ *
+ * @param this calling delete_payload_t object
+ * @param spi_count SPI count
+ */
+ void (*set_spi_count) (delete_payload_t *this, u_int16_t spi_count);
+
+ /**
+ * @brief Get the SPI count.
+ *
+ * @param this calling delete_payload_t object
+ * @return Number of SPI's
+ */
+ u_int16_t (*get_spi_count) (delete_payload_t *this);
+
+ /**
+ * @brief Set the SPI's.
+ *
+ * Data are getting cloned.
+ *
+ * @param this calling delete_payload_t object
+ * @param data SPI's as chunk_t
+ */
+ void (*set_spis) (delete_payload_t *this, chunk_t spis);
+
+ /**
+ * @brief Get the SPI's.
+ *
+ * Returned data are a copy of the internal one.
+ *
+ * @param this calling delete_payload_t object
+ * @return SPI's chunk_t
+ */
+ chunk_t (*get_spis_clone) (delete_payload_t *this);
+
+ /**
+ * @brief Get the SPI's.
+ *
+ * Returned data are NOT copied.
+ *
+ * @param this calling delete_payload_t object
+ * @return SPI's as chunk_t
+ */
+ chunk_t (*get_spis) (delete_payload_t *this);
+
+ /**
+ * @brief Destroys an delete_payload_t object.
+ *
+ * @param this delete_payload_t object to destroy
+ */
+ void (*destroy) (delete_payload_t *this);
+};
+
+/**
+ * @brief Creates an empty delete_payload_t object.
+ *
+ * @return delete_payload_t object
+ *
+ * @ingroup payloads
+ */
+delete_payload_t *delete_payload_create();
+
+
+#endif /* DELETE_PAYLOAD_H_ */
diff --git a/programs/charon/charon/encoding/payloads/eap_payload.c b/programs/charon/charon/encoding/payloads/eap_payload.c
new file mode 100644
index 000000000..2a0e17679
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/eap_payload.c
@@ -0,0 +1,227 @@
+/**
+ * @file eap_payload.c
+ *
+ * @brief Implementation of eap_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stddef.h>
+
+#include "eap_payload.h"
+
+
+typedef struct private_eap_payload_t private_eap_payload_t;
+
+/**
+ * Private data of an eap_payload_t object.
+ *
+ */
+struct private_eap_payload_t {
+ /**
+ * Public eap_payload_t interface.
+ */
+ eap_payload_t public;
+
+ /**
+ * Next payload type.
+ */
+ u_int8_t next_payload;
+
+ /**
+ * Critical flag.
+ */
+ bool critical;
+
+ /**
+ * Length of this payload.
+ */
+ u_int16_t payload_length;
+
+ /**
+ * The contained message.
+ */
+ chunk_t message;
+};
+
+/**
+ * Encoding rules to parse or generate a EAP payload.
+ *
+ * The defined offsets are the positions in a object of type
+ * private_eap_payload_t.
+ *
+ */
+encoding_rule_t eap_payload_encodings[] = {
+ /* 1 Byte next payload type, stored in the field next_payload */
+ { U_INT_8, offsetof(private_eap_payload_t, next_payload) },
+ /* the critical bit */
+ { FLAG, offsetof(private_eap_payload_t, critical) },
+ /* 7 Bit reserved bits, nowhere stored */
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ /* Length of the whole payload*/
+ { PAYLOAD_LENGTH, offsetof(private_eap_payload_t, payload_length)},
+ /* some eap data bytes, length is defined in PAYLOAD_LENGTH */
+ { EAP_MESSAGE, offsetof(private_eap_payload_t, message) }
+};
+
+/*
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Next Payload !C! RESERVED ! Payload Length !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! !
+ ~ EAP Message ~
+ ! !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+/**
+ * Implementation of payload_t.verify.
+ */
+static status_t verify(private_eap_payload_t *this)
+{
+ return SUCCESS;
+}
+
+/**
+ * Implementation of eap_payload_t.get_encoding_rules.
+ */
+static void get_encoding_rules(private_eap_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
+{
+ *rules = eap_payload_encodings;
+ *rule_count = sizeof(eap_payload_encodings) / sizeof(encoding_rule_t);
+}
+
+/**
+ * Implementation of payload_t.get_type.
+ */
+static payload_type_t get_payload_type(private_eap_payload_t *this)
+{
+ return EXTENSIBLE_AUTHENTICATION;
+}
+
+/**
+ * Implementation of payload_t.get_next_type.
+ */
+static payload_type_t get_next_type(private_eap_payload_t *this)
+{
+ return (this->next_payload);
+}
+
+/**
+ * Implementation of payload_t.set_next_type.
+ */
+static void set_next_type(private_eap_payload_t *this,payload_type_t type)
+{
+ this->next_payload = type;
+}
+
+/**
+ * Implementation of payload_t.get_length.
+ */
+static size_t get_length(private_eap_payload_t *this)
+{
+ return this->payload_length;
+}
+
+/**
+ * Implementation of eap_payload_t.set_message.
+ */
+static void set_message (private_eap_payload_t *this, chunk_t message)
+{
+ if (this->message.ptr != NULL)
+ {
+ chunk_free(&(this->message));
+ }
+ this->message.ptr = clalloc(message.ptr,message.len);
+ this->message.len = message.len;
+ this->payload_length = EAP_PAYLOAD_HEADER_LENGTH + this->message.len;
+}
+
+/**
+ * Implementation of eap_payload_t.get_message.
+ */
+static chunk_t get_message (private_eap_payload_t *this)
+{
+ return (this->message);
+}
+
+/**
+ * Implementation of eap_payload_t.get_data_clone.
+ */
+static chunk_t get_message_clone (private_eap_payload_t *this)
+{
+ chunk_t cloned_message;
+ if (this->message.ptr == NULL)
+ {
+ return (this->message);
+ }
+ cloned_message.ptr = clalloc(this->message.ptr,this->message.len);
+ cloned_message.len = this->message.len;
+ return cloned_message;
+}
+
+/**
+ * Implementation of payload_t.destroy and eap_payload_t.destroy.
+ */
+static void destroy(private_eap_payload_t *this)
+{
+ if (this->message.ptr != NULL)
+ {
+ chunk_free(&(this->message));
+ }
+
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+eap_payload_t *eap_payload_create()
+{
+ private_eap_payload_t *this = malloc_thing(private_eap_payload_t);
+
+ /* interface functions */
+ this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
+ this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
+ this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
+ this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
+ this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
+ this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_payload_type;
+ this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
+
+ /* public functions */
+ this->public.destroy = (void (*) (eap_payload_t *)) destroy;
+ this->public.set_message = (void (*) (eap_payload_t *,chunk_t)) set_message;
+ this->public.get_message_clone = (chunk_t (*) (eap_payload_t *)) get_message_clone;
+ this->public.get_message = (chunk_t (*) (eap_payload_t *)) get_message;
+
+ /* private variables */
+ this->critical = FALSE;
+ this->next_payload = NO_PAYLOAD;
+ this->payload_length = EAP_PAYLOAD_HEADER_LENGTH;
+ this->message = CHUNK_INITIALIZER;
+
+ return (&(this->public));
+}
diff --git a/programs/charon/charon/encoding/payloads/eap_payload.h b/programs/charon/charon/encoding/payloads/eap_payload.h
new file mode 100644
index 000000000..5e5a0c6d8
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/eap_payload.h
@@ -0,0 +1,105 @@
+/**
+ * @file eap_payload.h
+ *
+ * @brief Interface of eap_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef EAP_PAYLOAD_H_
+#define EAP_PAYLOAD_H_
+
+#include <types.h>
+#include <encoding/payloads/payload.h>
+
+/**
+ * Length of a EAP payload without the EAP Message in bytes.
+ *
+ * @ingroup payloads
+ */
+#define EAP_PAYLOAD_HEADER_LENGTH 4
+
+
+typedef struct eap_payload_t eap_payload_t;
+
+/**
+ * @brief Class representing an IKEv2 EAP payload.
+ *
+ * The EAP payload format is described in RFC section 3.16.
+ *
+ * @b Constructors:
+ * - eap_payload_create()
+ *
+ * @todo Implement functionality for this payload
+ *
+ * @ingroup payloads
+ */
+struct eap_payload_t {
+ /**
+ * The payload_t interface.
+ */
+ payload_t payload_interface;
+
+ /**
+ * @brief Set the EAP Message.
+ *
+ * Data are getting cloned.
+ *
+ * @param this calling eap_payload_t object
+ * @param message EAP message as chunk_t
+ */
+ void (*set_message) (eap_payload_t *this, chunk_t message);
+
+ /**
+ * @brief Get the EAP message.
+ *
+ * Returned data are a copy of the internal one.
+ *
+ * @param this calling eap_payload_t object
+ * @return EAP message as chunk_t
+ */
+ chunk_t (*get_message_clone) (eap_payload_t *this);
+
+ /**
+ * @brief Get the EAP message.
+ *
+ * Returned data are NOT copied.
+ *
+ * @param this calling eap_payload_t object
+ * @return EAP message as chunk_t
+ */
+ chunk_t (*get_message) (eap_payload_t *this);
+
+ /**
+ * @brief Destroys an eap_payload_t object.
+ *
+ * @param this eap_payload_t object to destroy
+ */
+ void (*destroy) (eap_payload_t *this);
+};
+
+/**
+ * @brief Creates an empty eap_payload_t object.
+ *
+ * @return eap_payload_t object
+ *
+ * @ingroup payloads
+ */
+eap_payload_t *eap_payload_create();
+
+
+#endif /* EAP_PAYLOAD_H_ */
diff --git a/programs/charon/charon/encoding/payloads/encodings.c b/programs/charon/charon/encoding/payloads/encodings.c
new file mode 100644
index 000000000..da39467a9
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/encodings.c
@@ -0,0 +1,68 @@
+/**
+ * @file encodings.c
+ *
+ * @brief String mappings of encoding_type_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#include "encodings.h"
+
+
+mapping_t encoding_type_m[] = {
+ {U_INT_4, "U_INT_4"},
+ {U_INT_8, "U_INT_8"},
+ {U_INT_16, "U_INT_16"},
+ {U_INT_32, "U_INT_32"},
+ {U_INT_64, "U_INT_64"},
+ {IKE_SPI, "IKE_SPI"},
+ {RESERVED_BIT, "RESERVED_BIT"},
+ {RESERVED_BYTE, "RESERVED_BYTE"},
+ {FLAG, "FLAG"},
+ {PAYLOAD_LENGTH, "PAYLOAD_LENGTH"},
+ {HEADER_LENGTH, "HEADER_LENGTH"},
+ {SPI_SIZE, "SPI_SIZE"},
+ {SPI, "SPI"},
+ {KEY_EXCHANGE_DATA, "KEY_EXCHANGE_DATA"},
+ {NOTIFICATION_DATA, "NOTIFICATION_DATA"},
+ {PROPOSALS, "PROPOSALS"},
+ {TRANSFORMS, "TRANSFORMS"},
+ {TRANSFORM_ATTRIBUTES, "TRANSFORM_ATTRIBUTES"},
+ {ATTRIBUTE_FORMAT, "ATTRIBUTE_FORMAT"},
+ {ATTRIBUTE_TYPE, "ATTRIBUTE_TYPE"},
+ {ATTRIBUTE_LENGTH_OR_VALUE, "ATTRIBUTE_LENGTH_OR_VALUE"},
+ {ATTRIBUTE_VALUE, "ATTRIBUTE_VALUE"},
+ {NONCE_DATA, "NONCE_DATA"},
+ {ID_DATA, "ID_DATA"},
+ {AUTH_DATA, "AUTH_DATA"},
+ {ENCRYPTED_DATA, "ENCRYPTED_DATA"},
+ {TS_TYPE, "TS_TYPE"},
+ {ADDRESS, "ADDRESS"},
+ {TRAFFIC_SELECTORS, "TRAFFIC_SELECTORS"},
+ {CERT_DATA, "CERT_DATA"},
+ {CERTREQ_DATA, "CERTREQ_DATA"},
+ {SPIS, "SPIS"},
+ {VID_DATA, "VID_DATA"},
+ {VID_DATA, "VID_DATA"},
+ {CONFIGURATION_ATTRIBUTES, "CONFIGURATION_ATTRIBUTES"},
+ {CONFIGURATION_ATTRIBUTE_LENGTH, "CONFIGURATION_ATTRIBUTE_LENGTH"},
+ {CONFIGURATION_ATTRIBUTE_VALUE, "CONFIGURATION_ATTRIBUTE_VALUE"},
+ {EAP_MESSAGE, "EAP_MESSAGE"},
+ {UNKNOWN_DATA,"UNKNOWN_DATA"},
+ {MAPPING_END, NULL}
+};
diff --git a/programs/charon/charon/encoding/payloads/encodings.h b/programs/charon/charon/encoding/payloads/encodings.h
new file mode 100644
index 000000000..e30e1c215
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/encodings.h
@@ -0,0 +1,540 @@
+/**
+ * @file encodings.h
+ *
+ * @brief Definition of encoding_type_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef ENCODINGS_H_
+#define ENCODINGS_H_
+
+#include <types.h>
+#include <definitions.h>
+
+
+typedef enum encoding_type_t encoding_type_t;
+
+/**
+ * @brief All different kinds of encoding types.
+ *
+ * Each field of an IKEv2-Message (in header or payload)
+ * which has to be parsed or generated differently has its own
+ * type defined here.
+ *
+ * Header is parsed like a payload and gets its one payload_id
+ * from PRIVATE USE space. Also the substructures
+ * of specific payload types get their own payload_id
+ * from PRIVATE_USE space. See IKEv2-Draft for more informations.
+ *
+ * @ingroup payloads
+ */
+enum encoding_type_t {
+
+ /**
+ * Representing a 4 Bit unsigned int value.
+ *
+ *
+ * When generating it must be changed from host to network order.
+ * The value is read from the associated data struct.
+ * The current write position is moved 4 bit forward afterwards.
+ *
+ * When parsing it must be changed from network to host order.
+ * The value is written to the associated data struct.
+ * The current read pointer is moved 4 bit forward afterwards.
+ */
+ U_INT_4,
+
+ /**
+ * Representing a 8 Bit unsigned int value.
+ *
+ *
+ * When generating it must be changed from host to network order.
+ * The value is read from the associated data struct.
+ * The current write position is moved 8 bit forward afterwards.
+ *
+ * When parsing it must be changed from network to host order.
+ * The value is written to the associated data struct.
+ * The current read pointer is moved 8 bit forward afterwards.
+ */
+ U_INT_8,
+
+ /**
+ * Representing a 16 Bit unsigned int value.
+ *
+ *
+ * When generating it must be changed from host to network order.
+ * The value is read from the associated data struct.
+ * The current write position is moved 16 bit forward afterwards.
+ *
+ * When parsing it must be changed from network to host order.
+ * The value is written to the associated data struct.
+ * The current read pointer is moved 16 bit forward afterwards.
+ */
+ U_INT_16,
+
+ /**
+ * Representing a 32 Bit unsigned int value.
+ *
+ * When generating it must be changed from host to network order.
+ * The value is read from the associated data struct.
+ * The current write position is moved 32 bit forward afterwards.
+ *
+ * When parsing it must be changed from network to host order.
+ * The value is written to the associated data struct.
+ * The current read pointer is moved 32 bit forward afterwards.
+ */
+ U_INT_32,
+
+ /**
+ * Representing a 64 Bit unsigned int value.
+ *
+ * When generating it must be changed from host to network order.
+ * The value is read from the associated data struct.
+ * The current write position is moved 64 bit forward afterwards.
+ *
+ * When parsing it must be changed from network to host order.
+ * The value is written to the associated data struct.
+ * The current read pointer is moved 64 bit forward afterwards.
+ */
+ U_INT_64,
+
+ /**
+ * @brief represents a RESERVED_BIT used in FLAG-Bytes.
+ *
+ * When generating, the next bit is set to zero and the current write
+ * position is moved one bit forward.
+ * No value is read from the associated data struct.
+ * The current write position is moved 1 bit forward afterwards.
+ *
+ * When parsing, the current read pointer is moved one bit forward.
+ * No value is written to the associated data struct.
+ * The current read pointer is moved 1 bit forward afterwards.
+ */
+ RESERVED_BIT,
+
+ /**
+ * @brief represents a RESERVED_BYTE.
+ *
+ * When generating, the next byte is set to zero and the current write
+ * position is moved one byte forward.
+ * No value is read from the associated data struct.
+ * The current write position is moved 1 byte forward afterwards.
+ *
+ * When parsing, the current read pointer is moved one byte forward.
+ * No value is written to the associated data struct.
+ * The current read pointer is moved 1 byte forward afterwards.
+ */
+ RESERVED_BYTE,
+
+ /**
+ * Representing a 1 Bit flag.
+ *
+ * When generation, the next bit is set to 1 if the associated value
+ * in the data struct is TRUE, 0 otherwise. The current write position
+ * is moved 1 bit forward afterwards.
+ *
+ * When parsing, the next bit is read and stored in the associated data
+ * struct. 0 means FALSE, 1 means TRUE, The current read pointer
+ * is moved 1 bit forward afterwards
+ */
+ FLAG,
+
+ /**
+ * Representating a length field of a payload.
+ *
+ * When generating it must be changed from host to network order.
+ * The value is read from the associated data struct.
+ * The current write position is moved 16 bit forward afterwards.
+ *
+ * When parsing it must be changed from network to host order.
+ * The value is written to the associated data struct.
+ * The current read pointer is moved 16 bit forward afterwards.
+ */
+ PAYLOAD_LENGTH,
+
+ /**
+ * Representating a length field of a header.
+ *
+ * When generating it must be changed from host to network order.
+ * The value is read from the associated data struct.
+ * The current write position is moved 32 bit forward afterwards.
+ *
+ * When parsing it must be changed from network to host order.
+ * The value is written to the associated data struct.
+ * The current read pointer is moved 32 bit forward afterwards.
+ */
+ HEADER_LENGTH,
+
+ /**
+ * Representating a spi size field.
+ *
+ * When generating it must be changed from host to network order.
+ * The value is read from the associated data struct.
+ * The current write position is moved 8 bit forward afterwards.
+ *
+ * When parsing it must be changed from network to host order.
+ * The value is written to the associated data struct.
+ * The current read pointer is moved 8 bit forward afterwards.
+ */
+ SPI_SIZE,
+
+ /**
+ * Representating a spi field.
+ *
+ * When generating the content of the chunkt pointing to
+ * is written.
+ *
+ * When parsing SPI_SIZE bytes are read and written into the chunk pointing to.
+ */
+ SPI,
+
+ /**
+ * Representating a Key Exchange Data field.
+ *
+ * When generating the content of the chunkt pointing to
+ * is written.
+ *
+ * When parsing (Payload Length - 8) bytes are read and written into the chunk pointing to.
+ */
+ KEY_EXCHANGE_DATA,
+
+ /**
+ * Representating a Notification field.
+ *
+ * When generating the content of the chunkt pointing to
+ * is written.
+ *
+ * When parsing (Payload Length - spi size - 8) bytes are read and written into the chunk pointing to.
+ */
+ NOTIFICATION_DATA,
+
+ /**
+ * Representating one or more proposal substructures.
+ *
+ * The offset points to a linked_list_t pointer.
+ *
+ * When generating the proposal_substructure_t objects are stored
+ * in the pointed linked_list.
+ *
+ * When parsing the parsed proposal_substructure_t objects have
+ * to be stored in the pointed linked_list.
+ */
+ PROPOSALS,
+
+ /**
+ * Representating one or more transform substructures.
+ *
+ * The offset points to a linked_list_t pointer.
+ *
+ * When generating the transform_substructure_t objects are stored
+ * in the pointed linked_list.
+ *
+ * When parsing the parsed transform_substructure_t objects have
+ * to be stored in the pointed linked_list.
+ */
+ TRANSFORMS,
+
+ /**
+ * Representating one or more Attributes of a transform substructure.
+ *
+ * The offset points to a linked_list_t pointer.
+ *
+ * When generating the transform_attribute_t objects are stored
+ * in the pointed linked_list.
+ *
+ * When parsing the parsed transform_attribute_t objects have
+ * to be stored in the pointed linked_list.
+ */
+ TRANSFORM_ATTRIBUTES,
+
+ /**
+ * Representating one or more Attributes of a configuration payload.
+ *
+ * The offset points to a linked_list_t pointer.
+ *
+ * When generating the configuration_attribute_t objects are stored
+ * in the pointed linked_list.
+ *
+ * When parsing the parsed configuration_attribute_t objects have
+ * to be stored in the pointed linked_list.
+ */
+ CONFIGURATION_ATTRIBUTES,
+
+ /**
+ *
+ * When generating the content of the chunkt pointing to
+ * is written.
+ *
+ * When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to.
+ */
+ CONFIGURATION_ATTRIBUTE_VALUE,
+
+ /**
+ * Representing a 1 Bit flag specifying the format of a transform attribute.
+ *
+ * When generation, the next bit is set to 1 if the associated value
+ * in the data struct is TRUE, 0 otherwise. The current write position
+ * is moved 1 bit forward afterwards.
+ *
+ * When parsing, the next bit is read and stored in the associated data
+ * struct. 0 means FALSE, 1 means TRUE, The current read pointer
+ * is moved 1 bit forward afterwards.
+ */
+ ATTRIBUTE_FORMAT,
+ /**
+ * Representing a 15 Bit unsigned int value used as attribute type
+ * in an attribute transform.
+ *
+ *
+ * When generating it must be changed from host to network order.
+ * The value is read from the associated data struct.
+ * The current write position is moved 15 bit forward afterwards.
+ *
+ * When parsing it must be changed from network to host order.
+ * The value is written to the associated data struct.
+ * The current read pointer is moved 15 bit forward afterwards.
+ */
+ ATTRIBUTE_TYPE,
+
+ /**
+ * Depending on the field of type ATTRIBUTE_FORMAT
+ * this field contains the length or the value of an transform attribute.
+ * Its stored in a 16 unsigned integer field.
+ *
+ * When generating it must be changed from host to network order.
+ * The value is read from the associated data struct.
+ * The current write position is moved 16 bit forward afterwards.
+ *
+ * When parsing it must be changed from network to host order.
+ * The value is written to the associated data struct.
+ * The current read pointer is moved 16 bit forward afterwards.
+ */
+ ATTRIBUTE_LENGTH_OR_VALUE,
+
+ /**
+ * This field contains the length or the value of an configuration attribute.
+ * Its stored in a 16 unsigned integer field.
+ *
+ * When generating it must be changed from host to network order.
+ * The value is read from the associated data struct.
+ * The current write position is moved 16 bit forward afterwards.
+ *
+ * When parsing it must be changed from network to host order.
+ * The value is written to the associated data struct.
+ * The current read pointer is moved 16 bit forward afterwards.
+ */
+ CONFIGURATION_ATTRIBUTE_LENGTH,
+
+ /**
+ * Depending on the field of type ATTRIBUTE_FORMAT
+ * this field is available or missing and so parsed/generated
+ * or not parsed/not generated.
+ *
+ * When generating the content of the chunkt pointing to
+ * is written.
+ *
+ * When parsing SPI_SIZE bytes are read and written into the chunk pointing to.
+ */
+ ATTRIBUTE_VALUE,
+
+ /**
+ * Representating one or more Traffic selectors of a TS payload.
+ *
+ * The offset points to a linked_list_t pointer.
+ *
+ * When generating the traffic_selector_substructure_t objects are stored
+ * in the pointed linked_list.
+ *
+ * When parsing the parsed traffic_selector_substructure_t objects have
+ * to be stored in the pointed linked_list.
+ */
+ TRAFFIC_SELECTORS,
+
+ /**
+ * Representating a Traffic selector type field.
+ *
+ * When generating it must be changed from host to network order.
+ * The value is read from the associated data struct.
+ * The current write position is moved 16 bit forward afterwards.
+ *
+ * When parsing it must be changed from network to host order.
+ * The value is written to the associated data struct.
+ * The current read pointer is moved 16 bit forward afterwards.
+ */
+ TS_TYPE,
+
+ /**
+ * Representating an address field in a traffic selector.
+ *
+ * Depending on the last field of type TS_TYPE
+ * this field is either 4 or 16 byte long.
+ *
+ * When generating the content of the chunkt pointing to
+ * is written.
+ *
+ * When parsing 4 or 16 bytes are read and written into the chunk pointing to.
+ */
+ ADDRESS,
+
+ /**
+ * Representating a Nonce Data field.
+ *
+ * When generating the content of the chunkt pointing to
+ * is written.
+ *
+ * When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to.
+ */
+ NONCE_DATA,
+
+ /**
+ * Representating a ID Data field.
+ *
+ * When generating the content of the chunkt pointing to
+ * is written.
+ *
+ * When parsing (Payload Length - 8) bytes are read and written into the chunk pointing to.
+ */
+ ID_DATA,
+
+ /**
+ * Representating a AUTH Data field.
+ *
+ * When generating the content of the chunkt pointing to
+ * is written.
+ *
+ * When parsing (Payload Length - 8) bytes are read and written into the chunk pointing to.
+ */
+ AUTH_DATA,
+
+ /**
+ * Representating a CERT Data field.
+ *
+ * When generating the content of the chunkt pointing to
+ * is written.
+ *
+ * When parsing (Payload Length - 5) bytes are read and written into the chunk pointing to.
+ */
+ CERT_DATA,
+
+ /**
+ * Representating a CERTREQ Data field.
+ *
+ * When generating the content of the chunkt pointing to
+ * is written.
+ *
+ * When parsing (Payload Length - 5) bytes are read and written into the chunk pointing to.
+ */
+ CERTREQ_DATA,
+
+ /**
+ * Representating an EAP message field.
+ *
+ * When generating the content of the chunkt pointing to
+ * is written.
+ *
+ * When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to.
+ */
+ EAP_MESSAGE,
+
+ /**
+ * Representating the SPIS field in a DELETE payload.
+ *
+ * When generating the content of the chunkt pointing to
+ * is written.
+ *
+ * When parsing (Payload Length - 8) bytes are read and written into the chunk pointing to.
+ */
+ SPIS,
+
+ /**
+ * Representating the VID DATA field in a VENDOR ID payload.
+ *
+ * When generating the content of the chunkt pointing to
+ * is written.
+ *
+ * When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to.
+ */
+ VID_DATA,
+
+ /**
+ * Representating the DATA of an unknown payload.
+ *
+ * When generating the content of the chunkt pointing to
+ * is written.
+ *
+ * When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to.
+ */
+ UNKNOWN_DATA,
+
+ /**
+ * Representating an IKE_SPI field in an IKEv2 Header.
+ *
+ * When generating the value of the u_int64_t pointing to
+ * is written (host and networ order is not changed).
+ *
+ * When parsing 8 bytes are read and written into the u_int64_t pointing to.
+ */
+ IKE_SPI,
+
+ /**
+ * Representing the encrypted data body of a encryption payload.
+ */
+ ENCRYPTED_DATA,
+};
+
+/**
+ * mappings to map encoding_type_t's to strings
+ *
+ * @ingroup payloads
+ */
+extern mapping_t encoding_type_m[];
+
+
+typedef struct encoding_rule_t encoding_rule_t;
+
+/**
+ * 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 {
+
+ /**
+ * Encoding type.
+ */
+ encoding_type_t type;
+
+ /**
+ * Offset in the data struct.
+ *
+ * When parsing, data are written to this offset of the
+ * data struct.
+ *
+ * When generating, data are read from this offset in the
+ * data struct.
+ */
+ u_int32_t offset;
+};
+
+#endif /*ENCODINGS_H_*/
diff --git a/programs/charon/charon/encoding/payloads/encryption_payload.c b/programs/charon/charon/encoding/payloads/encryption_payload.c
new file mode 100644
index 000000000..e0ca74ff4
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/encryption_payload.c
@@ -0,0 +1,702 @@
+/**
+ * @file encryption_payload.c
+ *
+ * @brief Implementation of encryption_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+#include "encryption_payload.h"
+
+#include <daemon.h>
+#include <encoding/payloads/encodings.h>
+#include <utils/linked_list.h>
+#include <utils/logger.h>
+#include <encoding/generator.h>
+#include <encoding/parser.h>
+#include <utils/iterator.h>
+#include <utils/randomizer.h>
+#include <crypto/signers/signer.h>
+
+
+
+
+typedef struct private_encryption_payload_t private_encryption_payload_t;
+
+/**
+ * Private data of an encryption_payload_t' Object.
+ *
+ */
+struct private_encryption_payload_t {
+
+ /**
+ * Public encryption_payload_t interface.
+ */
+ encryption_payload_t public;
+
+ /**
+ * There is no next payload for an encryption payload,
+ * since encryption payload MUST be the last one.
+ * next_payload means here the first payload of the
+ * contained, encrypted payload.
+ */
+ u_int8_t next_payload;
+
+ /**
+ * Critical flag.
+ */
+ bool critical;
+
+ /**
+ * Length of this payload
+ */
+ u_int16_t payload_length;
+
+ /**
+ * Chunk containing the iv, data, padding,
+ * and (an eventually not calculated) signature.
+ */
+ chunk_t encrypted;
+
+ /**
+ * Chunk containing the data in decrypted (unpadded) form.
+ */
+ chunk_t decrypted;
+
+ /**
+ * Signer set by set_signer.
+ */
+ signer_t *signer;
+
+ /**
+ * Crypter, supplied by encrypt/decrypt
+ */
+ crypter_t *crypter;
+
+ /**
+ * Contained payloads of this encrpytion_payload.
+ */
+ linked_list_t *payloads;
+
+ /**
+ * logger for this payload, uses MESSAGE context
+ */
+ logger_t *logger;
+
+ /**
+ * @brief Computes the length of this payload.
+ *
+ * @param this calling private_encryption_payload_t object
+ */
+ void (*compute_length) (private_encryption_payload_t *this);
+
+ /**
+ * @brief Generate payloads (unencrypted) in chunk decrypted.
+ *
+ * @param this calling private_encryption_payload_t object
+ */
+ void (*generate) (private_encryption_payload_t *this);
+
+ /**
+ * @brief Parse payloads from a (unencrypted) chunk.
+ *
+ * @param this calling private_encryption_payload_t object
+ */
+ status_t (*parse) (private_encryption_payload_t *this);
+};
+
+/**
+ * Encoding rules to parse or generate a IKEv2-Encryption Payload.
+ *
+ * The defined offsets are the positions in a object of type
+ * private_encryption_payload_t.
+ *
+ */
+encoding_rule_t encryption_payload_encodings[] = {
+ /* 1 Byte next payload type, stored in the field next_payload */
+ { U_INT_8, offsetof(private_encryption_payload_t, next_payload) },
+ /* the critical bit */
+ { FLAG, offsetof(private_encryption_payload_t, critical) },
+ /* 7 Bit reserved bits, nowhere stored */
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ /* Length of the whole encryption payload*/
+ { PAYLOAD_LENGTH, offsetof(private_encryption_payload_t, payload_length) },
+ /* encrypted data, stored in a chunk. contains iv, data, padding */
+ { ENCRYPTED_DATA, offsetof(private_encryption_payload_t, encrypted) },
+};
+
+/*
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Next Payload !C! RESERVED ! Payload Length !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Initialization Vector !
+ ! (length is block size for encryption algorithm) !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Encrypted IKE Payloads !
+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! ! Padding (0-255 octets) !
+ +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
+ ! ! Pad Length !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ~ Integrity Checksum Data ~
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+/**
+ * Implementation of payload_t.verify.
+ */
+static status_t verify(private_encryption_payload_t *this)
+{
+ return SUCCESS;
+}
+
+/**
+ * Implementation of payload_t.get_encoding_rules.
+ */
+static void get_encoding_rules(private_encryption_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
+{
+ *rules = encryption_payload_encodings;
+ *rule_count = sizeof(encryption_payload_encodings) / sizeof(encoding_rule_t);
+}
+
+/**
+ * Implementation of payload_t.get_type.
+ */
+static payload_type_t get_type(private_encryption_payload_t *this)
+{
+ return ENCRYPTED;
+}
+
+/**
+ * Implementation of payload_t.get_next_type.
+ */
+static payload_type_t get_next_type(private_encryption_payload_t *this)
+{
+ /* returns first contained payload here */
+ return (this->next_payload);
+}
+
+/**
+ * Implementation of payload_t.set_next_type.
+ */
+static void set_next_type(private_encryption_payload_t *this, payload_type_t type)
+{
+ /* set next type is not allowed, since this payload MUST be the last one
+ * and so nothing is done in here*/
+}
+
+/**
+ * Implementation of payload_t.get_length.
+ */
+static size_t get_length(private_encryption_payload_t *this)
+{
+ this->compute_length(this);
+ return this->payload_length;
+}
+
+/**
+ * Implementation of payload_t.create_payload_iterator.
+ */
+static iterator_t *create_payload_iterator (private_encryption_payload_t *this, bool forward)
+{
+ return (this->payloads->create_iterator(this->payloads, forward));
+}
+
+/**
+ * Implementation of payload_t.add_payload.
+ */
+static void add_payload(private_encryption_payload_t *this, payload_t *payload)
+{
+ payload_t *last_payload;
+ if (this->payloads->get_count(this->payloads) > 0)
+ {
+ this->payloads->get_last(this->payloads,(void **) &last_payload);
+ last_payload->set_next_type(last_payload, payload->get_type(payload));
+ }
+ else
+ {
+ this->next_payload = payload->get_type(payload);
+ }
+ payload->set_next_type(payload, NO_PAYLOAD);
+ this->payloads->insert_last(this->payloads, (void*)payload);
+ this->compute_length(this);
+}
+
+/**
+ * Implementation of encryption_payload_t.remove_first_payload.
+ */
+static status_t remove_first_payload(private_encryption_payload_t *this, payload_t **payload)
+{
+ return this->payloads->remove_first(this->payloads, (void**)payload);
+}
+
+/**
+ * Implementation of encryption_payload_t.get_payload_count.
+ */
+static size_t get_payload_count(private_encryption_payload_t *this)
+{
+ return this->payloads->get_count(this->payloads);
+}
+
+
+/**
+ * Implementation of encryption_payload_t.encrypt.
+ */
+static status_t encrypt(private_encryption_payload_t *this)
+{
+ chunk_t iv, padding, to_crypt, result;
+ randomizer_t *randomizer;
+ status_t status;
+ size_t block_size;
+
+ if (this->signer == NULL || this->crypter == NULL)
+ {
+ this->logger->log(this->logger, ERROR, "could not encrypt, signer/crypter not set");
+ return INVALID_STATE;
+ }
+
+ /* for random data in iv and padding */
+ randomizer = randomizer_create();
+
+
+ /* build payload chunk */
+ this->generate(this);
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "encrypting payloads");
+ this->logger->log_chunk(this->logger, RAW|LEVEL2, "data to encrypt", this->decrypted);
+
+ /* build padding */
+ block_size = this->crypter->get_block_size(this->crypter);
+ padding.len = block_size - ((this->decrypted.len + 1) % block_size);
+ status = randomizer->allocate_pseudo_random_bytes(randomizer, padding.len, &padding);
+ if (status != SUCCESS)
+ {
+ randomizer->destroy(randomizer);
+ return status;
+ }
+
+ /* concatenate payload data, padding, padding len */
+ to_crypt.len = this->decrypted.len + padding.len + 1;
+ to_crypt.ptr = malloc(to_crypt.len);
+
+ memcpy(to_crypt.ptr, this->decrypted.ptr, this->decrypted.len);
+ memcpy(to_crypt.ptr + this->decrypted.len, padding.ptr, padding.len);
+ *(to_crypt.ptr + to_crypt.len - 1) = padding.len;
+
+ /* build iv */
+ iv.len = block_size;
+ status = randomizer->allocate_pseudo_random_bytes(randomizer, iv.len, &iv);
+ randomizer->destroy(randomizer);
+ if (status != SUCCESS)
+ {
+ chunk_free(&to_crypt);
+ chunk_free(&padding);
+ return status;
+ }
+
+ this->logger->log_chunk(this->logger, RAW|LEVEL2, "data before encryption with padding", to_crypt);
+
+ /* encrypt to_crypt chunk */
+ free(this->encrypted.ptr);
+ status = this->crypter->encrypt(this->crypter, to_crypt, iv, &result);
+ free(padding.ptr);
+ free(to_crypt.ptr);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1, "encryption failed");
+ free(iv.ptr);
+ return status;
+ }
+ this->logger->log_chunk(this->logger, RAW|LEVEL2, "data after encryption", result);
+
+
+ /* build encrypted result with iv and signature */
+ this->encrypted.len = iv.len + result.len + this->signer->get_block_size(this->signer);
+ free(this->encrypted.ptr);
+ this->encrypted.ptr = malloc(this->encrypted.len);
+
+ /* fill in result, signature is left out */
+ memcpy(this->encrypted.ptr, iv.ptr, iv.len);
+ memcpy(this->encrypted.ptr + iv.len, result.ptr, result.len);
+
+ free(result.ptr);
+ free(iv.ptr);
+ this->logger->log_chunk(this->logger, RAW|LEVEL2, "data after encryption with IV and (invalid) signature", this->encrypted);
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of encryption_payload_t.encrypt.
+ */
+static status_t decrypt(private_encryption_payload_t *this)
+{
+ chunk_t iv, concatenated;
+ u_int8_t padding_length;
+ status_t status;
+
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "decrypting encryption payload");
+ this->logger->log_chunk(this->logger, RAW|LEVEL2, "data before decryption with IV and (invalid) signature", this->encrypted);
+
+
+ if (this->signer == NULL || this->crypter == NULL)
+ {
+ this->logger->log(this->logger, ERROR, "could not decrypt, no crypter/signer set");
+ return INVALID_STATE;
+ }
+
+ /* get IV */
+ iv.len = this->crypter->get_block_size(this->crypter);
+
+ iv.ptr = this->encrypted.ptr;
+
+ /* point concatenated to data + padding + padding_length*/
+ concatenated.ptr = this->encrypted.ptr + iv.len;
+ concatenated.len = this->encrypted.len - iv.len - this->signer->get_block_size(this->signer);
+
+ /* check the size of input:
+ * concatenated must be at least on block_size of crypter
+ */
+ if (concatenated.len < iv.len)
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1, "could not decrypt, invalid input");
+ return FAILED;
+ }
+
+ /* free previus data, if any */
+ free(this->decrypted.ptr);
+
+ this->logger->log_chunk(this->logger, RAW|LEVEL2, "data before decryption", concatenated);
+
+ status = this->crypter->decrypt(this->crypter, concatenated, iv, &(this->decrypted));
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1, "could not decrypt, decryption failed");
+ return FAILED;
+ }
+ this->logger->log_chunk(this->logger, RAW|LEVEL2, "data after decryption with padding", this->decrypted);
+
+
+ /* get padding length, sits just bevore signature */
+ padding_length = *(this->decrypted.ptr + this->decrypted.len - 1);
+ /* add one byte to the padding length, since the padding_length field is not included */
+ padding_length++;
+ this->decrypted.len -= padding_length;
+
+ /* check size again */
+ if (padding_length > concatenated.len || this->decrypted.len < 0)
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1, "decryption failed, invalid padding length found. Invalid key?");
+ /* decryption failed :-/ */
+ return FAILED;
+ }
+
+ /* free padding */
+ this->decrypted.ptr = realloc(this->decrypted.ptr, this->decrypted.len);
+ this->logger->log_chunk(this->logger, RAW|LEVEL2, "data after decryption without padding", this->decrypted);
+ this->logger->log(this->logger, CONTROL|LEVEL2, "decryption successful, trying to parse content");
+ return (this->parse(this));
+}
+
+/**
+ * Implementation of encryption_payload_t.set_transforms.
+ */
+static void set_transforms(private_encryption_payload_t *this, crypter_t* crypter, signer_t* signer)
+{
+ this->signer = signer;
+ this->crypter = crypter;
+}
+
+/**
+ * Implementation of encryption_payload_t.build_signature.
+ */
+static status_t build_signature(private_encryption_payload_t *this, chunk_t data)
+{
+ chunk_t data_without_sig = data;
+ chunk_t sig;
+
+ if (this->signer == NULL)
+ {
+ this->logger->log(this->logger, ERROR, "unable to build signature, no signer set");
+ return INVALID_STATE;
+ }
+
+ sig.len = this->signer->get_block_size(this->signer);
+ data_without_sig.len -= sig.len;
+ sig.ptr = data.ptr + data_without_sig.len;
+ this->logger->log(this->logger, CONTROL|LEVEL2, "building signature");
+ this->signer->get_signature(this->signer, data_without_sig, sig.ptr);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of encryption_payload_t.verify_signature.
+ */
+static status_t verify_signature(private_encryption_payload_t *this, chunk_t data)
+{
+ chunk_t sig, data_without_sig;
+ bool valid;
+
+ if (this->signer == NULL)
+ {
+ this->logger->log(this->logger, ERROR, "unable to verify signature, no signer set");
+ return INVALID_STATE;
+ }
+ /* find signature in data chunk */
+ sig.len = this->signer->get_block_size(this->signer);
+ if (data.len <= sig.len)
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1, "unable to verify signature, invalid input");
+ return FAILED;
+ }
+ sig.ptr = data.ptr + data.len - sig.len;
+
+ /* verify it */
+ data_without_sig.len = data.len - sig.len;
+ data_without_sig.ptr = data.ptr;
+ valid = this->signer->verify_signature(this->signer, data_without_sig, sig);
+
+ if (!valid)
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1, "signature verification failed");
+ return FAILED;
+ }
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "signature verification successful");
+ return SUCCESS;
+}
+
+/**
+ * Implementation of private_encryption_payload_t.generate.
+ */
+static void generate(private_encryption_payload_t *this)
+{
+ payload_t *current_payload, *next_payload;
+ generator_t *generator;
+ iterator_t *iterator;
+
+ /* recalculate length before generating */
+ this->compute_length(this);
+
+ /* create iterator */
+ iterator = this->payloads->create_iterator(this->payloads, TRUE);
+
+ /* get first payload */
+ if (iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void**)&current_payload);
+ this->next_payload = current_payload->get_type(current_payload);
+ }
+ else
+ {
+ /* no paylads? */
+ this->logger->log(this->logger, CONTROL|LEVEL1, "generating contained payloads, but no available");
+ free(this->decrypted.ptr);
+ this->decrypted = CHUNK_INITIALIZER;
+ iterator->destroy(iterator);
+ return;
+ }
+
+ generator = generator_create();
+
+ /* build all payload, except last */
+ while(iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void**)&next_payload);
+ current_payload->set_next_type(current_payload, next_payload->get_type(next_payload));
+ generator->generate_payload(generator, current_payload);
+ current_payload = next_payload;
+ }
+ iterator->destroy(iterator);
+
+ /* build last payload */
+ current_payload->set_next_type(current_payload, NO_PAYLOAD);
+ generator->generate_payload(generator, current_payload);
+
+ /* free already generated data */
+ free(this->decrypted.ptr);
+
+ generator->write_to_chunk(generator, &(this->decrypted));
+ generator->destroy(generator);
+ this->logger->log(this->logger, CONTROL|LEVEL1, "successfully generated content in encrpytion payload");
+}
+
+/**
+ * Implementation of private_encryption_payload_t.parse.
+ */
+static status_t parse(private_encryption_payload_t *this)
+{
+ parser_t *parser;
+ status_t status;
+ payload_type_t current_payload_type;
+
+ /* check if there is decrypted data */
+ if (this->decrypted.ptr == NULL)
+ {
+ this->logger->log(this->logger, ERROR, "unable to parse, no input!");
+ return INVALID_STATE;
+ }
+
+ /* build a parser on the decrypted data */
+ parser = parser_create(this->decrypted);
+
+ current_payload_type = this->next_payload;
+ /* parse all payloads */
+ while (current_payload_type != NO_PAYLOAD)
+ {
+ payload_t *current_payload;
+
+ status = parser->parse_payload(parser, current_payload_type, (payload_t**)&current_payload);
+ if (status != SUCCESS)
+ {
+ parser->destroy(parser);
+ return PARSE_ERROR;
+ }
+
+ status = current_payload->verify(current_payload);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1, "%s verification failed: %s",
+ mapping_find(payload_type_m,current_payload->get_type(current_payload)),
+ mapping_find(status_m, status));
+ current_payload->destroy(current_payload);
+ parser->destroy(parser);
+ return VERIFY_ERROR;
+ }
+
+ /* get next payload type */
+ current_payload_type = current_payload->get_next_type(current_payload);
+
+ this->payloads->insert_last(this->payloads,current_payload);
+ }
+ parser->destroy(parser);
+ this->logger->log(this->logger, CONTROL|LEVEL1, "succesfully parsed content of encryption payload");
+ return SUCCESS;
+}
+
+/**
+ * Implementation of private_encryption_payload_t.compute_length.
+ */
+static void compute_length(private_encryption_payload_t *this)
+{
+ iterator_t *iterator;
+ size_t block_size, length = 0;
+ iterator = this->payloads->create_iterator(this->payloads, TRUE);
+
+ /* count payload length */
+ while (iterator->has_next(iterator))
+ {
+ payload_t *current_payload;
+ iterator->current(iterator, (void **) &current_payload);
+ length += current_payload->get_length(current_payload);
+ }
+ iterator->destroy(iterator);
+
+ if (this->crypter && this->signer)
+ {
+ /* append one byte for padding length */
+ length++;
+ /* append padding */
+ block_size = this->crypter->get_block_size(this->crypter);
+ length += block_size - length % block_size;
+ /* add iv */
+ length += block_size;
+ /* add signature */
+ length += this->signer->get_block_size(this->signer);
+ }
+ length += ENCRYPTION_PAYLOAD_HEADER_LENGTH;
+ this->payload_length = length;
+}
+
+
+/**
+ * Implementation of payload_t.destroy.
+ */
+static void destroy(private_encryption_payload_t *this)
+{
+ /* all proposals are getting destroyed */
+ while (this->payloads->get_count(this->payloads) > 0)
+ {
+ payload_t *current_payload;
+ this->payloads->remove_last(this->payloads,(void **)&current_payload);
+ current_payload->destroy(current_payload);
+ }
+ this->payloads->destroy(this->payloads);
+ free(this->encrypted.ptr);
+ free(this->decrypted.ptr);
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+encryption_payload_t *encryption_payload_create()
+{
+ private_encryption_payload_t *this = malloc_thing(private_encryption_payload_t);
+
+ /* payload_t interface functions */
+ this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
+ this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
+ this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
+ this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
+ this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
+ this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_type;
+ this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
+
+ /* public functions */
+ this->public.create_payload_iterator = (iterator_t * (*) (encryption_payload_t *,bool)) create_payload_iterator;
+ this->public.add_payload = (void (*) (encryption_payload_t *,payload_t *)) add_payload;
+ this->public.remove_first_payload = (status_t (*)(encryption_payload_t*, payload_t **)) remove_first_payload;
+ this->public.get_payload_count = (size_t (*)(encryption_payload_t*)) get_payload_count;
+
+ this->public.encrypt = (status_t (*) (encryption_payload_t *)) encrypt;
+ this->public.decrypt = (status_t (*) (encryption_payload_t *)) decrypt;
+ this->public.set_transforms = (void (*) (encryption_payload_t*,crypter_t*,signer_t*)) set_transforms;
+ this->public.build_signature = (status_t (*) (encryption_payload_t*, chunk_t)) build_signature;
+ this->public.verify_signature = (status_t (*) (encryption_payload_t*, chunk_t)) verify_signature;
+ this->public.destroy = (void (*) (encryption_payload_t *)) destroy;
+
+ /* private functions */
+ this->compute_length = compute_length;
+ this->generate = generate;
+ this->parse = parse;
+ this->logger = logger_manager->get_logger(logger_manager, ENCRYPTION_PAYLOAD);
+
+ /* set default values of the fields */
+ this->critical = FALSE;
+ this->next_payload = NO_PAYLOAD;
+ this->payload_length = ENCRYPTION_PAYLOAD_HEADER_LENGTH;
+ this->encrypted = CHUNK_INITIALIZER;
+ this->decrypted = CHUNK_INITIALIZER;
+ this->signer = NULL;
+ this->crypter = NULL;
+ this->payloads = linked_list_create();
+
+ return (&(this->public));
+}
diff --git a/programs/charon/charon/encoding/payloads/encryption_payload.h b/programs/charon/charon/encoding/payloads/encryption_payload.h
new file mode 100644
index 000000000..77be246c5
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/encryption_payload.h
@@ -0,0 +1,196 @@
+/**
+ * @file encryption_payload.h
+ *
+ * @brief Interface of encryption_payload_t.
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef ENCRYPTION_PAYLOAD_H_
+#define ENCRYPTION_PAYLOAD_H_
+
+#include <types.h>
+#include <crypto/crypters/crypter.h>
+#include <crypto/signers/signer.h>
+#include <encoding/payloads/payload.h>
+#include <utils/linked_list.h>
+
+/**
+ * Encrpytion payload length in bytes without IV and following data.
+ *
+ * @ingroup payloads
+ */
+#define ENCRYPTION_PAYLOAD_HEADER_LENGTH 4
+
+
+typedef struct encryption_payload_t encryption_payload_t;
+
+/**
+ * @brief The encryption payload as described in RFC section 3.14.
+ *
+ * Before any crypt/decrypt/sign/verify operation can occur,
+ * the transforms must be set. After that, a parsed encryption payload
+ * can be decrypted, which also will parse the contained payloads.
+ * Encryption is done the same way, added payloads will get generated
+ * and then encrypted.
+ * For signature building, there is the FULL packet needed. Meaning it
+ * must be builded after generation of all payloads and the encryption
+ * of the encryption payload.
+ * Signature verificatin is done before decryption.
+ *
+ * @b Constructors:
+ * - encryption_payload_create()
+ *
+ * @ingroup payloads
+ */
+struct encryption_payload_t {
+ /**
+ * Implements payload_t interface.
+ */
+ payload_t payload_interface;
+
+ /**
+ * @brief Creates an iterator for all contained payloads.
+ *
+ * @warning 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)
+ * return created iterator_t object
+ */
+ iterator_t *(*create_payload_iterator) (encryption_payload_t *this, bool forward);
+
+ /**
+ * @brief 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.
+ *
+ * @param this calling encryption_payload_t object
+ * @param[out] payload removed payload
+ * @return
+ * - SUCCESS, or
+ * - NOT_FOUND if list empty
+ */
+ status_t (*remove_first_payload) (encryption_payload_t *this, payload_t **payload);
+
+ /**
+ * @brief 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.
+ *
+ * To decryption, encryption, signature building and verifying,
+ * the payload needs a crypter and a signer object.
+ *
+ * @warning Do NOT call this function again after encryption, since
+ * the signer must be the same while encrypting and signature building!
+ *
+ * @param 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.
+ *
+ * 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
+ */
+ status_t (*encrypt) (encryption_payload_t *this);
+
+ /**
+ * @brief 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
+ * - FAILED if data is invalid
+ */
+ status_t (*decrypt) (encryption_payload_t *this);
+
+ /**
+ * @brief 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
+ * - INVALID_STATE if transforms not set
+ */
+ status_t (*build_signature) (encryption_payload_t *this, chunk_t data);
+
+ /**
+ * @brief 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
+ * - FAILED if signature invalid, or
+ * - INVALID_STATE if transforms not set
+ */
+ 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
+ */
+ void (*destroy) (encryption_payload_t *this);
+};
+
+/**
+ * @brief Creates an empty encryption_payload_t object.
+ *
+ * @return encryption_payload_t object
+ *
+ * @ingroup payloads
+ */
+encryption_payload_t *encryption_payload_create();
+
+
+#endif /*ENCRYPTION_PAYLOAD_H_*/
diff --git a/programs/charon/charon/encoding/payloads/id_payload.c b/programs/charon/charon/encoding/payloads/id_payload.c
new file mode 100644
index 000000000..6a8d7738d
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/id_payload.c
@@ -0,0 +1,320 @@
+/**
+ * @file id_payload.h
+ *
+ * @brief Interface of id_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stddef.h>
+
+#include "id_payload.h"
+
+#include <encoding/payloads/encodings.h>
+
+typedef struct private_id_payload_t private_id_payload_t;
+
+/**
+ * Private data of an id_payload_t object.
+ *
+ */
+struct private_id_payload_t {
+ /**
+ * Public id_payload_t interface.
+ */
+ id_payload_t public;
+
+ /**
+ * TRUE if this ID payload is of type IDi, FALSE for IDr.
+ */
+ bool is_initiator;
+
+ /**
+ * Next payload type.
+ */
+ u_int8_t next_payload;
+
+ /**
+ * Critical flag.
+ */
+ bool critical;
+
+ /**
+ * Length of this payload.
+ */
+ u_int16_t payload_length;
+
+ /**
+ * Type of the ID Data.
+ */
+ u_int8_t id_type;
+
+ /**
+ * The contained id data value.
+ */
+ chunk_t id_data;
+};
+
+/**
+ * Encoding rules to parse or generate a ID payload
+ *
+ * The defined offsets are the positions in a object of type
+ * private_id_payload_t.
+ *
+ */
+encoding_rule_t id_payload_encodings[] = {
+ /* 1 Byte next payload type, stored in the field next_payload */
+ { U_INT_8, offsetof(private_id_payload_t, next_payload) },
+ /* the critical bit */
+ { FLAG, offsetof(private_id_payload_t, critical) },
+ /* 7 Bit reserved bits, nowhere stored */
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ /* Length of the whole payload*/
+ { PAYLOAD_LENGTH, offsetof(private_id_payload_t, payload_length) },
+ /* 1 Byte ID type*/
+ { U_INT_8, offsetof(private_id_payload_t, id_type) },
+ /* 3 reserved bytes */
+ { RESERVED_BYTE, 0 },
+ { RESERVED_BYTE, 0 },
+ { RESERVED_BYTE, 0 },
+ /* some id data bytes, length is defined in PAYLOAD_LENGTH */
+ { ID_DATA, offsetof(private_id_payload_t, id_data) }
+};
+
+/*
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Next Payload !C! RESERVED ! Payload Length !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! ID Type ! RESERVED |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! !
+ ~ Identification Data ~
+ ! !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+/**
+ * Implementation of payload_t.verify.
+ */
+static status_t verify(private_id_payload_t *this)
+{
+ if ((this->id_type == 0) ||
+ (this->id_type == 4) ||
+ ((this->id_type >= 6) && (this->id_type <= 8)) ||
+ ((this->id_type >= 12) && (this->id_type <= 200)))
+ {
+ /* reserved IDs */
+ return FAILED;
+ }
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of id_payload_t.get_encoding_rules.
+ */
+static void get_encoding_rules(private_id_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
+{
+ *rules = id_payload_encodings;
+ *rule_count = sizeof(id_payload_encodings) / sizeof(encoding_rule_t);
+}
+
+/**
+ * Implementation of payload_t.get_type.
+ */
+static payload_type_t get_payload_type(private_id_payload_t *this)
+{
+ if (this->is_initiator)
+ {
+ return ID_INITIATOR;
+ }
+ else
+ {
+ return ID_RESPONDER;
+ }
+}
+
+/**
+ * Implementation of payload_t.get_next_type.
+ */
+static payload_type_t get_next_type(private_id_payload_t *this)
+{
+ return (this->next_payload);
+}
+
+/**
+ * Implementation of payload_t.set_next_type.
+ */
+static void set_next_type(private_id_payload_t *this,payload_type_t type)
+{
+ this->next_payload = type;
+}
+
+/**
+ * Implementation of payload_t.get_length.
+ */
+static size_t get_length(private_id_payload_t *this)
+{
+ return this->payload_length;
+}
+
+/**
+ * Implementation of id_payload_t.set_type.
+ */
+static void set_id_type (private_id_payload_t *this, id_type_t type)
+{
+ this->id_type = type;
+}
+
+/**
+ * Implementation of id_payload_t.get_id_type.
+ */
+static id_type_t get_id_type (private_id_payload_t *this)
+{
+ return (this->id_type);
+}
+
+/**
+ * Implementation of id_payload_t.set_data.
+ */
+static void set_data (private_id_payload_t *this, chunk_t data)
+{
+ if (this->id_data.ptr != NULL)
+ {
+ chunk_free(&(this->id_data));
+ }
+ this->id_data.ptr = clalloc(data.ptr,data.len);
+ this->id_data.len = data.len;
+ this->payload_length = ID_PAYLOAD_HEADER_LENGTH + this->id_data.len;
+}
+
+
+/**
+ * Implementation of id_payload_t.get_data_clone.
+ */
+static chunk_t get_data (private_id_payload_t *this)
+{
+ return (this->id_data);
+}
+
+/**
+ * Implementation of id_payload_t.get_data_clone.
+ */
+static chunk_t get_data_clone (private_id_payload_t *this)
+{
+ chunk_t cloned_data;
+ if (this->id_data.ptr == NULL)
+ {
+ return (this->id_data);
+ }
+ cloned_data.ptr = clalloc(this->id_data.ptr,this->id_data.len);
+ cloned_data.len = this->id_data.len;
+ return cloned_data;
+}
+
+/**
+ * Implementation of id_payload_t.get_initiator.
+ */
+static bool get_initiator (private_id_payload_t *this)
+{
+ return (this->is_initiator);
+}
+
+/**
+ * Implementation of id_payload_t.set_initiator.
+ */
+static void set_initiator (private_id_payload_t *this,bool is_initiator)
+{
+ this->is_initiator = is_initiator;
+}
+
+/**
+ * Implementation of id_payload_t.get_identification.
+ */
+static identification_t *get_identification (private_id_payload_t *this)
+{
+ return identification_create_from_encoding(this->id_type,this->id_data);
+}
+
+/**
+ * Implementation of payload_t.destroy and id_payload_t.destroy.
+ */
+static void destroy(private_id_payload_t *this)
+{
+ if (this->id_data.ptr != NULL)
+ {
+ chunk_free(&(this->id_data));
+ }
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+id_payload_t *id_payload_create(bool is_initiator)
+{
+ private_id_payload_t *this = malloc_thing(private_id_payload_t);
+
+ /* interface functions */
+ this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
+ this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
+ this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
+ this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
+ this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
+ this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_payload_type;
+ this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
+
+ /* public functions */
+ this->public.destroy = (void (*) (id_payload_t *)) destroy;
+ this->public.set_id_type = (void (*) (id_payload_t *,id_type_t)) set_id_type;
+ this->public.get_id_type = (id_type_t (*) (id_payload_t *)) get_id_type;
+ this->public.set_data = (void (*) (id_payload_t *,chunk_t)) set_data;
+ this->public.get_data = (chunk_t (*) (id_payload_t *)) get_data;
+ this->public.get_data_clone = (chunk_t (*) (id_payload_t *)) get_data_clone;
+
+ this->public.get_initiator = (bool (*) (id_payload_t *)) get_initiator;
+ this->public.set_initiator = (void (*) (id_payload_t *,bool)) set_initiator;
+ this->public.get_identification = (identification_t * (*) (id_payload_t *this)) get_identification;
+
+ /* private variables */
+ this->critical = FALSE;
+ this->next_payload = NO_PAYLOAD;
+ this->payload_length =ID_PAYLOAD_HEADER_LENGTH;
+ this->id_data = CHUNK_INITIALIZER;
+ this->is_initiator = is_initiator;
+
+ return (&(this->public));
+}
+
+/*
+ * Described in header.
+ */
+id_payload_t *id_payload_create_from_identification(bool is_initiator,identification_t *identification)
+{
+ id_payload_t *this= id_payload_create(is_initiator);
+ this->set_data(this,identification->get_encoding(identification));
+ this->set_id_type(this,identification->get_type(identification));
+ return this;
+}
diff --git a/programs/charon/charon/encoding/payloads/id_payload.h b/programs/charon/charon/encoding/payloads/id_payload.h
new file mode 100644
index 000000000..c35b44d59
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/id_payload.h
@@ -0,0 +1,172 @@
+/**
+ * @file id_payload.h
+ *
+ * @brief Interface of id_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#ifndef ID_PAYLOAD_H_
+#define ID_PAYLOAD_H_
+
+#include <types.h>
+#include <utils/identification.h>
+#include <encoding/payloads/payload.h>
+
+/**
+ * Length of a id payload without the data in bytes.
+ *
+ * @ingroup payloads
+ */
+#define ID_PAYLOAD_HEADER_LENGTH 8
+
+
+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 {
+ /**
+ * The payload_t interface.
+ */
+ payload_t payload_interface;
+
+ /**
+ * @brief 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.
+ *
+ * @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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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 Get the type of ID payload (IDi or IDr).
+ *
+ * @param this calling id_payload_t object
+ * @return
+ * - TRUE if this payload is of type IDi
+ * - FALSE if this payload is of type IDr
+ *
+ */
+ bool (*get_initiator) (id_payload_t *this);
+
+ /**
+ * @brief Set the type of ID payload (IDi or IDr).
+ *
+ * @param this calling id_payload_t object
+ * @param is_initiator
+ * - TRUE if this payload is of type IDi
+ * - FALSE if this payload is of type IDr
+ *
+ */
+ void (*set_initiator) (id_payload_t *this,bool is_initiator);
+
+ /**
+ * @brief Destroys an id_payload_t object.
+ *
+ * @param this id_payload_t object to destroy
+ */
+ void (*destroy) (id_payload_t *this);
+};
+
+/**
+ * @brief Creates an empty id_payload_t object.
+ *
+ * @param is_initiator
+ * - TRUE if this payload is of type IDi
+ * - FALSE if this payload is of type IDr
+ *
+ * @return id_payload_t object
+ *
+ * @ingroup payloads
+ */
+id_payload_t *id_payload_create(bool is_initiator);
+
+/**
+ * @brief Creates an id_payload_t from an existing identification_t object.
+ *
+ * @param is_initiator
+ * - TRUE if this payload is of type IDi
+ * - FALSE if this payload is of type IDr
+ * @param identification identification_t object
+ * @return id_payload_t object
+ *
+ * @ingroup payloads
+ */
+id_payload_t *id_payload_create_from_identification(bool is_initiator,identification_t *identification);
+
+
+
+#endif /* ID_PAYLOAD_H_ */
diff --git a/programs/charon/charon/encoding/payloads/ike_header.c b/programs/charon/charon/encoding/payloads/ike_header.c
new file mode 100644
index 000000000..ad46d3d29
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/ike_header.c
@@ -0,0 +1,408 @@
+/**
+ * @file ike_header.c
+ *
+ * @brief Implementation of ike_header_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/* offsetof macro */
+#include <stddef.h>
+
+#include "ike_header.h"
+
+#include <encoding/payloads/encodings.h>
+
+
+typedef struct private_ike_header_t private_ike_header_t;
+
+/**
+ * Private data of an ike_header_t object.
+ *
+ */
+struct private_ike_header_t {
+ /**
+ * Public interface.
+ */
+ ike_header_t public;
+
+ /**
+ * SPI of the initiator.
+ */
+ u_int64_t initiator_spi;
+
+ /**
+ * SPI of the responder.
+ */
+ u_int64_t responder_spi;
+
+ /**
+ * Next payload type.
+ */
+ u_int8_t next_payload;
+ /**
+ * IKE major version.
+ */
+ u_int8_t maj_version;
+
+ /**
+ * IKE minor version.
+ */
+ u_int8_t min_version;
+
+ /**
+ * Exchange type .
+ */
+ u_int8_t exchange_type;
+
+ /**
+ * Flags of the Message.
+ *
+ */
+ struct {
+ /**
+ * Sender is initiator of the associated IKE_SA_INIT-Exchange.
+ */
+ bool initiator;
+
+ /**
+ * Is protocol supporting higher version?
+ */
+ bool version;
+
+ /**
+ * TRUE, if this is a response, FALSE if its a Request.
+ */
+ bool response;
+ } flags;
+
+ /**
+ * Associated Message-ID.
+ */
+ u_int32_t message_id;
+
+ /**
+ * Length of the whole IKEv2-Message (header and all payloads).
+ */
+ u_int32_t length;
+};
+
+/**
+ * Mappings used to get strings for exchange_type_t.
+ */
+mapping_t exchange_type_m[] = {
+ {EXCHANGE_TYPE_UNDEFINED, "EXCHANGE_TYPE_UNDEFINED"},
+ {IKE_SA_INIT, "IKE_SA_INIT"},
+ {IKE_AUTH, "IKE_AUTH"},
+ {CREATE_CHILD_SA, "CREATE_CHILD_SA"},
+ {INFORMATIONAL, "INFORMATIONAL"}
+};
+
+
+/**
+ * Encoding rules to parse or generate a IKEv2-Header.
+ *
+ * The defined offsets are the positions in a object of type
+ * ike_header_t.
+ *
+ */
+encoding_rule_t ike_header_encodings[] = {
+ /* 8 Byte SPI, stored in the field initiator_spi */
+ { IKE_SPI, offsetof(private_ike_header_t, initiator_spi) },
+ /* 8 Byte SPI, stored in the field responder_spi */
+ { IKE_SPI, offsetof(private_ike_header_t, responder_spi) },
+ /* 1 Byte next payload type, stored in the field next_payload */
+ { U_INT_8, offsetof(private_ike_header_t, next_payload) },
+ /* 4 Bit major version, stored in the field maj_version */
+ { U_INT_4, offsetof(private_ike_header_t, maj_version) },
+ /* 4 Bit minor version, stored in the field min_version */
+ { U_INT_4, offsetof(private_ike_header_t, min_version) },
+ /* 8 Bit for the exchange type */
+ { U_INT_8, offsetof(private_ike_header_t, exchange_type) },
+ /* 2 Bit reserved bits, nowhere stored */
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ /* 3 Bit flags, stored in the fields response, version and initiator */
+ { FLAG, offsetof(private_ike_header_t, flags.response) },
+ { FLAG, offsetof(private_ike_header_t, flags.version) },
+ { FLAG, offsetof(private_ike_header_t, flags.initiator) },
+ /* 3 Bit reserved bits, nowhere stored */
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ /* 4 Byte message id, stored in the field message_id */
+ { U_INT_32, offsetof(private_ike_header_t, message_id) },
+ /* 4 Byte length fied, stored in the field length */
+ { HEADER_LENGTH, offsetof(private_ike_header_t, length) }
+};
+
+
+/* 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! IKE_SA Initiator's SPI !
+ ! !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! IKE_SA Responder's SPI !
+ ! !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Next Payload ! MjVer ! MnVer ! Exchange Type ! Flags !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Message ID !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Length !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+
+/**
+ * Implementation of payload_t.verify.
+ */
+static status_t verify(private_ike_header_t *this)
+{
+ if ((this->exchange_type < IKE_SA_INIT) || (this->exchange_type > INFORMATIONAL))
+ {
+ /* unsupported exchange type */
+ return FAILED;
+ }
+ if (this->initiator_spi == 0)
+ {
+ /* initiator spi not set */
+ return FAILED;
+ }
+
+ /* verification of version is not done in here */
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of payload_t.set_next_type.
+ */
+static void set_next_type(payload_t *this,payload_type_t type)
+{
+ ((private_ike_header_t *)this)->next_payload = type;
+}
+/**
+ * Implementation of ike_header_t.get_initiator_spi.
+ */
+static u_int64_t get_initiator_spi(private_ike_header_t *this)
+{
+ return this->initiator_spi;
+}
+
+/**
+ * Implementation of ike_header_t.set_initiator_spi.
+ */
+static void set_initiator_spi(private_ike_header_t *this, u_int64_t initiator_spi)
+{
+ this->initiator_spi = initiator_spi;
+}
+
+/**
+ * Implementation of ike_header_t.get_responder_spi.
+ */
+static u_int64_t get_responder_spi(private_ike_header_t *this)
+{
+ return this->responder_spi;
+}
+
+/**
+ * Implementation of ike_header_t.set_responder_spi.
+ */
+static void set_responder_spi(private_ike_header_t *this, u_int64_t responder_spi)
+{
+ this->responder_spi = responder_spi;
+}
+
+/**
+ * Implementation of ike_header_t.get_maj_version.
+ */
+static u_int8_t get_maj_version(private_ike_header_t *this)
+{
+ return this->maj_version;
+}
+
+/**
+ * Implementation of ike_header_t.get_min_version.
+ */
+static u_int8_t get_min_version(private_ike_header_t *this)
+{
+ return this->min_version;
+}
+
+/**
+ * Implementation of ike_header_t.get_response_flag.
+ */
+static bool get_response_flag(private_ike_header_t *this)
+{
+ return this->flags.response;
+}
+
+/**
+ * Implementation of ike_header_t.set_response_flag.
+ */
+static void set_response_flag(private_ike_header_t *this, bool response)
+{
+ this->flags.response = response;
+}
+
+/**
+ * Implementation of ike_header_t.get_version_flag.
+ */
+static bool get_version_flag(private_ike_header_t *this)
+{
+ return this->flags.version;
+}
+
+/**
+ * Implementation of ike_header_t.get_initiator_flag.
+ */
+static bool get_initiator_flag(private_ike_header_t *this)
+{
+ return this->flags.initiator;
+}
+
+/**
+ * Implementation of ike_header_t.set_initiator_flag.
+ */
+static void set_initiator_flag(private_ike_header_t *this, bool initiator)
+{
+ this->flags.initiator = initiator;
+}
+
+/**
+ * Implementation of ike_header_t.get_exchange_type.
+ */
+static u_int8_t get_exchange_type(private_ike_header_t *this)
+{
+ return this->exchange_type;
+}
+
+/**
+ * Implementation of ike_header_t.set_exchange_type.
+ */
+static void set_exchange_type(private_ike_header_t *this, u_int8_t exchange_type)
+{
+ this->exchange_type = exchange_type;
+}
+
+/**
+ * Implements ike_header_t's get_message_id function.
+ * See #ike_header_t.get_message_id for description.
+ */
+static u_int32_t get_message_id(private_ike_header_t *this)
+{
+ return this->message_id;
+}
+
+/**
+ * Implementation of ike_header_t.set_message_id.
+ */
+static void set_message_id(private_ike_header_t *this, u_int32_t message_id)
+{
+ this->message_id = message_id;
+}
+
+/**
+ * Implementation of ike_header_t.destroy and payload_t.destroy.
+ */
+static void destroy(ike_header_t *this)
+{
+ free(this);
+}
+
+/**
+ * Implementation of payload_t.get_encoding_rules.
+ */
+static void get_encoding_rules(payload_t *this, encoding_rule_t **rules, size_t *rule_count)
+{
+ *rules = ike_header_encodings;
+ *rule_count = sizeof(ike_header_encodings) / sizeof(encoding_rule_t);
+}
+
+/**
+ * Implementation of payload_t.get_type.
+ */
+static payload_type_t get_type(payload_t *this)
+{
+ return HEADER;
+}
+
+/**
+ * Implementation of payload_t.get_next_type.
+ */
+static payload_type_t get_next_type(payload_t *this)
+{
+ return (((private_ike_header_t*)this)->next_payload);
+}
+
+/**
+ * Implementation of payload_t.get_length.
+ */
+static size_t get_length(payload_t *this)
+{
+ return (((private_ike_header_t*)this)->length);
+}
+
+/*
+ * Described in header.
+ */
+ike_header_t *ike_header_create()
+{
+ private_ike_header_t *this = malloc_thing(private_ike_header_t);
+
+ this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
+ this->public.payload_interface.get_encoding_rules = get_encoding_rules;
+ this->public.payload_interface.get_length = get_length;
+ this->public.payload_interface.get_next_type = get_next_type;
+ this->public.payload_interface.set_next_type = set_next_type;
+ this->public.payload_interface.get_type = get_type;
+ this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
+ this->public.destroy = destroy;
+
+ this->public.get_initiator_spi = (u_int64_t (*) (ike_header_t*))get_initiator_spi;
+ this->public.set_initiator_spi = (void (*) (ike_header_t*,u_int64_t))set_initiator_spi;
+ this->public.get_responder_spi = (u_int64_t (*) (ike_header_t*))get_responder_spi;
+ this->public.set_responder_spi = (void (*) (ike_header_t *,u_int64_t))set_responder_spi;
+ this->public.get_maj_version = (u_int8_t (*) (ike_header_t*))get_maj_version;
+ this->public.get_min_version = (u_int8_t (*) (ike_header_t*))get_min_version;
+ this->public.get_response_flag = (bool (*) (ike_header_t*))get_response_flag;
+ this->public.set_response_flag = (void (*) (ike_header_t*,bool))set_response_flag;
+ this->public.get_version_flag = (bool (*) (ike_header_t*))get_version_flag;
+ this->public.get_initiator_flag = (bool (*) (ike_header_t*))get_initiator_flag;
+ this->public.set_initiator_flag = (void (*) (ike_header_t*,bool))set_initiator_flag;
+ this->public.get_exchange_type = (u_int8_t (*) (ike_header_t*))get_exchange_type;
+ this->public.set_exchange_type = (void (*) (ike_header_t*,u_int8_t))set_exchange_type;
+ this->public.get_message_id = (u_int32_t (*) (ike_header_t*))get_message_id;
+ this->public.set_message_id = (void (*) (ike_header_t*,u_int32_t))set_message_id;
+
+ /* set default values of the fields */
+ this->initiator_spi = 0;
+ this->responder_spi = 0;
+ this->next_payload = 0;
+ this->maj_version = IKE_MAJOR_VERSION;
+ this->min_version = IKE_MINOR_VERSION;
+ this->exchange_type = EXCHANGE_TYPE_UNDEFINED;
+ this->flags.initiator = TRUE;
+ this->flags.version = HIGHER_VERSION_SUPPORTED_FLAG;
+ this->flags.response = FALSE;
+ this->message_id = 0;
+ this->length = IKE_HEADER_LENGTH;
+
+ return (ike_header_t*)this;
+}
diff --git a/programs/charon/charon/encoding/payloads/ike_header.h b/programs/charon/charon/encoding/payloads/ike_header.h
new file mode 100644
index 000000000..ec55f0e18
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/ike_header.h
@@ -0,0 +1,261 @@
+/**
+ * @file ike_header.h
+ *
+ * @brief Interface of ike_header_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef IKE_HEADER_H_
+#define IKE_HEADER_H_
+
+#include <types.h>
+#include <encoding/payloads/payload.h>
+
+/**
+ * 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
+
+typedef enum exchange_type_t exchange_type_t;
+
+/**
+ * @brief Different types of IKE-Exchanges.
+ *
+ * See Draft for different types.
+ *
+ * @ingroup payloads
+ */
+enum exchange_type_t{
+
+ /**
+ * EXCHANGE_TYPE_UNDEFINED. In private space, since not a official message type.
+ */
+ EXCHANGE_TYPE_UNDEFINED = 240,
+
+ /**
+ * IKE_SA_INIT.
+ */
+ IKE_SA_INIT = 34,
+
+ /**
+ * IKE_AUTH.
+ */
+ IKE_AUTH = 35,
+
+ /**
+ * CREATE_CHILD_SA.
+ */
+ CREATE_CHILD_SA = 36,
+
+ /**
+ * INFORMATIONAL.
+ */
+ INFORMATIONAL = 37
+};
+
+/**
+ * string mappings for exchange_type_t
+ *
+ * @ingroup payloads
+ */
+extern mapping_t exchange_type_m[];
+
+
+typedef struct ike_header_t ike_header_t;
+
+/**
+ * @brief 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 {
+ /**
+ * The payload_t interface.
+ */
+ payload_t payload_interface;
+
+ /**
+ * @brief 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.
+ *
+ * @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.
+ *
+ * @param this ike_header_t object
+ * @return responder_spi
+ */
+ u_int64_t (*get_responder_spi) (ike_header_t *this);
+
+ /**
+ * @brief 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.
+ *
+ * @param this ike_header_t object
+ * @return major version
+ */
+ u_int8_t (*get_maj_version) (ike_header_t *this);
+
+ /**
+ * @brief 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.
+ *
+ * @param this ike_header_t object
+ * @return response flag
+ */
+ bool (*get_response_flag) (ike_header_t *this);
+
+ /**
+ * @brief 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.
+ *
+ * @param this ike_header_t object
+ * @return version flag
+ */
+ bool (*get_version_flag) (ike_header_t *this);
+
+ /**
+ * @brief 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.
+ *
+ * @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.
+ *
+ * @param this ike_header_t object
+ * @return exchange type
+ */
+ u_int8_t (*get_exchange_type) (ike_header_t *this);
+
+ /**
+ * @brief 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.
+ *
+ * @param this ike_header_t object
+ * @return message id
+ */
+ u_int32_t (*get_message_id) (ike_header_t *this);
+
+ /**
+ * @brief 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
+ */
+ void (*destroy) (ike_header_t *this);
+};
+
+/**
+ * @brief Create an ike_header_t object
+ *
+ * @return ike_header_t object
+ *
+ * @ingroup payloads
+ */
+ike_header_t *ike_header_create();
+
+#endif /*IKE_HEADER_H_*/
diff --git a/programs/charon/charon/encoding/payloads/ke_payload.c b/programs/charon/charon/encoding/payloads/ke_payload.c
new file mode 100644
index 000000000..0c92e033d
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/ke_payload.c
@@ -0,0 +1,276 @@
+/**
+ * @file ke_payload.c
+ *
+ * @brief Implementation of ke_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stddef.h>
+
+#include "ke_payload.h"
+
+#include <encoding/payloads/encodings.h>
+
+
+typedef struct private_ke_payload_t private_ke_payload_t;
+
+/**
+ * Private data of an ke_payload_t object.
+ *
+ */
+struct private_ke_payload_t {
+ /**
+ * Public ke_payload_t interface.
+ */
+ ke_payload_t public;
+
+ /**
+ * Next payload type.
+ */
+ u_int8_t next_payload;
+
+ /**
+ * Critical flag.
+ */
+ bool critical;
+
+ /**
+ * Length of this payload.
+ */
+ u_int16_t payload_length;
+
+ /**
+ * DH Group Number.
+ */
+ diffie_hellman_group_t dh_group_number;
+
+ /**
+ * Key Exchange Data of this KE payload.
+ */
+ chunk_t key_exchange_data;
+
+ /**
+ * @brief Computes the length of this payload.
+ *
+ * @param this calling private_ke_payload_t object
+ */
+ void (*compute_length) (private_ke_payload_t *this);
+};
+
+/**
+ * Encoding rules to parse or generate a IKEv2-KE Payload.
+ *
+ * The defined offsets are the positions in a object of type
+ * private_ke_payload_t.
+ *
+ */
+encoding_rule_t ke_payload_encodings[] = {
+ /* 1 Byte next payload type, stored in the field next_payload */
+ { U_INT_8, offsetof(private_ke_payload_t, next_payload) },
+ /* the critical bit */
+ { FLAG, offsetof(private_ke_payload_t, critical) },
+ /* 7 Bit reserved bits, nowhere stored */
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ /* Length of the whole payload*/
+ { PAYLOAD_LENGTH, offsetof(private_ke_payload_t, payload_length) },
+ /* DH Group number as 16 bit field*/
+ { U_INT_16, offsetof(private_ke_payload_t, dh_group_number) },
+ { RESERVED_BYTE, 0 },
+ { RESERVED_BYTE, 0 },
+ /* Key Exchange Data is from variable size */
+ { KEY_EXCHANGE_DATA, offsetof(private_ke_payload_t, key_exchange_data)}
+};
+
+/*
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Next Payload !C! RESERVED ! Payload Length !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! DH Group # ! RESERVED !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! !
+ ~ Key Exchange Data ~
+ ! !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+/**
+ * Implementation of payload_t.verify.
+ */
+static status_t verify(private_ke_payload_t *this)
+{
+ /* dh group is not verified in here */
+ return SUCCESS;
+}
+
+/**
+ * Implementation of payload_t.destroy.
+ */
+static void destroy(private_ke_payload_t *this)
+{
+ if (this->key_exchange_data.ptr != NULL)
+ {
+ free(this->key_exchange_data.ptr);
+ }
+ free(this);
+}
+
+/**
+ * Implementation of payload_t.get_encoding_rules.
+ */
+static void get_encoding_rules(private_ke_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
+{
+ *rules = ke_payload_encodings;
+ *rule_count = sizeof(ke_payload_encodings) / sizeof(encoding_rule_t);
+}
+
+/**
+ * Implementation of payload_t.get_type.
+ */
+static payload_type_t get_type(private_ke_payload_t *this)
+{
+ return KEY_EXCHANGE;
+}
+
+/**
+ * Implementation of payload_t.get_next_type.
+ */
+static payload_type_t get_next_type(private_ke_payload_t *this)
+{
+ return (this->next_payload);
+}
+
+/**
+ * Implementation of payload_t.set_next_type.
+ */
+static void set_next_type(private_ke_payload_t *this,payload_type_t type)
+{
+ this->next_payload = type;
+}
+
+/**
+ * Implementation of payload_t.get_length.
+ */
+static size_t get_length(private_ke_payload_t *this)
+{
+ this->compute_length(this);
+ return this->payload_length;
+}
+
+/**
+ * Implementation of private_ke_payload_t.compute_length.
+ */
+static void compute_length (private_ke_payload_t *this)
+{
+ size_t length = KE_PAYLOAD_HEADER_LENGTH;
+ if (this->key_exchange_data.ptr != NULL)
+ {
+ length += this->key_exchange_data.len;
+ }
+ this->payload_length = length;
+}
+
+
+/**
+ * Implementation of ke_payload_t.get_key_exchange_data.
+ */
+static chunk_t get_key_exchange_data(private_ke_payload_t *this)
+{
+ return (this->key_exchange_data);
+}
+
+/**
+ * Implementation of ke_payload_t.set_key_exchange_data.
+ */
+static void set_key_exchange_data(private_ke_payload_t *this, chunk_t key_exchange_data)
+{
+ /* destroy existing data first */
+ if (this->key_exchange_data.ptr != NULL)
+ {
+ /* free existing value */
+ free(this->key_exchange_data.ptr);
+ this->key_exchange_data.ptr = NULL;
+ this->key_exchange_data.len = 0;
+
+ }
+
+ this->key_exchange_data.ptr = clalloc(key_exchange_data.ptr,key_exchange_data.len);
+
+ this->key_exchange_data.len = key_exchange_data.len;
+ this->compute_length(this);
+}
+
+/**
+ * Implementation of ke_payload_t.get_dh_group_number.
+ */
+static diffie_hellman_group_t get_dh_group_number(private_ke_payload_t *this)
+{
+ return this->dh_group_number;
+}
+
+/**
+ * Implementation of ke_payload_t.set_dh_group_number.
+ */
+static void set_dh_group_number(private_ke_payload_t *this, diffie_hellman_group_t dh_group_number)
+{
+ this->dh_group_number = dh_group_number;
+}
+
+/*
+ * Described in header
+ */
+ke_payload_t *ke_payload_create()
+{
+ private_ke_payload_t *this = malloc_thing(private_ke_payload_t);
+
+ /* interface functions */
+ this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
+ this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
+ this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
+ this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
+ this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
+ this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_type;
+ this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
+
+ /* public functions */
+ this->public.get_key_exchange_data = (chunk_t (*) (ke_payload_t *)) get_key_exchange_data;
+ this->public.set_key_exchange_data = (void (*) (ke_payload_t *,chunk_t)) set_key_exchange_data;
+ this->public.get_dh_group_number = (diffie_hellman_group_t (*) (ke_payload_t *)) get_dh_group_number;
+ this->public.set_dh_group_number =(void (*) (ke_payload_t *,diffie_hellman_group_t)) set_dh_group_number;
+ this->public.destroy = (void (*) (ke_payload_t *)) destroy;
+
+ /* private functions */
+ this->compute_length = compute_length;
+
+ /* set default values of the fields */
+ this->critical = FALSE;
+ this->next_payload = NO_PAYLOAD;
+ this->payload_length = KE_PAYLOAD_HEADER_LENGTH;
+ this->key_exchange_data.ptr = NULL;
+ this->key_exchange_data.len = 0;
+ this->dh_group_number = 0;
+
+ return (&(this->public));
+}
diff --git a/programs/charon/charon/encoding/payloads/ke_payload.h b/programs/charon/charon/encoding/payloads/ke_payload.h
new file mode 100644
index 000000000..982d29754
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/ke_payload.h
@@ -0,0 +1,110 @@
+/**
+ * @file ke_payload.h
+ *
+ * @brief Interface of ke_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef KE_PAYLOAD_H_
+#define KE_PAYLOAD_H_
+
+#include <types.h>
+#include <encoding/payloads/payload.h>
+#include <encoding/payloads/transform_substructure.h>
+#include <utils/linked_list.h>
+/**
+ * KE payload length in bytes without any key exchange data.
+ *
+ * @ingroup payloads
+ */
+#define KE_PAYLOAD_HEADER_LENGTH 8
+
+
+typedef struct ke_payload_t ke_payload_t;
+
+/**
+ * @brief 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 {
+ /**
+ * The payload_t interface.
+ */
+ payload_t payload_interface;
+
+ /**
+ * @brief 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.
+ *
+ * @warning Value is getting copied.
+ *
+ * @param this calling ke_payload_t object
+ * @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.
+ *
+ * @param this calling ke_payload_t object
+ * @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.
+ *
+ * @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);
+
+ /**
+ * @brief Destroys an ke_payload_t object.
+ *
+ * @param this ke_payload_t object to destroy
+ */
+ void (*destroy) (ke_payload_t *this);
+};
+
+/**
+ * @brief Creates an empty ke_payload_t object
+ *
+ * @return ke_payload_t object
+ *
+ * @ingroup payloads
+ */
+ke_payload_t *ke_payload_create();
+
+
+#endif /*KE_PAYLOAD_H_*/
diff --git a/programs/charon/charon/encoding/payloads/nonce_payload.c b/programs/charon/charon/encoding/payloads/nonce_payload.c
new file mode 100644
index 000000000..a7528fbfb
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/nonce_payload.c
@@ -0,0 +1,241 @@
+/**
+ * @file nonce_payload.h
+ *
+ * @brief Implementation of nonce_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/* offsetof macro */
+#include <stddef.h>
+
+#include "nonce_payload.h"
+
+#include <encoding/payloads/encodings.h>
+
+
+typedef struct private_nonce_payload_t private_nonce_payload_t;
+
+/**
+ * Private data of an nonce_payload_t object.
+ *
+ */
+struct private_nonce_payload_t {
+ /**
+ * Public nonce_payload_t interface.
+ */
+ nonce_payload_t public;
+
+ /**
+ * Next payload type.
+ */
+ u_int8_t next_payload;
+
+ /**
+ * Critical flag.
+ */
+ bool critical;
+
+ /**
+ * Length of this payload.
+ */
+ u_int16_t payload_length;
+
+ /**
+ * The contained nonce value.
+ */
+ chunk_t nonce;
+
+ /**
+ * @brief Computes the length of this payload.
+ *
+ * @param this calling private_nonce_payload_t object
+ */
+ void (*compute_length) (private_nonce_payload_t *this);
+};
+
+/**
+ * Encoding rules to parse or generate a nonce payload
+ *
+ * The defined offsets are the positions in a object of type
+ * private_nonce_payload_t.
+ *
+ */
+encoding_rule_t nonce_payload_encodings[] = {
+ /* 1 Byte next payload type, stored in the field next_payload */
+ { U_INT_8, offsetof(private_nonce_payload_t, next_payload) },
+ /* the critical bit */
+ { FLAG, offsetof(private_nonce_payload_t, critical) },
+ /* 7 Bit reserved bits, nowhere stored */
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ /* Length of the whole nonce payload*/
+ { PAYLOAD_LENGTH, offsetof(private_nonce_payload_t, payload_length) },
+ /* some nonce bytes, lenth is defined in PAYLOAD_LENGTH */
+ { NONCE_DATA, offsetof(private_nonce_payload_t, nonce) }
+};
+
+/* 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Next Payload !C! RESERVED ! Payload Length !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! !
+ ~ Nonce Data ~
+ ! !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+/**
+ * Implementation of payload_t.verify.
+ */
+static status_t verify(private_nonce_payload_t *this)
+{
+ if ((this->nonce.len < 16) || ((this->nonce.len > 256)))
+ {
+ /* nonce length is wrong */
+ return FAILED;
+ }
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of nonce_payload_t.set_nonce.
+ */
+static status_t set_nonce(private_nonce_payload_t *this, chunk_t nonce)
+{
+ this->nonce.ptr = clalloc(nonce.ptr, nonce.len);
+ this->nonce.len = nonce.len;
+ this->payload_length = NONCE_PAYLOAD_HEADER_LENGTH + nonce.len;
+ return SUCCESS;
+}
+
+/**
+ * Implementation of nonce_payload_t.get_nonce.
+ */
+static chunk_t get_nonce(private_nonce_payload_t *this)
+{
+ chunk_t nonce;
+ nonce.ptr = clalloc(this->nonce.ptr,this->nonce.len);
+ nonce.len = this->nonce.len;
+ return nonce;
+}
+
+/**
+ * Implementation of nonce_payload_t.get_encoding_rules.
+ */
+static void get_encoding_rules(private_nonce_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
+{
+ *rules = nonce_payload_encodings;
+ *rule_count = sizeof(nonce_payload_encodings) / sizeof(encoding_rule_t);
+}
+
+/**
+ * Implementation of payload_t.get_type.
+ */
+static payload_type_t get_type(private_nonce_payload_t *this)
+{
+ return NONCE;
+}
+
+/**
+ * Implementation of payload_t.get_next_type.
+ */
+static payload_type_t get_next_type(private_nonce_payload_t *this)
+{
+ return (this->next_payload);
+}
+
+/**
+ * Implementation of payload_t.set_next_type.
+ */
+static void set_next_type(private_nonce_payload_t *this,payload_type_t type)
+{
+ this->next_payload = type;
+}
+
+/**
+ * Implementation of payload_t.get_length.
+ */
+static size_t get_length(private_nonce_payload_t *this)
+{
+ this->compute_length(this);
+ return this->payload_length;
+}
+
+/**
+ * Implementation of private_id_payload_t.compute_length.
+ */
+static void compute_length(private_nonce_payload_t *this)
+{
+ this->payload_length = NONCE_PAYLOAD_HEADER_LENGTH + this->nonce.len;
+}
+
+/**
+ * Implementation of payload_t.destroy and nonce_payload_t.destroy.
+ */
+static void destroy(private_nonce_payload_t *this)
+{
+ if (this->nonce.ptr != NULL)
+ {
+ free(this->nonce.ptr);
+ }
+
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+nonce_payload_t *nonce_payload_create()
+{
+ private_nonce_payload_t *this = malloc_thing(private_nonce_payload_t);
+
+ /* interface functions */
+ this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
+ this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
+ this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
+ this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
+ this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
+ this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_type;
+ this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
+
+ /* public functions */
+ this->public.destroy = (void (*) (nonce_payload_t *)) destroy;
+ this->public.set_nonce = (void (*) (nonce_payload_t *,chunk_t)) set_nonce;
+ this->public.get_nonce = (chunk_t (*) (nonce_payload_t *)) get_nonce;
+
+ /* private functions */
+ this->compute_length = compute_length;
+
+ /* private variables */
+ this->critical = FALSE;
+ this->next_payload = NO_PAYLOAD;
+ this->payload_length = NONCE_PAYLOAD_HEADER_LENGTH;
+ this->nonce.ptr = NULL;
+ this->nonce.len = 0;
+
+ return (&(this->public));
+}
+
+
diff --git a/programs/charon/charon/encoding/payloads/nonce_payload.h b/programs/charon/charon/encoding/payloads/nonce_payload.h
new file mode 100644
index 000000000..366dfec15
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/nonce_payload.h
@@ -0,0 +1,89 @@
+/**
+ * @file nonce_payload.h
+ *
+ * @brief Interface of nonce_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef NONCE_PAYLOAD_H_
+#define NONCE_PAYLOAD_H_
+
+#include <types.h>
+#include <encoding/payloads/payload.h>
+
+/**
+ * Length of a nonce payload without a nonce in bytes.
+ *
+ * @ingroup payloads
+ */
+#define NONCE_PAYLOAD_HEADER_LENGTH 4
+
+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 {
+ /**
+ * The payload_t interface.
+ */
+ payload_t payload_interface;
+
+ /**
+ * @brief 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.
+ *
+ * @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
+ */
+ void (*destroy) (nonce_payload_t *this);
+};
+
+/**
+ * @brief Creates an empty nonce_payload_t object
+ *
+ * @return nonce_payload_t object
+ *
+ * @ingroup payloads
+ */
+
+nonce_payload_t *nonce_payload_create();
+
+
+#endif /*NONCE_PAYLOAD_H_*/
diff --git a/programs/charon/charon/encoding/payloads/notify_payload.c b/programs/charon/charon/encoding/payloads/notify_payload.c
new file mode 100644
index 000000000..43d0c5322
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/notify_payload.c
@@ -0,0 +1,441 @@
+/**
+ * @file notify_payload.c
+ *
+ * @brief Implementation of notify_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stddef.h>
+
+#include "notify_payload.h"
+
+#include <daemon.h>
+#include <encoding/payloads/encodings.h>
+
+/**
+ * String mappings for notify_message_type_t.
+ */
+mapping_t notify_message_type_m[] = {
+ {UNSUPPORTED_CRITICAL_PAYLOAD, "UNSUPPORTED_CRITICAL_PAYLOAD"},
+ {INVALID_IKE_SPI, "INVALID_IKE_SPI"},
+ {INVALID_MAJOR_VERSION, "INVALID_MAJOR_VERSION"},
+ {INVALID_SYNTAX, "INVALID_SYNTAX"},
+ {INVALID_MESSAGE_ID, "INVALID_MESSAGE_ID"},
+ {INVALID_SPI, "INVALID_SPI"},
+ {NO_PROPOSAL_CHOSEN, "NO_PROPOSAL_CHOSEN"},
+ {INVALID_KE_PAYLOAD, "INVALID_KE_PAYLOAD"},
+ {AUTHENTICATION_FAILED, "AUTHENTICATION_FAILED"},
+ {SINGLE_PAIR_REQUIRED, "SINGLE_PAIR_REQUIRED"},
+ {NO_ADDITIONAL_SAS, "NO_ADDITIONAL_SAS"},
+ {INTERNAL_ADDRESS_FAILURE, "INTERNAL_ADDRESS_FAILURE"},
+ {FAILED_CP_REQUIRED, "FAILED_CP_REQUIRED"},
+ {TS_UACCEPTABLE, "TS_UACCEPTABLE"},
+ {INVALID_SELECTORS, "INVALID_SELECTORS"},
+ {INITIAL_CONTACT, "INITIAL_CONTACT"},
+ {SET_WINDOW_SIZE, "SET_WINDOW_SIZE"},
+ {MAPPING_END, NULL}
+};
+
+typedef struct private_notify_payload_t private_notify_payload_t;
+
+/**
+ * Private data of an notify_payload_t object.
+ *
+ */
+struct private_notify_payload_t {
+ /**
+ * Public notify_payload_t interface.
+ */
+ notify_payload_t public;
+
+ /**
+ * Next payload type.
+ */
+ u_int8_t next_payload;
+
+ /**
+ * Critical flag.
+ */
+ bool critical;
+
+ /**
+ * Length of this payload.
+ */
+ u_int16_t payload_length;
+
+ /**
+ * Protocol id.
+ */
+ u_int8_t protocol_id;
+
+ /**
+ * Spi size.
+ */
+ u_int8_t spi_size;
+
+ /**
+ * Notify message type.
+ */
+ u_int16_t notify_message_type;
+
+ /**
+ * Security parameter index (spi).
+ */
+ chunk_t spi;
+
+ /**
+ * Notification data.
+ */
+ chunk_t notification_data;
+
+ /**
+ * Assigned logger
+ */
+ logger_t *logger;
+
+ /**
+ * @brief Computes the length of this payload.
+ *
+ * @param this calling private_ke_payload_t object
+ */
+ void (*compute_length) (private_notify_payload_t *this);
+};
+
+/**
+ * Encoding rules to parse or generate a IKEv2-Notify Payload.
+ *
+ * The defined offsets are the positions in a object of type
+ * private_notify_payload_t.
+ *
+ */
+encoding_rule_t notify_payload_encodings[] = {
+ /* 1 Byte next payload type, stored in the field next_payload */
+ { U_INT_8, offsetof(private_notify_payload_t, next_payload) },
+ /* the critical bit */
+ { FLAG, offsetof(private_notify_payload_t, critical) },
+ /* 7 Bit reserved bits, nowhere stored */
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ /* Length of the whole payload*/
+ { PAYLOAD_LENGTH, offsetof(private_notify_payload_t, payload_length) },
+ /* Protocol ID as 8 bit field*/
+ { U_INT_8, offsetof(private_notify_payload_t, protocol_id) },
+ /* SPI Size as 8 bit field*/
+ { SPI_SIZE, offsetof(private_notify_payload_t, spi_size) },
+ /* Notify message type as 16 bit field*/
+ { U_INT_16, offsetof(private_notify_payload_t, notify_message_type) },
+ /* SPI as variable length field*/
+ { SPI, offsetof(private_notify_payload_t, spi) },
+ /* Key Exchange Data is from variable size */
+ { NOTIFICATION_DATA, offsetof(private_notify_payload_t, notification_data) }
+};
+
+/*
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Next Payload !C! RESERVED ! Payload Length !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Protocol ID ! SPI Size ! Notify Message Type !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! !
+ ~ Security Parameter Index (SPI) ~
+ ! !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! !
+ ~ Notification Data ~
+ ! !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+/**
+ * Implementation of payload_t.verify.
+ */
+static status_t verify(private_notify_payload_t *this)
+{
+ if (this->protocol_id > 3)
+ {
+ /* reserved for future use */
+ return FAILED;
+ }
+
+ /* TODO: Check all kinds of notify */
+
+ if (this->notify_message_type == INVALID_KE_PAYLOAD)
+ {
+ /* check notification data */
+ diffie_hellman_group_t dh_group;
+ if (this->notification_data.len != 2)
+ {
+ return FAILED;
+ }
+ dh_group = ntohs(*((u_int16_t*)this->notification_data.ptr));
+ switch (dh_group)
+ {
+ case MODP_768_BIT:
+ case MODP_1024_BIT:
+ case MODP_1536_BIT:
+ case MODP_2048_BIT:
+ case MODP_3072_BIT:
+ case MODP_4096_BIT:
+ case MODP_6144_BIT:
+ case MODP_8192_BIT:
+ break;
+ default:
+ this->logger->log(this->logger, ERROR, "Bad DH group (%d)", dh_group);
+ return FAILED;
+ }
+ }
+ return SUCCESS;
+}
+
+/**
+ * Implementation of payload_t.get_encoding_rules.
+ */
+static void get_encoding_rules(private_notify_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
+{
+ *rules = notify_payload_encodings;
+ *rule_count = sizeof(notify_payload_encodings) / sizeof(encoding_rule_t);
+}
+
+/**
+ * Implementation of payload_t.get_type.
+ */
+static payload_type_t get_type(private_notify_payload_t *this)
+{
+ return NOTIFY;
+}
+
+/**
+ * Implementation of payload_t.get_next_type.
+ */
+static payload_type_t get_next_type(private_notify_payload_t *this)
+{
+ return (this->next_payload);
+}
+
+/**
+ * Implementation of payload_t.set_next_type.
+ */
+static void set_next_type(private_notify_payload_t *this,payload_type_t type)
+{
+ this->next_payload = type;
+}
+
+/**
+ * Implementation of payload_t.get_length.
+ */
+static size_t get_length(private_notify_payload_t *this)
+{
+ this->compute_length(this);
+ return this->payload_length;
+}
+
+/**
+ * Implementation of private_notify_payload_t.compute_length.
+ */
+static void compute_length (private_notify_payload_t *this)
+{
+ size_t length = NOTIFY_PAYLOAD_HEADER_LENGTH;
+ if (this->notification_data.ptr != NULL)
+ {
+ length += this->notification_data.len;
+ }
+ if (this->spi.ptr != NULL)
+ {
+ length += this->spi.len;
+ }
+
+ this->payload_length = length;
+
+}
+
+/**
+ * Implementation of notify_payload_t.get_protocol_id.
+ */
+static u_int8_t get_protocol_id(private_notify_payload_t *this)
+{
+ return this->protocol_id;
+}
+
+/**
+ * Implementation of notify_payload_t.set_protocol_id.
+ */
+static void set_protocol_id(private_notify_payload_t *this, u_int8_t protocol_id)
+{
+ this->protocol_id = protocol_id;
+}
+
+/**
+ * Implementation of notify_payload_t.get_notify_message_type.
+ */
+static u_int16_t get_notify_message_type(private_notify_payload_t *this)
+{
+ return this->notify_message_type;
+}
+
+/**
+ * Implementation of notify_payload_t.set_notify_message_type.
+ */
+static void set_notify_message_type(private_notify_payload_t *this, u_int16_t notify_message_type)
+{
+ this->notify_message_type = notify_message_type;
+}
+
+/**
+ * Implementation of notify_payload_t.get_spi.
+ */
+static chunk_t get_spi(private_notify_payload_t *this)
+{
+ return (this->spi);
+}
+
+/**
+ * Implementation of notify_payload_t.set_spi.
+ */
+static void set_spi(private_notify_payload_t *this, chunk_t spi)
+{
+ /* destroy existing data first */
+ if (this->spi.ptr != NULL)
+ {
+ /* free existing value */
+ free(this->spi.ptr);
+ this->spi.ptr = NULL;
+ this->spi.len = 0;
+
+ }
+
+ this->spi.ptr = clalloc(spi.ptr,spi.len);
+
+ this->spi.len = spi.len;
+ this->spi_size = spi.len;
+ this->compute_length(this);
+
+}
+
+/**
+ * Implementation of notify_payload_t.get_notification_data.
+ */
+static chunk_t get_notification_data(private_notify_payload_t *this)
+{
+ return (this->notification_data);
+}
+
+/**
+ * Implementation of notify_payload_t.set_notification_data.
+ */
+static status_t set_notification_data(private_notify_payload_t *this, chunk_t notification_data)
+{
+ /* destroy existing data first */
+ if (this->notification_data.ptr != NULL)
+ {
+ /* free existing value */
+ free(this->notification_data.ptr);
+ this->notification_data.ptr = NULL;
+ this->notification_data.len = 0;
+
+ }
+
+ this->notification_data.ptr = clalloc(notification_data.ptr,notification_data.len);
+ this->notification_data.len = notification_data.len;
+ this->compute_length(this);
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of notify_payload_t.destroy and notify_payload_t.destroy.
+ */
+static status_t destroy(private_notify_payload_t *this)
+{
+ if (this->notification_data.ptr != NULL)
+ {
+ free(this->notification_data.ptr);
+ }
+ if (this->spi.ptr != NULL)
+ {
+ free(this->spi.ptr);
+ }
+
+ free(this);
+ return SUCCESS;
+}
+
+/*
+ * Described in header
+ */
+notify_payload_t *notify_payload_create()
+{
+ private_notify_payload_t *this = malloc_thing(private_notify_payload_t);
+
+ /* interface functions */
+ this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
+ this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
+ this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
+ this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
+ this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
+ this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_type;
+ this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
+
+ /* public functions */
+ this->public.get_protocol_id = (u_int8_t (*) (notify_payload_t *)) get_protocol_id;
+ this->public.set_protocol_id = (void (*) (notify_payload_t *,u_int8_t)) set_protocol_id;
+ this->public.get_notify_message_type = (u_int16_t (*) (notify_payload_t *)) get_notify_message_type;
+ this->public.set_notify_message_type = (void (*) (notify_payload_t *,u_int16_t)) set_notify_message_type;
+ this->public.get_spi = (chunk_t (*) (notify_payload_t *)) get_spi;
+ this->public.set_spi = (void (*) (notify_payload_t *,chunk_t)) set_spi;
+ this->public.get_notification_data = (chunk_t (*) (notify_payload_t *)) get_notification_data;
+ this->public.set_notification_data = (void (*) (notify_payload_t *,chunk_t)) set_notification_data;
+ this->public.destroy = (void (*) (notify_payload_t *)) destroy;
+
+ /* private functions */
+ this->compute_length = compute_length;
+
+ /* set default values of the fields */
+ this->critical = FALSE;
+ this->next_payload = NO_PAYLOAD;
+ this->payload_length = NOTIFY_PAYLOAD_HEADER_LENGTH;
+ this->protocol_id = 0;
+ this->notify_message_type = 0;
+ this->spi.ptr = NULL;
+ this->spi.len = 0;
+ this->spi_size = 0;
+ this->notification_data.ptr = NULL;
+ this->notification_data.len = 0;
+ this->logger = logger_manager->get_logger(logger_manager, PAYLOAD);
+
+ return (&(this->public));
+}
+
+/*
+ * Described in header.
+ */
+notify_payload_t *notify_payload_create_from_protocol_and_type(protocol_id_t protocol_id, notify_message_type_t notify_message_type)
+{
+ notify_payload_t *notify = notify_payload_create();
+
+ notify->set_notify_message_type(notify,notify_message_type);
+ notify->set_protocol_id(notify,protocol_id);
+
+ return notify;
+}
diff --git a/programs/charon/charon/encoding/payloads/notify_payload.h b/programs/charon/charon/encoding/payloads/notify_payload.h
new file mode 100644
index 000000000..093f99144
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/notify_payload.h
@@ -0,0 +1,200 @@
+/**
+ * @file notify_payload.h
+ *
+ * @brief Interface of notify_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#ifndef NOTIFY_PAYLOAD_H_
+#define NOTIFY_PAYLOAD_H_
+
+#include <types.h>
+#include <encoding/payloads/payload.h>
+#include <encoding/payloads/proposal_substructure.h>
+#include <utils/linked_list.h>
+
+/**
+ * Notify payload length in bytes without any spi and notification data.
+ *
+ * @ingroup payloads
+ */
+#define NOTIFY_PAYLOAD_HEADER_LENGTH 8
+
+typedef enum notify_message_type_t notify_message_type_t;
+
+
+/**
+ * @brief Notify message types.
+ *
+ * See IKEv2 RFC 3.10.1.
+ *
+ * @ingroup payloads
+ */
+enum notify_message_type_t {
+ UNSUPPORTED_CRITICAL_PAYLOAD = 1,
+ INVALID_IKE_SPI = 4,
+ INVALID_MAJOR_VERSION = 5,
+ INVALID_SYNTAX = 7,
+ INVALID_MESSAGE_ID = 9,
+ INVALID_SPI = 11,
+ NO_PROPOSAL_CHOSEN = 14,
+ INVALID_KE_PAYLOAD = 17,
+ AUTHENTICATION_FAILED = 24,
+ SINGLE_PAIR_REQUIRED = 34,
+ NO_ADDITIONAL_SAS = 35,
+ INTERNAL_ADDRESS_FAILURE = 36,
+ FAILED_CP_REQUIRED = 37,
+ TS_UACCEPTABLE = 38,
+ INVALID_SELECTORS = 39,
+
+ INITIAL_CONTACT = 16384,
+ SET_WINDOW_SIZE = 16385
+};
+
+/**
+ * String mappings for notify_message_type_t.
+ *
+ * @ingroup payloads
+ */
+extern mapping_t notify_message_type_m[];
+
+
+typedef struct notify_payload_t notify_payload_t;
+
+/**
+ * @brief 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 {
+ /**
+ * The payload_t interface.
+ */
+ payload_t payload_interface;
+
+ /**
+ * @brief 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.
+ *
+ * @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.
+ *
+ * @param this calling notify_payload_t object
+ * @return notify message type of this payload
+ */
+ u_int16_t (*get_notify_message_type) (notify_payload_t *this);
+
+ /**
+ * @brief Sets notify message type of this payload.
+ *
+ * @param this calling notify_payload_t object
+ * @param notify_message_type notify message type to set
+ */
+ void (*set_notify_message_type) (notify_payload_t *this, u_int16_t notify_message_type);
+
+ /**
+ * @brief Returns the currently set spi of this payload.
+ *
+ * @warning Returned data are not copied.
+ *
+ * @param this calling notify_payload_t object
+ * @return chunk_t pointing to the value
+ */
+ chunk_t (*get_spi) (notify_payload_t *this);
+
+ /**
+ * @brief Sets the spi of this payload.
+ *
+ * @warning Value is getting copied.
+ *
+ * @param this calling notify_payload_t object
+ * @param spi chunk_t pointing to the value to set
+ */
+ void (*set_spi) (notify_payload_t *this, chunk_t spi);
+
+ /**
+ * @brief Returns the currently set notification data of payload.
+ *
+ * @warning 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.
+ *
+ * @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);
+
+ /**
+ * @brief Destroys an notify_payload_t object.
+ *
+ * @param this notify_payload_t object to destroy
+ */
+ void (*destroy) (notify_payload_t *this);
+};
+
+/**
+ * @brief Creates an empty notify_payload_t object
+ *
+ * @return created notify_payload_t object
+ *
+ * @ingroup payloads
+ */
+notify_payload_t *notify_payload_create();
+
+/**
+ * @brief Creates an notify_payload_t object of specific type for specific protocol id.
+ *
+ * @param protocol_id protocol id (IKE, AH or ESP)
+ * @param notify_message_type notify type (see notify_message_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_message_type_t notify_message_type);
+
+
+#endif /*NOTIFY_PAYLOAD_H_*/
diff --git a/programs/charon/charon/encoding/payloads/payload.c b/programs/charon/charon/encoding/payloads/payload.c
new file mode 100644
index 000000000..b89e80a53
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/payload.c
@@ -0,0 +1,131 @@
+/**
+ * @file payload.c
+ *
+ * @brief Generic constructor to the payload_t interface.
+ *
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#include "payload.h"
+
+#include <encoding/payloads/ike_header.h>
+#include <encoding/payloads/sa_payload.h>
+#include <encoding/payloads/nonce_payload.h>
+#include <encoding/payloads/id_payload.h>
+#include <encoding/payloads/ke_payload.h>
+#include <encoding/payloads/notify_payload.h>
+#include <encoding/payloads/auth_payload.h>
+#include <encoding/payloads/cert_payload.h>
+#include <encoding/payloads/certreq_payload.h>
+#include <encoding/payloads/encryption_payload.h>
+#include <encoding/payloads/ts_payload.h>
+#include <encoding/payloads/delete_payload.h>
+#include <encoding/payloads/vendor_id_payload.h>
+#include <encoding/payloads/cp_payload.h>
+#include <encoding/payloads/configuration_attribute.h>
+#include <encoding/payloads/eap_payload.h>
+#include <encoding/payloads/unknown_payload.h>
+
+/*
+ * build the mappings for payload_type_t
+ */
+mapping_t payload_type_m[] = {
+ {NO_PAYLOAD, "NO_PAYLOAD"},
+ {SECURITY_ASSOCIATION, "SECURITY_ASSOCIATION"},
+ {KEY_EXCHANGE, "KEY_EXCHANGE"},
+ {ID_INITIATOR, "ID_INITIATOR"},
+ {ID_RESPONDER, "ID_RESPONDER"},
+ {CERTIFICATE, "CERTIFICATE"},
+ {CERTIFICATE_REQUEST, "CERTIFICATE_REQUEST"},
+ {AUTHENTICATION, "AUTHENTICATION"},
+ {NONCE, "NONCE"},
+ {NOTIFY, "NOTIFY"},
+ {DELETE, "DELETE"},
+ {VENDOR_ID, "VENDOR_ID"},
+ {TRAFFIC_SELECTOR_INITIATOR, "TRAFFIC_SELECTOR_INITIATOR"},
+ {TRAFFIC_SELECTOR_RESPONDER, "TRAFFIC_SELECTOR_RESPONDER"},
+ {ENCRYPTED, "ENCRYPTED"},
+ {CONFIGURATION, "CONFIGURATION"},
+ {EXTENSIBLE_AUTHENTICATION, "EXTENSIBLE_AUTHENTICATION"},
+ {HEADER, "HEADER"},
+ {PROPOSAL_SUBSTRUCTURE, "PROPOSAL_SUBSTRUCTURE"},
+ {TRANSFORM_SUBSTRUCTURE, "TRANSFORM_SUBSTRUCTURE"},
+ {TRANSFORM_ATTRIBUTE, "TRANSFORM_ATTRIBUTE"},
+ {TRAFFIC_SELECTOR_SUBSTRUCTURE, "TRAFFIC_SELECTOR_SUBSTRUCTURE"},
+ {CONFIGURATION_ATTRIBUTE,"CONFIGURATION_ATTRIBUTE"},
+ {UNKNOWN_PAYLOAD,"UNKNOWN_PAYLOAD"},
+ {MAPPING_END, NULL}
+};
+
+/*
+ * see header
+ */
+payload_t *payload_create(payload_type_t type)
+{
+ switch (type)
+ {
+ case HEADER:
+ return (payload_t*)ike_header_create();
+ case SECURITY_ASSOCIATION:
+ return (payload_t*)sa_payload_create();
+ case PROPOSAL_SUBSTRUCTURE:
+ return (payload_t*)proposal_substructure_create();
+ case TRANSFORM_SUBSTRUCTURE:
+ return (payload_t*)transform_substructure_create();
+ case TRANSFORM_ATTRIBUTE:
+ return (payload_t*)transform_attribute_create();
+ case NONCE:
+ return (payload_t*)nonce_payload_create();
+ case ID_INITIATOR:
+ return (payload_t*)id_payload_create(TRUE);
+ case ID_RESPONDER:
+ return (payload_t*)id_payload_create(FALSE);
+ case AUTHENTICATION:
+ return (payload_t*)auth_payload_create();
+ case CERTIFICATE:
+ return (payload_t*)cert_payload_create();
+ case CERTIFICATE_REQUEST:
+ return (payload_t*)certreq_payload_create();
+ case TRAFFIC_SELECTOR_SUBSTRUCTURE:
+ return (payload_t*)traffic_selector_substructure_create();
+ case TRAFFIC_SELECTOR_INITIATOR:
+ return (payload_t*)ts_payload_create(TRUE);
+ case TRAFFIC_SELECTOR_RESPONDER:
+ return (payload_t*)ts_payload_create(FALSE);
+ case KEY_EXCHANGE:
+ return (payload_t*)ke_payload_create();
+ case NOTIFY:
+ return (payload_t*)notify_payload_create();
+ case DELETE:
+ return (payload_t*)delete_payload_create();
+ case VENDOR_ID:
+ return (payload_t*)vendor_id_payload_create();
+ case CONFIGURATION:
+ return (payload_t*)cp_payload_create();
+ case CONFIGURATION_ATTRIBUTE:
+ return (payload_t*)configuration_attribute_create();
+ case EXTENSIBLE_AUTHENTICATION:
+ return (payload_t*)eap_payload_create();
+ case ENCRYPTED:
+ return (payload_t*)encryption_payload_create();
+ default:
+ return (payload_t*)unknown_payload_create();
+ }
+}
+
diff --git a/programs/charon/charon/encoding/payloads/payload.h b/programs/charon/charon/encoding/payloads/payload.h
new file mode 100644
index 000000000..fc3457832
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/payload.h
@@ -0,0 +1,279 @@
+/**
+ * @file payload.h
+ *
+ * @brief Interface payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef PAYLOAD_H_
+#define PAYLOAD_H_
+
+#include <types.h>
+#include <definitions.h>
+#include <encoding/payloads/encodings.h>
+
+
+typedef enum payload_type_t payload_type_t;
+
+/**
+ * @brief 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{
+
+ /**
+ * End of payload list in next_payload
+ */
+ NO_PAYLOAD = 0,
+
+ /**
+ * The security association (SA) payload containing proposals.
+ */
+ SECURITY_ASSOCIATION = 33,
+
+ /**
+ * The key exchange (KE) payload containing diffie-hellman values.
+ */
+ KEY_EXCHANGE = 34,
+
+ /**
+ * Identification for the original initiator (IDi).
+ */
+ ID_INITIATOR = 35,
+
+ /**
+ * Identification for the original responder (IDr).
+ */
+ ID_RESPONDER = 36,
+
+ /**
+ * Certificate payload with certificates (CERT).
+ */
+ CERTIFICATE = 37,
+
+ /**
+ * Certificate request payload (CERTREQ).
+ */
+ CERTIFICATE_REQUEST = 38,
+
+ /**
+ * Authentication payload contains auth data (AUTH).
+ */
+ AUTHENTICATION = 39,
+
+ /**
+ * Nonces, for initator and responder (Ni, Nr, N)
+ */
+ NONCE = 40,
+
+ /**
+ * Notif paylaod (N).
+ */
+ NOTIFY = 41,
+
+ /**
+ * Delete payload (D)
+ */
+ DELETE = 42,
+
+ /**
+ * Vendor id paylpoad (V).
+ */
+ VENDOR_ID = 43,
+
+ /**
+ * Traffic selector for the original initiator (TSi).
+ */
+ TRAFFIC_SELECTOR_INITIATOR = 44,
+
+ /**
+ * Traffic selector for the original responser (TSr).
+ */
+ TRAFFIC_SELECTOR_RESPONDER = 45,
+
+ /**
+ * Encryption payload, contains other payloads (E).
+ */
+ ENCRYPTED = 46,
+
+ /**
+ * Configuration payload (CP).
+ */
+ CONFIGURATION = 47,
+
+ /**
+ * Extensible authentication payload (EAP).
+ */
+ EXTENSIBLE_AUTHENTICATION = 48,
+
+ /**
+ * Header has a value of PRIVATE USE space.
+ *
+ * This payload type is not send over wire and just
+ * used internally to handle IKEv2-Header like a payload.
+ */
+ HEADER = 140,
+
+ /**
+ * PROPOSAL_SUBSTRUCTURE has a value of PRIVATE USE space.
+ *
+ * This payload type is not send over wire and just
+ * used internally to handle a proposal substructure like a payload.
+ */
+ PROPOSAL_SUBSTRUCTURE = 141,
+
+ /**
+ * TRANSFORM_SUBSTRUCTURE has a value of PRIVATE USE space.
+ *
+ * This payload type is not send over wire and just
+ * used internally to handle a transform substructure like a payload.
+ */
+ TRANSFORM_SUBSTRUCTURE = 142,
+
+ /**
+ * TRANSFORM_ATTRIBUTE has a value of PRIVATE USE space.
+ *
+ * This payload type is not send over wire and just
+ * used internally to handle a transform attribute like a payload.
+ */
+ TRANSFORM_ATTRIBUTE = 143,
+
+ /**
+ * TRAFFIC_SELECTOR_SUBSTRUCTURE has a value of PRIVATE USE space.
+ *
+ * This payload type is not send over wire and just
+ * used internally to handle a transform selector like a payload.
+ */
+ TRAFFIC_SELECTOR_SUBSTRUCTURE = 144,
+
+ /**
+ * CONFIGURATION_ATTRIBUTE has a value of PRIVATE USE space.
+ *
+ * This payload type is not send over wire and just
+ * used internally to handle a transform attribute like a payload.
+ */
+ CONFIGURATION_ATTRIBUTE = 145,
+
+ /**
+ * A unknown payload has a value of PRIVATE USE space.
+ *
+ * This payload type is not send over wire and just
+ * used internally to handle a unknown payload.
+ */
+ UNKNOWN_PAYLOAD = 146,
+};
+
+
+/**
+ * String mappings for payload_type_t.
+ */
+extern mapping_t payload_type_m[];
+
+
+typedef struct payload_t payload_t;
+
+/**
+ * @brief 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 instanciate.
+ *
+ * @ingroup payloads
+ */
+struct payload_t {
+
+ /**
+ * @brief 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
+ */
+ void (*get_encoding_rules) (payload_t *this, encoding_rule_t **rules, size_t *rule_count);
+
+ /**
+ * @brief Get type of payload.
+ *
+ * @param this calling object
+ * @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.
+ *
+ * @param this calling object
+ * @return type of next payload
+ */
+ payload_type_t (*get_next_type) (payload_t *this);
+
+ /**
+ * @brief Set type of next payload.
+ *
+ * @param this calling object
+ * @param type type of next payload
+ */
+ void (*set_next_type) (payload_t *this,payload_type_t type);
+
+ /**
+ * @brief Get length of payload.
+ *
+ * @param this calling object
+ * @return length of this payload
+ */
+ size_t (*get_length) (payload_t *this);
+
+ /**
+ * @brief Verifies payload structure and makes consistence check.
+ *
+ * @param this calling object
+ * @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
+ */
+ void (*destroy) (payload_t *this);
+};
+
+/**
+ * @brief Create an empty payload.
+ *
+ * Useful for the parser, who wants a generic constructor for all payloads.
+ * It supports all payload_t methods. If a payload type is not known,
+ * an unknwon_paylod is created with the chunk of data in it.
+ *
+ * @param type type of the payload to create
+ * @return payload_t object
+ */
+payload_t *payload_create(payload_type_t type);
+
+#endif /*PAYLOAD_H_*/
diff --git a/programs/charon/charon/encoding/payloads/proposal_substructure.c b/programs/charon/charon/encoding/payloads/proposal_substructure.c
new file mode 100644
index 000000000..cb3c695b2
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/proposal_substructure.c
@@ -0,0 +1,629 @@
+/**
+ * @file proposal_substructure.h
+ *
+ * @brief Implementation of proposal_substructure_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stddef.h>
+
+#include "proposal_substructure.h"
+
+#include <encoding/payloads/encodings.h>
+#include <encoding/payloads/transform_substructure.h>
+#include <types.h>
+#include <utils/linked_list.h>
+
+
+/**
+ * IKEv1 Value for a proposal payload.
+ */
+#define PROPOSAL_TYPE_VALUE 2
+
+
+typedef struct private_proposal_substructure_t private_proposal_substructure_t;
+
+/**
+ * Private data of an proposal_substructure_t object.
+ *
+ */
+struct private_proposal_substructure_t {
+ /**
+ * Public proposal_substructure_t interface.
+ */
+ proposal_substructure_t public;
+
+ /**
+ * Next payload type.
+ */
+ u_int8_t next_payload;
+
+ /**
+ * Length of this payload.
+ */
+ u_int16_t proposal_length;
+
+ /**
+ * Proposal number.
+ */
+ u_int8_t proposal_number;
+
+ /**
+ * Protocol ID.
+ */
+ u_int8_t protocol_id;
+
+ /**
+ * SPI size of the following SPI.
+ */
+ u_int8_t spi_size;
+
+ /**
+ * Number of transforms.
+ */
+ u_int8_t transforms_count;
+
+ /**
+ * SPI is stored as chunk.
+ */
+ chunk_t spi;
+
+ /**
+ * Transforms are stored in a linked_list_t.
+ */
+ linked_list_t * transforms;
+
+ /**
+ * @brief Computes the length of this substructure.
+ *
+ * @param this calling private_proposal_substructure_t object
+ */
+ void (*compute_length) (private_proposal_substructure_t *this);
+};
+
+/**
+ * Encoding rules to parse or generate a Proposal substructure.
+ *
+ * The defined offsets are the positions in a object of type
+ * private_proposal_substructure_t.
+ *
+ */
+encoding_rule_t proposal_substructure_encodings[] = {
+ /* 1 Byte next payload type, stored in the field next_payload */
+ { U_INT_8, offsetof(private_proposal_substructure_t, next_payload) },
+ /* Reserved Byte is skipped */
+ { RESERVED_BYTE, 0 },
+ /* Length of the whole proposal substructure payload*/
+ { PAYLOAD_LENGTH, offsetof(private_proposal_substructure_t, proposal_length) },
+ /* proposal number is a number of 8 bit */
+ { U_INT_8, offsetof(private_proposal_substructure_t, proposal_number) },
+ /* protocol ID is a number of 8 bit */
+ { U_INT_8, offsetof(private_proposal_substructure_t, protocol_id) },
+ /* SPI Size has its own type */
+ { SPI_SIZE, offsetof(private_proposal_substructure_t, spi_size) },
+ /* Number of transforms is a number of 8 bit */
+ { U_INT_8, offsetof(private_proposal_substructure_t, transforms_count) },
+ /* SPI is a chunk of variable size*/
+ { SPI, offsetof(private_proposal_substructure_t, spi) },
+ /* Transforms are stored in a transform substructure,
+ offset points to a linked_list_t pointer */
+ { TRANSFORMS, offsetof(private_proposal_substructure_t, transforms) }
+};
+
+/*
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! 0 (last) or 2 ! RESERVED ! Proposal Length !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Proposal # ! Protocol ID ! SPI Size !# of Transforms!
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ~ SPI (variable) ~
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! !
+ ~ <Transforms> ~
+ ! !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+/**
+ * Implementation of payload_t.verify.
+ */
+static status_t verify(private_proposal_substructure_t *this)
+{
+ status_t status = SUCCESS;
+ iterator_t *iterator;
+
+ if ((this->next_payload != NO_PAYLOAD) && (this->next_payload != 2))
+ {
+ /* must be 0 or 2 */
+ return FAILED;
+ }
+ if (this->transforms_count != this->transforms->get_count(this->transforms))
+ {
+ /* must be the same! */
+ return FAILED;
+ }
+
+ if ((this->protocol_id == 0) || (this->protocol_id >= 4))
+ {
+ /* reserved are not supported */
+ return FAILED;
+ }
+
+ iterator = this->transforms->create_iterator(this->transforms,TRUE);
+
+ while(iterator->has_next(iterator))
+ {
+ payload_t *current_transform;
+ iterator->current(iterator,(void **)&current_transform);
+
+ status = current_transform->verify(current_transform);
+ if (status != SUCCESS)
+ {
+ break;
+ }
+ }
+
+ iterator->destroy(iterator);
+
+
+ /* proposal number is checked in SA payload */
+ return status;
+}
+
+/**
+ * Implementation of payload_t.get_encoding_rules.
+ */
+static void get_encoding_rules(private_proposal_substructure_t *this, encoding_rule_t **rules, size_t *rule_count)
+{
+ *rules = proposal_substructure_encodings;
+ *rule_count = sizeof(proposal_substructure_encodings) / sizeof(encoding_rule_t);
+}
+
+/**
+ * Implementation of payload_t.get_type.
+ */
+static payload_type_t get_type(private_proposal_substructure_t *this)
+{
+ return PROPOSAL_SUBSTRUCTURE;
+}
+
+/**
+ * Implementation of payload_t.get_next_type.
+ */
+static payload_type_t get_next_type(private_proposal_substructure_t *this)
+{
+ return (this->next_payload);
+}
+
+/**
+ * Implementation of payload_t.set_next_type.
+ */
+static void set_next_type(private_proposal_substructure_t *this,payload_type_t type)
+{
+}
+
+/**
+ * Implementation of payload_t.get_length.
+ */
+static size_t get_length(private_proposal_substructure_t *this)
+{
+ this->compute_length(this);
+ return this->proposal_length;
+}
+
+/**
+ * Implementation of proposal_substructure_t.create_transform_substructure_iterator.
+ */
+static iterator_t *create_transform_substructure_iterator (private_proposal_substructure_t *this,bool forward)
+{
+ return (this->transforms->create_iterator(this->transforms,forward));
+}
+
+/**
+ * Implementation of proposal_substructure_t.add_transform_substructure.
+ */
+static void add_transform_substructure (private_proposal_substructure_t *this,transform_substructure_t *transform)
+{
+ status_t status;
+ if (this->transforms->get_count(this->transforms) > 0)
+ {
+ transform_substructure_t *last_transform;
+ status = this->transforms->get_last(this->transforms,(void **) &last_transform);
+ /* last transform is now not anymore last one */
+ last_transform->set_is_last_transform(last_transform,FALSE);
+
+ }
+ transform->set_is_last_transform(transform,TRUE);
+
+ this->transforms->insert_last(this->transforms,(void *) transform);
+ this->compute_length(this);
+}
+
+/**
+ * Implementation of proposal_substructure_t.proposal_substructure_t.
+ */
+static void set_is_last_proposal (private_proposal_substructure_t *this, bool is_last)
+{
+ this->next_payload = (is_last) ? 0: PROPOSAL_TYPE_VALUE;
+}
+
+
+/**
+ * Implementation of proposal_substructure_t.set_proposal_number.
+ */
+static void set_proposal_number(private_proposal_substructure_t *this,u_int8_t proposal_number)
+{
+ this->proposal_number = proposal_number;
+}
+
+/**
+ * Implementation of proposal_substructure_t.get_proposal_number.
+ */
+static u_int8_t get_proposal_number (private_proposal_substructure_t *this)
+{
+ return (this->proposal_number);
+}
+
+/**
+ * Implementation of proposal_substructure_t.set_protocol_id.
+ */
+static void set_protocol_id(private_proposal_substructure_t *this,u_int8_t protocol_id)
+{
+ this->protocol_id = protocol_id;
+}
+
+/**
+ * Implementation of proposal_substructure_t.get_protocol_id.
+ */
+static u_int8_t get_protocol_id (private_proposal_substructure_t *this)
+{
+ return (this->protocol_id);
+}
+
+/**
+ * Implementation of proposal_substructure_t.set_spi.
+ */
+static void set_spi (private_proposal_substructure_t *this, chunk_t spi)
+{
+ /* first delete already set spi value */
+ if (this->spi.ptr != NULL)
+ {
+ free(this->spi.ptr);
+ this->spi.ptr = NULL;
+ this->spi.len = 0;
+ this->compute_length(this);
+ }
+
+ this->spi.ptr = clalloc(spi.ptr,spi.len);
+ this->spi.len = spi.len;
+ this->spi_size = spi.len;
+ this->compute_length(this);
+}
+
+/**
+ * Implementation of proposal_substructure_t.get_spi.
+ */
+static chunk_t get_spi (private_proposal_substructure_t *this)
+{
+ chunk_t spi;
+ spi.ptr = this->spi.ptr;
+ spi.len = this->spi.len;
+
+ return spi;
+}
+
+/**
+ * Implementation of proposal_substructure_t.get_info_for_transform_type.
+ */
+static status_t get_info_for_transform_type (private_proposal_substructure_t *this,transform_type_t type, u_int16_t *transform_id, u_int16_t *key_length)
+{
+ iterator_t *iterator;
+ status_t status;
+ u_int16_t found_transform_id;
+ u_int16_t found_key_length;
+
+ iterator = this->transforms->create_iterator(this->transforms,TRUE);
+
+ while (iterator->has_next(iterator))
+ {
+ transform_substructure_t *current_transform;
+ status = iterator->current(iterator,(void **) &current_transform);
+ if (status != SUCCESS)
+ {
+ break;
+ }
+ if (current_transform->get_transform_type(current_transform) == type)
+ {
+ /* now get data for specific type */
+ found_transform_id = current_transform->get_transform_id(current_transform);
+ status = current_transform->get_key_length(current_transform,&found_key_length);
+ *transform_id = found_transform_id;
+ *key_length = found_key_length;
+ iterator->destroy(iterator);
+ return status;
+ }
+ }
+ iterator->destroy(iterator);
+ return NOT_FOUND;
+}
+
+/**
+ * Implementation of private_proposal_substructure_t.compute_length.
+ */
+static void compute_length (private_proposal_substructure_t *this)
+{
+ iterator_t *iterator;
+ size_t transforms_count = 0;
+ size_t length = PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH;
+ iterator = this->transforms->create_iterator(this->transforms,TRUE);
+ while (iterator->has_next(iterator))
+ {
+ payload_t * current_transform;
+ iterator->current(iterator,(void **) &current_transform);
+ length += current_transform->get_length(current_transform);
+ transforms_count++;
+ }
+ iterator->destroy(iterator);
+
+ length += this->spi.len;
+ this->transforms_count = transforms_count;
+ this->proposal_length = length;
+}
+
+/**
+ * Implementation of proposal_substructure_t.get_transform_count.
+ */
+static size_t get_transform_count (private_proposal_substructure_t *this)
+{
+ return this->transforms->get_count(this->transforms);
+}
+
+/**
+ * Implementation of proposal_substructure_t.get_spi_size.
+ */
+static size_t get_spi_size (private_proposal_substructure_t *this)
+{
+ return this->spi.len;
+}
+
+/**
+ * Implementation of proposal_substructure_t.add_to_proposal.
+ */
+void add_to_proposal(private_proposal_substructure_t *this, proposal_t *proposal)
+{
+ iterator_t *iterator = this->transforms->create_iterator(this->transforms, TRUE);
+ u_int32_t spi;
+
+
+ while (iterator->has_next(iterator))
+ {
+ transform_substructure_t *transform;
+ transform_type_t transform_type;
+ u_int16_t transform_id;
+ u_int16_t key_length = 0;
+
+ iterator->current(iterator, (void**)&transform);
+
+ transform_type = transform->get_transform_type(transform);
+ transform_id = transform->get_transform_id(transform);
+ transform->get_key_length(transform, &key_length);
+
+ proposal->add_algorithm(proposal, this->protocol_id, transform_type, transform_id, key_length);
+ }
+ iterator->destroy(iterator);
+
+ spi = *((u_int32_t*)this->spi.ptr);
+
+ proposal->set_spi(proposal, this->protocol_id, spi);
+}
+
+/**
+ * Implementation of proposal_substructure_t.clone.
+ */
+static private_proposal_substructure_t* clone(private_proposal_substructure_t *this)
+{
+ private_proposal_substructure_t * new_clone;
+ iterator_t *transforms;
+
+ new_clone = (private_proposal_substructure_t *) proposal_substructure_create();
+
+ new_clone->next_payload = this->next_payload;
+ new_clone->proposal_number = this->proposal_number;
+ new_clone->protocol_id = this->protocol_id;
+ new_clone->spi_size = this->spi_size;
+ if (this->spi.ptr != NULL)
+ {
+ new_clone->spi.ptr = clalloc(this->spi.ptr,this->spi.len);
+ new_clone->spi.len = this->spi.len;
+ }
+
+ transforms = this->transforms->create_iterator(this->transforms,FALSE);
+
+ while (transforms->has_next(transforms))
+ {
+ transform_substructure_t *current_transform;
+ transform_substructure_t *current_transform_clone;
+
+ transforms->current(transforms,(void **) &current_transform);
+
+ current_transform_clone = current_transform->clone(current_transform);
+
+ new_clone->public.add_transform_substructure(&(new_clone->public),current_transform_clone);
+ }
+
+ transforms->destroy(transforms);
+
+ return new_clone;
+}
+
+/**
+ * Implements payload_t's and proposal_substructure_t's destroy function.
+ * See #payload_s.destroy or proposal_substructure_s.destroy for description.
+ */
+static status_t destroy(private_proposal_substructure_t *this)
+{
+ /* all proposals are getting destroyed */
+ while (this->transforms->get_count(this->transforms) > 0)
+ {
+ transform_substructure_t *current_transform;
+ if (this->transforms->remove_last(this->transforms,(void **)&current_transform) != SUCCESS)
+ {
+ break;
+ }
+ current_transform->destroy(current_transform);
+ }
+ this->transforms->destroy(this->transforms);
+
+ if (this->spi.ptr != NULL)
+ {
+ free(this->spi.ptr);
+ }
+
+ free(this);
+
+ return SUCCESS;
+}
+
+/*
+ * Described in header.
+ */
+proposal_substructure_t *proposal_substructure_create()
+{
+ private_proposal_substructure_t *this = malloc_thing(private_proposal_substructure_t);
+
+ /* interface functions */
+ this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
+ this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
+ this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
+ this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
+ this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
+ this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_type;
+ this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
+
+
+ /* public functions */
+ this->public.create_transform_substructure_iterator = (iterator_t* (*) (proposal_substructure_t *,bool)) create_transform_substructure_iterator;
+ this->public.add_transform_substructure = (void (*) (proposal_substructure_t *,transform_substructure_t *)) add_transform_substructure;
+ this->public.set_proposal_number = (void (*) (proposal_substructure_t *,u_int8_t))set_proposal_number;
+ this->public.get_proposal_number = (u_int8_t (*) (proposal_substructure_t *)) get_proposal_number;
+ this->public.set_protocol_id = (void (*) (proposal_substructure_t *,u_int8_t))set_protocol_id;
+ this->public.get_protocol_id = (u_int8_t (*) (proposal_substructure_t *)) get_protocol_id;
+ this->public.get_info_for_transform_type = (status_t (*) (proposal_substructure_t *,transform_type_t,u_int16_t *, u_int16_t *))get_info_for_transform_type;
+ this->public.set_is_last_proposal = (void (*) (proposal_substructure_t *,bool)) set_is_last_proposal;
+ this->public.add_to_proposal = (void (*) (proposal_substructure_t*,proposal_t*))add_to_proposal;
+ this->public.set_spi = (void (*) (proposal_substructure_t *,chunk_t))set_spi;
+ this->public.get_spi = (chunk_t (*) (proposal_substructure_t *)) get_spi;
+ this->public.get_transform_count = (size_t (*) (proposal_substructure_t *)) get_transform_count;
+ this->public.get_spi_size = (size_t (*) (proposal_substructure_t *)) get_spi_size;
+ this->public.clone = (proposal_substructure_t * (*) (proposal_substructure_t *)) clone;
+ this->public.destroy = (void (*) (proposal_substructure_t *)) destroy;
+
+ /* private functions */
+ this->compute_length = compute_length;
+
+ /* set default values of the fields */
+ this->next_payload = NO_PAYLOAD;
+ this->proposal_length = 0;
+ this->proposal_number = 0;
+ this->protocol_id = 0;
+ this->transforms_count = 0;
+ this->spi_size = 0;
+ this->spi.ptr = NULL;
+ this->spi.len = 0;
+
+ this->transforms = linked_list_create();
+
+ return (&(this->public));
+}
+
+/*
+ * Described in header.
+ */
+proposal_substructure_t *proposal_substructure_create_from_proposal(proposal_t *proposal, protocol_id_t proto)
+{
+ private_proposal_substructure_t *this = (private_proposal_substructure_t*)proposal_substructure_create();
+ iterator_t *iterator;
+ algorithm_t *algo;
+ transform_substructure_t *transform;
+
+ /* encryption algorithm is only availble in ESP */
+ iterator = proposal->create_algorithm_iterator(proposal, proto, ENCRYPTION_ALGORITHM);
+ while (iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void**)&algo);
+ transform = transform_substructure_create_type(ENCRYPTION_ALGORITHM, algo->algorithm, algo->key_size);
+ this->public.add_transform_substructure(&(this->public), transform);
+ }
+ iterator->destroy(iterator);
+
+ /* integrity algorithms */
+ iterator = proposal->create_algorithm_iterator(proposal, proto, INTEGRITY_ALGORITHM);
+ while (iterator->has_next(iterator))
+ {
+ algorithm_t *algo;
+ iterator->current(iterator, (void**)&algo);
+ transform = transform_substructure_create_type(INTEGRITY_ALGORITHM, algo->algorithm, algo->key_size);
+ this->public.add_transform_substructure(&(this->public), transform);
+ }
+ iterator->destroy(iterator);
+
+ /* prf algorithms */
+ iterator = proposal->create_algorithm_iterator(proposal, proto, PSEUDO_RANDOM_FUNCTION);
+ while (iterator->has_next(iterator))
+ {
+ algorithm_t *algo;
+ iterator->current(iterator, (void**)&algo);
+ transform = transform_substructure_create_type(PSEUDO_RANDOM_FUNCTION, algo->algorithm, algo->key_size);
+ this->public.add_transform_substructure(&(this->public), transform);
+ }
+ iterator->destroy(iterator);
+
+ /* dh groups */
+ iterator = proposal->create_algorithm_iterator(proposal, proto, DIFFIE_HELLMAN_GROUP);
+ while (iterator->has_next(iterator))
+ {
+ algorithm_t *algo;
+ iterator->current(iterator, (void**)&algo);
+ transform = transform_substructure_create_type(DIFFIE_HELLMAN_GROUP, algo->algorithm, 0);
+ this->public.add_transform_substructure(&(this->public), transform);
+ }
+ iterator->destroy(iterator);
+
+ /* extended sequence numbers */
+ iterator = proposal->create_algorithm_iterator(proposal, proto, EXTENDED_SEQUENCE_NUMBERS);
+ while (iterator->has_next(iterator))
+ {
+ algorithm_t *algo;
+ iterator->current(iterator, (void**)&algo);
+ transform = transform_substructure_create_type(EXTENDED_SEQUENCE_NUMBERS, algo->algorithm, 0);
+ this->public.add_transform_substructure(&(this->public), transform);
+ }
+ iterator->destroy(iterator);
+
+ /* take over general infos */
+ this->spi_size = proto == PROTO_IKE ? 8 : 4;
+ this->spi.len = this->spi_size;
+ this->spi.ptr = malloc(this->spi_size);
+ *((u_int32_t*)this->spi.ptr) = proposal->get_spi(proposal, proto);
+ this->proposal_number = proposal->get_number(proposal);
+ this->protocol_id = proto;
+
+ return &(this->public);
+}
diff --git a/programs/charon/charon/encoding/payloads/proposal_substructure.h b/programs/charon/charon/encoding/payloads/proposal_substructure.h
new file mode 100644
index 000000000..506d25800
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/proposal_substructure.h
@@ -0,0 +1,231 @@
+/**
+ * @file proposal_substructure.h
+ *
+ * @brief Interface of proposal_substructure_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef PROPOSAL_SUBSTRUCTURE_H_
+#define PROPOSAL_SUBSTRUCTURE_H_
+
+#include <types.h>
+#include <encoding/payloads/payload.h>
+#include <encoding/payloads/transform_substructure.h>
+#include <config/proposal.h>
+#include <utils/linked_list.h>
+
+
+/**
+ * Length of the proposal substructure header (without spi).
+ *
+ * @ingroup payloads
+ */
+#define PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH 8
+
+
+typedef struct proposal_substructure_t proposal_substructure_t;
+
+/**
+ * @brief 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 {
+ /**
+ * The payload_t interface.
+ */
+ 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.
+ *
+ * @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);
+
+ /**
+ * @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.
+ *
+ * @param this calling proposal_substructure_t object
+ * @param transform transform_substructure_t object to add
+ */
+ void (*add_transform_substructure) (proposal_substructure_t *this,transform_substructure_t *transform);
+
+ /**
+ * @brief Sets the proposal number of current proposal.
+ *
+ * @param this calling proposal_substructure_t object
+ * @param id proposal number to set
+ */
+ void (*set_proposal_number) (proposal_substructure_t *this,u_int8_t proposal_number);
+
+ /**
+ * @brief 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.
+ *
+ * @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.
+ *
+ * @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.
+ *
+ * @param this calling proposal_substructure_t object
+ * @param id protocol id to set
+ */
+ void (*set_protocol_id) (proposal_substructure_t *this,u_int8_t protocol_id);
+
+ /**
+ * @brief 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 Get informations for a specific transform type.
+ *
+ * @param this calling proposal_substructure_t object
+ * @param type type to get informations for
+ * @param transform_id transform id of the specific type
+ * @param key_length key length of the specific key length transform attribute
+ * @return
+ * - SUCCESS if transform type is part of this proposal and
+ * all data (incl. key length) could be fetched
+ * - NOT_FOUND if transform type is not part of this proposal
+ */
+ status_t (*get_info_for_transform_type) (proposal_substructure_t *this,transform_type_t type, u_int16_t *transform_id, u_int16_t *key_length);
+
+ /**
+ * @brief 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
+ */
+ chunk_t (*get_spi) (proposal_substructure_t *this);
+
+ /**
+ * @brief 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
+ */
+ void (*set_spi) (proposal_substructure_t *this, chunk_t spi);
+
+ /**
+ * @brief Add this proposal_substructure to a proposal.
+ *
+ * Since a proposal_t may contain the data of multiple
+ * proposal_sbustructure_t's, it may be necessary to call
+ * the function multiple times with the same proposal.
+ *
+ * @param this calling proposal_substructure_t object
+ * @param proposal proposal where the data should be added
+ */
+ void (*add_to_proposal) (proposal_substructure_t *this, proposal_t *proposal);
+
+ /**
+ * @brief 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
+ */
+ void (*destroy) (proposal_substructure_t *this);
+};
+
+/**
+ * @brief Creates an empty proposal_substructure_t object
+ *
+ * @return proposal_substructure_t object
+ *
+ * @ingroup payloads
+ */
+proposal_substructure_t *proposal_substructure_create();
+
+/**
+ * @brief Creates a proposal substructure from a proposal.
+ *
+ * Since a child proposal may contain data for both AH and ESP,
+ * the protocol must be specified. If the proposal does not contain
+ * data for proto, NULL is returned. Call twice, once with AH, once
+ * with ESP, with the same proposal to build the two substructures
+ * for it.
+ *
+ * @param proposal proposal to build a substruct out of it
+ * @param proto for which protocol the substructure should be built
+ * @return proposal_substructure_t object, or NULL
+ *
+ * @ingroup payloads
+ */
+proposal_substructure_t *proposal_substructure_create_from_proposal(proposal_t *proposal, protocol_id_t proto);
+
+
+#endif /*PROPOSAL_SUBSTRUCTURE_H_*/
diff --git a/programs/charon/charon/encoding/payloads/sa_payload.c b/programs/charon/charon/encoding/payloads/sa_payload.c
new file mode 100644
index 000000000..81b4e6709
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/sa_payload.c
@@ -0,0 +1,390 @@
+/**
+ * @file sa_payload.c
+ *
+ * @brief Implementation of sa_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stddef.h>
+
+#include "sa_payload.h"
+
+#include <encoding/payloads/encodings.h>
+#include <utils/linked_list.h>
+
+
+typedef struct private_sa_payload_t private_sa_payload_t;
+
+/**
+ * Private data of an sa_payload_t object.
+ *
+ */
+struct private_sa_payload_t {
+ /**
+ * Public sa_payload_t interface.
+ */
+ sa_payload_t public;
+
+ /**
+ * Next payload type.
+ */
+ u_int8_t next_payload;
+
+ /**
+ * Critical flag.
+ */
+ bool critical;
+
+ /**
+ * Length of this payload.
+ */
+ u_int16_t payload_length;
+
+ /**
+ * Proposals in this payload are stored in a linked_list_t.
+ */
+ linked_list_t * proposals;
+
+ /**
+ * @brief Computes the length of this payload.
+ *
+ * @param this calling private_sa_payload_t object
+ */
+ void (*compute_length) (private_sa_payload_t *this);
+};
+
+/**
+ * Encoding rules to parse or generate a IKEv2-SA Payload
+ *
+ * The defined offsets are the positions in a object of type
+ * private_sa_payload_t.
+ *
+ */
+encoding_rule_t sa_payload_encodings[] = {
+ /* 1 Byte next payload type, stored in the field next_payload */
+ { U_INT_8, offsetof(private_sa_payload_t, next_payload) },
+ /* the critical bit */
+ { FLAG, offsetof(private_sa_payload_t, critical) },
+ /* 7 Bit reserved bits, nowhere stored */
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ /* Length of the whole SA payload*/
+ { PAYLOAD_LENGTH, offsetof(private_sa_payload_t, payload_length) },
+ /* Proposals are stored in a proposal substructure,
+ offset points to a linked_list_t pointer */
+ { PROPOSALS, offsetof(private_sa_payload_t, proposals) }
+};
+
+/*
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Next Payload !C! RESERVED ! Payload Length !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! !
+ ~ <Proposals> ~
+ ! !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+/**
+ * Implementation of payload_t.verify.
+ */
+static status_t verify(private_sa_payload_t *this)
+{
+ int proposal_number = 1;
+ status_t status = SUCCESS;
+ iterator_t *iterator;
+ bool first = TRUE;
+
+ /* check proposal numbering */
+ iterator = this->proposals->create_iterator(this->proposals,TRUE);
+
+ while(iterator->has_next(iterator))
+ {
+ proposal_substructure_t *current_proposal;
+ iterator->current(iterator,(void **)&current_proposal);
+ if (current_proposal->get_proposal_number(current_proposal) > proposal_number)
+ {
+ if (first)
+ {
+ /* first number must be 1 */
+ status = FAILED;
+ break;
+ }
+
+ if (current_proposal->get_proposal_number(current_proposal) != (proposal_number + 1))
+ {
+ /* must be only one more then previous proposal */
+ status = FAILED;
+ break;
+ }
+ }
+ else if (current_proposal->get_proposal_number(current_proposal) < proposal_number)
+ {
+ /* must not be smaller then proceeding one */
+ status = FAILED;
+ break;
+ }
+
+ status = current_proposal->payload_interface.verify(&(current_proposal->payload_interface));
+ if (status != SUCCESS)
+ {
+ break;
+ }
+ first = FALSE;
+ }
+
+ iterator->destroy(iterator);
+ return status;
+}
+
+
+/**
+ * Implementation of payload_t.destroy and sa_payload_t.destroy.
+ */
+static status_t destroy(private_sa_payload_t *this)
+{
+ /* all proposals are getting destroyed */
+ while (this->proposals->get_count(this->proposals) > 0)
+ {
+ proposal_substructure_t *current_proposal;
+ this->proposals->remove_last(this->proposals,(void **)&current_proposal);
+ current_proposal->destroy(current_proposal);
+ }
+ this->proposals->destroy(this->proposals);
+
+ free(this);
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of payload_t.get_encoding_rules.
+ */
+static void get_encoding_rules(private_sa_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
+{
+ *rules = sa_payload_encodings;
+ *rule_count = sizeof(sa_payload_encodings) / sizeof(encoding_rule_t);
+}
+
+/**
+ * Implementation of payload_t.get_type.
+ */
+static payload_type_t get_type(private_sa_payload_t *this)
+{
+ return SECURITY_ASSOCIATION;
+}
+
+/**
+ * Implementation of payload_t.get_next_type.
+ */
+static payload_type_t get_next_type(private_sa_payload_t *this)
+{
+ return (this->next_payload);
+}
+
+/**
+ * Implementation of payload_t.set_next_type.
+ */
+static void set_next_type(private_sa_payload_t *this,payload_type_t type)
+{
+ this->next_payload = type;
+}
+
+/**
+ * Implementation of payload_t.get_length.
+ */
+static size_t get_length(private_sa_payload_t *this)
+{
+ this->compute_length(this);
+ return this->payload_length;
+}
+
+/**
+ * Implementation of sa_payload_t.create_proposal_substructure_iterator.
+ */
+static iterator_t *create_proposal_substructure_iterator (private_sa_payload_t *this,bool forward)
+{
+ return this->proposals->create_iterator(this->proposals,forward);
+}
+
+/**
+ * Implementation of sa_payload_t.add_proposal_substructure.
+ */
+static void add_proposal_substructure (private_sa_payload_t *this,proposal_substructure_t *proposal)
+{
+ status_t status;
+ if (this->proposals->get_count(this->proposals) > 0)
+ {
+ proposal_substructure_t *last_proposal;
+ status = this->proposals->get_last(this->proposals,(void **) &last_proposal);
+ /* last transform is now not anymore last one */
+ last_proposal->set_is_last_proposal(last_proposal,FALSE);
+ }
+ proposal->set_is_last_proposal(proposal,TRUE);
+
+ this->proposals->insert_last(this->proposals,(void *) proposal);
+ this->compute_length(this);
+}
+
+/**
+ * Implementation of sa_payload_t.add_proposal.
+ */
+static void add_proposal(private_sa_payload_t *this, proposal_t *proposal)
+{
+ proposal_substructure_t *substructure;
+ protocol_id_t proto[2];
+ u_int i;
+
+ /* build the substructures for every protocol */
+ proposal->get_protocols(proposal, proto);
+ for (i = 0; i<2; i++)
+ {
+ if (proto[i] != PROTO_NONE)
+ {
+ substructure = proposal_substructure_create_from_proposal(proposal, proto[i]);
+ add_proposal_substructure(this, substructure);
+ }
+ }
+}
+
+/**
+ * Implementation of sa_payload_t.get_proposals.
+ */
+static linked_list_t *get_proposals(private_sa_payload_t *this)
+{
+ int proposal_struct_number = 0;
+ iterator_t *iterator;
+ proposal_t *proposal;
+ linked_list_t *proposal_list;
+
+ /* this list will hold our proposals */
+ proposal_list = linked_list_create();
+
+ /* iterate over structures, one OR MORE structures will result in a proposal */
+ iterator = this->proposals->create_iterator(this->proposals,TRUE);
+ while (iterator->has_next(iterator))
+ {
+ proposal_substructure_t *proposal_struct;
+ iterator->current(iterator,(void **)&(proposal_struct));
+
+ if (proposal_struct->get_proposal_number(proposal_struct) > proposal_struct_number)
+ {
+ /* here starts a new proposal, create a new one and add it to the list */
+ proposal_struct_number = proposal_struct->get_proposal_number(proposal_struct);
+ proposal = proposal_create(proposal_struct_number);
+ proposal_list->insert_last(proposal_list, proposal);
+ }
+ /* proposal_substructure_t does the dirty work and builds up the proposal */
+ proposal_struct->add_to_proposal(proposal_struct, proposal);
+ }
+ iterator->destroy(iterator);
+ return proposal_list;
+}
+
+/**
+ * Implementation of private_sa_payload_t.compute_length.
+ */
+static void compute_length (private_sa_payload_t *this)
+{
+ iterator_t *iterator;
+ size_t length = SA_PAYLOAD_HEADER_LENGTH;
+ iterator = this->proposals->create_iterator(this->proposals,TRUE);
+ while (iterator->has_next(iterator))
+ {
+ payload_t *current_proposal;
+ iterator->current(iterator,(void **) &current_proposal);
+ length += current_proposal->get_length(current_proposal);
+ }
+ iterator->destroy(iterator);
+
+ this->payload_length = length;
+}
+
+/*
+ * Described in header.
+ */
+sa_payload_t *sa_payload_create()
+{
+ private_sa_payload_t *this = malloc_thing(private_sa_payload_t);
+
+ /* public interface */
+ this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
+ this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
+ this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
+ this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
+ this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
+ this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_type;
+ this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
+
+ /* public functions */
+ this->public.create_proposal_substructure_iterator = (iterator_t* (*) (sa_payload_t *,bool)) create_proposal_substructure_iterator;
+ this->public.add_proposal_substructure = (void (*) (sa_payload_t *,proposal_substructure_t *)) add_proposal_substructure;
+ this->public.get_proposals = (linked_list_t* (*) (sa_payload_t *)) get_proposals;
+ this->public.destroy = (void (*) (sa_payload_t *)) destroy;
+
+ /* private functions */
+ this->compute_length = compute_length;
+
+ /* set default values of the fields */
+ this->critical = FALSE;
+ this->next_payload = NO_PAYLOAD;
+ this->payload_length = SA_PAYLOAD_HEADER_LENGTH;
+
+ this->proposals = linked_list_create();
+ return (&(this->public));
+}
+
+/*
+ * Described in header.
+ */
+sa_payload_t *sa_payload_create_from_proposal_list(linked_list_t *proposals)
+{
+ iterator_t *iterator;
+ proposal_t *proposal;
+ sa_payload_t *sa_payload = sa_payload_create();
+
+ /* add every payload from the list */
+ iterator = proposals->create_iterator(proposals, TRUE);
+ while (iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void**)&proposal);
+ add_proposal((private_sa_payload_t*)sa_payload, proposal);
+ }
+ iterator->destroy(iterator);
+
+ return sa_payload;
+}
+
+/*
+ * Described in header.
+ */
+sa_payload_t *sa_payload_create_from_proposal(proposal_t *proposal)
+{
+ sa_payload_t *sa_payload = sa_payload_create();
+
+ add_proposal((private_sa_payload_t*)sa_payload, proposal);
+
+ return sa_payload;
+}
diff --git a/programs/charon/charon/encoding/payloads/sa_payload.h b/programs/charon/charon/encoding/payloads/sa_payload.h
new file mode 100644
index 000000000..45095c030
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/sa_payload.h
@@ -0,0 +1,140 @@
+/**
+ * @file sa_payload.h
+ *
+ * @brief Interface of sa_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef SA_PAYLOAD_H_
+#define SA_PAYLOAD_H_
+
+#include <types.h>
+#include <encoding/payloads/payload.h>
+#include <encoding/payloads/proposal_substructure.h>
+#include <utils/linked_list.h>
+
+/**
+ * SA_PAYLOAD length in bytes without any proposal substructure.
+ *
+ * @ingroup payloads
+ */
+#define SA_PAYLOAD_HEADER_LENGTH 4
+
+typedef struct sa_payload_t sa_payload_t;
+
+/**
+ * @brief 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 {
+ /**
+ * The payload_t interface.
+ */
+ payload_t payload_interface;
+
+ /**
+ * @brief 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()!
+ *
+ * @param this calling sa_payload_t object
+ * @param[in] forward iterator direction (TRUE: front to end)
+ * @return created iterator_t object
+ */
+ 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.
+ *
+ * @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);
+
+ /**
+ * @brief 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.
+ *
+ * @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
+ */
+ void (*destroy) (sa_payload_t *this);
+};
+
+/**
+ * @brief Creates an empty sa_payload_t object
+ *
+ * @return created sa_payload_t object
+ *
+ * @ingroup payloads
+ */
+sa_payload_t *sa_payload_create();
+
+/**
+ * @brief 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.
+ *
+ * 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_*/
diff --git a/programs/charon/charon/encoding/payloads/traffic_selector_substructure.c b/programs/charon/charon/encoding/payloads/traffic_selector_substructure.c
new file mode 100644
index 000000000..c1a461e8a
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/traffic_selector_substructure.c
@@ -0,0 +1,374 @@
+/**
+ * @file traffic_selector_substructure.c
+ *
+ * @brief Interface of traffic_selector_substructure_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "traffic_selector_substructure.h"
+
+#include <encoding/payloads/encodings.h>
+#include <utils/linked_list.h>
+
+/**
+ * String mappings for ts_type_t.
+ */
+mapping_t ts_type_m[] = {
+ {TS_IPV4_ADDR_RANGE, "TS_IPV4_ADDR_RANGE"},
+ {TS_IPV6_ADDR_RANGE, "TS_IPV6_ADDR_RANGE"},
+ {MAPPING_END, NULL}
+};
+
+
+typedef struct private_traffic_selector_substructure_t private_traffic_selector_substructure_t;
+
+/**
+ * Private data of an traffic_selector_substructure_t object.
+ *
+ */
+struct private_traffic_selector_substructure_t {
+ /**
+ * Public traffic_selector_substructure_t interface.
+ */
+ traffic_selector_substructure_t public;
+
+ /**
+ * Type of traffic selector.
+ */
+ u_int8_t ts_type;
+
+ /**
+ * IP Protocol ID.
+ */
+ u_int8_t ip_protocol_id;
+
+ /**
+ * Length of this payload.
+ */
+ u_int16_t payload_length;
+
+ /**
+ * Start port number.
+ */
+ u_int16_t start_port;
+
+ /**
+ * End port number.
+ */
+ u_int16_t end_port;
+
+ /**
+ * Starting address.
+ */
+ chunk_t starting_address;
+
+ /**
+ * Ending address.
+ */
+ chunk_t ending_address;
+
+ /**
+ * update length
+ */
+ void (*compute_length) (private_traffic_selector_substructure_t *this);
+};
+
+/**
+ * Encoding rules to parse or generate a TS payload
+ *
+ * The defined offsets are the positions in a object of type
+ * private_traffic_selector_substructure_t.
+ *
+ */
+encoding_rule_t traffic_selector_substructure_encodings[] = {
+ /* 1 Byte next ts type*/
+ { TS_TYPE, offsetof(private_traffic_selector_substructure_t, ts_type) },
+ /* 1 Byte IP protocol id*/
+ { U_INT_8, offsetof(private_traffic_selector_substructure_t, ip_protocol_id) },
+ /* Length of the whole payload*/
+ { PAYLOAD_LENGTH, offsetof(private_traffic_selector_substructure_t, payload_length) },
+ /* 2 Byte start port*/
+ { U_INT_16, offsetof(private_traffic_selector_substructure_t, start_port) },
+ /* 2 Byte end port*/
+ { U_INT_16, offsetof(private_traffic_selector_substructure_t, end_port) },
+ /* starting address is either 4 or 16 byte */
+ { ADDRESS, offsetof(private_traffic_selector_substructure_t, starting_address) },
+ /* ending address is either 4 or 16 byte */
+ { ADDRESS, offsetof(private_traffic_selector_substructure_t, ending_address) }
+
+};
+
+/*
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! TS Type !IP Protocol ID*| Selector Length |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Start Port* | End Port* |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! !
+ ~ Starting Address* ~
+ ! !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! !
+ ~ Ending Address* ~
+ ! !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+/**
+ * Implementation of payload_t.verify.
+ */
+static status_t verify(private_traffic_selector_substructure_t *this)
+{
+
+ if (this->start_port > this->end_port)
+ {
+ return FAILED;
+ }
+ switch (this->ts_type)
+ {
+ case TS_IPV4_ADDR_RANGE:
+ {
+ if ((this->starting_address.len != 4) ||
+ (this->ending_address.len != 4))
+ {
+ /* ipv4 address must be 4 bytes long */
+ return FAILED;
+ }
+ break;
+ }
+ case TS_IPV6_ADDR_RANGE:
+ default:
+ {
+ /* not supported ts type */
+ return FAILED;
+ }
+ }
+
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of traffic_selector_substructure_t.get_encoding_rules.
+ */
+static void get_encoding_rules(private_traffic_selector_substructure_t *this, encoding_rule_t **rules, size_t *rule_count)
+{
+ *rules = traffic_selector_substructure_encodings;
+ *rule_count = sizeof(traffic_selector_substructure_encodings) / sizeof(encoding_rule_t);
+}
+
+/**
+ * Implementation of payload_t.get_type.
+ */
+static payload_type_t get_payload_type(private_traffic_selector_substructure_t *this)
+{
+ return TRAFFIC_SELECTOR_SUBSTRUCTURE;
+}
+
+/**
+ * Implementation of payload_t.get_next_type.
+ */
+static payload_type_t get_next_type(private_traffic_selector_substructure_t *this)
+{
+ return 0;
+}
+
+/**
+ * Implementation of payload_t.set_next_type.
+ */
+static void set_next_type(private_traffic_selector_substructure_t *this,payload_type_t type)
+{
+}
+
+/**
+ * Implementation of payload_t.get_length.
+ */
+static size_t get_length(private_traffic_selector_substructure_t *this)
+{
+ return this->payload_length;
+}
+
+/**
+ * Implementation of traffic_selector_substructure_t.get_ts_type.
+ */
+static ts_type_t get_ts_type (private_traffic_selector_substructure_t *this)
+{
+ return this->ts_type;
+}
+
+/**
+ * Implementation of traffic_selector_substructure_t.set_ts_type.
+ */
+static void set_ts_type (private_traffic_selector_substructure_t *this,ts_type_t ts_type)
+{
+ this->ts_type = ts_type;
+}
+
+/**
+ * Implementation of traffic_selector_substructure_t.get_protocol_id.
+ */
+static u_int8_t get_protocol_id (private_traffic_selector_substructure_t *this)
+{
+ return this->ip_protocol_id;
+}
+
+/**
+ * Implementation of traffic_selector_substructure_t.set_protocol_id.
+ */
+static void set_protocol_id (private_traffic_selector_substructure_t *this,u_int8_t protocol_id)
+{
+ this->ip_protocol_id = protocol_id;
+}
+
+/**
+ * Implementation of traffic_selector_substructure_t.get_start_host.
+ */
+static host_t * get_start_host (private_traffic_selector_substructure_t *this)
+{
+ return (host_create_from_chunk(AF_INET,this->starting_address, this->start_port));
+}
+
+/**
+ * Implementation of traffic_selector_substructure_t.set_start_host.
+ */
+static void set_start_host (private_traffic_selector_substructure_t *this,host_t *start_host)
+{
+ this->start_port = start_host->get_port(start_host);
+ if (this->starting_address.ptr != NULL)
+ {
+ chunk_free(&(this->starting_address));
+ }
+ this->starting_address = start_host->get_address_as_chunk(start_host);
+ this->compute_length(this);
+}
+
+/**
+ * Implementation of traffic_selector_substructure_t.get_end_host.
+ */
+static host_t *get_end_host (private_traffic_selector_substructure_t *this)
+{
+ return (host_create_from_chunk(AF_INET,this->ending_address, this->end_port));
+}
+
+/**
+ * Implementation of traffic_selector_substructure_t.set_end_host.
+ */
+static void set_end_host (private_traffic_selector_substructure_t *this,host_t *end_host)
+{
+ this->end_port = end_host->get_port(end_host);
+ if (this->ending_address.ptr != NULL)
+ {
+ chunk_free(&(this->ending_address));
+ }
+ this->ending_address = end_host->get_address_as_chunk(end_host);
+ this->compute_length(this);
+}
+
+/**
+ * Implementation of traffic_selector_substructure_t.get_traffic_selector.
+ */
+static traffic_selector_t *get_traffic_selector(private_traffic_selector_substructure_t *this)
+{
+ traffic_selector_t *ts;
+ ts = traffic_selector_create_from_bytes(this->ip_protocol_id, this->ts_type,
+ this->starting_address, this->start_port,
+ this->ending_address, this->end_port);
+ return ts;
+}
+
+/**
+ * Implementation of private_ts_payload_t.compute_length
+ */
+void compute_length(private_traffic_selector_substructure_t *this)
+{
+ this->payload_length = TRAFFIC_SELECTOR_HEADER_LENGTH + this->ending_address.len + this->starting_address.len;
+}
+
+/**
+ * Implementation of payload_t.destroy and traffic_selector_substructure_t.destroy.
+ */
+static void destroy(private_traffic_selector_substructure_t *this)
+{
+ free(this->starting_address.ptr);
+ free(this->ending_address.ptr);
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+traffic_selector_substructure_t *traffic_selector_substructure_create()
+{
+ private_traffic_selector_substructure_t *this = malloc_thing(private_traffic_selector_substructure_t);
+
+ /* interface functions */
+ this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
+ this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
+ this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
+ this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
+ this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
+ this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_payload_type;
+ this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
+
+ /* public functions */
+ this->public.destroy = (void (*) (traffic_selector_substructure_t *)) destroy;
+ this->public.get_ts_type = (ts_type_t (*) (traffic_selector_substructure_t *)) get_ts_type;
+ this->public.set_ts_type = (void (*) (traffic_selector_substructure_t *,ts_type_t)) set_ts_type;
+ this->public.get_protocol_id = (u_int8_t (*) (traffic_selector_substructure_t *)) get_protocol_id;
+ this->public.set_protocol_id = (void (*) (traffic_selector_substructure_t *,u_int8_t)) set_protocol_id;
+ this->public.get_start_host = (host_t * (*) (traffic_selector_substructure_t *))get_start_host;
+ this->public.set_start_host = (void (*) (traffic_selector_substructure_t *, host_t *))set_start_host;
+ this->public.get_end_host = (host_t * (*) (traffic_selector_substructure_t *))get_end_host;
+ this->public.set_end_host = (void (*) (traffic_selector_substructure_t *, host_t *))set_end_host;
+ this->public.get_traffic_selector = (traffic_selector_t* (*)(traffic_selector_substructure_t*))get_traffic_selector;
+
+ /* private functions */
+ this->compute_length = compute_length;
+
+ /* private variables */
+ this->payload_length = TRAFFIC_SELECTOR_HEADER_LENGTH;
+ this->start_port = 0;
+ this->end_port = 0;
+ this->starting_address = CHUNK_INITIALIZER;
+ this->ending_address = CHUNK_INITIALIZER;
+ this->ip_protocol_id = 0;
+ /* must be set to be valid */
+ this->ts_type = TS_IPV4_ADDR_RANGE;
+
+ return (&(this->public));
+}
+
+/*
+ * Described in header
+ */
+traffic_selector_substructure_t *traffic_selector_substructure_create_from_traffic_selector(traffic_selector_t *traffic_selector)
+{
+ private_traffic_selector_substructure_t *this = (private_traffic_selector_substructure_t*)traffic_selector_substructure_create();
+ this->ts_type = traffic_selector->get_type(traffic_selector);
+ this->ip_protocol_id = traffic_selector->get_protocol(traffic_selector);
+ this->start_port = traffic_selector->get_from_port(traffic_selector);
+ this->end_port = traffic_selector->get_to_port(traffic_selector);
+ this->starting_address = traffic_selector->get_from_address(traffic_selector);
+ this->ending_address = traffic_selector->get_to_address(traffic_selector);
+
+ this->compute_length(this);
+
+ return &(this->public);
+}
diff --git a/programs/charon/charon/encoding/payloads/traffic_selector_substructure.h b/programs/charon/charon/encoding/payloads/traffic_selector_substructure.h
new file mode 100644
index 000000000..755917055
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/traffic_selector_substructure.h
@@ -0,0 +1,171 @@
+/**
+ * @file traffic_selector_substructure.h
+ *
+ * @brief Interface of traffic_selector_substructure_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#ifndef TRAFFIC_SELECTOR_SUBSTRUCTURE_H_
+#define TRAFFIC_SELECTOR_SUBSTRUCTURE_H_
+
+#include <types.h>
+#include <encoding/payloads/payload.h>
+#include <utils/host.h>
+#include <config/traffic_selector.h>
+
+/**
+ * Length of a TRAFFIC SELECTOR SUBSTRUCTURE without start and end address.
+ *
+ * @ingroup payloads
+ */
+#define TRAFFIC_SELECTOR_HEADER_LENGTH 8
+
+typedef struct traffic_selector_substructure_t traffic_selector_substructure_t;
+
+/**
+ * @brief 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 {
+ /**
+ * The payload_t interface.
+ */
+ payload_t payload_interface;
+
+ /**
+ * @brief 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.
+ *
+ * @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);
+
+ /**
+ * @brief 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
+ *
+ * @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);
+
+ /**
+ * @brief 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.
+ *
+ * @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);
+
+ /**
+ * @brief 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.
+ *
+ * @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);
+
+ /**
+ * @brief 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);
+
+ /**
+ * @brief Destroys an traffic_selector_substructure_t object.
+ *
+ * @param this traffic_selector_substructure_t object to destroy
+ */
+ void (*destroy) (traffic_selector_substructure_t *this);
+};
+
+/**
+ * @brief 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();
+
+/**
+ * @brief 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);
+
+
+#endif /* /TRAFFIC_SELECTOR_SUBSTRUCTURE_H_ */
diff --git a/programs/charon/charon/encoding/payloads/transform_attribute.c b/programs/charon/charon/encoding/payloads/transform_attribute.c
new file mode 100644
index 000000000..71cdd59e2
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/transform_attribute.c
@@ -0,0 +1,333 @@
+/**
+ * @file transform_attribute.c
+ *
+ * @brief Implementation of transform_attribute_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+#include <stddef.h>
+
+#include "transform_attribute.h"
+
+#include <encoding/payloads/encodings.h>
+#include <types.h>
+
+typedef struct private_transform_attribute_t private_transform_attribute_t;
+
+/**
+ * Private data of an transform_attribute_t object.
+ *
+ */
+struct private_transform_attribute_t {
+ /**
+ * Public transform_attribute_t interface.
+ */
+ transform_attribute_t public;
+
+ /**
+ * Attribute Format Flag.
+ *
+ * - TRUE means value is stored in attribute_length_or_value
+ * - FALSE means value is stored in attribute_value
+ */
+ bool attribute_format;
+
+ /**
+ * Type of the attribute.
+ */
+ u_int16_t attribute_type;
+
+ /**
+ * Attribute Length if attribute_format is 0, attribute Value otherwise.
+ */
+ u_int16_t attribute_length_or_value;
+
+ /**
+ * Attribute value as chunk if attribute_format is 0 (FALSE).
+ */
+ chunk_t attribute_value;
+};
+
+/**
+ * String mappings for transform_attribute_type_t.
+ */
+mapping_t transform_attribute_type_m[] = {
+ {ATTRIBUTE_UNDEFINED, "ATTRIBUTE_UNDEFINED"},
+ {KEY_LENGTH, "KEY_LENGTH"},
+ {MAPPING_END, NULL}
+};
+
+/**
+ * Encoding rules to parse or generate a Transform attribute.
+ *
+ * The defined offsets are the positions in a object of type
+ * private_transform_attribute_t.
+ *
+ */
+encoding_rule_t transform_attribute_encodings[] = {
+ /* Flag defining the format of this payload */
+ { ATTRIBUTE_FORMAT, offsetof(private_transform_attribute_t, attribute_format) },
+ /* type of the attribute as 15 bit unsigned integer */
+ { ATTRIBUTE_TYPE, offsetof(private_transform_attribute_t, attribute_type) },
+ /* Length or value, depending on the attribute format flag */
+ { ATTRIBUTE_LENGTH_OR_VALUE, offsetof(private_transform_attribute_t, attribute_length_or_value) },
+ /* Value of attribute if attribute format flag is zero */
+ { ATTRIBUTE_VALUE, offsetof(private_transform_attribute_t, attribute_value) }
+};
+
+/*
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ !A! Attribute Type ! AF=0 Attribute Length !
+ !F! ! AF=1 Attribute Value !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! AF=0 Attribute Value !
+ ! AF=1 Not Transmitted !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+/**
+ * Implementation of payload_t.verify.
+ */
+static status_t verify(private_transform_attribute_t *this)
+{
+ if (this->attribute_type != KEY_LENGTH)
+ {
+ return FAILED;
+ }
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of payload_t.get_encoding_rules.
+ */
+static void get_encoding_rules(private_transform_attribute_t *this, encoding_rule_t **rules, size_t *rule_count)
+{
+ *rules = transform_attribute_encodings;
+ *rule_count = sizeof(transform_attribute_encodings) / sizeof(encoding_rule_t);
+}
+
+/**
+ * Implementation of payload_t.get_type.
+ */
+static payload_type_t get_type(private_transform_attribute_t *this)
+{
+ return TRANSFORM_ATTRIBUTE;
+}
+
+/**
+ * Implementation of payload_t.get_next_type.
+ */
+static payload_type_t get_next_type(private_transform_attribute_t *this)
+{
+ return (NO_PAYLOAD);
+}
+
+/**
+ * Implementation of payload_t.set_next_type.
+ */
+static void set_next_type(private_transform_attribute_t *this,payload_type_t type)
+{
+}
+
+/**
+ * Implementation of transform_attribute_t.get_length.
+ */
+static size_t get_length(private_transform_attribute_t *this)
+{
+ if (this->attribute_format == TRUE)
+ {
+ /*Attribute size is only 4 byte */
+ return 4;
+ }
+ return (this->attribute_length_or_value + 4);
+}
+
+/**
+ * Implementation of transform_attribute_t.set_value_chunk.
+ */
+static void set_value_chunk(private_transform_attribute_t *this, chunk_t value)
+{
+ if (this->attribute_value.ptr != NULL)
+ {
+ /* free existing value */
+ free(this->attribute_value.ptr);
+ this->attribute_value.ptr = NULL;
+ this->attribute_value.len = 0;
+
+ }
+
+ if (value.len > 2)
+ {
+ this->attribute_value.ptr = clalloc(value.ptr,value.len);
+ this->attribute_value.len = value.len;
+ this->attribute_length_or_value = value.len;
+ /* attribute has not a fixed length */
+ this->attribute_format = FALSE;
+ }
+ else
+ {
+ memcpy(&(this->attribute_length_or_value),value.ptr,value.len);
+ }
+}
+
+/**
+ * Implementation of transform_attribute_t.set_value.
+ */
+static void set_value(private_transform_attribute_t *this, u_int16_t value)
+{
+ if (this->attribute_value.ptr != NULL)
+ {
+ /* free existing value */
+ free(this->attribute_value.ptr);
+ this->attribute_value.ptr = NULL;
+ this->attribute_value.len = 0;
+
+ }
+ this->attribute_length_or_value = value;
+}
+
+/**
+ * Implementation of transform_attribute_t.get_value_chunk.
+ */
+static chunk_t get_value_chunk (private_transform_attribute_t *this)
+{
+ chunk_t value;
+
+ if (this->attribute_format == FALSE)
+ {
+ value.ptr = this->attribute_value.ptr;
+ value.len = this->attribute_value.len;
+ }
+ else
+ {
+ value.ptr = (void *) &(this->attribute_length_or_value);
+ value.len = 2;
+ }
+
+ return value;
+}
+
+/**
+ * Implementation of transform_attribute_t.get_value.
+ */
+static u_int16_t get_value (private_transform_attribute_t *this)
+{
+ return this->attribute_length_or_value;
+}
+
+
+/**
+ * Implementation of transform_attribute_t.set_attribute_type.
+ */
+static void set_attribute_type (private_transform_attribute_t *this, u_int16_t type)
+{
+ this->attribute_type = type & 0x7FFF;
+}
+
+/**
+ * Implementation of transform_attribute_t.get_attribute_type.
+ */
+static u_int16_t get_attribute_type (private_transform_attribute_t *this)
+{
+ return this->attribute_type;
+}
+
+/**
+ * Implementation of transform_attribute_t.clone.
+ */
+static transform_attribute_t * clone(private_transform_attribute_t *this)
+{
+ private_transform_attribute_t *new_clone;
+
+ new_clone = (private_transform_attribute_t *) transform_attribute_create();
+
+ new_clone->attribute_format = this->attribute_format;
+ new_clone->attribute_type = this->attribute_type;
+ new_clone->attribute_length_or_value = this->attribute_length_or_value;
+
+ if (!new_clone->attribute_format)
+ {
+ new_clone->attribute_value.ptr = clalloc(this->attribute_value.ptr,this->attribute_value.len);
+ new_clone->attribute_value.len = this->attribute_value.len;
+ }
+
+ return (transform_attribute_t *) new_clone;
+}
+
+/**
+ * Implementation of transform_attribute_t.destroy and payload_t.destroy.
+ */
+static void destroy(private_transform_attribute_t *this)
+{
+ if (this->attribute_value.ptr != NULL)
+ {
+ free(this->attribute_value.ptr);
+ }
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+transform_attribute_t *transform_attribute_create()
+{
+ private_transform_attribute_t *this = malloc_thing(private_transform_attribute_t);
+
+ /* payload interface */
+ this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
+ this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
+ this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
+ this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
+ this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
+ this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_type;
+ this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
+
+ /* public functions */
+ this->public.set_value_chunk = (void (*) (transform_attribute_t *,chunk_t)) set_value_chunk;
+ this->public.set_value = (void (*) (transform_attribute_t *,u_int16_t)) set_value;
+ this->public.get_value_chunk = (chunk_t (*) (transform_attribute_t *)) get_value_chunk;
+ this->public.get_value = (u_int16_t (*) (transform_attribute_t *)) get_value;
+ this->public.set_attribute_type = (void (*) (transform_attribute_t *,u_int16_t type)) set_attribute_type;
+ this->public.get_attribute_type = (u_int16_t (*) (transform_attribute_t *)) get_attribute_type;
+ this->public.clone = (transform_attribute_t * (*) (transform_attribute_t *)) clone;
+ this->public.destroy = (void (*) (transform_attribute_t *)) destroy;
+
+ /* set default values of the fields */
+ this->attribute_format = TRUE;
+ this->attribute_type = 0;
+ this->attribute_length_or_value = 0;
+ this->attribute_value.ptr = NULL;
+ this->attribute_value.len = 0;
+
+ return (&(this->public));
+}
+
+/*
+ * Described in header.
+ */
+transform_attribute_t *transform_attribute_create_key_length(u_int16_t key_length)
+{
+ transform_attribute_t *attribute = transform_attribute_create();
+ attribute->set_attribute_type(attribute,KEY_LENGTH);
+ attribute->set_value(attribute,key_length);
+ return attribute;
+}
diff --git a/programs/charon/charon/encoding/payloads/transform_attribute.h b/programs/charon/charon/encoding/payloads/transform_attribute.h
new file mode 100644
index 000000000..547699915
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/transform_attribute.h
@@ -0,0 +1,154 @@
+/**
+ * @file transform_attribute.h
+ *
+ * @brief Interface of transform_attribute_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef TRANSFORM_ATTRIBUTE_H_
+#define TRANSFORM_ATTRIBUTE_H_
+
+#include <types.h>
+#include <encoding/payloads/payload.h>
+
+
+typedef enum transform_attribute_type_t transform_attribute_type_t;
+
+/**
+ * Type of the attribute, as in IKEv2 RFC 3.3.5.
+ *
+ * @ingroup payloads
+ */
+enum transform_attribute_type_t {
+ ATTRIBUTE_UNDEFINED = 16384,
+ KEY_LENGTH = 14
+};
+
+/**
+ * String mappings for transform_attribute_type_t.
+ *
+ * @ingroup payloads
+ */
+extern mapping_t transform_attribute_type_m[];
+
+typedef struct transform_attribute_t transform_attribute_t;
+
+/**
+ * @brief Class representing an IKEv2- TRANSFORM Attribute.
+ *
+ * The TRANSFORM ATTRIBUTE format is described in RFC section 3.3.5.
+ *
+ * @ingroup payloads
+ */
+struct transform_attribute_t {
+ /**
+ * The payload_t interface.
+ */
+ payload_t payload_interface;
+
+ /**
+ * @brief Returns the currently set value of the attribute.
+ *
+ * @warning 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.
+ *
+ * @warning 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.
+ *
+ * @warning 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.
+ *
+ * @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.
+ *
+ * @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.
+ *
+ * @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.
+ *
+ * @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
+ */
+ void (*destroy) (transform_attribute_t *this);
+};
+
+/**
+ * @brief Creates an empty transform_attribute_t object.
+ *
+ * @return transform_attribute_t object
+ *
+ * @ingroup payloads
+ */
+transform_attribute_t *transform_attribute_create();
+
+/**
+ * @brief 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_*/
diff --git a/programs/charon/charon/encoding/payloads/transform_substructure.c b/programs/charon/charon/encoding/payloads/transform_substructure.c
new file mode 100644
index 000000000..350ad63e4
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/transform_substructure.c
@@ -0,0 +1,485 @@
+/**
+ * @file transform_substructure.h
+ *
+ * @brief Implementation of transform_substructure_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stddef.h>
+
+#include "transform_substructure.h"
+
+#include <encoding/payloads/transform_attribute.h>
+#include <encoding/payloads/encodings.h>
+#include <types.h>
+#include <utils/linked_list.h>
+
+
+typedef struct private_transform_substructure_t private_transform_substructure_t;
+
+/**
+ * Private data of an transform_substructure_t object.
+ *
+ */
+struct private_transform_substructure_t {
+ /**
+ * Public transform_substructure_t interface.
+ */
+ transform_substructure_t public;
+
+ /**
+ * Next payload type.
+ */
+ u_int8_t next_payload;
+
+
+ /**
+ * Length of this payload.
+ */
+ u_int16_t transform_length;
+
+
+ /**
+ * Type of the transform.
+ */
+ u_int8_t transform_type;
+
+ /**
+ * Transform ID.
+ */
+ u_int16_t transform_id;
+
+ /**
+ * Transforms Attributes are stored in a linked_list_t.
+ */
+ linked_list_t *attributes;
+
+ /**
+ * @brief Computes the length of this substructure.
+ *
+ * @param this calling private_transform_substructure_t object
+ */
+ void (*compute_length) (private_transform_substructure_t *this);
+};
+
+
+/**
+ * Encoding rules to parse or generate a Transform substructure.
+ *
+ * The defined offsets are the positions in a object of type
+ * private_transform_substructure_t.
+ *
+ */
+encoding_rule_t transform_substructure_encodings[] = {
+ /* 1 Byte next payload type, stored in the field next_payload */
+ { U_INT_8, offsetof(private_transform_substructure_t, next_payload) },
+ /* Reserved Byte is skipped */
+ { RESERVED_BYTE, 0 },
+ /* Length of the whole transform substructure*/
+ { PAYLOAD_LENGTH, offsetof(private_transform_substructure_t, transform_length) },
+ /* transform type is a number of 8 bit */
+ { U_INT_8, offsetof(private_transform_substructure_t, transform_type) },
+ /* Reserved Byte is skipped */
+ { RESERVED_BYTE, 0 },
+ /* tranform ID is a number of 8 bit */
+ { U_INT_16, offsetof(private_transform_substructure_t, transform_id) },
+ /* Attributes are stored in a transform attribute,
+ offset points to a linked_list_t pointer */
+ { TRANSFORM_ATTRIBUTES, offsetof(private_transform_substructure_t, attributes) }
+};
+
+/*
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! 0 (last) or 3 ! RESERVED ! Transform Length !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ !Transform Type ! RESERVED ! Transform ID !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! !
+ ~ Transform Attributes ~
+ ! !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+
+/**
+ * Implementation of payload_t.verify.
+ */
+static status_t verify(private_transform_substructure_t *this)
+{
+ status_t status = SUCCESS;
+ iterator_t *iterator;
+
+ if ((this->next_payload != NO_PAYLOAD) && (this->next_payload != 3))
+ {
+ /* must be 0 or 3 */
+ return FAILED;
+ }
+
+ switch (this->transform_type)
+ {
+ case ENCRYPTION_ALGORITHM:
+ {
+ if ((this->transform_id < ENCR_DES_IV64) || (this->transform_id > ENCR_AES_CTR))
+ {
+ return FAILED;
+ }
+ break;
+ }
+ case PSEUDO_RANDOM_FUNCTION:
+ {
+ if ((this->transform_id < PRF_HMAC_MD5) || (this->transform_id > PRF_AES128_CBC))
+ {
+ return FAILED;
+ }
+ break;
+ }
+ case INTEGRITY_ALGORITHM:
+ {
+ if ((this->transform_id < AUTH_HMAC_MD5_96) || (this->transform_id > AUTH_AES_XCBC_96))
+ {
+ return FAILED;
+ }
+ break;
+ }
+ case DIFFIE_HELLMAN_GROUP:
+ {
+ switch (this->transform_id)
+ {
+ case MODP_768_BIT:
+ case MODP_1024_BIT:
+ case MODP_1536_BIT:
+ case MODP_2048_BIT:
+ case MODP_3072_BIT:
+ case MODP_4096_BIT:
+ case MODP_6144_BIT:
+ case MODP_8192_BIT:
+ {
+ break;
+ }
+ default:
+ {
+ return FAILED;
+ }
+ }
+
+
+ break;
+ }
+ case EXTENDED_SEQUENCE_NUMBERS:
+ {
+ if ((this->transform_id != NO_EXT_SEQ_NUMBERS) && (this->transform_id != EXT_SEQ_NUMBERS))
+ {
+ return FAILED;
+ }
+ break;
+ }
+ default:
+ {
+ /* not a supported transform type! */
+ return FAILED;
+ }
+ }
+ iterator = this->attributes->create_iterator(this->attributes,TRUE);
+
+ while(iterator->has_next(iterator))
+ {
+ payload_t *current_attributes;
+ iterator->current(iterator,(void **)&current_attributes);
+
+ status = current_attributes->verify(current_attributes);
+ if (status != SUCCESS)
+ {
+ break;
+ }
+ }
+
+ iterator->destroy(iterator);
+
+
+ /* proposal number is checked in SA payload */
+ return status;
+}
+
+/**
+ * Implementation of payload_t.get_encoding_rules.
+ */
+static void get_encoding_rules(private_transform_substructure_t *this, encoding_rule_t **rules, size_t *rule_count)
+{
+ *rules = transform_substructure_encodings;
+ *rule_count = sizeof(transform_substructure_encodings) / sizeof(encoding_rule_t);
+}
+
+/**
+ * Implementation of payload_t.get_type.
+ */
+static payload_type_t get_type(private_transform_substructure_t *this)
+{
+ return TRANSFORM_SUBSTRUCTURE;
+}
+
+/**
+ * Implementation of payload_t.get_next_type.
+ */
+static payload_type_t get_next_type(private_transform_substructure_t *this)
+{
+ return (this->next_payload);
+}
+
+/**
+ * Implementation of payload_t.get_length.
+ */
+static size_t get_length(private_transform_substructure_t *this)
+{
+ this->compute_length(this);
+
+ return this->transform_length;
+}
+
+/**
+ * Implementation of transform_substructure_t.create_transform_attribute_iterator.
+ */
+static iterator_t *create_transform_attribute_iterator (private_transform_substructure_t *this,bool forward)
+{
+ return this->attributes->create_iterator(this->attributes,forward);
+}
+
+/**
+ * Implementation of transform_substructure_t.add_transform_attribute.
+ */
+static void add_transform_attribute (private_transform_substructure_t *this,transform_attribute_t *attribute)
+{
+ this->attributes->insert_last(this->attributes,(void *) attribute);
+ this->compute_length(this);
+}
+
+/**
+ * Implementation of transform_substructure_t.set_is_last_transform.
+ */
+static void set_is_last_transform (private_transform_substructure_t *this, bool is_last)
+{
+ this->next_payload = (is_last) ? 0: TRANSFORM_TYPE_VALUE;
+}
+
+/**
+ * Implementation of transform_substructure_t.get_is_last_transform.
+ */
+static bool get_is_last_transform (private_transform_substructure_t *this)
+{
+ return ((this->next_payload == TRANSFORM_TYPE_VALUE) ? FALSE : TRUE);
+}
+
+/**
+ * Implementation of payload_t.set_next_type.
+ */
+static void set_next_type(private_transform_substructure_t *this,payload_type_t type)
+{
+}
+
+/**
+ * Implementation of transform_substructure_t.set_transform_type.
+ */
+static void set_transform_type (private_transform_substructure_t *this,u_int8_t type)
+{
+ this->transform_type = type;
+}
+
+/**
+ * Implementation of transform_substructure_t.get_transform_type.
+ */
+static u_int8_t get_transform_type (private_transform_substructure_t *this)
+{
+ return this->transform_type;
+}
+
+/**
+ * Implementation of transform_substructure_t.set_transform_id.
+ */
+static void set_transform_id (private_transform_substructure_t *this,u_int16_t id)
+{
+ this->transform_id = id;
+}
+
+/**
+ * Implementation of transform_substructure_t.get_transform_id.
+ */
+static u_int16_t get_transform_id (private_transform_substructure_t *this)
+{
+ return this->transform_id;
+}
+
+/**
+ * Implementation of private_transform_substructure_t.compute_length.
+ */
+static void compute_length (private_transform_substructure_t *this)
+{
+ iterator_t *iterator;
+ size_t length = TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH;
+ iterator = this->attributes->create_iterator(this->attributes,TRUE);
+ while (iterator->has_next(iterator))
+ {
+ payload_t * current_attribute;
+ iterator->current(iterator,(void **) &current_attribute);
+ length += current_attribute->get_length(current_attribute);
+ }
+ iterator->destroy(iterator);
+
+ this->transform_length = length;
+}
+
+/**
+ * Implementation of transform_substructure_t.clone.
+ */
+static transform_substructure_t *clone(private_transform_substructure_t *this)
+{
+ private_transform_substructure_t *new_clone;
+ iterator_t *attributes;
+
+ new_clone = (private_transform_substructure_t *) transform_substructure_create();
+
+ new_clone->next_payload = this->next_payload;
+ new_clone->transform_type = this->transform_type;
+ new_clone->transform_id = this->transform_id;
+
+ attributes = this->attributes->create_iterator(this->attributes,FALSE);
+
+ while (attributes->has_next(attributes))
+ {
+ transform_attribute_t *current_attribute;
+ transform_attribute_t *current_attribute_clone;
+ attributes->current(attributes,(void **) &current_attribute);
+
+ current_attribute_clone = current_attribute->clone(current_attribute);
+
+ new_clone->public.add_transform_attribute(&(new_clone->public),current_attribute_clone);
+ }
+
+ attributes->destroy(attributes);
+
+ return &(new_clone->public);
+}
+
+
+/**
+ * Implementation of transform_substructure_t.get_key_length.
+ */
+static status_t get_key_length(private_transform_substructure_t *this, u_int16_t *key_length)
+{
+ iterator_t *attributes;
+
+ attributes = this->attributes->create_iterator(this->attributes,TRUE);
+
+ while (attributes->has_next(attributes))
+ {
+ transform_attribute_t *current_attribute;
+ attributes->current(attributes,(void **) &current_attribute);
+
+ if (current_attribute->get_attribute_type(current_attribute) == KEY_LENGTH)
+ {
+ *key_length = current_attribute->get_value(current_attribute);
+ attributes->destroy(attributes);
+ return SUCCESS;
+ }
+
+ }
+ attributes->destroy(attributes);
+
+ return FAILED;
+}
+
+
+/**
+ * Implementation of transform_substructure_t.destroy and payload_t.destroy.
+ */
+static void destroy(private_transform_substructure_t *this)
+{
+ /* all proposals are getting destroyed */
+ while (this->attributes->get_count(this->attributes) > 0)
+ {
+ transform_attribute_t *current_attribute;
+ this->attributes->remove_last(this->attributes,(void **)&current_attribute);
+ current_attribute->destroy(current_attribute);
+ }
+ this->attributes->destroy(this->attributes);
+
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+transform_substructure_t *transform_substructure_create()
+{
+ private_transform_substructure_t *this = malloc_thing(private_transform_substructure_t);
+
+ /* payload interface */
+ this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
+ this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
+ this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
+ this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
+ this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
+ this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_type;
+ this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
+
+ /* public functions */
+ this->public.create_transform_attribute_iterator = (iterator_t * (*) (transform_substructure_t *,bool)) create_transform_attribute_iterator;
+ this->public.add_transform_attribute = (void (*) (transform_substructure_t *,transform_attribute_t *)) add_transform_attribute;
+ this->public.set_is_last_transform = (void (*) (transform_substructure_t *,bool)) set_is_last_transform;
+ this->public.get_is_last_transform = (bool (*) (transform_substructure_t *)) get_is_last_transform;
+ this->public.set_transform_type = (void (*) (transform_substructure_t *,u_int8_t)) set_transform_type;
+ this->public.get_transform_type = (u_int8_t (*) (transform_substructure_t *)) get_transform_type;
+ this->public.set_transform_id = (void (*) (transform_substructure_t *,u_int16_t)) set_transform_id;
+ this->public.get_transform_id = (u_int16_t (*) (transform_substructure_t *)) get_transform_id;
+ this->public.get_key_length = (status_t (*) (transform_substructure_t *,u_int16_t *)) get_key_length;
+ this->public.clone = (transform_substructure_t* (*) (transform_substructure_t *)) clone;
+ this->public.destroy = (void (*) (transform_substructure_t *)) destroy;
+
+ /* private functions */
+ this->compute_length = compute_length;
+
+ /* set default values of the fields */
+ this->next_payload = NO_PAYLOAD;
+ this->transform_length = TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH;
+ this->transform_id = 0;
+ this->transform_type = 0;
+ this->attributes = linked_list_create();
+
+ return (&(this->public));
+}
+
+/*
+ * Described in header
+ */
+transform_substructure_t *transform_substructure_create_type(transform_type_t transform_type, u_int16_t transform_id, u_int16_t key_length)
+{
+ transform_substructure_t *transform = transform_substructure_create();
+
+ transform->set_transform_type(transform,transform_type);
+ transform->set_transform_id(transform,transform_id);
+
+ /* a keylength attribute is only created for AES encryption */
+ if (transform_type == ENCRYPTION_ALGORITHM &&
+ transform_id == ENCR_AES_CBC)
+ {
+ transform_attribute_t *attribute = transform_attribute_create_key_length(key_length);
+ transform->add_transform_attribute(transform,attribute);
+ }
+
+ return transform;
+}
diff --git a/programs/charon/charon/encoding/payloads/transform_substructure.h b/programs/charon/charon/encoding/payloads/transform_substructure.h
new file mode 100644
index 000000000..f6af3ee59
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/transform_substructure.h
@@ -0,0 +1,198 @@
+/**
+ * @file transform_substructure.h
+ *
+ * @brief Interface of transform_substructure_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef TRANSFORM_SUBSTRUCTURE_H_
+#define TRANSFORM_SUBSTRUCTURE_H_
+
+#include <types.h>
+#include <definitions.h>
+#include <encoding/payloads/payload.h>
+#include <encoding/payloads/transform_attribute.h>
+#include <utils/linked_list.h>
+#include <crypto/diffie_hellman.h>
+#include <crypto/signers/signer.h>
+#include <crypto/prfs/prf.h>
+#include <crypto/crypters/crypter.h>
+#include <config/proposal.h>
+
+
+/**
+ * IKEv1 Value for a transform payload.
+ *
+ * @ingroup payloads
+ */
+#define TRANSFORM_TYPE_VALUE 3
+
+/**
+ * Length of the transform substructure header in bytes.
+ *
+ * @ingroup payloads
+ */
+#define TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH 8
+
+
+typedef struct transform_substructure_t transform_substructure_t;
+
+/**
+ * @brief Class representing an IKEv2- TRANSFORM SUBSTRUCTURE.
+ *
+ * The TRANSFORM SUBSTRUCTURE format is described in RFC section 3.3.2.
+ *
+ * @ingroup payloads
+ */
+struct transform_substructure_t {
+ /**
+ * The payload_t interface.
+ */
+ 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!
+ *
+ * @warning 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)
+ * @return created iterator_t object.
+ */
+ 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.
+ *
+ * @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);
+
+ /**
+ * @brief 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.
+ *
+ * @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.
+ *
+ * @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);
+
+ /**
+ * @brief 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.
+ *
+ * @param this calling transform_substructure_t object
+ * @param id transform id to set
+ */
+ void (*set_transform_id) (transform_substructure_t *this,u_int16_t id);
+
+ /**
+ * @brief 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.
+ *
+ * @param this calling transform_substructure_t object
+ * @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);
+
+ /**
+ * @brief 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
+ */
+ void (*destroy) (transform_substructure_t *this);
+};
+
+/**
+ * @brief Creates an empty transform_substructure_t object.
+ *
+ * @return created transform_substructure_t object
+ *
+ * @ingroup payloads
+ */
+transform_substructure_t *transform_substructure_create();
+
+/**
+ * @brief Creates an empty transform_substructure_t object.
+ *
+ * The key length is used for the transport types ENCRYPTION_ALGORITHM,
+ * PSEUDO_RANDOM_FUNCTION, INTEGRITY_ALGORITHM. For all
+ * other transport types the key_length parameter is not used
+ *
+ * @param transform_type type of transform to create
+ * @param transform_id transform id specifying the specific algorithm of a transform type
+ * @param key_length Key length for key lenght attribute
+ * @return transform_substructure_t object
+ *
+ * @ingroup payloads
+ */
+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_*/
diff --git a/programs/charon/charon/encoding/payloads/ts_payload.c b/programs/charon/charon/encoding/payloads/ts_payload.c
new file mode 100644
index 000000000..58772e666
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/ts_payload.c
@@ -0,0 +1,365 @@
+/**
+ * @file ts_payload.c
+ *
+ * @brief Implementation of ts_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stddef.h>
+
+#include "ts_payload.h"
+
+#include <encoding/payloads/encodings.h>
+#include <utils/linked_list.h>
+
+typedef struct private_ts_payload_t private_ts_payload_t;
+
+/**
+ * Private data of an ts_payload_t object.
+ *
+ */
+struct private_ts_payload_t {
+ /**
+ * Public ts_payload_t interface.
+ */
+ ts_payload_t public;
+
+ /**
+ * TRUE if this TS payload is of type TSi, FALSE for TSr.
+ */
+ bool is_initiator;
+
+ /**
+ * Next payload type.
+ */
+ u_int8_t next_payload;
+
+ /**
+ * Critical flag.
+ */
+ bool critical;
+
+ /**
+ * Length of this payload.
+ */
+ u_int16_t payload_length;
+
+ /**
+ * Number of traffic selectors
+ */
+ u_int8_t number_of_traffic_selectors;
+
+ /**
+ * Contains the traffic selectors of type traffic_selector_substructure_t.
+ */
+ linked_list_t *traffic_selectors;
+
+ /**
+ * @brief Computes the length of this payload.
+ *
+ * @param this calling private_ts_payload_t object
+ */
+ void (*compute_length) (private_ts_payload_t *this);
+};
+
+/**
+ * Encoding rules to parse or generate a TS payload
+ *
+ * The defined offsets are the positions in a object of type
+ * private_ts_payload_t.
+ *
+ */
+encoding_rule_t ts_payload_encodings[] = {
+ /* 1 Byte next payload type, stored in the field next_payload */
+ { U_INT_8, offsetof(private_ts_payload_t, next_payload) },
+ /* the critical bit */
+ { FLAG, offsetof(private_ts_payload_t, critical) },
+ /* 7 Bit reserved bits, nowhere stored */
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ /* Length of the whole payload*/
+ { PAYLOAD_LENGTH, offsetof(private_ts_payload_t, payload_length)},
+ /* 1 Byte TS type*/
+ { U_INT_8, offsetof(private_ts_payload_t, number_of_traffic_selectors) },
+ /* 3 reserved bytes */
+ { RESERVED_BYTE, 0 },
+ { RESERVED_BYTE, 0 },
+ { RESERVED_BYTE, 0 },
+ /* some ts data bytes, length is defined in PAYLOAD_LENGTH */
+ { TRAFFIC_SELECTORS, offsetof(private_ts_payload_t, traffic_selectors) }
+};
+
+/*
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Next Payload !C! RESERVED ! Payload Length !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Number of TSs ! RESERVED !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! !
+ ~ <Traffic Selectors> ~
+ ! !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+/**
+ * Implementation of payload_t.verify.
+ */
+static status_t verify(private_ts_payload_t *this)
+{
+ iterator_t *iterator;
+ status_t status = SUCCESS;
+
+ if (this->number_of_traffic_selectors != (this->traffic_selectors->get_count(this->traffic_selectors)))
+ {
+ /* must be the same */
+ return FAILED;
+ }
+
+ iterator = this->traffic_selectors->create_iterator(this->traffic_selectors,TRUE);
+ while(iterator->has_next(iterator))
+ {
+ payload_t *current_traffic_selector;
+ iterator->current(iterator,(void **)&current_traffic_selector);
+
+ status = current_traffic_selector->verify(current_traffic_selector);
+ if (status != SUCCESS)
+ {
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+
+ return status;
+}
+
+/**
+ * Implementation of ts_payload_t.get_encoding_rules.
+ */
+static void get_encoding_rules(private_ts_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
+{
+ *rules = ts_payload_encodings;
+ *rule_count = sizeof(ts_payload_encodings) / sizeof(encoding_rule_t);
+}
+
+/**
+ * Implementation of payload_t.get_type.
+ */
+static payload_type_t get_payload_type(private_ts_payload_t *this)
+{
+ if (this->is_initiator)
+ {
+ return TRAFFIC_SELECTOR_INITIATOR;
+ }
+ else
+ {
+ return TRAFFIC_SELECTOR_RESPONDER;
+ }
+}
+
+/**
+ * Implementation of payload_t.get_next_type.
+ */
+static payload_type_t get_next_type(private_ts_payload_t *this)
+{
+ return (this->next_payload);
+}
+
+/**
+ * Implementation of payload_t.set_next_type.
+ */
+static void set_next_type(private_ts_payload_t *this,payload_type_t type)
+{
+ this->next_payload = type;
+}
+
+/**
+ * Implementation of payload_t.get_length.
+ */
+static size_t get_length(private_ts_payload_t *this)
+{
+ this->compute_length(this);
+ return this->payload_length;
+}
+
+/**
+ * Implementation of ts_payload_t.get_initiator.
+ */
+static bool get_initiator (private_ts_payload_t *this)
+{
+ return (this->is_initiator);
+}
+
+/**
+ * Implementation of ts_payload_t.set_initiator.
+ */
+static void set_initiator (private_ts_payload_t *this,bool is_initiator)
+{
+ this->is_initiator = is_initiator;
+}
+
+/**
+ * Implementation of ts_payload_t.add_traffic_selector_substructure.
+ */
+static void add_traffic_selector_substructure (private_ts_payload_t *this,traffic_selector_substructure_t *traffic_selector)
+{
+ this->traffic_selectors->insert_last(this->traffic_selectors,traffic_selector);
+ this->number_of_traffic_selectors = this->traffic_selectors->get_count(this->traffic_selectors);
+}
+
+/**
+ * Implementation of ts_payload_t.create_traffic_selector_substructure_iterator.
+ */
+static iterator_t * create_traffic_selector_substructure_iterator (private_ts_payload_t *this, bool forward)
+{
+ return this->traffic_selectors->create_iterator(this->traffic_selectors,forward);
+}
+
+/**
+ * Implementation of ts_payload_t.get_traffic_selectors.
+ */
+static linked_list_t *get_traffic_selectors(private_ts_payload_t *this)
+{
+ traffic_selector_t *ts;
+ iterator_t *iterator;
+ linked_list_t *ts_list = linked_list_create();
+
+ iterator = this->traffic_selectors->create_iterator(this->traffic_selectors, TRUE);
+ while (iterator->has_next(iterator))
+ {
+ traffic_selector_substructure_t *ts_substructure;
+ iterator->current(iterator, (void**)&ts_substructure);
+ ts = ts_substructure->get_traffic_selector(ts_substructure);
+ ts_list->insert_last(ts_list, (void*)ts);
+ }
+ iterator->destroy(iterator);
+
+ return ts_list;
+}
+
+/**
+ * Implementation of private_ts_payload_t.compute_length.
+ */
+static void compute_length (private_ts_payload_t *this)
+{
+ iterator_t *iterator;
+ size_t ts_count = 0;
+ size_t length = TS_PAYLOAD_HEADER_LENGTH;
+ iterator = this->traffic_selectors->create_iterator(this->traffic_selectors,TRUE);
+ while (iterator->has_next(iterator))
+ {
+ payload_t * current_traffic_selector;
+ iterator->current(iterator,(void **) &current_traffic_selector);
+ length += current_traffic_selector->get_length(current_traffic_selector);
+ ts_count++;
+ }
+ iterator->destroy(iterator);
+
+ this->number_of_traffic_selectors= ts_count;
+ this->payload_length = length;
+
+}
+
+
+/**
+ * Implementation of payload_t.destroy and ts_payload_t.destroy.
+ */
+static void destroy(private_ts_payload_t *this)
+{
+ while (this->traffic_selectors->get_count(this->traffic_selectors) > 0)
+ {
+ payload_t *current_traffic_selector;
+
+ this->traffic_selectors->remove_last(this->traffic_selectors,(void **) &current_traffic_selector);
+
+ current_traffic_selector->destroy(current_traffic_selector);
+ }
+
+ this->traffic_selectors->destroy(this->traffic_selectors);
+
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+ts_payload_t *ts_payload_create(bool is_initiator)
+{
+ private_ts_payload_t *this = malloc_thing(private_ts_payload_t);
+
+ /* interface functions */
+ this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
+ this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
+ this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
+ this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
+ this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
+ this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_payload_type;
+ this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
+
+ /* public functions */
+ this->public.destroy = (void (*) (ts_payload_t *)) destroy;
+ this->public.get_initiator = (bool (*) (ts_payload_t *)) get_initiator;
+ this->public.set_initiator = (void (*) (ts_payload_t *,bool)) set_initiator;
+ this->public.add_traffic_selector_substructure = (void (*) (ts_payload_t *,traffic_selector_substructure_t *)) add_traffic_selector_substructure;
+ this->public.create_traffic_selector_substructure_iterator = (iterator_t* (*) (ts_payload_t *,bool)) create_traffic_selector_substructure_iterator;
+ this->public.get_traffic_selectors = (linked_list_t *(*) (ts_payload_t *)) get_traffic_selectors;
+
+ /* private functions */
+ this->compute_length = compute_length;
+
+ /* private variables */
+ this->critical = FALSE;
+ this->next_payload = NO_PAYLOAD;
+ this->payload_length =TS_PAYLOAD_HEADER_LENGTH;
+ this->is_initiator = is_initiator;
+ this->number_of_traffic_selectors = 0;
+ this->traffic_selectors = linked_list_create();
+
+ return &(this->public);
+}
+
+/*
+ * Described in header
+ */
+ts_payload_t *ts_payload_create_from_traffic_selectors(bool is_initiator, linked_list_t *traffic_selectors)
+{
+ iterator_t *iterator;
+ traffic_selector_t *ts;
+ traffic_selector_substructure_t *ts_substructure;
+ private_ts_payload_t *this;
+
+ this = (private_ts_payload_t*)ts_payload_create(is_initiator);
+
+ iterator = traffic_selectors->create_iterator(traffic_selectors, TRUE);
+ while (iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void**)&ts);
+ ts_substructure = traffic_selector_substructure_create_from_traffic_selector(ts);
+ this->public.add_traffic_selector_substructure(&(this->public), ts_substructure);
+ }
+ iterator->destroy(iterator);
+
+ return &(this->public);
+}
+
diff --git a/programs/charon/charon/encoding/payloads/ts_payload.h b/programs/charon/charon/encoding/payloads/ts_payload.h
new file mode 100644
index 000000000..775ff6134
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/ts_payload.h
@@ -0,0 +1,152 @@
+/**
+ * @file ts_payload.h
+ *
+ * @brief Interface of ts_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#ifndef TS_PAYLOAD_H_
+#define TS_PAYLOAD_H_
+
+#include <types.h>
+#include <utils/linked_list.h>
+#include <config/traffic_selector.h>
+#include <encoding/payloads/payload.h>
+#include <encoding/payloads/traffic_selector_substructure.h>
+
+/**
+ * Length of a TS payload without the Traffic selectors.
+ *
+ * @ingroup payloads
+ */
+#define TS_PAYLOAD_HEADER_LENGTH 8
+
+
+typedef struct ts_payload_t ts_payload_t;
+
+/**
+ * @brief 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 {
+ /**
+ * The payload_t interface.
+ */
+ payload_t payload_interface;
+
+ /**
+ * @brief 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
+ */
+ bool (*get_initiator) (ts_payload_t *this);
+
+ /**
+ * @brief 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
+ */
+ 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.
+ *
+ * @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);
+
+ /**
+ * @brief 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!
+ *
+ * @param this calling ts_payload_t object
+ * @param[in] 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);
+
+ /**
+ * @brief 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
+ */
+ void (*destroy) (ts_payload_t *this);
+};
+
+/**
+ * @brief 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
+ *
+ *
+ * @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);
+
+
+#endif /* TS_PAYLOAD_H_ */
diff --git a/programs/charon/charon/encoding/payloads/unknown_payload.c b/programs/charon/charon/encoding/payloads/unknown_payload.c
new file mode 100644
index 000000000..25bb37d59
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/unknown_payload.c
@@ -0,0 +1,207 @@
+/**
+ * @file unknown_payload.c
+ *
+ * @brief Implementation of unknown_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stddef.h>
+
+#include "unknown_payload.h"
+
+
+
+typedef struct private_unknown_payload_t private_unknown_payload_t;
+
+/**
+ * Private data of an unknown_payload_t object.
+ */
+struct private_unknown_payload_t {
+
+ /**
+ * Public unknown_payload_t interface.
+ */
+ unknown_payload_t public;
+
+ /**
+ * Next payload type.
+ */
+ u_int8_t next_payload;
+
+ /**
+ * Critical flag.
+ */
+ bool critical;
+
+ /**
+ * Length of this payload.
+ */
+ u_int16_t payload_length;
+
+ /**
+ * The contained data.
+ */
+ chunk_t data;
+};
+
+/**
+ * Encoding rules to parse an payload which is not further specified.
+ *
+ * The defined offsets are the positions in a object of type
+ * private_unknown_payload_t.
+ *
+ */
+encoding_rule_t unknown_payload_encodings[] = {
+ /* 1 Byte next payload type, stored in the field next_payload */
+ { U_INT_8, offsetof(private_unknown_payload_t, next_payload)},
+ /* the critical bit */
+ { FLAG, offsetof(private_unknown_payload_t, critical) },
+ /* 7 Bit reserved bits, nowhere stored */
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ /* Length of the whole payload*/
+ { PAYLOAD_LENGTH, offsetof(private_unknown_payload_t, payload_length)},
+ /* some unknown data bytes, length is defined in PAYLOAD_LENGTH */
+ { UNKNOWN_DATA, offsetof(private_unknown_payload_t, data) }
+};
+
+/*
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Next Payload !C! RESERVED ! Payload Length !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! !
+ ~ Data of any type ~
+ ! !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+/**
+ * Implementation of payload_t.verify.
+ */
+static status_t verify(private_unknown_payload_t *this)
+{
+ /* can't do any checks, so we assume its good */
+ return SUCCESS;
+}
+
+/**
+ * Implementation of payload_t.get_encoding_rules.
+ */
+static void get_encoding_rules(private_unknown_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
+{
+ *rules = unknown_payload_encodings;
+ *rule_count = sizeof(unknown_payload_encodings) / sizeof(encoding_rule_t);
+}
+
+/**
+ * Implementation of payload_t.get_type.
+ */
+static payload_type_t get_payload_type(private_unknown_payload_t *this)
+{
+ return UNKNOWN_PAYLOAD;
+}
+
+/**
+ * Implementation of payload_t.get_next_type.
+ */
+static payload_type_t get_next_type(private_unknown_payload_t *this)
+{
+ return (this->next_payload);
+}
+
+/**
+ * Implementation of payload_t.set_next_type.
+ */
+static void set_next_type(private_unknown_payload_t *this,payload_type_t type)
+{
+ this->next_payload = type;
+}
+
+/**
+ * Implementation of payload_t.get_length.
+ */
+static size_t get_length(private_unknown_payload_t *this)
+{
+ return this->payload_length;
+}
+
+/**
+ * Implementation of unknown_payload_t.get_data.
+ */
+static bool is_critical(private_unknown_payload_t *this)
+{
+ return this->critical;
+}
+
+/**
+ * Implementation of unknown_payload_t.get_data.
+ */
+static chunk_t get_data (private_unknown_payload_t *this)
+{
+ return (this->data);
+}
+
+/**
+ * Implementation of payload_t.destroy and unknown_payload_t.destroy.
+ */
+static void destroy(private_unknown_payload_t *this)
+{
+ if (this->data.ptr != NULL)
+ {
+ chunk_free(&(this->data));
+ }
+
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+unknown_payload_t *unknown_payload_create()
+{
+ private_unknown_payload_t *this = malloc_thing(private_unknown_payload_t);
+
+ /* interface functions */
+ this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
+ this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
+ this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
+ this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
+ this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
+ this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_payload_type;
+ this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
+
+ /* public functions */
+ this->public.destroy = (void (*) (unknown_payload_t *)) destroy;
+ this->public.is_critical = (bool (*) (unknown_payload_t *)) is_critical;
+ this->public.get_data = (chunk_t (*) (unknown_payload_t *)) get_data;
+
+ /* private variables */
+ this->critical = FALSE;
+ this->next_payload = NO_PAYLOAD;
+ this->payload_length = UNKNOWN_PAYLOAD_HEADER_LENGTH;
+ this->data = CHUNK_INITIALIZER;
+
+ return (&(this->public));
+}
diff --git a/programs/charon/charon/encoding/payloads/unknown_payload.h b/programs/charon/charon/encoding/payloads/unknown_payload.h
new file mode 100644
index 000000000..9c4926ea7
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/unknown_payload.h
@@ -0,0 +1,95 @@
+/**
+ * @file unknown_payload.h
+ *
+ * @brief Interface of unknown_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef UNKNOWN_PAYLOAD_H_
+#define UNKNOWN_PAYLOAD_H_
+
+#include <types.h>
+#include <encoding/payloads/payload.h>
+
+/**
+ * Header length of the unknown payload.
+ *
+ * @ingroup payloads
+ */
+#define UNKNOWN_PAYLOAD_HEADER_LENGTH 4
+
+
+typedef struct unknown_payload_t unknown_payload_t;
+
+/**
+ * @brief 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 {
+
+ /**
+ * The payload_t interface.
+ */
+ payload_t payload_interface;
+
+ /**
+ * @brief 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.
+ *
+ * @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
+ */
+ void (*destroy) (unknown_payload_t *this);
+};
+
+/**
+ * @brief Creates an empty unknown_payload_t object.
+ *
+ * @return unknown_payload_t object
+ *
+ * @ingroup payloads
+ */
+unknown_payload_t *unknown_payload_create();
+
+
+#endif /* UNKNOWN_PAYLOAD_H_ */
diff --git a/programs/charon/charon/encoding/payloads/vendor_id_payload.c b/programs/charon/charon/encoding/payloads/vendor_id_payload.c
new file mode 100644
index 000000000..436b82d79
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/vendor_id_payload.c
@@ -0,0 +1,227 @@
+/**
+ * @file vendor_id_payload.c
+ *
+ * @brief Implementation of vendor_id_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stddef.h>
+
+#include "vendor_id_payload.h"
+
+
+typedef struct private_vendor_id_payload_t private_vendor_id_payload_t;
+
+/**
+ * Private data of an vendor_id_payload_t object.
+ *
+ */
+struct private_vendor_id_payload_t {
+ /**
+ * Public vendor_id_payload_t interface.
+ */
+ vendor_id_payload_t public;
+
+ /**
+ * Next payload type.
+ */
+ u_int8_t next_payload;
+
+ /**
+ * Critical flag.
+ */
+ bool critical;
+
+ /**
+ * Length of this payload.
+ */
+ u_int16_t payload_length;
+
+ /**
+ * The contained vendor_id data value.
+ */
+ chunk_t vendor_id_data;
+};
+
+/**
+ * Encoding rules to parse or generate a VENDOR ID payload
+ *
+ * The defined offsets are the positions in a object of type
+ * private_vendor_id_payload_t.
+ *
+ */
+encoding_rule_t vendor_id_payload_encodings[] = {
+ /* 1 Byte next payload type, stored in the field next_payload */
+ { U_INT_8, offsetof(private_vendor_id_payload_t, next_payload) },
+ /* the critical bit */
+ { FLAG, offsetof(private_vendor_id_payload_t, critical) },
+ /* 7 Bit reserved bits, nowhere stored */
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ { RESERVED_BIT, 0 },
+ /* Length of the whole payload*/
+ { PAYLOAD_LENGTH, offsetof(private_vendor_id_payload_t, payload_length)},
+ /* some vendor_id data bytes, length is defined in PAYLOAD_LENGTH */
+ { VID_DATA, offsetof(private_vendor_id_payload_t, vendor_id_data) }
+};
+
+/*
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Next Payload !C! RESERVED ! Payload Length !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Cert Encoding ! !
+ +-+-+-+-+-+-+-+-+ !
+ ~ Certificate Data ~
+ ! !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+/**
+ * Implementation of payload_t.verify.
+ */
+static status_t verify(private_vendor_id_payload_t *this)
+{
+ return SUCCESS;
+}
+
+/**
+ * Implementation of vendor_id_payload_t.get_encoding_rules.
+ */
+static void get_encoding_rules(private_vendor_id_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
+{
+ *rules = vendor_id_payload_encodings;
+ *rule_count = sizeof(vendor_id_payload_encodings) / sizeof(encoding_rule_t);
+}
+
+/**
+ * Implementation of payload_t.get_type.
+ */
+static payload_type_t get_payload_type(private_vendor_id_payload_t *this)
+{
+ return VENDOR_ID;
+}
+
+/**
+ * Implementation of payload_t.get_next_type.
+ */
+static payload_type_t get_next_type(private_vendor_id_payload_t *this)
+{
+ return (this->next_payload);
+}
+
+/**
+ * Implementation of payload_t.set_next_type.
+ */
+static void set_next_type(private_vendor_id_payload_t *this,payload_type_t type)
+{
+ this->next_payload = type;
+}
+
+/**
+ * Implementation of payload_t.get_length.
+ */
+static size_t get_length(private_vendor_id_payload_t *this)
+{
+ return this->payload_length;
+}
+
+/**
+ * Implementation of vendor_id_payload_t.set_data.
+ */
+static void set_data (private_vendor_id_payload_t *this, chunk_t data)
+{
+ if (this->vendor_id_data.ptr != NULL)
+ {
+ chunk_free(&(this->vendor_id_data));
+ }
+ this->vendor_id_data.ptr = clalloc(data.ptr,data.len);
+ this->vendor_id_data.len = data.len;
+ this->payload_length = VENDOR_ID_PAYLOAD_HEADER_LENGTH + this->vendor_id_data.len;
+}
+
+/**
+ * Implementation of vendor_id_payload_t.get_data.
+ */
+static chunk_t get_data (private_vendor_id_payload_t *this)
+{
+ return (this->vendor_id_data);
+}
+
+/**
+ * Implementation of vendor_id_payload_t.get_data_clone.
+ */
+static chunk_t get_data_clone (private_vendor_id_payload_t *this)
+{
+ chunk_t cloned_data;
+ if (this->vendor_id_data.ptr == NULL)
+ {
+ return (this->vendor_id_data);
+ }
+ cloned_data.ptr = clalloc(this->vendor_id_data.ptr,this->vendor_id_data.len);
+ cloned_data.len = this->vendor_id_data.len;
+ return cloned_data;
+}
+
+/**
+ * Implementation of payload_t.destroy and vendor_id_payload_t.destroy.
+ */
+static void destroy(private_vendor_id_payload_t *this)
+{
+ if (this->vendor_id_data.ptr != NULL)
+ {
+ chunk_free(&(this->vendor_id_data));
+ }
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+vendor_id_payload_t *vendor_id_payload_create()
+{
+ private_vendor_id_payload_t *this = malloc_thing(private_vendor_id_payload_t);
+
+ /* interface functions */
+ this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
+ this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
+ this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
+ this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
+ this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
+ this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_payload_type;
+ this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
+
+ /* public functions */
+ this->public.destroy = (void (*) (vendor_id_payload_t *)) destroy;
+ this->public.set_data = (void (*) (vendor_id_payload_t *,chunk_t)) set_data;
+ this->public.get_data_clone = (chunk_t (*) (vendor_id_payload_t *)) get_data_clone;
+ this->public.get_data = (chunk_t (*) (vendor_id_payload_t *)) get_data;
+
+ /* private variables */
+ this->critical = FALSE;
+ this->next_payload = NO_PAYLOAD;
+ this->payload_length = VENDOR_ID_PAYLOAD_HEADER_LENGTH;
+ this->vendor_id_data = CHUNK_INITIALIZER;
+
+ return (&(this->public));
+}
diff --git a/programs/charon/charon/encoding/payloads/vendor_id_payload.h b/programs/charon/charon/encoding/payloads/vendor_id_payload.h
new file mode 100644
index 000000000..c9ead4337
--- /dev/null
+++ b/programs/charon/charon/encoding/payloads/vendor_id_payload.h
@@ -0,0 +1,103 @@
+/**
+ * @file vendor_id_payload.h
+ *
+ * @brief Interface of vendor_id_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef VENDOR_ID_PAYLOAD_H_
+#define VENDOR_ID_PAYLOAD_H_
+
+#include <types.h>
+#include <encoding/payloads/payload.h>
+
+/**
+ * Length of a VENDOR ID payload without the VID data in bytes.
+ *
+ * @ingroup payloads
+ */
+#define VENDOR_ID_PAYLOAD_HEADER_LENGTH 4
+
+
+typedef struct vendor_id_payload_t vendor_id_payload_t;
+
+/**
+ * @brief 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 {
+ /**
+ * The payload_t interface.
+ */
+ payload_t payload_interface;
+
+ /**
+ * @brief 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.
+ *
+ * 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.
+ *
+ * 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
+ */
+ void (*destroy) (vendor_id_payload_t *this);
+};
+
+/**
+ * @brief Creates an empty vendor_id_payload_t object.
+ *
+ * @return vendor_id_payload_t object
+ *
+ * @ingroup payloads
+ */
+vendor_id_payload_t *vendor_id_payload_create();
+
+
+#endif /* VENDOR_ID_PAYLOAD_H_ */
diff --git a/programs/charon/charon/network/Makefile.network b/programs/charon/charon/network/Makefile.network
new file mode 100644
index 000000000..fd99bd085
--- /dev/null
+++ b/programs/charon/charon/network/Makefile.network
@@ -0,0 +1,24 @@
+# Copyright (C) 2005 Jan Hutter, Martin Willi
+# Hochschule fuer Technik Rapperswil
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+
+NETWORK_DIR= $(CHARON_DIR)network/
+
+
+CHARON_OBJS+= $(BUILD_DIR)packet.o
+$(BUILD_DIR)packet.o : $(NETWORK_DIR)packet.c $(NETWORK_DIR)packet.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)socket.o
+$(BUILD_DIR)socket.o : $(NETWORK_DIR)socket.c $(NETWORK_DIR)socket.h
+ $(CC) $(CFLAGS) -c -o $@ $< \ No newline at end of file
diff --git a/programs/charon/charon/network/packet.c b/programs/charon/charon/network/packet.c
new file mode 100644
index 000000000..6cded72a3
--- /dev/null
+++ b/programs/charon/charon/network/packet.c
@@ -0,0 +1,189 @@
+/**
+ * @file packet.c
+ *
+ * @brief Implementation of packet_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#include "packet.h"
+
+
+typedef struct private_packet_t private_packet_t;
+
+/**
+ * Private data of an packet_t object.
+ */
+struct private_packet_t {
+
+ /**
+ * Public part of a packet_t object.
+ */
+ packet_t public;
+
+ /**
+ * source address
+ */
+ host_t *source;
+
+ /**
+ * destination address
+ */
+ host_t *destination;
+
+ /**
+ * message data
+ */
+ chunk_t data;
+};
+
+/**
+ * Implements packet_t.get_source
+ */
+static void set_source(private_packet_t *this, host_t *source)
+{
+ if (this->source)
+ {
+ this->source->destroy(this->source);
+ }
+ this->source = source;
+}
+
+/**
+ * Implements packet_t.set_destination
+ */
+static void set_destination(private_packet_t *this, host_t *destination)
+{
+ if (this->destination)
+ {
+ this->destination->destroy(this->destination);
+ }
+ this->destination = destination;
+}
+
+/**
+ * Implements packet_t.get_source
+ */
+static host_t *get_source(private_packet_t *this)
+{
+ return this->source;
+}
+
+/**
+ * Implements packet_t.get_destination
+ */
+static host_t *get_destination(private_packet_t *this)
+{
+ return this->destination;
+}
+
+/**
+ * Implements packet_t.get_data
+ */
+static chunk_t get_data(private_packet_t *this)
+{
+ return this->data;
+}
+
+/**
+ * Implements packet_t.set_data
+ */
+static void set_data(private_packet_t *this, chunk_t data)
+{
+ free(this->data.ptr);
+ this->data = data;
+}
+
+/**
+ * Implements packet_t.destroy.
+ */
+static void destroy(private_packet_t *this)
+{
+ if (this->source != NULL)
+ {
+ this->source->destroy(this->source);
+ }
+ if (this->destination != NULL)
+ {
+ this->destination->destroy(this->destination);
+ }
+ free(this->data.ptr);
+ free(this);
+}
+
+/**
+ * Implements packet_t.clone.
+ */
+static packet_t *clone(private_packet_t *this)
+{
+ private_packet_t *other = (private_packet_t*)packet_create();
+
+ if (this->destination != NULL)
+ {
+ other->destination = this->destination->clone(this->destination);
+ }
+ else
+ {
+ other->destination = NULL;
+ }
+
+ if (this->source != NULL)
+ {
+ other->source = this->source->clone(this->source);
+ }
+ else
+ {
+ other->source = NULL;
+ }
+
+ /* only clone existing chunks :-) */
+ if (this->data.ptr != NULL)
+ {
+ other->data.ptr = clalloc(this->data.ptr,this->data.len);
+ other->data.len = this->data.len;
+ }
+ else
+ {
+ other->data = CHUNK_INITIALIZER;
+ }
+ return &(other->public);
+}
+
+
+/*
+ * Documented in header
+ */
+packet_t *packet_create()
+{
+ private_packet_t *this = malloc_thing(private_packet_t);
+
+ this->public.set_data = (void(*) (packet_t *,chunk_t)) set_data;
+ this->public.get_data = (chunk_t(*) (packet_t *)) get_data;
+ this->public.set_source = (void(*) (packet_t *,host_t*)) set_source;
+ this->public.get_source = (host_t*(*) (packet_t *)) get_source;
+ this->public.set_destination = (void(*) (packet_t *,host_t*)) set_destination;
+ this->public.get_destination = (host_t*(*) (packet_t *)) get_destination;
+ this->public.clone = (packet_t*(*) (packet_t *))clone;
+ this->public.destroy = (void(*) (packet_t *)) destroy;
+
+ this->destination = NULL;
+ this->source = NULL;
+ this->data = CHUNK_INITIALIZER;
+
+ return &(this->public);
+}
diff --git a/programs/charon/charon/network/packet.h b/programs/charon/charon/network/packet.h
new file mode 100644
index 000000000..a2620d391
--- /dev/null
+++ b/programs/charon/charon/network/packet.h
@@ -0,0 +1,135 @@
+/**
+ * @file packet.h
+ *
+ * @brief Interface of packet_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef PACKET_H_
+#define PACKET_H_
+
+
+#include <types.h>
+#include <utils/host.h>
+
+
+typedef struct packet_t packet_t;
+
+/**
+ * @brief Abstraction of an UDP-Packet, contains data, sender and receiver.
+ *
+ * @b Constructors:
+ * - packet_create()
+ *
+ * @ingroup network
+ */
+struct packet_t {
+
+ /**
+ * @brief 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 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * @param packet calling object
+ * @param clone pointer to a packet_t object pointer where the new object is stored
+ */
+ packet_t* (*clone) (packet_t *packet);
+
+ /**
+ * @brief Destroy the packet, freeing contained data.
+ *
+ * @param packet packet to destroy
+ */
+ void (*destroy) (packet_t *packet);
+};
+
+/**
+ * @brief create an empty packet
+ *
+ * @return packet_t object
+ *
+ * @ingroup network
+ */
+packet_t *packet_create();
+
+
+#endif /*PACKET_H_*/
diff --git a/programs/charon/charon/network/socket.c b/programs/charon/charon/network/socket.c
new file mode 100644
index 000000000..32ff84538
--- /dev/null
+++ b/programs/charon/charon/network/socket.c
@@ -0,0 +1,457 @@
+/**
+ * @file socket.c
+ *
+ * @brief Implementation of socket_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ * Copyright (C) 1998-2002 D. Hugh Redelmeier.
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ *
+ * Some parts of interface lookup code from pluto.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <linux/filter.h>
+
+#include "socket.h"
+
+#include <daemon.h>
+#include <utils/logger_manager.h>
+
+
+#define IP_HEADER_LENGTH 20
+#define UDP_HEADER_LENGTH 8
+
+
+/**
+ * This filter code filters out all non-IKEv2 traffic on
+ * a SOCK_RAW IP_PROTP_UDP socket. Handling of other
+ * IKE versions is done in pluto.
+ */
+struct sock_filter ikev2_filter_code[] =
+{
+ /* Protocol must be UDP */
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 9),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, IPPROTO_UDP, 0, 7),
+ /* Destination Port must be 500 */
+ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 22),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 500, 0, 5),
+ /* IKE version must be 2.0 */
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 45),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x20, 0, 3),
+ /* packet length is length in IKEv2 header + ip header + udp header */
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 52),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, IP_HEADER_LENGTH + UDP_HEADER_LENGTH),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ /* packet doesn't match IKEv2, ignore */
+ BPF_STMT(BPF_RET+BPF_K, 0),
+};
+
+/**
+ * Filter struct to use with setsockopt
+ */
+struct sock_fprog ikev2_filter = {
+ sizeof(ikev2_filter_code) / sizeof(struct sock_filter),
+ ikev2_filter_code
+};
+
+
+typedef struct interface_t interface_t;
+
+/**
+ * An interface on which we listen.
+ */
+struct interface_t {
+
+ /**
+ * Name of the interface
+ */
+ char name[IFNAMSIZ];
+
+ /**
+ * Associated socket
+ */
+ int socket_fd;
+
+ /**
+ * Host with listening address
+ */
+ host_t *address;
+};
+
+typedef struct private_socket_t private_socket_t;
+
+/**
+ * Private data of an socket_t object
+ */
+struct private_socket_t{
+ /**
+ * public functions
+ */
+ socket_t public;
+
+ /**
+ * Master socket
+ */
+ int master_fd;
+
+ /**
+ * List of all socket to listen
+ */
+ linked_list_t* interfaces;
+
+ /**
+ * logger for this socket
+ */
+ logger_t *logger;
+};
+
+/**
+ * implementation of socket_t.receive
+ */
+static status_t receiver(private_socket_t *this, packet_t **packet)
+{
+ char buffer[MAX_PACKET];
+ chunk_t data;
+ packet_t *pkt = packet_create();
+ host_t *source, *dest;
+ int bytes_read = 0;
+
+
+ while (bytes_read >= 0)
+ {
+ int max_fd = 1;
+ fd_set readfds;
+ iterator_t *iterator;
+ int oldstate;
+ interface_t *interface;
+
+ /* build fd_set */
+ FD_ZERO(&readfds);
+ iterator = this->interfaces->create_iterator(this->interfaces, TRUE);
+ while (iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void**)&interface);
+ FD_SET(interface->socket_fd, &readfds);
+ if (interface->socket_fd > max_fd)
+ {
+ max_fd = interface->socket_fd + 1;
+ }
+ }
+ iterator->destroy(iterator);
+
+ /* add packet destroy handler for cancellation, enable cancellation */
+ pthread_cleanup_push((void(*)(void*))pkt->destroy, (void*)pkt);
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
+
+ this->logger->log(this->logger, CONTROL|LEVEL1, "waiting on sockets");
+ bytes_read = select(max_fd, &readfds, NULL, NULL, NULL);
+
+ /* reset cancellation, remove packet destroy handler (without executing) */
+ pthread_setcancelstate(oldstate, NULL);
+ pthread_cleanup_pop(0);
+
+ /* read on the first nonblocking socket */
+ bytes_read = 0;
+ iterator = this->interfaces->create_iterator(this->interfaces, TRUE);
+ while (iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void**)&interface);
+ if (FD_ISSET(interface->socket_fd, &readfds))
+ {
+ /* do the read */
+ bytes_read = recv(interface->socket_fd, buffer, MAX_PACKET, 0);
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+
+ if (bytes_read < 0)
+ {
+ this->logger->log(this->logger, ERROR, "error reading from socket: %s", strerror(errno));
+ continue;
+ }
+ if (bytes_read > IP_HEADER_LENGTH + UDP_HEADER_LENGTH)
+ {
+ /* read source/dest from raw IP/UDP header */
+ chunk_t source_chunk = {buffer + 12, 4};
+ chunk_t dest_chunk = {buffer + 16, 4};
+ u_int16_t source_port = ntohs(*(u_int16_t*)(buffer + 20));
+ u_int16_t dest_port = ntohs(*(u_int16_t*)(buffer + 22));
+ source = host_create_from_chunk(AF_INET, source_chunk, source_port);
+ dest = host_create_from_chunk(AF_INET, dest_chunk, dest_port);
+ pkt->set_source(pkt, source);
+ pkt->set_destination(pkt, dest);
+ break;
+ }
+ this->logger->log(this->logger, ERROR|LEVEL1, "too short packet received");
+ }
+
+ this->logger->log(this->logger, CONTROL, "received packet: from %s:%d to %s:%d",
+ source->get_address(source), source->get_port(source),
+ dest->get_address(dest), dest->get_port(dest));
+
+ /* fill in packet */
+ data.len = bytes_read - IP_HEADER_LENGTH - UDP_HEADER_LENGTH;
+ data.ptr = malloc(data.len);
+ memcpy(data.ptr, buffer + IP_HEADER_LENGTH + UDP_HEADER_LENGTH, data.len);
+ pkt->set_data(pkt, data);
+
+ /* return packet */
+ *packet = pkt;
+
+ return SUCCESS;
+}
+
+/**
+ * implementation of socket_t.send
+ */
+status_t sender(private_socket_t *this, packet_t *packet)
+{
+ ssize_t bytes_sent;
+ chunk_t data;
+ host_t *src, *dst;
+
+ src = packet->get_source(packet);
+ dst = packet->get_destination(packet);
+ data = packet->get_data(packet);
+
+ this->logger->log(this->logger, CONTROL, "sending packet: from %s:%d to %s:%d",
+ src->get_address(src), src->get_port(src),
+ dst->get_address(dst), dst->get_port(dst));
+
+ /* send data */
+ /* TODO: should we send via the interface we received the packet? */
+ bytes_sent = sendto(this->master_fd, data.ptr, data.len, 0,
+ dst->get_sockaddr(dst), *(dst->get_sockaddr_len(dst)));
+
+ if (bytes_sent != data.len)
+ {
+ this->logger->log(this->logger, ERROR, "error writing to socket: %s", strerror(errno));
+ return FAILED;
+ }
+ return SUCCESS;
+}
+
+/**
+ * Find all suitable interfaces, bind them and add them to the list
+ */
+static status_t build_interface_list(private_socket_t *this, u_int16_t port)
+{
+ int on = TRUE;
+ int i;
+ struct sockaddr_in addr;
+ struct ifconf ifconf;
+ struct ifreq buf[300];
+
+ /* master socket for querying socket for a specific interfaces */
+ this->master_fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (this->master_fd == -1)
+ {
+ this->logger->log(this->logger, ERROR, "could not open IPv4 master socket!");
+ return FAILED;
+ }
+
+ /* allow binding of multiplo sockets */
+ if (setsockopt(this->master_fd, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0)
+ {
+ this->logger->log(this->logger, ERROR, "unable to set SO_REUSEADDR on master socket!");
+ return FAILED;
+ }
+
+ /* bind the master socket */
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = INADDR_ANY;
+ addr.sin_port = htons(port);
+ if (bind(this->master_fd,(struct sockaddr*)&addr, sizeof(addr)) < 0)
+ {
+ this->logger->log(this->logger, ERROR, "unable to bind master socket: %s!", strerror(errno));
+ return FAILED;
+ }
+
+ /* get all interfaces */
+ ifconf.ifc_len = sizeof(buf);
+ ifconf.ifc_buf = (void*) buf;
+ memset(buf, 0, sizeof(buf));
+ if (ioctl(this->master_fd, SIOCGIFCONF, &ifconf) == -1)
+ {
+ this->logger->log(this->logger, ERROR, "unable to get interfaces!");
+ return FAILED;
+ }
+
+ /* add every interesting interfaces to our interface list */
+ for (i = 0; (i+1) * sizeof(*buf) <= (size_t)ifconf.ifc_len; i++)
+ {
+ struct sockaddr_in *current = (struct sockaddr_in*) &buf[i].ifr_addr;
+ struct ifreq auxinfo;
+ int skt;
+ interface_t *interface;
+
+ if (current->sin_family != AF_INET)
+ {
+ /* ignore all but AF_INET interfaces */
+ continue;
+ }
+
+ /* get auxilary info about socket */
+ memset(&auxinfo, 0, sizeof(auxinfo));
+ memcpy(auxinfo.ifr_name, buf[i].ifr_name, IFNAMSIZ);
+ if (ioctl(this->master_fd, SIOCGIFFLAGS, &auxinfo) == -1)
+ {
+ this->logger->log(this->logger, ERROR, "unable to SIOCGIFFLAGS master socket!");
+ continue;
+ }
+ if (!(auxinfo.ifr_flags & IFF_UP))
+ {
+ /* ignore an interface that isn't up */
+ continue;
+ }
+ if (current->sin_addr.s_addr == 0)
+ {
+ /* ignore unconfigured interfaces */
+ continue;
+ }
+
+ /* set up interface socket */
+ skt = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
+ if (socket < 0)
+ {
+ this->logger->log(this->logger, ERROR, "unable to open interface socket!");
+ continue;
+ }
+ if (setsockopt(skt, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0)
+ {
+ this->logger->log(this->logger, ERROR, "unable to set SO_REUSEADDR on interface socket!");
+ close(skt);
+ continue;
+ }
+ current->sin_port = htons(port);
+ current->sin_family = AF_INET;
+ if (bind(skt, (struct sockaddr*)current, sizeof(struct sockaddr_in)) < 0)
+ {
+ this->logger->log(this->logger, ERROR, "unable to bind interface socket!");
+ close(skt);
+ continue;
+ }
+
+ if (setsockopt(skt, SOL_SOCKET, SO_ATTACH_FILTER, &ikev2_filter, sizeof(ikev2_filter)) < 0)
+ {
+ this->logger->log(this->logger, ERROR, "unable to attack IKEv2 filter to interface socket!");
+ close(skt);
+ continue;
+ }
+
+ /* add socket with interface name to list */
+ interface = malloc_thing(interface_t);
+ memcpy(interface->name, buf[i].ifr_name, IFNAMSIZ);
+ interface->name[IFNAMSIZ-1] = '\0';
+ interface->socket_fd = skt;
+ interface->address = host_create_from_sockaddr((struct sockaddr*)current);
+ this->logger->log(this->logger, CONTROL, "listening on %s (%s)",
+ interface->name, interface->address->get_address(interface->address));
+ this->interfaces->insert_last(this->interfaces, (void*)interface);
+ }
+
+ if (this->interfaces->get_count(this->interfaces) == 0)
+ {
+ this->logger->log(this->logger, ERROR, "unable to find any usable interface!");
+ return FAILED;
+ }
+ return SUCCESS;
+}
+
+/**
+ * implementation of socket_t.is_listening_on
+ */
+static bool is_listening_on(private_socket_t *this, host_t *host)
+{
+ iterator_t *iterator;
+
+ /* listening on 0.0.0.0 is always TRUE */
+ if (host->is_default_route(host))
+ {
+ return TRUE;
+ }
+
+ /* compare host with all interfaces */
+ iterator = this->interfaces->create_iterator(this->interfaces, TRUE);
+ while (iterator->has_next(iterator))
+ {
+ interface_t *interface;
+ iterator->current(iterator, (void**)&interface);
+ if (host->equals(host, interface->address))
+ {
+ iterator->destroy(iterator);
+ return TRUE;
+ }
+ }
+ iterator->destroy(iterator);
+ return FALSE;
+}
+
+/**
+ * implementation of socket_t.destroy
+ */
+static void destroy(private_socket_t *this)
+{
+ interface_t *interface;
+ while (this->interfaces->remove_last(this->interfaces, (void**)&interface) == SUCCESS)
+ {
+ interface->address->destroy(interface->address);
+ close(interface->socket_fd);
+ free(interface);
+ }
+ this->interfaces->destroy(this->interfaces);
+ close(this->master_fd);
+ free(this);
+}
+
+/*
+ * See header for description
+ */
+socket_t *socket_create(u_int16_t port)
+{
+ private_socket_t *this = malloc_thing(private_socket_t);
+
+ /* public functions */
+ this->public.send = (status_t(*)(socket_t*, packet_t*))sender;
+ this->public.receive = (status_t(*)(socket_t*, packet_t**))receiver;
+ this->public.is_listening_on = (bool (*)(socket_t*,host_t*))is_listening_on;
+ this->public.destroy = (void(*)(socket_t*)) destroy;
+
+ this->logger = logger_manager->get_logger(logger_manager, SOCKET);
+ this->interfaces = linked_list_create();
+
+ if (build_interface_list(this, port) != SUCCESS)
+ {
+ this->interfaces->destroy(this->interfaces);
+ free(this);
+ charon->kill(charon, "could not bind any interface!");
+ }
+
+ return (socket_t*)this;
+}
diff --git a/programs/charon/charon/network/socket.h b/programs/charon/charon/network/socket.h
new file mode 100644
index 000000000..498e7700a
--- /dev/null
+++ b/programs/charon/charon/network/socket.h
@@ -0,0 +1,128 @@
+/**
+ * @file socket.h
+ *
+ * @brief Interface for socket_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef SOCKET_H_
+#define SOCKET_H_
+
+
+#include <types.h>
+#include <network/packet.h>
+
+
+/**
+ * @brief Maximum size of a packet.
+ *
+ * 3000 Bytes should be sufficient, see IKEv2 RFC.
+ *
+ * @ingroup network
+ */
+#define MAX_PACKET 3000
+
+
+typedef struct socket_t socket_t;
+
+/**
+ * @brief Abstraction all sockets (currently IPv4 only).
+ *
+ * All available IPv4 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()
+ *
+ * @todo add IPv6 support
+ *
+ * @todo We currently use multiple sockets for historic reasons. With the
+ * new RAW socket mechanism, we could use just one socket and filter
+ * addresses in userspace (or via linux socket filter). This would allow
+ * realtime interface/address management in a easy way...
+ *
+ * @ingroup network
+ */
+struct socket_t {
+ /**
+ * @brief Receive a packet.
+ *
+ * Reads a packet from the socket and sets source/dest
+ * appropriately.
+ *
+ * @param sock socket_t object to work on
+ * @param packet pinter gets address from allocated packet_t
+ * @return
+ * - SUCCESS when packet successfully received
+ * - FAILED when unable to receive
+ */
+ status_t (*receive) (socket_t *sock, packet_t **packet);
+
+ /**
+ * @brief 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 sock socket_t object to work on
+ * @param packet[out] packet_t to send
+ * @return
+ * - SUCCESS when packet successfully sent
+ * - FAILED when unable to send
+ */
+ status_t (*send) (socket_t *sock, packet_t *packet);
+
+ /**
+ * @brief Check if socket listens on an address.
+ *
+ * @param sock socket_t object to work on
+ * @param host address to check
+ * @return TRUE if listening on host, FALSE otherwise
+ */
+ bool (*is_listening_on) (socket_t *sock, host_t *host);
+
+ /**
+ * @brief Destroy sockets.
+ *
+ * close sockets and destroy socket_t object
+ *
+ * @param sock socket_t to destroy
+ */
+ void (*destroy) (socket_t *sock);
+};
+
+/**
+ * @brief Create a socket_t, wich binds multiple sockets.
+ *
+ * currently creates one socket, listening on all addresses
+ * on "port".
+ *
+ * @param port port to bind socket to
+ * @return socket_t object
+ *
+ * @ingroup network
+ */
+socket_t *socket_create(u_int16_t port);
+
+
+#endif /*SOCKET_H_*/
diff --git a/programs/charon/charon/queues/Makefile.queues b/programs/charon/charon/queues/Makefile.queues
new file mode 100644
index 000000000..eeb012d2b
--- /dev/null
+++ b/programs/charon/charon/queues/Makefile.queues
@@ -0,0 +1,30 @@
+# Copyright (C) 2005 Jan Hutter, Martin Willi
+# Hochschule fuer Technik Rapperswil
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+
+QUEUES_DIR= $(CHARON_DIR)queues/
+
+CHARON_OBJS+= $(BUILD_DIR)event_queue.o
+$(BUILD_DIR)event_queue.o : $(QUEUES_DIR)event_queue.c $(QUEUES_DIR)event_queue.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)job_queue.o
+$(BUILD_DIR)job_queue.o : $(QUEUES_DIR)job_queue.c $(QUEUES_DIR)job_queue.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)send_queue.o
+$(BUILD_DIR)send_queue.o : $(QUEUES_DIR)send_queue.c $(QUEUES_DIR)send_queue.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+
+include $(QUEUES_DIR)jobs/Makefile.jobs \ No newline at end of file
diff --git a/programs/charon/charon/queues/event_queue.c b/programs/charon/charon/queues/event_queue.c
new file mode 100644
index 000000000..ece9d1513
--- /dev/null
+++ b/programs/charon/charon/queues/event_queue.c
@@ -0,0 +1,349 @@
+/**
+ * @file event_queue.c
+ *
+ * @brief Implementation of event_queue_t
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <pthread.h>
+#include <stdlib.h>
+
+#include "event_queue.h"
+
+#include <types.h>
+#include <utils/linked_list.h>
+
+
+
+typedef struct event_t event_t;
+
+/**
+ * @brief Represents an event as it is stored in the event queue.
+ *
+ * A event consists of a event time and an assigned job object.
+ *
+ */
+struct event_t{
+ /**
+ * Time to fire the event.
+ */
+ timeval_t time;
+
+ /**
+ * Every event has its assigned job.
+ */
+ job_t * job;
+
+ /**
+ * @brief Destroys a event_t object.
+ *
+ * @param event_t calling object
+ */
+ void (*destroy) (event_t *event);
+};
+
+
+/**
+ * implements event_t.destroy
+ */
+static void event_destroy(event_t *event)
+{
+ free(event);
+}
+
+/**
+ * @brief Creates a event for a specific time
+ *
+ * @param time absolute time to fire the event
+ * @param job job to add to job-queue at specific time
+ *
+ * @returns created event_t object
+ */
+static event_t *event_create(timeval_t time, job_t *job)
+{
+ event_t *this = malloc_thing(event_t);
+
+ this->destroy = event_destroy;
+ this->time = time;
+ this->job = job;
+
+ return this;
+}
+
+
+typedef struct private_event_queue_t private_event_queue_t;
+
+/**
+ * Private Variables and Functions of event_queue_t class.
+ *
+ */
+struct private_event_queue_t {
+ /**
+ * Public part.
+ */
+ event_queue_t public;
+
+ /**
+ * The events are stored in a linked list of type linked_list_t.
+ */
+ linked_list_t *list;
+
+ /**
+ * Access to linked_list is locked through this mutex.
+ */
+ pthread_mutex_t mutex;
+
+ /**
+ * If the queue is empty or an event has not to be fired
+ * a thread has to wait.
+ *
+ * This condvar is used to wake up such a thread.
+ */
+ pthread_cond_t condvar;
+};
+
+/**
+ * Returns the difference of to timeval structs in microseconds
+ *
+ * @param end_time end time
+ * @param start_time start time
+ *
+ * @warning this function is also defined in the tester class
+ * In later improvements, this function can be added to a general
+ * class type!
+ *
+ * @return difference in microseconds (end time - start time)
+ */
+static long time_difference(struct timeval *end_time, struct timeval *start_time)
+{
+ long seconds, microseconds;
+
+ seconds = (end_time->tv_sec - start_time->tv_sec);
+ microseconds = (end_time->tv_usec - start_time->tv_usec);
+ return ((seconds * 1000000) + microseconds);
+}
+
+
+/**
+ * Implements event_queue_t.get_count
+ */
+static int get_count (private_event_queue_t *this)
+{
+ int count;
+ pthread_mutex_lock(&(this->mutex));
+ count = this->list->get_count(this->list);
+ pthread_mutex_unlock(&(this->mutex));
+ return count;
+}
+
+/**
+ * Implements event_queue_t.get
+ */
+static job_t *get(private_event_queue_t *this)
+{
+ timespec_t timeout;
+ timeval_t current_time;
+ event_t * next_event;
+ job_t *job;
+ int oldstate;
+
+ pthread_mutex_lock(&(this->mutex));
+
+ while (1)
+ {
+ while(this->list->get_count(this->list) == 0)
+ {
+ /* add mutex unlock handler for cancellation, enable cancellation */
+ pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock, (void*)&(this->mutex));
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
+
+ pthread_cond_wait( &(this->condvar), &(this->mutex));
+
+ /* reset cancellation, remove mutex-unlock handler (without executing) */
+ pthread_setcancelstate(oldstate, NULL);
+ pthread_cleanup_pop(0);
+ }
+
+ this->list->get_first(this->list,(void **) &next_event);
+
+ gettimeofday(&current_time,NULL);
+ long difference = time_difference(&current_time,&(next_event->time));
+ if (difference <= 0)
+ {
+ timeout.tv_sec = next_event->time.tv_sec;
+ timeout.tv_nsec = next_event->time.tv_usec * 1000;
+
+ /* add mutex unlock handler for cancellation, enable cancellation */
+ pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock, (void*)&(this->mutex));
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
+
+ pthread_cond_timedwait( &(this->condvar), &(this->mutex),&timeout);
+
+ /* reset cancellation, remove mutex-unlock handler (without executing) */
+ pthread_setcancelstate(oldstate, NULL);
+ pthread_cleanup_pop(0);
+ }
+ else
+ {
+ /* event available */
+ this->list->remove_first(this->list,(void **) &next_event);
+
+ job = next_event->job;
+
+ next_event->destroy(next_event);
+ break;
+ }
+
+ }
+ pthread_cond_signal( &(this->condvar));
+
+ pthread_mutex_unlock(&(this->mutex));
+
+ return job;
+}
+
+/**
+ * Implements function add_absolute of event_queue_t.
+ * See #event_queue_s.add_absolute for description.
+ */
+static void add_absolute(private_event_queue_t *this, job_t *job, timeval_t time)
+{
+ event_t *event = event_create(time,job);
+ event_t *current_event;
+ status_t status;
+
+ pthread_mutex_lock(&(this->mutex));
+
+ /* while just used to break out */
+ while(1)
+ {
+ if (this->list->get_count(this->list) == 0)
+ {
+ this->list->insert_first(this->list,event);
+ break;
+ }
+
+ /* check last entry */
+ this->list->get_last(this->list,(void **) &current_event);
+
+ if (time_difference(&(event->time), &(current_event->time)) >= 0)
+ {
+ /* my event has to be fired after the last event in list */
+ this->list->insert_last(this->list,event);
+ break;
+ }
+
+ /* check first entry */
+ this->list->get_first(this->list,(void **) &current_event);
+
+ if (time_difference(&(event->time), &(current_event->time)) < 0)
+ {
+ /* my event has to be fired before the first event in list */
+ this->list->insert_first(this->list,event);
+ break;
+ }
+
+ iterator_t * iterator;
+
+ iterator = this->list->create_iterator(this->list,TRUE);
+
+ iterator->has_next(iterator);
+ /* first element has not to be checked (already done) */
+
+ while(iterator->has_next(iterator))
+ {
+ status = iterator->current(iterator,(void **) &current_event);
+
+ if (time_difference(&(event->time), &(current_event->time)) <= 0)
+ {
+ /* my event has to be fired before the current event in list */
+ iterator->insert_before(iterator,event);
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ break;
+ }
+
+ pthread_cond_signal( &(this->condvar));
+ pthread_mutex_unlock(&(this->mutex));
+}
+
+/**
+ * Implements event_queue_t.add_relative.
+ */
+static void add_relative(event_queue_t *this, job_t *job, u_int32_t ms)
+{
+ timeval_t current_time;
+ timeval_t time;
+ int micros = ms * 1000;
+
+ gettimeofday(&current_time, NULL);
+
+ time.tv_usec = ((current_time.tv_usec + micros) % 1000000);
+ time.tv_sec = current_time.tv_sec + ((current_time.tv_usec + micros)/ 1000000);
+
+ this->add_absolute(this, job, time);
+}
+
+
+/**
+ * Implements event_queue_t.destroy.
+ */
+static void event_queue_destroy(private_event_queue_t *this)
+{
+ while (this->list->get_count(this->list) > 0)
+ {
+ event_t *event;
+
+ if (this->list->remove_first(this->list,(void *) &event) != SUCCESS)
+ {
+ this->list->destroy(this->list);
+ break;
+ }
+ event->job->destroy_all(event->job);
+ event->destroy(event);
+ }
+ this->list->destroy(this->list);
+
+ pthread_mutex_destroy(&(this->mutex));
+
+ pthread_cond_destroy(&(this->condvar));
+
+ free(this);
+}
+
+/*
+ * Documented in header
+ */
+event_queue_t *event_queue_create()
+{
+ private_event_queue_t *this = malloc_thing(private_event_queue_t);
+
+ this->public.get_count = (int (*) (event_queue_t *event_queue)) get_count;
+ this->public.get = (job_t *(*) (event_queue_t *event_queue)) get;
+ this->public.add_absolute = (void (*) (event_queue_t *event_queue, job_t *job, timeval_t time)) add_absolute;
+ this->public.add_relative = (void (*) (event_queue_t *event_queue, job_t *job, u_int32_t ms)) add_relative;
+ this->public.destroy = (void (*) (event_queue_t *event_queue)) event_queue_destroy;
+
+ this->list = linked_list_create();
+ pthread_mutex_init(&(this->mutex), NULL);
+ pthread_cond_init(&(this->condvar), NULL);
+
+ return (&this->public);
+}
diff --git a/programs/charon/charon/queues/event_queue.h b/programs/charon/charon/queues/event_queue.h
new file mode 100644
index 000000000..a60424100
--- /dev/null
+++ b/programs/charon/charon/queues/event_queue.h
@@ -0,0 +1,117 @@
+/**
+ * @file event_queue.h
+ *
+ * @brief Interface of job_queue_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef EVENT_QUEUE_H_
+#define EVENT_QUEUE_H_
+
+#include <sys/time.h>
+
+#include <types.h>
+#include <queues/jobs/job.h>
+
+typedef struct event_queue_t event_queue_t;
+
+/**
+ * @brief Event-Queue used to store timed events.
+ *
+ * Added events are sorted. The get method blocks until
+ * the time is elapsed to process the next event. The get
+ * method is called from the scheduler_t thread, which
+ * will add the jobs to to job_queue_t for further processing.
+ *
+ * Although the event-queue is based on a linked_list_t
+ * all access functions are thread-save implemented.
+ *
+ * @b Constructors:
+ * - event_queue_create()
+ *
+ * @ingroup queues
+ */
+struct event_queue_t {
+
+ /**
+ * @brief Returns number of events in queue.
+ *
+ * @param event_queue calling object
+ * @return number of events in queue
+ */
+ int (*get_count) (event_queue_t *event_queue);
+
+ /**
+ * @brief Get the next job from the event-queue.
+ *
+ * If no event is pending, this function blocks until a job can be returned.
+ *
+ * @param event_queue calling object
+ * @param[out] job pointer to a job pointer where to job is returned to
+ * @return next job
+ */
+ job_t *(*get) (event_queue_t *event_queue);
+
+ /**
+ * @brief Adds a event to the queue, using a relative time.
+ *
+ * This function is non blocking and adds a job_t at a specific time to the list.
+ * The specific job object has to get destroyed by the thread which
+ * removes the job.
+ *
+ * @param event_queue calling object
+ * @param[in] job job to add to the queue (job is not copied)
+ * @param[in] time relative time, when the event has to get fired
+ */
+ void (*add_relative) (event_queue_t *event_queue, job_t *job, u_int32_t ms);
+
+ /**
+ * @brief Adds a event to the queue, using an absolute time.
+ *
+ * This function is non blocking and adds a job_t at a specific time to the list.
+ * The specific job object has to get destroyed by the thread which
+ * removes the job.
+ *
+ * @param event_queue calling object
+ * @param[in] job job to add to the queue (job is not copied)
+ * @param[in] absolute time time, when the event has to get fired
+ */
+ void (*add_absolute) (event_queue_t *event_queue, job_t *job, timeval_t time);
+
+ /**
+ * @brief Destroys a event_queue object.
+ *
+ * @warning The caller of this function has to make sure
+ * that no thread is going to add or get an event from the event_queue
+ * after calling this function.
+ *
+ * @param event_queue calling object
+ */
+ void (*destroy) (event_queue_t *event_queue);
+};
+
+/**
+ * @brief Creates an empty event_queue.
+ *
+ * @returns event_queue_t object
+ *
+ * @ingroup queues
+ */
+event_queue_t *event_queue_create();
+
+#endif /*EVENT_QUEUE_H_*/
diff --git a/programs/charon/charon/queues/job_queue.c b/programs/charon/charon/queues/job_queue.c
new file mode 100644
index 000000000..3640395ab
--- /dev/null
+++ b/programs/charon/charon/queues/job_queue.c
@@ -0,0 +1,153 @@
+/**
+ * @file job_queue.c
+ *
+ * @brief Implementation of job_queue_t
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stdlib.h>
+#include <pthread.h>
+
+#include "job_queue.h"
+
+#include <utils/linked_list.h>
+
+
+typedef struct private_job_queue_t private_job_queue_t;
+
+/**
+ * @brief Private Variables and Functions of job_queue class
+ *
+ */
+struct private_job_queue_t {
+
+ /**
+ * public members
+ */
+ job_queue_t public;
+
+ /**
+ * The jobs are stored in a linked list
+ */
+ linked_list_t *list;
+
+ /**
+ * access to linked_list is locked through this mutex
+ */
+ pthread_mutex_t mutex;
+
+ /**
+ * If the queue is empty a thread has to wait
+ * This condvar is used to wake up such a thread
+ */
+ pthread_cond_t condvar;
+};
+
+
+/**
+ * implements job_queue_t.get_count
+ */
+static int get_count(private_job_queue_t *this)
+{
+ int count;
+ pthread_mutex_lock(&(this->mutex));
+ count = this->list->get_count(this->list);
+ pthread_mutex_unlock(&(this->mutex));
+ return count;
+}
+
+/**
+ * implements job_queue_t.get
+ */
+static job_t *get(private_job_queue_t *this)
+{
+ int oldstate;
+ job_t *job;
+ pthread_mutex_lock(&(this->mutex));
+ /* go to wait while no jobs available */
+ while(this->list->get_count(this->list) == 0)
+ {
+ /* add mutex unlock handler for cancellation, enable cancellation */
+ pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock, (void*)&(this->mutex));
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
+
+ pthread_cond_wait( &(this->condvar), &(this->mutex));
+
+ /* reset cancellation, remove mutex-unlock handler (without executing) */
+ pthread_setcancelstate(oldstate, NULL);
+ pthread_cleanup_pop(0);
+ }
+ this->list->remove_first(this->list,(void **) &job);
+ pthread_mutex_unlock(&(this->mutex));
+ return job;
+}
+
+/**
+ * implements function job_queue_t.add
+ */
+static void add(private_job_queue_t *this, job_t *job)
+{
+ pthread_mutex_lock(&(this->mutex));
+ this->list->insert_last(this->list,job);
+ pthread_cond_signal( &(this->condvar));
+ pthread_mutex_unlock(&(this->mutex));
+}
+
+/**
+ * implements job_queue_t.destroy
+ */
+static void job_queue_destroy (private_job_queue_t *this)
+{
+ while (this->list->get_count(this->list) > 0)
+ {
+ job_t *job;
+ if (this->list->remove_first(this->list,(void *) &job) != SUCCESS)
+ {
+ this->list->destroy(this->list);
+ break;
+ }
+ job->destroy_all(job);
+ }
+ this->list->destroy(this->list);
+
+ pthread_mutex_destroy(&(this->mutex));
+
+ pthread_cond_destroy(&(this->condvar));
+
+ free(this);
+}
+
+/*
+ *
+ * Documented in header
+ */
+job_queue_t *job_queue_create()
+{
+ private_job_queue_t *this = malloc_thing(private_job_queue_t);
+
+ this->public.get_count = (int(*)(job_queue_t*))get_count;
+ this->public.get = (job_t*(*)(job_queue_t*))get;
+ this->public.add = (void(*)(job_queue_t*, job_t*))add;
+ this->public.destroy = (void(*)(job_queue_t*))job_queue_destroy;
+
+ this->list = linked_list_create();
+ pthread_mutex_init(&(this->mutex), NULL);
+ pthread_cond_init(&(this->condvar), NULL);
+
+ return (&this->public);
+}
diff --git a/programs/charon/charon/queues/job_queue.h b/programs/charon/charon/queues/job_queue.h
new file mode 100644
index 000000000..9fcf08001
--- /dev/null
+++ b/programs/charon/charon/queues/job_queue.h
@@ -0,0 +1,99 @@
+/**
+ * @file job_queue.h
+ *
+ * @brief Interface of job_queue_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef JOB_QUEUE_H_
+#define JOB_QUEUE_H_
+
+#include <types.h>
+#include <queues/jobs/job.h>
+
+typedef struct job_queue_t job_queue_t;
+
+/**
+ * @brief The job queue stores jobs, which will be processed by the thread_pool_t.
+ *
+ * Jobs are added from various sources, from the threads and
+ * from the event_queue_t.
+ * Although the job-queue is based on a linked_list_t
+ * all access functions are thread-save implemented.
+ *
+ * @b Constructors:
+ * - job_queue_create()
+ *
+ * @ingroup queues
+ */
+struct job_queue_t {
+
+ /**
+ * @brief Returns number of jobs in queue.
+ *
+ * @param job_queue_t calling object
+ * @returns number of items in queue
+ */
+ int (*get_count) (job_queue_t *job_queue);
+
+ /**
+ * @brief Get the next job from the queue.
+ *
+ * If the queue is empty, this function blocks until a job can be returned.
+ * After using, the returned job has to get destroyed by the caller.
+ *
+ * @param job_queue_t calling object
+ * @param[out] job pointer to a job pointer where to job is returned to
+ * @return next job
+ */
+ job_t *(*get) (job_queue_t *job_queue);
+
+ /**
+ * @brief Adds a job to the queue.
+ *
+ * This function is non blocking and adds a job_t to the list.
+ * The specific job object has to get destroyed by the thread which
+ * removes the job.
+ *
+ * @param job_queue_t calling object
+ * @param job job to add to the queue (job is not copied)
+ */
+ void (*add) (job_queue_t *job_queue, job_t *job);
+
+ /**
+ * @brief Destroys a job_queue object.
+ *
+ * @warning The caller of this function has to make sure
+ * that no thread is going to add or get a job from the job_queue
+ * after calling this function.
+ *
+ * @param job_queue_t calling object
+ */
+ void (*destroy) (job_queue_t *job_queue);
+};
+
+/**
+ * @brief Creates an empty job_queue.
+ *
+ * @return job_queue_t object
+ *
+ * @ingroup queues
+ */
+job_queue_t *job_queue_create();
+
+#endif /*JOB_QUEUE_H_*/
diff --git a/programs/charon/charon/queues/jobs/Makefile.jobs b/programs/charon/charon/queues/jobs/Makefile.jobs
new file mode 100644
index 000000000..db89987bc
--- /dev/null
+++ b/programs/charon/charon/queues/jobs/Makefile.jobs
@@ -0,0 +1,40 @@
+# Copyright (C) 2005 Jan Hutter, Martin Willi
+# Hochschule fuer Technik Rapperswil
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+
+JOBS_DIR= $(QUEUES_DIR)jobs/
+
+CHARON_OBJS+= $(BUILD_DIR)delete_half_open_ike_sa_job.o
+$(BUILD_DIR)delete_half_open_ike_sa_job.o : $(JOBS_DIR)delete_half_open_ike_sa_job.c $(JOBS_DIR)delete_half_open_ike_sa_job.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)delete_established_ike_sa_job.o
+$(BUILD_DIR)delete_established_ike_sa_job.o : $(JOBS_DIR)delete_established_ike_sa_job.c $(JOBS_DIR)delete_established_ike_sa_job.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)incoming_packet_job.o
+$(BUILD_DIR)incoming_packet_job.o : $(JOBS_DIR)incoming_packet_job.c $(JOBS_DIR)incoming_packet_job.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)initiate_ike_sa_job.o
+$(BUILD_DIR)initiate_ike_sa_job.o : $(JOBS_DIR)initiate_ike_sa_job.c $(JOBS_DIR)initiate_ike_sa_job.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)retransmit_request_job.o
+$(BUILD_DIR)retransmit_request_job.o : $(JOBS_DIR)retransmit_request_job.c $(JOBS_DIR)retransmit_request_job.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)job.o
+$(BUILD_DIR)job.o : $(JOBS_DIR)job.c $(JOBS_DIR)job.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+ \ No newline at end of file
diff --git a/programs/charon/charon/queues/jobs/delete_established_ike_sa_job.c b/programs/charon/charon/queues/jobs/delete_established_ike_sa_job.c
new file mode 100644
index 000000000..7251e2ca4
--- /dev/null
+++ b/programs/charon/charon/queues/jobs/delete_established_ike_sa_job.c
@@ -0,0 +1,90 @@
+/**
+ * @file delete_established_ike_sa_job.c
+ *
+ * @brief Implementation of delete_established_ike_sa_job_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "delete_established_ike_sa_job.h"
+
+
+
+typedef struct private_delete_established_ike_sa_job_t private_delete_established_ike_sa_job_t;
+
+/**
+ * Private data of an delete_established_ike_sa_job_t object.
+ */
+struct private_delete_established_ike_sa_job_t {
+ /**
+ * Public delete_established_ike_sa_job_t interface.
+ */
+ delete_established_ike_sa_job_t public;
+
+ /**
+ * ID of the ike_sa to delete.
+ */
+ ike_sa_id_t *ike_sa_id;
+};
+
+/**
+ * Implementation of job_t.get_type.
+ */
+static job_type_t get_type(private_delete_established_ike_sa_job_t *this)
+{
+ return DELETE_ESTABLISHED_IKE_SA;
+}
+
+/**
+ * Implementation of delete_established_ike_sa_job_t.get_ike_sa_id
+ */
+static ike_sa_id_t *get_ike_sa_id(private_delete_established_ike_sa_job_t *this)
+{
+ return this->ike_sa_id;
+}
+
+/**
+ * Implementation of job_t.destroy.
+ */
+static void destroy(private_delete_established_ike_sa_job_t *this)
+{
+ this->ike_sa_id->destroy(this->ike_sa_id);
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+delete_established_ike_sa_job_t *delete_established_ike_sa_job_create(ike_sa_id_t *ike_sa_id)
+{
+ private_delete_established_ike_sa_job_t *this = malloc_thing(private_delete_established_ike_sa_job_t);
+
+ /* interface functions */
+ this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
+ /* same as destroy */
+ this->public.job_interface.destroy_all = (void (*) (job_t *)) destroy;
+ this->public.job_interface.destroy = (void (*)(job_t*)) destroy;
+
+ /* public functions */
+ this->public.get_ike_sa_id = (ike_sa_id_t * (*)(delete_established_ike_sa_job_t *)) get_ike_sa_id;
+ this->public.destroy = (void (*)(delete_established_ike_sa_job_t *)) destroy;
+
+ /* private variables */
+ this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
+
+ return &(this->public);
+}
diff --git a/programs/charon/charon/queues/jobs/delete_established_ike_sa_job.h b/programs/charon/charon/queues/jobs/delete_established_ike_sa_job.h
new file mode 100644
index 000000000..762dceae6
--- /dev/null
+++ b/programs/charon/charon/queues/jobs/delete_established_ike_sa_job.h
@@ -0,0 +1,78 @@
+/**
+ * @file delete_established_ike_sa_job.h
+ *
+ * @brief Interface of delete_established_ike_sa_job_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef DELETE_ESTABLISHED_IKE_SA_JOB_H_
+#define DELETE_ESTABLISHED_IKE_SA_JOB_H_
+
+#include <types.h>
+#include <sa/ike_sa_id.h>
+#include <queues/jobs/job.h>
+
+
+typedef struct delete_established_ike_sa_job_t delete_established_ike_sa_job_t;
+
+/**
+ * @brief Class representing an DELETE_ESTABLISHED_IKE_SA Job.
+ *
+ * This job initiates the deletion of an IKE_SA. The SA
+ * to delete is specified via an ike_sa_id_t.
+ *
+ * @b Constructors:
+ * - delete_established_ike_sa_job_create()
+ *
+ * @ingroup jobs
+ */
+struct delete_established_ike_sa_job_t {
+ /**
+ * The job_t interface.
+ */
+ job_t job_interface;
+
+ /**
+ * @brief Returns the currently set ike_sa_id.
+ *
+ * @warning Returned object is not copied.
+ *
+ * @param this calling delete_established_ike_sa_job_t object
+ * @return ike_sa_id_t object
+ */
+ ike_sa_id_t * (*get_ike_sa_id) (delete_established_ike_sa_job_t *this);
+
+ /**
+ * @brief Destroys an delete_established_ike_sa_job_t object (including assigned data).
+ *
+ * @param this delete_established_ike_sa_job_t object to destroy
+ */
+ void (*destroy) (delete_established_ike_sa_job_t *this);
+};
+
+/**
+ * @brief Creates a job of type DELETE_ESTABLISHED_IKE_SA.
+ *
+ * @param ike_sa_id id of the IKE_SA to delete
+ * @return delete_established_ike_sa_job_t object
+ *
+ * @ingroup jobs
+ */
+delete_established_ike_sa_job_t *delete_established_ike_sa_job_create(ike_sa_id_t *ike_sa_id);
+
+#endif /*DELETE_ESTABLISHED_IKE_SA_JOB_H_*/
diff --git a/programs/charon/charon/queues/jobs/delete_half_open_ike_sa_job.c b/programs/charon/charon/queues/jobs/delete_half_open_ike_sa_job.c
new file mode 100644
index 000000000..610285e20
--- /dev/null
+++ b/programs/charon/charon/queues/jobs/delete_half_open_ike_sa_job.c
@@ -0,0 +1,90 @@
+/**
+ * @file delete_half_open_ike_sa_job.c
+ *
+ * @brief Implementation of delete_half_open_ike_sa_job_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "delete_half_open_ike_sa_job.h"
+
+
+
+typedef struct private_delete_half_open_ike_sa_job_t private_delete_half_open_ike_sa_job_t;
+
+/**
+ * Private data of an delete_half_open_ike_sa_job_t Object
+ */
+struct private_delete_half_open_ike_sa_job_t {
+ /**
+ * public delete_half_open_ike_sa_job_t interface
+ */
+ delete_half_open_ike_sa_job_t public;
+
+ /**
+ * ID of the ike_sa to delete
+ */
+ ike_sa_id_t *ike_sa_id;
+};
+
+/**
+ * Implements job_t.get_type.
+ */
+static job_type_t get_type(private_delete_half_open_ike_sa_job_t *this)
+{
+ return DELETE_HALF_OPEN_IKE_SA;
+}
+
+/**
+ * Implements elete_ike_sa_job_t.get_ike_sa_id
+ */
+static ike_sa_id_t *get_ike_sa_id(private_delete_half_open_ike_sa_job_t *this)
+{
+ return this->ike_sa_id;
+}
+
+/**
+ * Implements job_t.destroy.
+ */
+static void destroy(private_delete_half_open_ike_sa_job_t *this)
+{
+ this->ike_sa_id->destroy(this->ike_sa_id);
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+delete_half_open_ike_sa_job_t *delete_half_open_ike_sa_job_create(ike_sa_id_t *ike_sa_id)
+{
+ private_delete_half_open_ike_sa_job_t *this = malloc_thing(private_delete_half_open_ike_sa_job_t);
+
+ /* interface functions */
+ this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
+ /* same as destroy */
+ this->public.job_interface.destroy_all = (void (*) (job_t *)) destroy;
+ this->public.job_interface.destroy = (void (*)(job_t *)) destroy;;
+
+ /* public functions */
+ this->public.get_ike_sa_id = (ike_sa_id_t * (*)(delete_half_open_ike_sa_job_t *)) get_ike_sa_id;
+ this->public.destroy = (void (*)(delete_half_open_ike_sa_job_t *)) destroy;
+
+ /* private variables */
+ this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
+
+ return &(this->public);
+}
diff --git a/programs/charon/charon/queues/jobs/delete_half_open_ike_sa_job.h b/programs/charon/charon/queues/jobs/delete_half_open_ike_sa_job.h
new file mode 100644
index 000000000..ea42be8f2
--- /dev/null
+++ b/programs/charon/charon/queues/jobs/delete_half_open_ike_sa_job.h
@@ -0,0 +1,79 @@
+/**
+ * @file delete_half_open_ike_sa_job.h
+ *
+ * @brief Interface of delete_half_open_ike_sa_job_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef DELETE_HALF_OPEN_IKE_SA_JOB_H_
+#define DELETE_HALF_OPEN_IKE_SA_JOB_H_
+
+#include <types.h>
+#include <sa/ike_sa_id.h>
+#include <queues/jobs/job.h>
+
+
+typedef struct delete_half_open_ike_sa_job_t delete_half_open_ike_sa_job_t;
+
+/**
+ * @brief Class representing an DELETE_HALF_OPEN_IKE_SA Job.
+ *
+ * This job is responsible for deleting of half open IKE_SAs. A half
+ * open IKE_SA is every IKE_SA which hasn't reache the ike_sa_established
+ * state.
+ *
+ * @b Constructors:
+ * - delete_half_open_ike_sa_job_create()
+ *
+ * @ingroup jobs
+ */
+struct delete_half_open_ike_sa_job_t {
+ /**
+ * The job_t interface.
+ */
+ job_t job_interface;
+
+ /**
+ * @brief Returns the currently set ike_sa_id.
+ *
+ * @warning Returned object is not copied.
+ *
+ * @param this calling delete_half_open_ike_sa_job_t object
+ * @return ike_sa_id_t object
+ */
+ ike_sa_id_t * (*get_ike_sa_id) (delete_half_open_ike_sa_job_t *this);
+
+ /**
+ * @brief Destroys an delete_half_open_ike_sa_job_t object (including assigned data).
+ *
+ * @param this delete_half_open_ike_sa_job_t object to destroy
+ */
+ void (*destroy) (delete_half_open_ike_sa_job_t *this);
+};
+
+/**
+ * @brief Creates a job of type DELETE_HALF_OPEN_IKE_SA.
+ *
+ * @param ike_sa_id id of the IKE_SA to delete
+ * @return created delete_half_open_ike_sa_job_t object
+ *
+ * @ingroup jobs
+ */
+delete_half_open_ike_sa_job_t *delete_half_open_ike_sa_job_create(ike_sa_id_t *ike_sa_id);
+
+#endif /*DELETE_HALF_OPEN_IKE_SA_JOB_H_*/
diff --git a/programs/charon/charon/queues/jobs/incoming_packet_job.c b/programs/charon/charon/queues/jobs/incoming_packet_job.c
new file mode 100644
index 000000000..fc71f63ea
--- /dev/null
+++ b/programs/charon/charon/queues/jobs/incoming_packet_job.c
@@ -0,0 +1,102 @@
+/**
+ * @file incoming_packet_job.h
+ *
+ * @brief Implementation of incoming_packet_job_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#include "incoming_packet_job.h"
+
+
+
+typedef struct private_incoming_packet_job_t private_incoming_packet_job_t;
+
+/**
+ * Private data of an incoming_packet_job_t Object
+ */
+struct private_incoming_packet_job_t {
+ /**
+ * public incoming_packet_job_t interface
+ */
+ incoming_packet_job_t public;
+
+ /**
+ * Assigned packet
+ */
+ packet_t *packet;
+};
+
+/**
+ * Implements job_t.get_type.
+ */
+static job_type_t get_type(private_incoming_packet_job_t *this)
+{
+ return INCOMING_PACKET;
+}
+
+/**
+ * Implements incoming_packet_job_t.get_packet.
+ */
+static packet_t *get_packet(private_incoming_packet_job_t *this)
+{
+ return this->packet;
+}
+
+/**
+ * Implements job_t.destroy_all.
+ */
+static void destroy_all(private_incoming_packet_job_t *this)
+{
+ if (this->packet != NULL)
+ {
+ this->packet->destroy(this->packet);
+ }
+ free(this);
+}
+
+/**
+ * Implements job_t.destroy.
+ */
+static void destroy(job_t *job)
+{
+ private_incoming_packet_job_t *this = (private_incoming_packet_job_t *) job;
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+incoming_packet_job_t *incoming_packet_job_create(packet_t *packet)
+{
+ private_incoming_packet_job_t *this = malloc_thing(private_incoming_packet_job_t);
+
+ /* interface functions */
+ this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
+ this->public.job_interface.destroy_all = (void (*) (job_t *)) destroy_all;
+ this->public.job_interface.destroy = destroy;
+
+ /* public functions */
+ this->public.get_packet = (packet_t * (*)(incoming_packet_job_t *)) get_packet;
+ this->public.destroy = (void (*)(incoming_packet_job_t *)) destroy;
+
+ /* private variables */
+ this->packet = packet;
+
+ return &(this->public);
+}
diff --git a/programs/charon/charon/queues/jobs/incoming_packet_job.h b/programs/charon/charon/queues/jobs/incoming_packet_job.h
new file mode 100644
index 000000000..e3fb5797e
--- /dev/null
+++ b/programs/charon/charon/queues/jobs/incoming_packet_job.h
@@ -0,0 +1,78 @@
+/**
+ * @file incoming_packet_job.h
+ *
+ * @brief Interface of incoming_packet_job_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef INCOMING_PACKET_JOB_H_
+#define INCOMING_PACKET_JOB_H_
+
+#include <types.h>
+#include <network/packet.h>
+#include <queues/jobs/job.h>
+
+
+typedef struct incoming_packet_job_t incoming_packet_job_t;
+
+/**
+ * @brief Class representing an INCOMING_PACKET Job.
+ *
+ * An incoming pack job is created from the receiver, which has
+ * read a packet to process from the socket.
+ *
+ * @b Constructors:
+ * - incoming_packet_job_create()
+ *
+ * @ingroup jobs
+ */
+struct incoming_packet_job_t {
+ /**
+ * implements job_t interface
+ */
+ job_t job_interface;
+
+ /**
+ * @brief Returns the assigned packet_t object
+ *
+ * @warning Returned packet is not cloned and has to get destroyed by the caller.
+ *
+ * @param this calling incoming_packet_job_t object
+ * @return assigned packet
+ */
+ packet_t *(*get_packet) (incoming_packet_job_t *this);
+
+ /**
+ * @brief Destroys an incoming_packet_job_t object.
+ *
+ * @param this incoming_packet_job_t object to destroy
+ */
+ void (*destroy) (incoming_packet_job_t *this);
+};
+
+/**
+ * @brief Creates a job of type INCOMING_PACKET
+ *
+ * @param[in] packet packet to assign with this job
+ * @return created incoming_packet_job_t object
+ *
+ * @ingroup jobs
+ */
+incoming_packet_job_t *incoming_packet_job_create(packet_t *packet);
+
+#endif /*INCOMING_PACKET_JOB_H_*/
diff --git a/programs/charon/charon/queues/jobs/initiate_ike_sa_job.c b/programs/charon/charon/queues/jobs/initiate_ike_sa_job.c
new file mode 100644
index 000000000..ac9ace36c
--- /dev/null
+++ b/programs/charon/charon/queues/jobs/initiate_ike_sa_job.c
@@ -0,0 +1,101 @@
+/**
+ * @file initiate_ike_sa_job.c
+ *
+ * @brief Implementation of initiate_ike_sa_job_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#include <stdlib.h>
+
+#include "initiate_ike_sa_job.h"
+
+
+
+typedef struct private_initiate_ike_sa_job_t private_initiate_ike_sa_job_t;
+
+/**
+ * Private data of an initiate_ike_sa_job_t Object
+ */
+struct private_initiate_ike_sa_job_t {
+ /**
+ * public initiate_ike_sa_job_t interface
+ */
+ initiate_ike_sa_job_t public;
+
+ /**
+ * associated connection object to initiate
+ */
+ connection_t *connection;
+};
+
+
+/**
+ * Implements initiate_ike_sa_job_t.get_type.
+ */
+static job_type_t get_type(private_initiate_ike_sa_job_t *this)
+{
+ return INITIATE_IKE_SA;
+}
+
+/**
+ * Implements initiate_ike_sa_job_t.get_configuration_name.
+ */
+static connection_t *get_connection(private_initiate_ike_sa_job_t *this)
+{
+ return this->connection;
+}
+
+/**
+ * Implements job_t.destroy.
+ */
+static void destroy_all(private_initiate_ike_sa_job_t *this)
+{
+ this->connection->destroy(this->connection);
+ free(this);
+}
+
+/**
+ * Implements job_t.destroy.
+ */
+static void destroy(private_initiate_ike_sa_job_t *this)
+{
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+initiate_ike_sa_job_t *initiate_ike_sa_job_create(connection_t *connection)
+{
+ private_initiate_ike_sa_job_t *this = malloc_thing(private_initiate_ike_sa_job_t);
+
+ /* interface functions */
+ this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
+ this->public.job_interface.destroy_all = (void (*) (job_t *)) destroy_all;
+ this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
+
+ /* public functions */
+ this->public.get_connection = (connection_t* (*)(initiate_ike_sa_job_t *)) get_connection;
+ this->public.destroy = (void (*)(initiate_ike_sa_job_t *)) destroy;
+
+ /* private variables */
+ this->connection = connection;
+
+ return &(this->public);
+}
diff --git a/programs/charon/charon/queues/jobs/initiate_ike_sa_job.h b/programs/charon/charon/queues/jobs/initiate_ike_sa_job.h
new file mode 100644
index 000000000..cee31f07b
--- /dev/null
+++ b/programs/charon/charon/queues/jobs/initiate_ike_sa_job.h
@@ -0,0 +1,75 @@
+/**
+ * @file initiate_ike_sa_job.h
+ *
+ * @brief Interface of initiate_ike_sa_job_t.
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef INITIATE_IKE_SA_JOB_H_
+#define INITIATE_IKE_SA_JOB_H_
+
+#include <types.h>
+#include <queues/jobs/job.h>
+#include <config/connections/connection.h>
+
+
+typedef struct initiate_ike_sa_job_t initiate_ike_sa_job_t;
+
+/**
+ * @brief Class representing an INITIATE_IKE_SA Job.
+ *
+ * This job is created if an IKE_SA should be iniated. This
+ * happens via a user request, or via the kernel interface.
+ *
+ * @b Constructors:
+ * - initiate_ike_sa_job_create()
+ *
+ * @ingroup jobs
+ */
+struct initiate_ike_sa_job_t {
+ /**
+ * implements job_t interface
+ */
+ job_t job_interface;
+
+ /**
+ * @brief Returns the connection_t to initialize
+ *
+ * @param this calling initiate_ike_sa_job_t object
+ * @return connection_t
+ */
+ connection_t *(*get_connection) (initiate_ike_sa_job_t *this);
+
+ /**
+ * @brief Destroys an initiate_ike_sa_job_t object.
+ *
+ * @param this initiate_ike_sa_job_t object to destroy
+ */
+ void (*destroy) (initiate_ike_sa_job_t *this);
+};
+
+/**
+ * @brief Creates a job of type INITIATE_IKE_SA.
+ *
+ * @param connection connection_t to initializes
+ * @return initiate_ike_sa_job_t object
+ *
+ * @ingroup jobs
+ */
+initiate_ike_sa_job_t *initiate_ike_sa_job_create(connection_t *connection);
+
+#endif /*INITIATE_IKE_SA_JOB_H_*/
diff --git a/programs/charon/charon/queues/jobs/job.c b/programs/charon/charon/queues/jobs/job.c
new file mode 100644
index 000000000..df739f9e5
--- /dev/null
+++ b/programs/charon/charon/queues/jobs/job.c
@@ -0,0 +1,34 @@
+/**
+ * @file job.c
+ *
+ * @brief Interface additions to job_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#include "job.h"
+
+
+mapping_t job_type_m[] = {
+ {INCOMING_PACKET, "INCOMING_PACKET"},
+ {RETRANSMIT_REQUEST, "RETRANSMIT_REQUEST"},
+ {INITIATE_IKE_SA, "INITIATE_IKE_SA"},
+ {DELETE_HALF_OPEN_IKE_SA, "DELETE_HALF_OPEN_IKE_SA"},
+ {DELETE_ESTABLISHED_IKE_SA, "DELETE_ESTABLISHED_IKE_SA"},
+ {MAPPING_END, NULL}
+};
diff --git a/programs/charon/charon/queues/jobs/job.h b/programs/charon/charon/queues/jobs/job.h
new file mode 100644
index 000000000..eea4da09e
--- /dev/null
+++ b/programs/charon/charon/queues/jobs/job.h
@@ -0,0 +1,120 @@
+/**
+ * @file job.h
+ *
+ * @brief Interface job_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef JOB_H_
+#define JOB_H_
+
+#include <types.h>
+#include <definitions.h>
+
+
+typedef enum job_type_t job_type_t;
+
+/**
+ * @brief Definition of the various job types.
+ *
+ * @todo add more jobs, such as rekeying.
+ *
+ * @ingroup jobs
+ */
+enum job_type_t {
+ /**
+ * Process an incoming IKEv2-Message.
+ *
+ * Job is implemented in class type incoming_packet_job_t
+ */
+ INCOMING_PACKET,
+
+ /**
+ * Retransmit an IKEv2-Message.
+ */
+ RETRANSMIT_REQUEST,
+
+ /**
+ * Establish an ike sa as initiator.
+ *
+ * Job is implemented in class type initiate_ike_sa_job_t
+ */
+ INITIATE_IKE_SA,
+
+ /**
+ * Delete an ike sa which is still not established.
+ *
+ * Job is implemented in class type delete_half_open_ike_sa_job_t
+ */
+ DELETE_HALF_OPEN_IKE_SA,
+
+ /**
+ * Delete an ike sa which is established.
+ *
+ * Job is implemented in class type delete_established_ike_sa_job_t
+ */
+ DELETE_ESTABLISHED_IKE_SA
+};
+
+/**
+ * string mappings for job_type_t
+ *
+ * @ingroup jobs
+ */
+extern mapping_t job_type_m[];
+
+
+typedef struct job_t job_t;
+
+/**
+ * @brief Job-Interface as it is stored in the job queue.
+ *
+ * A job consists of a job-type and one or more assigned values.
+ *
+ * @b Constructors:
+ * - None, use specific implementation of the interface.
+ *
+ * @ingroup jobs
+ */
+struct job_t {
+
+ /**
+ * @brief get type of job.
+ *
+ * @param this calling object
+ * @return type of this job
+ */
+ job_type_t (*get_type) (job_t *this);
+
+ /**
+ * @brief Destroys a job_t object and all assigned data!
+ *
+ * @param job_t calling object
+ */
+ void (*destroy_all) (job_t *job);
+
+ /**
+ * @brief Destroys a job_t object
+ *
+ * @param job_t calling object
+ */
+ void (*destroy) (job_t *job);
+};
+
+
+#endif /*JOB_H_*/
diff --git a/programs/charon/charon/queues/jobs/retransmit_request_job.c b/programs/charon/charon/queues/jobs/retransmit_request_job.c
new file mode 100644
index 000000000..e171df5bd
--- /dev/null
+++ b/programs/charon/charon/queues/jobs/retransmit_request_job.c
@@ -0,0 +1,132 @@
+/**
+ * @file retransmit_request_job.c
+ *
+ * @brief Implementation of retransmit_request_job_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "retransmit_request_job.h"
+
+
+
+
+typedef struct private_retransmit_request_job_t private_retransmit_request_job_t;
+
+/**
+ * Private data of an retransmit_request_job_t Object.
+ */
+struct private_retransmit_request_job_t {
+ /**
+ * Public retransmit_request_job_t interface.
+ */
+ retransmit_request_job_t public;
+
+ /**
+ * Message ID of the request to resend.
+ */
+ u_int32_t message_id;
+
+ /**
+ * ID of the IKE_SA which the message belongs to.
+ */
+ ike_sa_id_t *ike_sa_id;
+
+ /**
+ * Number of times a request was retransmitted
+ */
+ u_int32_t retransmit_count;
+};
+
+
+/**
+ * Implements job_t.get_type.
+ */
+static job_type_t get_type(private_retransmit_request_job_t *this)
+{
+ return RETRANSMIT_REQUEST;
+}
+
+/**
+ * Implements retransmit_request_job_t.get_ike_sa_id.
+ */
+static ike_sa_id_t *get_ike_sa_id(private_retransmit_request_job_t *this)
+{
+ return this->ike_sa_id;
+}
+
+/**
+ * Implements retransmit_request_job_t.get_retransmit_count.
+ */
+static u_int32_t get_retransmit_count(private_retransmit_request_job_t *this)
+{
+ return this->retransmit_count;
+}
+
+/**
+ * Implements retransmit_request_job_t.increase_retransmit_count.
+ */
+static void increase_retransmit_count(private_retransmit_request_job_t *this)
+{
+ this->retransmit_count++;
+}
+
+/**
+ * Implements retransmit_request_job_t.get_message_id.
+ */
+static u_int32_t get_message_id(private_retransmit_request_job_t *this)
+{
+ return this->message_id;
+}
+
+
+/**
+ * Implements job_t.destroy.
+ */
+static void destroy(private_retransmit_request_job_t *this)
+{
+ this->ike_sa_id->destroy(this->ike_sa_id);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+retransmit_request_job_t *retransmit_request_job_create(u_int32_t message_id,ike_sa_id_t *ike_sa_id)
+{
+ private_retransmit_request_job_t *this = malloc_thing(private_retransmit_request_job_t);
+
+ /* interface functions */
+ this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
+ /* same as destroy */
+ this->public.job_interface.destroy_all = (void (*) (job_t *)) destroy;
+ this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
+
+ /* public functions */
+ this->public.get_ike_sa_id = (ike_sa_id_t * (*)(retransmit_request_job_t *)) get_ike_sa_id;
+ this->public.get_message_id = (u_int32_t (*)(retransmit_request_job_t *)) get_message_id;
+ this->public.destroy = (void (*)(retransmit_request_job_t *)) destroy;
+ this->public.get_retransmit_count = (u_int32_t (*)(retransmit_request_job_t *)) get_retransmit_count;
+ this->public.increase_retransmit_count = (void (*)(retransmit_request_job_t *)) increase_retransmit_count;
+
+ /* private variables */
+ this->message_id = message_id;
+ this->retransmit_count = 0;
+ this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
+
+ return &(this->public);
+}
diff --git a/programs/charon/charon/queues/jobs/retransmit_request_job.h b/programs/charon/charon/queues/jobs/retransmit_request_job.h
new file mode 100644
index 000000000..2349d3f5e
--- /dev/null
+++ b/programs/charon/charon/queues/jobs/retransmit_request_job.h
@@ -0,0 +1,105 @@
+/**
+ * @file retransmit_request_job.h
+ *
+ * @brief Interface of retransmit_request_job_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef RESEND_MESSAGE_JOB_H_
+#define RESEND_MESSAGE_JOB_H_
+
+#include <types.h>
+#include <queues/jobs/job.h>
+#include <sa/ike_sa_id.h>
+
+
+typedef struct retransmit_request_job_t retransmit_request_job_t;
+
+/**
+ * @brief Class representing an RETRANSMIT_REQUEST 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_request_job_create()
+ *
+ * @ingroup jobs
+ */
+struct retransmit_request_job_t {
+ /**
+ * The job_t interface.
+ */
+ job_t job_interface;
+
+ /**
+ * @brief Returns the retransmit count for a specific request.
+ *
+ * @param this calling retransmit_request_job_t object
+ * @return retransmit count of request
+ */
+ u_int32_t (*get_retransmit_count) (retransmit_request_job_t *this);
+
+ /**
+ * @brief Increases number of retransmitt attemps.
+ *
+ * @param this calling retransmit_request_job_t object
+ */
+ void (*increase_retransmit_count) (retransmit_request_job_t *this);
+
+ /**
+ * @brief Returns the message_id of the request to be resent
+ *
+ * @param this calling retransmit_request_job_t object
+ * @return message id of the request to resend
+ */
+ u_int32_t (*get_message_id) (retransmit_request_job_t *this);
+
+ /**
+ * @brief Returns the ike_sa_id_t object of the IKE_SA
+ * which the request belongs to
+ *
+ * @warning returned ike_sa_id_t object is getting destroyed in
+ * retransmit_request_job_t.destroy.
+ *
+ * @param this calling retransmit_request_job_t object
+ * @return ike_sa_id_t object to identify IKE_SA (gets NOT cloned)
+ */
+ ike_sa_id_t *(*get_ike_sa_id) (retransmit_request_job_t *this);
+
+ /**
+ * @brief Destroys an retransmit_request_job_t object.
+ *
+ * @param this retransmit_request_job_t object to destroy
+ */
+ void (*destroy) (retransmit_request_job_t *this);
+};
+
+/**
+ * @brief Creates a job of type RETRANSMIT_REQUEST.
+ *
+ * @param message_id message_id of the request to resend
+ * @param ike_sa_id identification of the ike_sa as ike_sa_id_t object (gets cloned)
+ * @return retransmit_request_job_t object
+ *
+ * @ingroup jobs
+ */
+retransmit_request_job_t *retransmit_request_job_create(u_int32_t message_id,ike_sa_id_t *ike_sa_id);
+
+#endif /* RESEND_MESSAGE_JOB_H_ */
diff --git a/programs/charon/charon/queues/send_queue.c b/programs/charon/charon/queues/send_queue.c
new file mode 100644
index 000000000..0852e5303
--- /dev/null
+++ b/programs/charon/charon/queues/send_queue.c
@@ -0,0 +1,153 @@
+/**
+ * @file send_queue.c
+ *
+ * @brief Implementation of send_queue_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <pthread.h>
+
+#include "send_queue.h"
+
+#include <utils/linked_list.h>
+
+
+typedef struct private_send_queue_t private_send_queue_t;
+
+/**
+ * @brief Private Variables and Functions of send_queue class
+ *
+ */
+struct private_send_queue_t {
+ /**
+ * Public part of the send_queue_t object
+ */
+ send_queue_t public;
+
+ /**
+ * The packets are stored in a linked list
+ */
+ linked_list_t *list;
+
+ /**
+ * access to linked_list is locked through this mutex
+ */
+ pthread_mutex_t mutex;
+
+ /**
+ * If the queue is empty a thread has to wait
+ * This condvar is used to wake up such a thread
+ */
+ pthread_cond_t condvar;
+};
+
+
+/**
+ * implements send_queue_t.get_count
+ */
+static int get_count(private_send_queue_t *this)
+{
+ int count;
+ pthread_mutex_lock(&(this->mutex));
+ count = this->list->get_count(this->list);
+ pthread_mutex_unlock(&(this->mutex));
+ return count;
+}
+
+/**
+ * implements send_queue_t.get
+ */
+static packet_t *get(private_send_queue_t *this)
+{
+ int oldstate;
+ packet_t *packet;
+ pthread_mutex_lock(&(this->mutex));
+ /* go to wait while no packets available */
+
+ while(this->list->get_count(this->list) == 0)
+ {
+ /* add mutex unlock handler for cancellation, enable cancellation */
+ pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock, (void*)&(this->mutex));
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
+ pthread_cond_wait( &(this->condvar), &(this->mutex));
+
+ /* reset cancellation, remove mutex-unlock handler (without executing) */
+ pthread_setcancelstate(oldstate, NULL);
+ pthread_cleanup_pop(0);
+ }
+ this->list->remove_first(this->list,(void **)&packet);
+ pthread_mutex_unlock(&(this->mutex));
+ return packet;
+}
+
+/**
+ * implements send_queue_t.add
+ */
+static void add(private_send_queue_t *this, packet_t *packet)
+{
+ pthread_mutex_lock(&(this->mutex));
+ this->list->insert_last(this->list,packet);
+ pthread_cond_signal( &(this->condvar));
+ pthread_mutex_unlock(&(this->mutex));
+}
+
+/**
+ * implements send_queue_t.destroy
+ */
+static void destroy (private_send_queue_t *this)
+{
+
+ /* destroy all packets in list before destroying list */
+ while (this->list->get_count(this->list) > 0)
+ {
+ packet_t *packet;
+ if (this->list->remove_first(this->list,(void *) &packet) != SUCCESS)
+ {
+ this->list->destroy(this->list);
+ break;
+ }
+ packet->destroy(packet);
+ }
+ this->list->destroy(this->list);
+
+ pthread_mutex_destroy(&(this->mutex));
+
+ pthread_cond_destroy(&(this->condvar));
+
+ free(this);
+}
+
+/*
+ *
+ * Documented in header
+ */
+send_queue_t *send_queue_create()
+{
+ private_send_queue_t *this = malloc_thing(private_send_queue_t);
+
+ this->public.get_count = (int(*)(send_queue_t*)) get_count;
+ this->public.get = (packet_t*(*)(send_queue_t*)) get;
+ this->public.add = (void(*)(send_queue_t*, packet_t*)) add;
+ this->public.destroy = (void(*)(send_queue_t*)) destroy;
+
+ this->list = linked_list_create();
+ pthread_mutex_init(&(this->mutex), NULL);
+ pthread_cond_init(&(this->condvar), NULL);
+
+ return (&this->public);
+}
diff --git a/programs/charon/charon/queues/send_queue.h b/programs/charon/charon/queues/send_queue.h
new file mode 100644
index 000000000..6dc5867eb
--- /dev/null
+++ b/programs/charon/charon/queues/send_queue.h
@@ -0,0 +1,100 @@
+/**
+ * @file send_queue.h
+ *
+ * @brief Interface of send_queue_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef SEND_QUEUE_H_
+#define SEND_QUEUE_H_
+
+#include <types.h>
+#include <network/packet.h>
+
+
+typedef struct send_queue_t send_queue_t;
+
+/**
+ * @brief The send queue stores packet for the sender_t instance.
+ *
+ * The sender_t will send them consequently over the wire.
+ * Although the send-queue is based on a linked_list_t
+ * all access functions are thread-save implemented.
+ *
+ * @b Constructors:
+ * - send_queue_create()
+ *
+ * @ingroup queues
+ */
+struct send_queue_t {
+
+ /**
+ * @brief returns number of packets in queue
+ *
+ * @param send_queue_t calling object
+ * @param[out] count integer pointer to store the count in
+ * @returns number of items in queue
+ */
+ int (*get_count) (send_queue_t *send_queue);
+
+ /**
+ * @brief get the next packet from the queue.
+ *
+ * If the queue is empty, this function blocks until a packet can be returned.
+ *
+ * After using, the returned packet has to get destroyed by the caller.
+ *
+ * @param send_queue_t calling object
+ * @return next packet from the queue
+ */
+ packet_t *(*get) (send_queue_t *send_queue);
+
+ /**
+ * @brief adds a packet to the queue.
+ *
+ * This function is non blocking and adds a packet_t to the list.
+ * The specific packet object has to get destroyed by the thread which
+ * removes the packet.
+ *
+ * @param send_queue_t calling object
+ * @param packet packet_t to add to the queue (packet is not copied)
+ */
+ void (*add) (send_queue_t *send_queue, packet_t *packet);
+
+ /**
+ * @brief destroys a send_queue object.
+ *
+ * @warning The caller of this function has to make sure
+ * that no thread is going to add or get a packet from the send_queue
+ * after calling this function.
+ *
+ * @param send_queue_t calling object
+ */
+ void (*destroy) (send_queue_t *send_queue);
+};
+
+/**
+ * @brief Creates an empty send_queue_t.
+ *
+ * @return send_queue_t object
+ *
+ * @ingroup queues
+ */
+send_queue_t *send_queue_create();
+
+#endif /*SEND_QUEUE_H_*/
diff --git a/programs/charon/charon/sa/Makefile.sa b/programs/charon/charon/sa/Makefile.sa
new file mode 100644
index 000000000..825c19959
--- /dev/null
+++ b/programs/charon/charon/sa/Makefile.sa
@@ -0,0 +1,37 @@
+# Copyright (C) 2005 Jan Hutter, Martin Willi
+# Hochschule fuer Technik Rapperswil
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+
+SA_DIR= $(CHARON_DIR)sa/
+
+CHARON_OBJS+= $(BUILD_DIR)ike_sa_id.o
+$(BUILD_DIR)ike_sa_id.o : $(SA_DIR)ike_sa_id.c $(SA_DIR)ike_sa_id.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)ike_sa_manager.o
+$(BUILD_DIR)ike_sa_manager.o : $(SA_DIR)ike_sa_manager.c $(SA_DIR)ike_sa_manager.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)ike_sa.o
+$(BUILD_DIR)ike_sa.o : $(SA_DIR)ike_sa.c $(SA_DIR)ike_sa.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)authenticator.o
+$(BUILD_DIR)authenticator.o : $(SA_DIR)authenticator.c $(SA_DIR)authenticator.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)child_sa.o
+$(BUILD_DIR)child_sa.o : $(SA_DIR)child_sa.c $(SA_DIR)child_sa.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+include $(SA_DIR)states/Makefile.states \ No newline at end of file
diff --git a/programs/charon/charon/sa/authenticator.c b/programs/charon/charon/sa/authenticator.c
new file mode 100644
index 000000000..3aeb8795f
--- /dev/null
+++ b/programs/charon/charon/sa/authenticator.c
@@ -0,0 +1,405 @@
+/**
+ * @file authenticator.c
+ *
+ * @brief Implementation of authenticator_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+
+#include "authenticator.h"
+
+#include <daemon.h>
+
+/**
+ * Key pad for the AUTH method SHARED_KEY_MESSAGE_INTEGRITY_CODE.
+ */
+#define IKEV2_KEY_PAD "Key Pad for IKEv2"
+
+
+typedef struct private_authenticator_t private_authenticator_t;
+
+/**
+ * Private data of an authenticator_t object.
+ */
+struct private_authenticator_t {
+
+ /**
+ * Public authenticator_t interface.
+ */
+ authenticator_t public;
+
+ /**
+ * Assigned IKE_SA. Needed to get objects of type prf_t and logger_t.
+ */
+ protected_ike_sa_t *ike_sa;
+
+ /**
+ * PRF taken from the IKE_SA.
+ */
+ prf_t *prf;
+
+ /**
+ * A logger for.
+ *
+ * Using logger of IKE_SA.
+ */
+ logger_t *logger;
+
+ /**
+ * @brief Creates the octets which are signed (RSA) or MACed (shared secret) as described in section
+ * 2.15 of RFC.
+ *
+ * @param this calling object
+ * @param last_message the last message to include in created octets
+ * (either binary form of IKE_SA_INIT request or IKE_SA_INIT response)
+ * @param other_nonce Nonce data received from other peer
+ * @param my_id id_payload_t object representing an ID payload
+ * @param initiator Type of peer. TRUE, if it is original initiator, FALSE otherwise
+ * @return octets as described in section 2.15. Memory gets allocated and has to get
+ * destroyed by caller.
+ */
+ chunk_t (*allocate_octets) (private_authenticator_t *this,
+ chunk_t last_message,
+ chunk_t other_nonce,
+ id_payload_t *my_id,
+ bool initiator);
+
+ /**
+ * @brief Creates the AUTH data using auth method SHARED_KEY_MESSAGE_INTEGRITY_CODE.
+ *
+ * @param this calling object
+ * @param last_message the last message
+ * (either binary form of IKE_SA_INIT request or IKE_SA_INIT response)
+ * @param nonce Nonce data to include in auth data compution
+ * @param id_payload id_payload_t object representing an ID payload
+ * @param initiator Type of peer. TRUE, if it is original initiator, FALSE otherwise
+ * @param shared_secret shared secret as chunk_t. If shared secret is a string,
+ * the NULL termination is not included.
+ * @return AUTH data as dscribed in section 2.15 for
+ * AUTH method SHARED_KEY_MESSAGE_INTEGRITY_CODE.
+ * Memory gets allocated and has to get destroyed by caller.
+ */
+ chunk_t (*build_preshared_secret_signature) (private_authenticator_t *this,
+ chunk_t last_message,
+ chunk_t nonce,
+ id_payload_t *id_payload,
+ bool initiator,
+ chunk_t preshared_secret);
+};
+
+/**
+ * Implementation of private_authenticator_t.allocate_octets.
+ */
+static chunk_t allocate_octets(private_authenticator_t *this,
+ chunk_t last_message,
+ chunk_t other_nonce,
+ id_payload_t *my_id,
+ bool initiator)
+{
+ prf_t *prf;
+ chunk_t id_chunk = my_id->get_data(my_id);
+ u_int8_t id_with_header[4 + id_chunk.len];
+ /*
+ * IKEv2 for linux (http://sf.net/projects/ikev2/)
+ * is not compatible with IKEv2 Draft and so not compatible with this
+ * implementation, cause AUTH data are computed without
+ * ID type and the three reserved bytes.
+ */
+ chunk_t id_with_header_chunk = {ptr:id_with_header, len: sizeof(id_with_header)};
+ u_int8_t *current_pos;
+ chunk_t octets;
+
+ id_with_header[0] = my_id->get_id_type(my_id);
+ id_with_header[1] = 0x00;
+ id_with_header[2] = 0x00;
+ id_with_header[3] = 0x00;
+ memcpy(id_with_header + 4,id_chunk.ptr,id_chunk.len);
+
+ if (initiator)
+ {
+ prf = this->ike_sa->get_prf_auth_i(this->ike_sa);
+ }
+ else
+ {
+ prf = this->ike_sa->get_prf_auth_r(this->ike_sa);
+ }
+
+ /* 4 bytes are id type and reserved fields of id payload */
+ octets.len = last_message.len + other_nonce.len + prf->get_block_size(prf);
+ octets.ptr = malloc(octets.len);
+ current_pos = octets.ptr;
+ memcpy(current_pos,last_message.ptr,last_message.len);
+ current_pos += last_message.len;
+ memcpy(current_pos,other_nonce.ptr,other_nonce.len);
+ current_pos += other_nonce.len;
+ prf->get_bytes(prf, id_with_header_chunk, current_pos);
+
+ this->logger->log_chunk(this->logger,RAW | LEVEL2, "Octets (Mesage + Nonce + prf(Sk_px,Idx)",octets);
+ return octets;
+}
+
+/**
+ * Implementation of private_authenticator_t.build_preshared_secret_signature.
+ */
+static chunk_t build_preshared_secret_signature(private_authenticator_t *this,
+ chunk_t last_message,
+ chunk_t nonce,
+ id_payload_t *id_payload,
+ bool initiator,
+ chunk_t preshared_secret)
+{
+ chunk_t key_pad = {ptr: IKEV2_KEY_PAD, len:strlen(IKEV2_KEY_PAD)};
+ u_int8_t key_buffer[this->prf->get_block_size(this->prf)];
+ chunk_t key = {ptr: key_buffer, len: sizeof(key_buffer)};
+ chunk_t auth_data;
+
+ chunk_t octets = this->allocate_octets(this,last_message,nonce,id_payload,initiator);
+
+ /* AUTH = prf(prf(Shared Secret,"Key Pad for IKEv2"), <msg octets>) */
+ this->prf->set_key(this->prf, preshared_secret);
+ this->prf->get_bytes(this->prf, key_pad, key_buffer);
+ this->prf->set_key(this->prf, key);
+ this->prf->allocate_bytes(this->prf, octets, &auth_data);
+ chunk_free(&octets);
+ this->logger->log_chunk(this->logger,RAW | LEVEL2, "Authenticated data",auth_data);
+
+ return auth_data;
+}
+
+/**
+ * Implementation of authenticator_t.verify_auth_data.
+ */
+static status_t verify_auth_data (private_authenticator_t *this,
+ auth_payload_t *auth_payload,
+ chunk_t last_received_packet,
+ chunk_t my_nonce,
+ id_payload_t *other_id_payload,
+ bool initiator)
+{
+ switch(auth_payload->get_auth_method(auth_payload))
+ {
+ case SHARED_KEY_MESSAGE_INTEGRITY_CODE:
+ {
+ identification_t *other_id = other_id_payload->get_identification(other_id_payload);
+ chunk_t auth_data = auth_payload->get_data(auth_payload);
+ chunk_t preshared_secret;
+ status_t status;
+
+ status = charon->credentials->get_shared_secret(charon->credentials,
+ other_id,
+ &preshared_secret);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1, "No shared secret found for %s",
+ other_id->get_string(other_id));
+ other_id->destroy(other_id);
+ return status;
+ }
+
+ chunk_t my_auth_data = this->build_preshared_secret_signature(this,
+ last_received_packet,
+ my_nonce,
+ other_id_payload,
+ initiator,
+ preshared_secret);
+ chunk_free(&preshared_secret);
+
+ if (auth_data.len != my_auth_data.len)
+ {
+ chunk_free(&my_auth_data);
+ status = FAILED;
+ }
+ else if (memcmp(auth_data.ptr,my_auth_data.ptr, my_auth_data.len) == 0)
+ {
+ this->logger->log(this->logger, CONTROL, "Authentication of %s with preshared secret successful",
+ other_id->get_string(other_id));
+ status = SUCCESS;
+ }
+ else
+ {
+ this->logger->log(this->logger, CONTROL, "Authentication of %s with preshared secret failed",
+ other_id->get_string(other_id));
+ status = FAILED;
+ }
+ other_id->destroy(other_id);
+ chunk_free(&my_auth_data);
+ return status;
+ }
+ case RSA_DIGITAL_SIGNATURE:
+ {
+ identification_t *other_id = other_id_payload->get_identification(other_id_payload);
+ rsa_public_key_t *public_key;
+ status_t status;
+ chunk_t octets, auth_data;
+
+ auth_data = auth_payload->get_data(auth_payload);
+
+ public_key = charon->credentials->get_rsa_public_key(charon->credentials,
+ other_id);
+ if (public_key == NULL)
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1, "No RSA public key found for %s",
+ other_id->get_string(other_id));
+ other_id->destroy(other_id);
+ return NOT_FOUND;
+ }
+
+ octets = this->allocate_octets(this,last_received_packet, my_nonce,other_id_payload, initiator);
+
+ status = public_key->verify_emsa_pkcs1_signature(public_key, octets, auth_data);
+ if (status == SUCCESS)
+ {
+ this->logger->log(this->logger, CONTROL, "Authentication of %s with RSA successful",
+ other_id->get_string(other_id));
+ }
+ else
+ {
+ this->logger->log(this->logger, CONTROL, "Authentication of %s with RSA failed",
+ other_id->get_string(other_id));
+ }
+
+ public_key->destroy(public_key);
+ other_id->destroy(other_id);
+ chunk_free(&octets);
+ return status;
+ }
+ default:
+ {
+ return NOT_SUPPORTED;
+ }
+ }
+}
+
+/**
+ * Implementation of authenticator_t.compute_auth_data.
+ */
+static status_t compute_auth_data (private_authenticator_t *this,
+ auth_payload_t **auth_payload,
+ chunk_t last_sent_packet,
+ chunk_t other_nonce,
+ id_payload_t *my_id_payload,
+ bool initiator)
+{
+ connection_t *connection = this->ike_sa->get_connection(this->ike_sa);
+
+ switch(connection->get_auth_method(connection))
+ {
+ case SHARED_KEY_MESSAGE_INTEGRITY_CODE:
+ {
+ identification_t *my_id = my_id_payload->get_identification(my_id_payload);
+ chunk_t preshared_secret;
+ status_t status;
+ chunk_t auth_data;
+
+ status = charon->credentials->get_shared_secret(charon->credentials,
+ my_id,
+ &preshared_secret);
+
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1, "No shared secret found for %s",
+ my_id->get_string(my_id));
+ my_id->destroy(my_id);
+ return status;
+ }
+ my_id->destroy(my_id);
+
+ auth_data = this->build_preshared_secret_signature(this, last_sent_packet, other_nonce,
+ my_id_payload, initiator, preshared_secret);
+ chunk_free(&preshared_secret);
+ *auth_payload = auth_payload_create();
+ (*auth_payload)->set_auth_method(*auth_payload, SHARED_KEY_MESSAGE_INTEGRITY_CODE);
+ (*auth_payload)->set_data(*auth_payload, auth_data);
+
+ chunk_free(&auth_data);
+ return SUCCESS;
+ }
+ case RSA_DIGITAL_SIGNATURE:
+ {
+ identification_t *my_id = my_id_payload->get_identification(my_id_payload);
+ rsa_private_key_t *private_key;
+ status_t status;
+ chunk_t octets, auth_data;
+
+ private_key = charon->credentials->get_rsa_private_key(charon->credentials, my_id);
+ if (private_key == NULL)
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1, "No RSA private key found for %s",
+ my_id->get_string(my_id));
+ my_id->destroy(my_id);
+ return NOT_FOUND;
+ }
+ my_id->destroy(my_id);
+
+ octets = this->allocate_octets(this,last_sent_packet,other_nonce,my_id_payload,initiator);
+
+ status = private_key->build_emsa_pkcs1_signature(private_key, HASH_SHA1, octets, &auth_data);
+ chunk_free(&octets);
+ if (status != SUCCESS)
+ {
+ private_key->destroy(private_key);
+ return status;
+ }
+
+ *auth_payload = auth_payload_create();
+ (*auth_payload)->set_auth_method(*auth_payload, RSA_DIGITAL_SIGNATURE);
+ (*auth_payload)->set_data(*auth_payload, auth_data);
+
+ private_key->destroy(private_key);
+ chunk_free(&auth_data);
+ return SUCCESS;
+ }
+ default:
+ {
+ return NOT_SUPPORTED;
+ }
+ }
+}
+
+/**
+ * Implementation of authenticator_t.destroy.
+ */
+static void destroy (private_authenticator_t *this)
+{
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+authenticator_t *authenticator_create(protected_ike_sa_t *ike_sa)
+{
+ private_authenticator_t *this = malloc_thing(private_authenticator_t);
+
+ /* Public functions */
+ this->public.destroy = (void(*)(authenticator_t*))destroy;
+ this->public.verify_auth_data = (status_t (*) (authenticator_t *,auth_payload_t *, chunk_t ,chunk_t ,id_payload_t *,bool)) verify_auth_data;
+ this->public.compute_auth_data = (status_t (*) (authenticator_t *,auth_payload_t **, chunk_t ,chunk_t ,id_payload_t *,bool)) compute_auth_data;
+
+ /* private functions */
+ this->allocate_octets = allocate_octets;
+ this->build_preshared_secret_signature = build_preshared_secret_signature;
+
+ /* private data */
+ this->ike_sa = ike_sa;
+ this->prf = this->ike_sa->get_prf(this->ike_sa);
+ this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
+
+ return &(this->public);
+}
diff --git a/programs/charon/charon/sa/authenticator.h b/programs/charon/charon/sa/authenticator.h
new file mode 100644
index 000000000..b6bc317ac
--- /dev/null
+++ b/programs/charon/charon/sa/authenticator.h
@@ -0,0 +1,138 @@
+/**
+ * @file authenticator.h
+ *
+ * @brief Interface of authenticator_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef AUTHENTICATOR_H_
+#define AUTHENTICATOR_H_
+
+#include <types.h>
+#include <sa/ike_sa.h>
+#include <network/packet.h>
+#include <encoding/payloads/auth_payload.h>
+#include <encoding/payloads/id_payload.h>
+
+
+typedef struct authenticator_t authenticator_t;
+
+/**
+ * @brief Class used to authenticate a peer.
+ *
+ * Currently the following two AUTH methods are supported:
+ * - SHARED_KEY_MESSAGE_INTEGRITY_CODE
+ * - RSA_DIGITAL_SIGNATURE
+ *
+ * This class retrieves needed data for specific AUTH methods (RSA keys, shared secrets, etc.)
+ * over an internal stored protected_ike_sa_t object or directly from the configuration_t over
+ * the daemon_t object "charon".
+ *
+ * @b Constructors:
+ * - authenticator_create()
+ *
+ * @ingroup sa
+ */
+struct authenticator_t {
+
+ /**
+ * @brief Verify's given authentication data.
+ *
+ * To verify a received AUTH payload the following data must be provided:
+ * - the last received IKEv2 Message from the other peer in binary form
+ * - the nonce value sent to the other peer
+ * - the ID payload of the other peer
+ *
+ * @param this calling object
+ * @param last_received_packet binary representation of the last received IKEv2-Message
+ * @param my_nonce the sent nonce (without payload header)
+ * @param other_id_payload the ID payload received from other peer
+ * @param initiator type of other peer. TRUE, if it is original initiator, FALSE otherwise
+ *
+ * @todo Document RSA error status types
+ *
+ * @return
+ * - SUCCESS if verification successful
+ * - FAILED if verification failed
+ * - NOT_SUPPORTED if AUTH method not supported
+ * - NOT_FOUND if the data for specific AUTH method could not be found
+ * (e.g. shared secret, rsa key)
+ */
+ status_t (*verify_auth_data) (authenticator_t *this,
+ auth_payload_t *auth_payload,
+ chunk_t last_received_packet,
+ chunk_t my_nonce,
+ id_payload_t *other_id_payload,
+ bool initiator);
+
+ /**
+ * @brief Computes authentication data and creates specific AUTH payload.
+ *
+ * To create an AUTH payload, the following data must be provided:
+ * - the last sent IKEv2 Message in binary form
+ * - the nonce value received from the other peer
+ * - the ID payload of myself
+ *
+ * @param this calling object
+ * @param[out] auth_payload The object of typee auth_payload_t will be created at pointing location
+ * @param last_sent_packet binary representation of the last sent IKEv2-Message
+ * @param other_nonce the received nonce (without payload header)
+ * @param my_id_payload the ID payload going to send to other peer
+ * @param initiator type of myself. TRUE, if I'm original initiator, FALSE otherwise
+ *
+ * @todo Document RSA error status types
+ *
+ * @return
+ * - SUCCESS if authentication data could be computed
+ * - NOT_SUPPORTED if AUTH method not supported
+ * - NOT_FOUND if the data for AUTH method could not be found
+ */
+ status_t (*compute_auth_data) (authenticator_t *this,
+ auth_payload_t **auth_payload,
+ chunk_t last_sent_packet,
+ chunk_t other_nonce,
+ id_payload_t *my_id_payload,
+ bool initiator);
+
+ /**
+ * @brief Destroys a authenticator_t object.
+ *
+ * @param this calling object
+ */
+ void (*destroy) (authenticator_t *this);
+};
+
+/**
+ * @brief Creates an authenticator object.
+ *
+ * @warning: The following functions of the assigned protected_ike_sa_t object
+ * must return a valid value:
+ * - protected_ike_sa_t.get_policy
+ * - protected_ike_sa_t.get_prf
+ * - protected_ike_sa_t.get_logger
+ * This preconditions are not given in IKE_SA states INITIATOR_INIT or RESPONDER_INIT!
+ *
+ * @param ike_sa object of type protected_ike_sa_t
+ *
+ * @return authenticator_t object
+ *
+ * @ingroup sa
+ */
+authenticator_t *authenticator_create(protected_ike_sa_t *ike_sa);
+
+#endif /* AUTHENTICATOR_H_ */
diff --git a/programs/charon/charon/sa/child_sa.c b/programs/charon/charon/sa/child_sa.c
new file mode 100644
index 000000000..a678ea9b8
--- /dev/null
+++ b/programs/charon/charon/sa/child_sa.c
@@ -0,0 +1,590 @@
+/**
+ * @file child_sa.c
+ *
+ * @brief Implementation of child_sa_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <netdb.h>
+
+#include "child_sa.h"
+
+#include <daemon.h>
+
+
+typedef struct sa_policy_t sa_policy_t;
+
+/**
+ * Struct used to store information for a policy. This
+ * is needed since we must provide all this information
+ * for deleting a policy...
+ */
+struct sa_policy_t {
+
+ /**
+ * Network on local side
+ */
+ host_t *my_net;
+
+ /**
+ * Network on remote side
+ */
+ host_t *other_net;
+
+ /**
+ * Number of bits for local network (subnet size)
+ */
+ u_int8_t my_net_mask;
+
+ /**
+ * Number of bits for remote network (subnet size)
+ */
+ u_int8_t other_net_mask;
+
+ /**
+ * Protocol for this policy, such as TCP/UDP/ICMP...
+ */
+ int upper_proto;
+};
+
+typedef struct private_child_sa_t private_child_sa_t;
+
+/**
+ * Private data of a child_sa_t object.
+ */
+struct private_child_sa_t {
+ /**
+ * Public interface of child_sa_t.
+ */
+ child_sa_t public;
+
+ /**
+ * IP of this peer
+ */
+ host_t *me;
+
+ /**
+ * IP of other peer
+ */
+ host_t *other;
+
+ /**
+ * Local security parameter index for AH protocol, 0 if not used
+ */
+ u_int32_t my_ah_spi;
+
+ /**
+ * Local security parameter index for ESP protocol, 0 if not used
+ */
+ u_int32_t my_esp_spi;
+
+ /**
+ * Remote security parameter index for AH protocol, 0 if not used
+ */
+ u_int32_t other_ah_spi;
+
+ /**
+ * Remote security parameter index for ESP protocol, 0 if not used
+ */
+ u_int32_t other_esp_spi;
+
+ /**
+ * List containing policy_id_t objects
+ */
+ linked_list_t *policies;
+
+ /**
+ * reqid used for this child_sa
+ */
+ u_int32_t reqid;
+
+ /**
+ * CHILD_SAs own logger
+ */
+ logger_t *logger;
+};
+
+/**
+ * Implements child_sa_t.alloc
+ */
+static status_t alloc(private_child_sa_t *this, linked_list_t *proposals)
+{
+ protocol_id_t protocols[2];
+ iterator_t *iterator;
+ proposal_t *proposal;
+ status_t status;
+ u_int i;
+
+ /* iterator through proposals */
+ iterator = proposals->create_iterator(proposals, TRUE);
+ while(iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void**)&proposal);
+ proposal->get_protocols(proposal, protocols);
+
+ /* check all protocols */
+ for (i = 0; i<2; i++)
+ {
+ switch (protocols[i])
+ {
+ case PROTO_AH:
+ /* do we already have an spi for AH?*/
+ if (this->my_ah_spi == 0)
+ {
+ /* nope, get one */
+ status = charon->kernel_interface->get_spi(
+ charon->kernel_interface,
+ this->me, this->other,
+ PROTO_AH, FALSE,
+ &(this->my_ah_spi));
+ }
+ /* update proposal */
+ proposal->set_spi(proposal, PROTO_AH, (u_int64_t)this->my_ah_spi);
+ break;
+ case PROTO_ESP:
+ /* do we already have an spi for ESP?*/
+ if (this->my_esp_spi == 0)
+ {
+ /* nope, get one */
+ status = charon->kernel_interface->get_spi(
+ charon->kernel_interface,
+ this->me, this->other,
+ PROTO_ESP, FALSE,
+ &(this->my_esp_spi));
+ }
+ /* update proposal */
+ proposal->set_spi(proposal, PROTO_ESP, (u_int64_t)this->my_esp_spi);
+ break;
+ default:
+ break;
+ }
+ if (status != SUCCESS)
+ {
+ iterator->destroy(iterator);
+ return FAILED;
+ }
+ }
+ }
+ iterator->destroy(iterator);
+ return SUCCESS;
+}
+
+static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus, bool mine)
+{
+ protocol_id_t protocols[2];
+ u_int32_t spi;
+ encryption_algorithm_t enc_algo;
+ integrity_algorithm_t int_algo;
+ chunk_t enc_key, int_key;
+ algorithm_t *algo;
+ crypter_t *crypter;
+ signer_t *signer;
+ size_t key_size;
+ host_t *src;
+ host_t *dst;
+ status_t status;
+ u_int i;
+
+ /* we must assign the roles to correctly set up the SAs */
+ if (mine)
+ {
+ src = this->me;
+ dst = this->other;
+ }
+ else
+ {
+ dst = this->me;
+ src = this->other;
+ }
+
+ proposal->get_protocols(proposal, protocols);
+ /* derive keys in order as protocols appear */
+ for (i = 0; i<2; i++)
+ {
+ if (protocols[i] != PROTO_NONE)
+ {
+
+ /* now we have to decide which spi to use. Use self allocated, if "mine",
+ * or the one in the proposal, if not "mine" (others). */
+ if (mine)
+ {
+ if (protocols[i] == PROTO_AH)
+ {
+ spi = this->my_ah_spi;
+ }
+ else
+ {
+ spi = this->my_esp_spi;
+ }
+ }
+ else /* use proposals spi */
+ {
+ spi = proposal->get_spi(proposal, protocols[i]);
+ if (protocols[i] == PROTO_AH)
+ {
+ this->other_ah_spi = spi;
+ }
+ else
+ {
+ this->other_esp_spi = spi;
+ }
+ }
+
+ /* derive encryption key first */
+ if (proposal->get_algorithm(proposal, protocols[i], ENCRYPTION_ALGORITHM, &algo))
+ {
+ enc_algo = algo->algorithm;
+ this->logger->log(this->logger, CONTROL|LEVEL1, "%s for %s: using %s %s, ",
+ mapping_find(protocol_id_m, protocols[i]),
+ mine ? "me" : "other",
+ mapping_find(transform_type_m, ENCRYPTION_ALGORITHM),
+ mapping_find(encryption_algorithm_m, enc_algo));
+
+ /* we must create a (unused) crypter, since its the only way to get the size
+ * of the key. This is not so nice, since charon must support all algorithms
+ * the kernel supports...
+ * TODO: build something of a encryption algorithm lookup function
+ */
+ crypter = crypter_create(enc_algo, algo->key_size);
+ key_size = crypter->get_key_size(crypter);
+ crypter->destroy(crypter);
+ prf_plus->allocate_bytes(prf_plus, key_size, &enc_key);
+ this->logger->log_chunk(this->logger, PRIVATE, "key:", enc_key);
+ }
+ else
+ {
+ enc_algo = ENCR_UNDEFINED;
+ }
+
+ /* derive integrity key */
+ if (proposal->get_algorithm(proposal, protocols[i], INTEGRITY_ALGORITHM, &algo))
+ {
+ int_algo = algo->algorithm;
+ this->logger->log(this->logger, CONTROL|LEVEL1, "%s for %s: using %s %s,",
+ mapping_find(protocol_id_m, protocols[i]),
+ mine ? "me" : "other",
+ mapping_find(transform_type_m, INTEGRITY_ALGORITHM),
+ mapping_find(integrity_algorithm_m, algo->algorithm));
+
+ signer = signer_create(int_algo);
+ key_size = signer->get_key_size(signer);
+ signer->destroy(signer);
+ prf_plus->allocate_bytes(prf_plus, key_size, &int_key);
+ this->logger->log_chunk(this->logger, PRIVATE, "key:", int_key);
+ }
+ else
+ {
+ int_algo = AUTH_UNDEFINED;
+ }
+ /* send keys down to kernel */
+ this->logger->log(this->logger, CONTROL|LEVEL1,
+ "installing 0x%.8x for %s, src %s dst %s",
+ ntohl(spi), mapping_find(protocol_id_m, protocols[i]),
+ src->get_address(src), dst->get_address(dst));
+ status = charon->kernel_interface->add_sa(charon->kernel_interface,
+ src, dst,
+ spi, protocols[i],
+ this->reqid,
+ enc_algo, enc_key,
+ int_algo, int_key, mine);
+ /* clean up for next round */
+ if (enc_algo != ENCR_UNDEFINED)
+ {
+ chunk_free(&enc_key);
+ }
+ if (int_algo != AUTH_UNDEFINED)
+ {
+ chunk_free(&int_key);
+ }
+
+ if (status != SUCCESS)
+ {
+ return FAILED;
+ }
+
+
+ }
+ }
+ return SUCCESS;
+}
+
+static status_t add(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus)
+{
+ linked_list_t *list;
+
+ /* install others (initiators) SAs*/
+ if (install(this, proposal, prf_plus, FALSE) != SUCCESS)
+ {
+ return FAILED;
+ }
+
+ /* get SPIs for our SAs */
+ list = linked_list_create();
+ list->insert_last(list, proposal);
+ if (alloc(this, list) != SUCCESS)
+ {
+ list->destroy(list);
+ return FAILED;
+ }
+ list->destroy(list);
+
+ /* install our (responders) SAs */
+ if (install(this, proposal, prf_plus, TRUE) != SUCCESS)
+ {
+ return FAILED;
+ }
+
+ return SUCCESS;
+}
+
+static status_t update(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus)
+{
+ /* install our (initator) SAs */
+ if (install(this, proposal, prf_plus, TRUE) != SUCCESS)
+ {
+ return FAILED;
+ }
+ /* install his (responder) SAs */
+ if (install(this, proposal, prf_plus, FALSE) != SUCCESS)
+ {
+ return FAILED;
+ }
+
+ return SUCCESS;
+}
+
+static status_t add_policies(private_child_sa_t *this, linked_list_t *my_ts_list, linked_list_t *other_ts_list)
+{
+ iterator_t *my_iter, *other_iter;
+ traffic_selector_t *my_ts, *other_ts;
+
+ /* iterate over both lists */
+ my_iter = my_ts_list->create_iterator(my_ts_list, TRUE);
+ other_iter = other_ts_list->create_iterator(other_ts_list, TRUE);
+ while (my_iter->has_next(my_iter))
+ {
+ my_iter->current(my_iter, (void**)&my_ts);
+ other_iter->reset(other_iter);
+ while (other_iter->has_next(other_iter))
+ {
+ /* set up policies for every entry in my_ts_list to every entry in other_ts_list */
+ int family;
+ chunk_t from_addr;
+ u_int16_t from_port, to_port;
+ sa_policy_t *policy;
+ status_t status;
+
+ other_iter->current(other_iter, (void**)&other_ts);
+
+ /* only set up policies if protocol matches */
+ if (my_ts->get_protocol(my_ts) != other_ts->get_protocol(other_ts))
+ {
+ continue;
+ }
+ policy = malloc_thing(sa_policy_t);
+ policy->upper_proto = my_ts->get_protocol(my_ts);
+
+ /* calculate net and ports for local side */
+ family = my_ts->get_type(my_ts) == TS_IPV4_ADDR_RANGE ? AF_INET : AF_INET6;
+ from_addr = my_ts->get_from_address(my_ts);
+ from_port = my_ts->get_from_port(my_ts);
+ to_port = my_ts->get_to_port(my_ts);
+ from_port = (from_port != to_port) ? 0 : from_port;
+ policy->my_net = host_create_from_chunk(family, from_addr, from_port);
+ policy->my_net_mask = my_ts->get_netmask(my_ts);
+ chunk_free(&from_addr);
+
+ /* calculate net and ports for remote side */
+ family = other_ts->get_type(other_ts) == TS_IPV4_ADDR_RANGE ? AF_INET : AF_INET6;
+ from_addr = other_ts->get_from_address(other_ts);
+ from_port = other_ts->get_from_port(other_ts);
+ to_port = other_ts->get_to_port(other_ts);
+ from_port = (from_port != to_port) ? 0 : from_port;
+ policy->other_net = host_create_from_chunk(family, from_addr, from_port);
+ policy->other_net_mask = other_ts->get_netmask(other_ts);
+ chunk_free(&from_addr);
+
+ /* install 3 policies: out, in and forward */
+ status = charon->kernel_interface->add_policy(charon->kernel_interface,
+ this->me, this->other,
+ policy->my_net, policy->other_net,
+ policy->my_net_mask, policy->other_net_mask,
+ XFRM_POLICY_OUT, policy->upper_proto,
+ this->my_ah_spi, this->my_esp_spi,
+ this->reqid);
+
+ status |= charon->kernel_interface->add_policy(charon->kernel_interface,
+ this->other, this->me,
+ policy->other_net, policy->my_net,
+ policy->other_net_mask, policy->my_net_mask,
+ XFRM_POLICY_IN, policy->upper_proto,
+ this->my_ah_spi, this->my_esp_spi,
+ this->reqid);
+
+ status |= charon->kernel_interface->add_policy(charon->kernel_interface,
+ this->other, this->me,
+ policy->other_net, policy->my_net,
+ policy->other_net_mask, policy->my_net_mask,
+ XFRM_POLICY_FWD, policy->upper_proto,
+ this->my_ah_spi, this->my_esp_spi,
+ this->reqid);
+
+ if (status != SUCCESS)
+ {
+ my_iter->destroy(my_iter);
+ other_iter->destroy(other_iter);
+ policy->my_net->destroy(policy->my_net);
+ policy->other_net->destroy(policy->other_net);
+ free(policy);
+ return status;
+ }
+
+ /* add it to the policy list, since we want to know which policies we own */
+ this->policies->insert_last(this->policies, policy);
+ }
+ }
+
+ my_iter->destroy(my_iter);
+ other_iter->destroy(other_iter);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of child_sa_t.log_status.
+ */
+static void log_status(private_child_sa_t *this, logger_t *logger, char* name)
+{
+ iterator_t *iterator;
+ sa_policy_t *policy;
+ struct protoent *proto;
+ char proto_buf[8] = "";
+ char *proto_name = proto_buf;
+
+ if (logger == NULL)
+ {
+ logger = this->logger;
+ }
+ logger->log(logger, CONTROL|LEVEL1, "\"%s\": protected with ESP (0x%x/0x%x), AH (0x%x,0x%x):",
+ name,
+ htonl(this->my_esp_spi), htonl(this->other_esp_spi),
+ htonl(this->my_ah_spi), htonl(this->other_ah_spi));
+ iterator = this->policies->create_iterator(this->policies, TRUE);
+ while (iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void**)&policy);
+ if (policy->upper_proto)
+ {
+ proto = getprotobynumber(policy->upper_proto);
+ if (proto)
+ {
+ proto_name = proto->p_name;
+ }
+ else
+ {
+ snprintf(proto_buf, sizeof(proto_buf), "<%d>", policy->upper_proto);
+ }
+ }
+ logger->log(logger, CONTROL, "\"%s\": %s/%d==%s==%s/%d",
+ name,
+ policy->my_net->get_address(policy->my_net), policy->my_net_mask,
+ proto_name,
+ policy->other_net->get_address(policy->other_net), policy->other_net_mask);
+ }
+ iterator->destroy(iterator);
+}
+
+/**
+ * Implementation of child_sa_t.destroy.
+ */
+static void destroy(private_child_sa_t *this)
+{
+ /* delete all policys in the kernel */
+ sa_policy_t *policy;
+ while (this->policies->remove_last(this->policies, (void**)&policy) == SUCCESS)
+ {
+ charon->kernel_interface->del_policy(charon->kernel_interface,
+ this->me, this->other,
+ policy->my_net, policy->other_net,
+ policy->my_net_mask, policy->other_net_mask,
+ XFRM_POLICY_OUT, policy->upper_proto);
+
+ charon->kernel_interface->del_policy(charon->kernel_interface,
+ this->other, this->me,
+ policy->other_net, policy->my_net,
+ policy->other_net_mask, policy->my_net_mask,
+ XFRM_POLICY_IN, policy->upper_proto);
+
+ charon->kernel_interface->del_policy(charon->kernel_interface,
+ this->other, this->me,
+ policy->other_net, policy->my_net,
+ policy->other_net_mask, policy->my_net_mask,
+ XFRM_POLICY_FWD, policy->upper_proto);
+
+ policy->my_net->destroy(policy->my_net);
+ policy->other_net->destroy(policy->other_net);
+ free(policy);
+ }
+ this->policies->destroy(this->policies);
+
+ /* delete SAs in the kernel, if they are set up */
+ if (this->my_ah_spi)
+ {
+ charon->kernel_interface->del_sa(charon->kernel_interface,
+ this->other, this->my_ah_spi, PROTO_AH);
+ charon->kernel_interface->del_sa(charon->kernel_interface,
+ this->me, this->other_ah_spi, PROTO_AH);
+ }
+ if (this->my_esp_spi)
+ {
+ charon->kernel_interface->del_sa(charon->kernel_interface,
+ this->other, this->my_esp_spi, PROTO_ESP);
+ charon->kernel_interface->del_sa(charon->kernel_interface,
+ this->me, this->other_esp_spi, PROTO_ESP);
+ }
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+child_sa_t * child_sa_create(host_t *me, host_t* other)
+{
+ static u_int32_t reqid = 0xc0000000;
+ private_child_sa_t *this = malloc_thing(private_child_sa_t);
+
+ /* public functions */
+ this->public.alloc = (status_t(*)(child_sa_t*,linked_list_t*))alloc;
+ this->public.add = (status_t(*)(child_sa_t*,proposal_t*,prf_plus_t*))add;
+ this->public.update = (status_t(*)(child_sa_t*,proposal_t*,prf_plus_t*))update;
+ this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*))add_policies;
+ this->public.log_status = (void (*)(child_sa_t*, logger_t*, char*))log_status;
+ this->public.destroy = (void(*)(child_sa_t*))destroy;
+
+ /* private data */
+ this->logger = logger_manager->get_logger(logger_manager, CHILD_SA);
+ this->me = me;
+ this->other = other;
+ this->my_ah_spi = 0;
+ this->my_esp_spi = 0;
+ this->other_ah_spi = 0;
+ this->other_esp_spi = 0;
+ this->reqid = reqid++;
+ this->policies = linked_list_create();
+
+ return (&this->public);
+}
diff --git a/programs/charon/charon/sa/child_sa.h b/programs/charon/charon/sa/child_sa.h
new file mode 100644
index 000000000..6ccbff13f
--- /dev/null
+++ b/programs/charon/charon/sa/child_sa.h
@@ -0,0 +1,149 @@
+/**
+ * @file child_sa.h
+ *
+ * @brief Interface of child_sa_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#ifndef CHILD_SA_H_
+#define CHILD_SA_H_
+
+#include <types.h>
+#include <crypto/prf_plus.h>
+#include <encoding/payloads/proposal_substructure.h>
+#include <utils/logger.h>
+
+typedef struct child_sa_t child_sa_t;
+
+/**
+ * @brief Represents multiple IPsec SAs between two hosts.
+ *
+ * A child_sa_t contains multiple SAs. SAs for both
+ * directions are managed in one child_sa_t object, and
+ * if both AH and ESP is set up, both protocols are managed
+ * by one child_sa_t. This means we can have two or
+ * in the AH+ESP case four IPsec-SAs in one child_sa_t.
+ *
+ * The procedure for child sa setup is as follows:
+ * - A gets SPIs for a proposal via child_sa_t.alloc
+ * - A send the updated proposal to B
+ * - B selects a suitable proposal
+ * - B calls child_sa_t.add to add and update the selected proposal
+ * - B sends the updated proposal to A
+ * - 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 Allocate SPIs for a given proposals.
+ *
+ * Since the kernel manages SPIs for us, we need
+ * to allocate them. If the proposal contains more
+ * than one protocol, for each protocol an SPI is
+ * allocated. SPIs are stored internally and written
+ * back to the proposal.
+ *
+ * @param this calling object
+ * @param proposal proposal for which SPIs are allocated
+ */
+ status_t (*alloc)(child_sa_t *this, linked_list_t* proposals);
+
+ /**
+ * @brief Install the kernel SAs for a proposal.
+ *
+ * Since the kernel manages SPIs for us, we need
+ * to allocate them. If the proposal contains more
+ * than one protocol, for each protocol an SPI is
+ * allocated. SPIs are stored internally and written
+ * back to the proposal.
+ *
+ * @param this calling object
+ * @param proposal proposal for which SPIs are allocated
+ * @param prf_plus key material to use for key derivation
+ */
+ status_t (*add)(child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus);
+
+ /**
+ * @brief Install the kernel SAs for a proposal, if SPIs already allocated.
+ *
+ * This one updates the SAs in the kernel, which are
+ * allocated via alloc, with a selected proposals.
+ *
+ * @param this calling object
+ * @param proposal proposal for which SPIs are allocated
+ * @param prf_plus key material to use for key derivation
+ */
+ status_t (*update)(child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus);
+
+ /**
+ * @brief Install the policies using some traffic selectors.
+ *
+ * Spplied 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
+ * @return SUCCESS or FAILED
+ */
+ status_t (*add_policies) (child_sa_t *this, linked_list_t *my_ts_list, linked_list_t *other_ts_list);
+
+ /**
+ * @brief Log the status of a child_sa to a logger.
+ *
+ * The status of ESP/AH SAs is logged with the supplied logger in
+ * a human readable form.
+ * Supplying NULL as logger uses the internal child_sa logger
+ * to do the logging. The name is only a log-prefix without further
+ * meaning.
+ *
+ * @param this calling object
+ * @param logger logger to use for logging
+ * @param name connection name
+ */
+ void (*log_status) (child_sa_t *this, logger_t *logger, char *name);
+
+ /**
+ * @brief Destroys a child_sa.
+ *
+ * @param this calling object
+ */
+ void (*destroy) (child_sa_t *this);
+};
+
+/**
+ * @brief Constructor to create a new child_sa_t.
+ *
+ * @param me own address
+ * @param other remote address
+ * @return child_sa_t object
+ *
+ * @ingroup sa
+ */
+child_sa_t * child_sa_create(host_t *me, host_t *other);
+
+#endif /*CHILD_SA_H_*/
diff --git a/programs/charon/charon/sa/ike_sa.c b/programs/charon/charon/sa/ike_sa.c
new file mode 100644
index 000000000..6322eb8e9
--- /dev/null
+++ b/programs/charon/charon/sa/ike_sa.c
@@ -0,0 +1,1199 @@
+/**
+ * @file ike_sa.c
+ *
+ * @brief Implementation of ike_sa_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+#include <string.h>
+
+#include "ike_sa.h"
+
+#include <types.h>
+#include <daemon.h>
+#include <definitions.h>
+#include <utils/linked_list.h>
+#include <utils/logger_manager.h>
+#include <utils/randomizer.h>
+#include <crypto/diffie_hellman.h>
+#include <crypto/prf_plus.h>
+#include <crypto/crypters/crypter.h>
+#include <encoding/payloads/sa_payload.h>
+#include <encoding/payloads/nonce_payload.h>
+#include <encoding/payloads/ke_payload.h>
+#include <encoding/payloads/delete_payload.h>
+#include <encoding/payloads/transform_substructure.h>
+#include <encoding/payloads/transform_attribute.h>
+#include <sa/states/initiator_init.h>
+#include <sa/states/responder_init.h>
+#include <queues/jobs/retransmit_request_job.h>
+#include <queues/jobs/delete_established_ike_sa_job.h>
+
+
+
+
+typedef struct private_ike_sa_t private_ike_sa_t;
+
+/**
+ * Private data of an ike_sa_t object.
+ */
+struct private_ike_sa_t {
+
+ /**
+ * Protected part of a ike_sa_t object.
+ */
+ protected_ike_sa_t protected;
+
+ /**
+ * Identifier for the current IKE_SA.
+ */
+ ike_sa_id_t *ike_sa_id;
+
+ /**
+ * Linked List containing the child sa's of the current IKE_SA.
+ */
+ linked_list_t *child_sas;
+
+ /**
+ * Current state of the IKE_SA represented as state_t object.
+ *
+ * A state object representates one of the following states and is processing
+ * messages in the specific state:
+ * - INITIATOR_INIT
+ * - RESPONDER_INIT
+ * - IKE_SA_INIT_REQUESTED
+ * - IKE_SA_INIT_RESPONDED
+ * - IKE_AUTH_REQUESTED
+ * -IKE_SA_ESTABLISHED
+ */
+ state_t *current_state;
+
+ /**
+ * INIT configuration, needed for the IKE_SA_INIT exchange.
+ *
+ * Gets set in states:
+ * - INITATOR_INIT
+ * - RESPONDER_INIT
+ *
+ * Available in states:
+ * - IKE_SA_INIT_REQUESTED
+ * - IKE_SA_INIT_RESPONDED
+ * - IKE_AUTH_REQUESTED
+ * -IKE_SA_ESTABLISHED
+ */
+ connection_t *connection;
+
+ /**
+ * SA configuration, needed for all other exchanges after IKE_SA_INIT exchange.
+ *
+ * Gets set in states:
+ * - IKE_SA_INIT_REQUESTED
+ * - IKE_SA_INIT_RESPONDED
+ *
+ * Available in states:
+ * - IKE_AUTH_REQUESTED
+ * -IKE_SA_ESTABLISHED
+ */
+ policy_t *policy;
+
+ /**
+ * This SA's source for random data.
+ *
+ * Is available in every state.
+ */
+ randomizer_t *randomizer;
+
+ /**
+ * The last responded message.
+ */
+ message_t *last_responded_message;
+
+ /**
+ * The ast requested message.
+ */
+ message_t *last_requested_message;
+
+ /**
+ * Crypter object for initiator.
+ */
+ crypter_t *crypter_initiator;
+
+ /**
+ * Crypter object for responder.
+ */
+ crypter_t *crypter_responder;
+
+ /**
+ * Signer object for initiator.
+ */
+ signer_t *signer_initiator;
+
+ /**
+ * Signer object for responder.
+ */
+ signer_t *signer_responder;
+
+ /**
+ * Multi purpose prf, set key, use it, forget it
+ */
+ prf_t *prf;
+
+ /**
+ * Prf function for derivating keymat child SAs
+ */
+ prf_t *child_prf;
+
+ /**
+ * PRF, with key set to pi_key, used for authentication
+ */
+ prf_t *prf_auth_i;
+
+ /**
+ * PRF, with key set to pr_key, used for authentication
+ */
+ prf_t *prf_auth_r;
+
+ /**
+ * Next message id to receive.
+ */
+ u_int32_t message_id_in;
+
+ /**
+ * Next message id to send.
+ */
+ u_int32_t message_id_out;
+
+ /**
+ * Last reply id which was successfully received.
+ */
+ int32_t last_replied_message_id;
+
+ /**
+ * A logger for this IKE_SA.
+ */
+ logger_t *logger;
+
+ /**
+ * Resends the last sent reply.
+ *
+ * @param this calling object
+ */
+ status_t (*resend_last_reply) (private_ike_sa_t *this);
+};
+
+/**
+ * Implementation of ike_sa_t.process_message.
+ */
+static status_t process_message (private_ike_sa_t *this, message_t *message)
+{
+ u_int32_t message_id;
+ exchange_type_t exchange_type;
+ bool is_request;
+
+ /* We must process each request or response from remote host */
+
+ /* Find out type of message (request or response) */
+ is_request = message->get_request(message);
+ exchange_type = message->get_exchange_type(message);
+
+ this->logger->log(this->logger, CONTROL|LEVEL1, "Process %s of exchange type %s",
+ (is_request) ? "request" : "response",mapping_find(exchange_type_m,exchange_type));
+
+ message_id = message->get_message_id(message);
+
+ /*
+ * It has to be checked, if the message has to be resent cause of lost packets!
+ */
+ if (is_request && (message_id == (this->message_id_in - 1)))
+ {
+ /* Message can be resent ! */
+ this->logger->log(this->logger, CONTROL|LEVEL1, "Resent request detected. Send stored reply.");
+ return (this->resend_last_reply(this));
+ }
+
+ /* Now, the message id is checked for request AND reply */
+ if (is_request)
+ {
+ /* In a request, the message has to be this->message_id_in (other case is already handled) */
+ if (message_id != this->message_id_in)
+ {
+ this->logger->log(this->logger, ERROR | LEVEL1,
+ "Message request with message id %d received, but %d expected",
+ message_id,this->message_id_in);
+ return FAILED;
+ }
+ }
+ else
+ {
+ /* In a reply, the message has to be this->message_id_out -1 cause it is the reply to the last sent message*/
+ if (message_id != (this->message_id_out - 1))
+ {
+ this->logger->log(this->logger, ERROR | LEVEL1,
+ "Message reply with message id %d received, but %d expected",
+ message_id,this->message_id_in);
+ return FAILED;
+ }
+ }
+
+ /* now the message is processed by the current state object.
+ * The specific state object is responsible to check if a message can be received in
+ * the state it represents.
+ * The current state is also responsible to change the state object to the next state
+ * by calling protected_ike_sa_t.set_new_state*/
+ return this->current_state->process_message(this->current_state,message);
+}
+
+/**
+ * Implementation of protected_ike_sa_t.build_message.
+ */
+static void build_message(private_ike_sa_t *this, exchange_type_t type, bool request, message_t **message)
+{
+ message_t *new_message;
+ host_t *me, *other;
+
+ me = this->connection->get_my_host(this->connection);
+ other = this->connection->get_other_host(this->connection);
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Build empty message");
+ new_message = message_create();
+ new_message->set_source(new_message, me->clone(me));
+ new_message->set_destination(new_message, other->clone(other));
+ new_message->set_exchange_type(new_message, type);
+ new_message->set_request(new_message, request);
+ new_message->set_message_id(new_message, (request) ? this->message_id_out : this->message_id_in);
+ new_message->set_ike_sa_id(new_message, this->ike_sa_id);
+
+ *message = new_message;
+}
+
+/**
+ * Implementation of protected_ike_sa_t.initiate_connection.
+ */
+static status_t initiate_connection(private_ike_sa_t *this, connection_t *connection)
+{
+ initiator_init_t *current_state;
+
+ /* Work is done in state object of type INITIATOR_INIT. All other states are not
+ * initial states and so don't have a initiate_connection function */
+
+ if (this->current_state->get_state(this->current_state) != INITIATOR_INIT)
+ {
+ return FAILED;
+ }
+
+ current_state = (initiator_init_t *) this->current_state;
+
+ return current_state->initiate_connection(current_state, connection);
+}
+
+/**
+ * Implementation of ike_sa_t.send_delete_ike_sa_request.
+ */
+static void send_delete_ike_sa_request (private_ike_sa_t *this)
+{
+ message_t *informational_request;
+ delete_payload_t *delete_payload;
+ crypter_t *crypter;
+ signer_t *signer;
+ packet_t *packet;
+ status_t status;
+
+ if (this->current_state->get_state(this->current_state) != IKE_SA_ESTABLISHED)
+ {
+ return;
+ }
+
+ /* build empty INFORMATIONAL message */
+ this->protected.build_message(&(this->protected), INFORMATIONAL, TRUE, &informational_request);
+
+ delete_payload = delete_payload_create();
+ delete_payload->set_protocol_id(delete_payload, PROTO_IKE);
+
+ informational_request->add_payload(informational_request,(payload_t *)delete_payload);
+
+ if (this->ike_sa_id->is_initiator(this->ike_sa_id))
+ {
+ crypter = this->crypter_initiator;
+ signer = this->signer_initiator;
+ }
+ else
+ {
+ crypter = this->crypter_responder;
+ signer = this->signer_responder;
+ }
+
+ status = informational_request->generate(informational_request,
+ crypter,
+ signer, &packet);
+ informational_request->destroy(informational_request);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, ERROR, "Could not generate packet from message");
+ return ;
+ }
+
+ charon->send_queue->add(charon->send_queue,packet);
+}
+
+/**
+ * Implementation of ike_sa_t.get_id.
+ */
+static ike_sa_id_t* get_id(private_ike_sa_t *this)
+{
+ return this->ike_sa_id;
+}
+
+/**
+ * Implementation of ike_sa_t.get_my_host.
+ */
+static host_t* get_my_host(private_ike_sa_t *this)
+{
+ return this->connection->get_my_host(this->connection);;
+}
+
+/**
+ * Implementation of ike_sa_t.get_other_host.
+ */
+static host_t* get_other_host(private_ike_sa_t *this)
+{
+ return this->connection->get_other_host(this->connection);;
+}
+
+/**
+ * Implementation of ike_sa_t.get_my_id.
+ */
+static identification_t* get_my_id(private_ike_sa_t *this)
+{
+ return this->connection->get_my_id(this->connection);;
+}
+
+/**
+ * Implementation of ike_sa_t.get_other_id.
+ */
+static identification_t* get_other_id(private_ike_sa_t *this)
+{
+ return this->connection->get_other_id(this->connection);;
+}
+
+/**
+ * Implementation of private_ike_sa_t.resend_last_reply.
+ */
+static status_t resend_last_reply(private_ike_sa_t *this)
+{
+ packet_t *packet;
+
+ this->logger->log(this->logger, CONTROL | LEVEL1, "Going to retransmit last reply");
+ packet = this->last_responded_message->get_packet(this->last_responded_message);
+ charon->send_queue->add(charon->send_queue, packet);
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of ike_sa_t.retransmit_request.
+ */
+status_t retransmit_request (private_ike_sa_t *this, u_int32_t message_id)
+{
+ packet_t *packet;
+
+ if (this->last_requested_message == NULL)
+ {
+ return NOT_FOUND;
+ }
+
+ if (message_id == this->last_replied_message_id)
+ {
+ return NOT_FOUND;
+ }
+
+ if ((this->last_requested_message->get_message_id(this->last_requested_message)) != message_id)
+ {
+ return NOT_FOUND;
+ }
+
+ this->logger->log(this->logger, CONTROL | LEVEL1, "Going to retransmit message with id %d",message_id);
+ packet = this->last_requested_message->get_packet(this->last_requested_message);
+ charon->send_queue->add(charon->send_queue, packet);
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of protected_ike_sa_t.set_new_state.
+ */
+static void set_new_state (private_ike_sa_t *this, state_t *state)
+{
+ this->logger->log(this->logger, CONTROL, "statechange: %s => %s",
+ mapping_find(ike_sa_state_m,this->current_state->get_state(this->current_state)),
+ mapping_find(ike_sa_state_m,state->get_state(state)));
+ this->current_state = state;
+}
+
+/**
+ * Implementation of protected_ike_sa_t.get_connection.
+ */
+static connection_t *get_connection (private_ike_sa_t *this)
+{
+ return this->connection;
+}
+
+/**
+ * Implementation of protected_ike_sa_t.set_connection.
+ */
+static void set_connection (private_ike_sa_t *this,connection_t * connection)
+{
+ this->connection = connection;
+}
+
+/**
+ * Implementation of protected_ike_sa_t.get_policy.
+ */
+static policy_t *get_policy (private_ike_sa_t *this)
+{
+ return this->policy;
+}
+
+/**
+ * Implementation of protected_ike_sa_t.set_policy.
+ */
+static void set_policy (private_ike_sa_t *this,policy_t * policy)
+{
+ this->policy = policy;
+}
+
+/**
+ * Implementation of protected_ike_sa_t.get_prf.
+ */
+static prf_t *get_prf (private_ike_sa_t *this)
+{
+ return this->prf;
+}
+
+/**
+ * Implementation of protected_ike_sa_t.get_prf.
+ */
+static prf_t *get_child_prf (private_ike_sa_t *this)
+{
+ return this->child_prf;
+}
+
+/**
+ * Implementation of protected_ike_sa_t.get_prf_auth_i.
+ */
+static prf_t *get_prf_auth_i (private_ike_sa_t *this)
+{
+ return this->prf_auth_i;
+}
+
+/**
+ * Implementation of protected_ike_sa_t.get_prf_auth_r.
+ */
+static prf_t *get_prf_auth_r (private_ike_sa_t *this)
+{
+ return this->prf_auth_r;
+}
+
+
+/**
+ * Implementation of protected_ike_sa_t.build_transforms.
+ */
+static status_t build_transforms(private_ike_sa_t *this, proposal_t *proposal, diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r)
+{
+ chunk_t nonces, nonces_spis, skeyseed, key, secret;
+ u_int64_t spi_i, spi_r;
+ prf_plus_t *prf_plus;
+ algorithm_t *algo;
+ size_t key_size;
+
+ /*
+ * Build the PRF+ instance for deriving keys
+ */
+ if (this->prf != NULL)
+ {
+ this->prf->destroy(this->prf);
+ }
+ proposal->get_algorithm(proposal, PROTO_IKE, PSEUDO_RANDOM_FUNCTION, &algo);
+ if (algo == NULL)
+ {
+ this->logger->log(this->logger, ERROR|LEVEL2, "No PRF algoithm selected!?");
+ return FAILED;
+ }
+ this->prf = prf_create(algo->algorithm);
+ if (this->prf == NULL)
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1,
+ "PSEUDO_RANDOM_FUNCTION %s not supported!",
+ mapping_find(pseudo_random_function_m, algo->algorithm));
+ return FAILED;
+ }
+
+ /* concatenate nonces = nonce_i | nonce_r */
+ nonces = chunk_alloc(nonce_i.len + nonce_r.len);
+ memcpy(nonces.ptr, nonce_i.ptr, nonce_i.len);
+ memcpy(nonces.ptr + nonce_i.len, nonce_r.ptr, nonce_r.len);
+
+ /* concatenate prf_seed = nonce_i | nonce_r | spi_i | spi_r */
+ nonces_spis = chunk_alloc(nonces.len + 16);
+ memcpy(nonces_spis.ptr, nonces.ptr, nonces.len);
+ spi_i = this->ike_sa_id->get_initiator_spi(this->ike_sa_id);
+ spi_r = this->ike_sa_id->get_responder_spi(this->ike_sa_id);
+ memcpy(nonces_spis.ptr + nonces.len, &spi_i, 8);
+ memcpy(nonces_spis.ptr + nonces.len + 8, &spi_r, 8);
+
+ /* SKEYSEED = prf(Ni | Nr, g^ir) */
+ dh->get_shared_secret(dh, &secret);
+ this->logger->log_chunk(this->logger, PRIVATE, "Shared Diffie Hellman secret", secret);
+ this->prf->set_key(this->prf, nonces);
+ this->prf->allocate_bytes(this->prf, secret, &skeyseed);
+ this->logger->log_chunk(this->logger, PRIVATE | LEVEL1, "SKEYSEED", skeyseed);
+ chunk_free(&secret);
+
+ /* prf+ (SKEYSEED, Ni | Nr | SPIi | SPIr )
+ * = SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr
+ *
+ * we use the prf directly for prf+
+ */
+ this->prf->set_key(this->prf, skeyseed);
+ prf_plus = prf_plus_create(this->prf, nonces_spis);
+
+ /* clean up unused stuff */
+ chunk_free(&nonces);
+ chunk_free(&nonces_spis);
+ chunk_free(&skeyseed);
+
+
+ /*
+ * We now can derive all of our key. We build the transforms
+ * directly.
+ */
+
+
+ /* SK_d used for prf+ to derive keys for child SAs */
+ this->child_prf = prf_create(algo->algorithm);
+ key_size = this->child_prf->get_key_size(this->child_prf);
+ prf_plus->allocate_bytes(prf_plus, key_size, &key);
+ this->logger->log_chunk(this->logger, PRIVATE, "Sk_d secret", key);
+ this->child_prf->set_key(this->child_prf, key);
+ chunk_free(&key);
+
+
+ /* SK_ai/SK_ar used for integrity protection */
+ proposal->get_algorithm(proposal, PROTO_IKE, INTEGRITY_ALGORITHM, &algo);
+ if (algo == NULL)
+ {
+ this->logger->log(this->logger, ERROR|LEVEL2, "No integrity algoithm selected?!");
+ return FAILED;
+ }
+ if (this->signer_initiator != NULL)
+ {
+ this->signer_initiator->destroy(this->signer_initiator);
+ }
+ if (this->signer_responder != NULL)
+ {
+ this->signer_responder->destroy(this->signer_responder);
+ }
+
+ this->signer_initiator = signer_create(algo->algorithm);
+ this->signer_responder = signer_create(algo->algorithm);
+ if (this->signer_initiator == NULL || this->signer_responder == NULL)
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1,
+ "INTEGRITY_ALGORITHM %s not supported!",
+ mapping_find(integrity_algorithm_m,algo->algorithm));
+ return FAILED;
+ }
+ key_size = this->signer_initiator->get_key_size(this->signer_initiator);
+
+ prf_plus->allocate_bytes(prf_plus, key_size, &key);
+ this->logger->log_chunk(this->logger, PRIVATE, "Sk_ai secret", key);
+ this->signer_initiator->set_key(this->signer_initiator, key);
+ chunk_free(&key);
+
+ prf_plus->allocate_bytes(prf_plus, key_size, &key);
+ this->logger->log_chunk(this->logger, PRIVATE, "Sk_ar secret", key);
+ this->signer_responder->set_key(this->signer_responder, key);
+ chunk_free(&key);
+
+
+ /* SK_ei/SK_er used for encryption */
+ proposal->get_algorithm(proposal, PROTO_IKE, ENCRYPTION_ALGORITHM, &algo);
+ if (algo == NULL)
+ {
+ this->logger->log(this->logger, ERROR|LEVEL2, "No encryption algoithm selected!?");
+ return FAILED;
+ }
+ if (this->crypter_initiator != NULL)
+ {
+ this->crypter_initiator->destroy(this->crypter_initiator);
+ }
+ if (this->crypter_responder != NULL)
+ {
+ this->crypter_responder->destroy(this->crypter_responder);
+ }
+
+ this->crypter_initiator = crypter_create(algo->algorithm, algo->key_size);
+ this->crypter_responder = crypter_create(algo->algorithm, algo->key_size);
+ if (this->crypter_initiator == NULL || this->crypter_responder == NULL)
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1,
+ "ENCRYPTION_ALGORITHM %s (key size %d) not supported!",
+ mapping_find(encryption_algorithm_m, algo->algorithm),
+ algo->key_size);
+ return FAILED;
+ }
+ key_size = this->crypter_initiator->get_key_size(this->crypter_initiator);
+
+ prf_plus->allocate_bytes(prf_plus, key_size, &key);
+ this->logger->log_chunk(this->logger, PRIVATE, "Sk_ei secret", key);
+ this->crypter_initiator->set_key(this->crypter_initiator, key);
+ chunk_free(&key);
+
+ prf_plus->allocate_bytes(prf_plus, key_size, &key);
+ this->logger->log_chunk(this->logger, PRIVATE, "Sk_er secret", key);
+ this->crypter_responder->set_key(this->crypter_responder, key);
+ chunk_free(&key);
+
+ /* SK_pi/SK_pr used for authentication */
+ proposal->get_algorithm(proposal, PROTO_IKE, PSEUDO_RANDOM_FUNCTION, &algo);
+ if (this->prf_auth_i != NULL)
+ {
+ this->prf_auth_i->destroy(this->prf_auth_i);
+ }
+ if (this->prf_auth_r != NULL)
+ {
+ this->prf_auth_r->destroy(this->prf_auth_r);
+ }
+
+ this->prf_auth_i = prf_create(algo->algorithm);
+ this->prf_auth_r = prf_create(algo->algorithm);
+
+ key_size = this->prf_auth_i->get_key_size(this->prf_auth_i);
+ prf_plus->allocate_bytes(prf_plus, key_size, &key);
+ this->logger->log_chunk(this->logger, PRIVATE, "Sk_pi secret", key);
+ this->prf_auth_i->set_key(this->prf_auth_i, key);
+ chunk_free(&key);
+
+ prf_plus->allocate_bytes(prf_plus, key_size, &key);
+ this->logger->log_chunk(this->logger, PRIVATE, "Sk_pr secret", key);
+ this->prf_auth_r->set_key(this->prf_auth_r, key);
+ chunk_free(&key);
+
+ /* all done, prf_plus not needed anymore */
+ prf_plus->destroy(prf_plus);
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of protected_ike_sa_t.get_randomizer.
+ */
+static randomizer_t *get_randomizer (private_ike_sa_t *this)
+{
+ return this->randomizer;
+}
+
+/**
+ * Implementation of protected_ike_sa_t.get_crypter_initiator.
+ */
+static crypter_t *get_crypter_initiator (private_ike_sa_t *this)
+{
+ return this->crypter_initiator;
+}
+
+/**
+ * Implementation of protected_ike_sa_t.get_signer_initiator.
+ */
+static signer_t *get_signer_initiator (private_ike_sa_t *this)
+{
+ return this->signer_initiator;
+}
+
+/**
+ * Implementation of protected_ike_sa_t.get_crypter_responder.
+ */
+static crypter_t *get_crypter_responder(private_ike_sa_t *this)
+{
+ return this->crypter_responder;
+}
+
+/**
+ * Implementation of protected_ike_sa_t.get_signer_responder.
+ */
+static signer_t *get_signer_responder (private_ike_sa_t *this)
+{
+ return this->signer_responder;
+}
+
+/**
+ * Implementation of protected_ike_sa_t.send_request.
+ */
+static status_t send_request (private_ike_sa_t *this,message_t * message)
+{
+ retransmit_request_job_t *retransmit_job;
+ u_int32_t timeout;
+ crypter_t *crypter;
+ signer_t *signer;
+ packet_t *packet;
+ status_t status;
+
+ if (message->get_message_id(message) != this->message_id_out)
+ {
+ this->logger->log(this->logger, ERROR, "Message could not be sent cause id (%d) was not as expected (%d)",
+ message->get_message_id(message),this->message_id_out);
+ return FAILED;
+ }
+
+ /* generate packet */
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Generate packet from message");
+
+ if (this->ike_sa_id->is_initiator(this->ike_sa_id))
+ {
+ crypter = this->crypter_initiator;
+ signer = this->signer_initiator;
+ }
+ else
+ {
+ crypter = this->crypter_responder;
+ signer =this->signer_responder;
+ }
+
+ status = message->generate(message, crypter,signer, &packet);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, ERROR, "Could not generate packet from message");
+ return FAILED;
+ }
+
+ this->logger->log(this->logger, CONTROL|LEVEL3,
+ "Add request packet with message id %d to global send queue",
+ this->message_id_out);
+ charon->send_queue->add(charon->send_queue, packet);
+
+ if (this->last_requested_message != NULL)
+ {
+ /* destroy message */
+ this->last_requested_message->destroy(this->last_requested_message);
+ }
+
+ this->logger->log(this->logger, CONTROL|LEVEL3, "Replace last requested message with new one");
+ this->last_requested_message = message;
+
+ retransmit_job = retransmit_request_job_create(this->message_id_out,this->ike_sa_id);
+
+ status = charon->configuration->get_retransmit_timeout (charon->configuration,
+ retransmit_job->get_retransmit_count(retransmit_job),&timeout);
+
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, CONTROL|LEVEL2, "No retransmit job for message created!");
+ retransmit_job->destroy(retransmit_job);
+ }
+ else
+ {
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Request will be retransmitted in %d ms.",timeout);
+ charon->event_queue->add_relative(charon->event_queue,(job_t *) retransmit_job,timeout);
+ }
+
+ /* message counter can now be increased */
+ this->logger->log(this->logger, CONTROL|LEVEL3,
+ "Increase message counter for outgoing messages from %d",
+ this->message_id_out);
+ this->message_id_out++;
+ return SUCCESS;
+}
+
+/**
+ * Implementation of protected_ike_sa_t.send_response.
+ */
+static status_t send_response (private_ike_sa_t *this,message_t * message)
+{
+ crypter_t *crypter;
+ signer_t *signer;
+ packet_t *packet;
+ status_t status;
+
+ if (message->get_message_id(message) != this->message_id_in)
+ {
+ this->logger->log(this->logger, ERROR, "Message could not be sent cause id was not as expected");
+ return FAILED;
+ }
+
+
+ if (this->ike_sa_id->is_initiator(this->ike_sa_id))
+ {
+ crypter = this->crypter_initiator;
+ signer = this->signer_initiator;
+ }
+ else
+ {
+ crypter = this->crypter_responder;
+ signer =this->signer_responder;
+ }
+
+ status = message->generate(message, crypter,signer, &packet);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, ERROR, "Could not generate packet from message");
+ return FAILED;
+ }
+
+ this->logger->log(this->logger, CONTROL|LEVEL3,
+ "Add response packet with message id %d to global send queue",
+ this->message_id_in);
+ charon->send_queue->add(charon->send_queue, packet);
+
+ if (this->last_responded_message != NULL)
+ {
+ /* destroy message */
+ this->last_responded_message->destroy(this->last_responded_message);
+ }
+
+ this->logger->log(this->logger, CONTROL|LEVEL3, "Replace last responded message with new one");
+ this->last_responded_message = message;
+
+ /* message counter can now be increased */
+ this->logger->log(this->logger, CONTROL|LEVEL3, "Increase message counter for incoming messages");
+ this->message_id_in++;
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of of private_responder_init_t.send_notify_reply.
+ */
+static void send_notify(private_ike_sa_t *this, exchange_type_t exchange_type, notify_message_type_t type, chunk_t data)
+{
+ notify_payload_t *payload;
+ message_t *response;
+ packet_t *packet;
+ status_t status;
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Going to build message with notify payload");
+ /* set up the reply */
+ this->protected.build_message(&(this->protected), exchange_type, FALSE, &response);
+ payload = notify_payload_create_from_protocol_and_type(PROTO_IKE, type);
+ if ((data.ptr != NULL) && (data.len > 0))
+ {
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Add Data to notify payload");
+ payload->set_notification_data(payload,data);
+ }
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Add Notify payload to message");
+ response->add_payload(response,(payload_t *) payload);
+
+ /* generate packet */
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Generate packet from message");
+ status = response->generate(response, this->crypter_responder, this->signer_responder, &packet);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1, "Could not generate notify message");
+ response->destroy(response);
+ return;
+ }
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Add packet to global send queue");
+ charon->send_queue->add(charon->send_queue, packet);
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Destroy message");
+ response->destroy(response);
+}
+
+/**
+ * Implementation of protected_ike_sa_t.set_last_replied_message_id.
+ */
+static void set_last_replied_message_id (private_ike_sa_t *this,u_int32_t message_id)
+{
+ this->last_replied_message_id = message_id;
+}
+
+/**
+ * Implementation of protected_ike_sa_t.get_last_responded_message.
+ */
+static message_t * get_last_responded_message (private_ike_sa_t *this)
+{
+ return this->last_responded_message;
+}
+
+/**
+ * Implementation of protected_ike_sa_t.get_last_requested_message.
+ */
+static message_t * get_last_requested_message (private_ike_sa_t *this)
+{
+ return this->last_requested_message;
+}
+
+/**
+ * Implementation of protected_ike_sa_t.get_state.
+ */
+static ike_sa_state_t get_state (private_ike_sa_t *this)
+{
+ return this->current_state->get_state(this->current_state);
+}
+
+/**
+ * Implementation of protected_ike_sa_t.get_state.
+ */
+static void add_child_sa (private_ike_sa_t *this, child_sa_t *child_sa)
+{
+ this->child_sas->insert_last(this->child_sas, child_sa);
+}
+
+/**
+ * Implementation of protected_ike_sa_t.reset_message_buffers.
+ */
+static void reset_message_buffers (private_ike_sa_t *this)
+{
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Reset message counters and destroy stored messages");
+ /* destroy stored requested message */
+ if (this->last_requested_message != NULL)
+ {
+ this->last_requested_message->destroy(this->last_requested_message);
+ this->last_requested_message = NULL;
+ }
+
+ /* destroy stored responded messages */
+ if (this->last_responded_message != NULL)
+ {
+ this->last_responded_message->destroy(this->last_responded_message);
+ this->last_responded_message = NULL;
+ }
+
+ this->message_id_out = 0;
+ this->message_id_in = 0;
+ this->last_replied_message_id = -1;
+}
+
+/**
+ * Implementation of protected_ike_sa_t.log_status.
+ */
+static void log_status(private_ike_sa_t *this, logger_t *logger, char *name)
+{
+ iterator_t *iterator;
+ child_sa_t *child_sa;
+
+ /* only log if name == NULL or name == connection_name */
+ if (name)
+ {
+ if (strcmp(this->connection->get_name(this->connection), name) != 0)
+ {
+ return;
+ }
+ }
+ else
+ {
+ name = this->connection->get_name(this->connection);
+ }
+
+ host_t *my_host = this->connection->get_my_host(this->connection);
+ host_t *other_host = this->connection->get_other_host(this->connection);
+
+ identification_t *my_id = this->connection->get_my_id(this->connection);
+ identification_t *other_id = this->connection->get_other_id(this->connection);
+
+ if (logger == NULL)
+ {
+ logger = this->logger;
+ }
+ logger->log(logger, CONTROL|LEVEL1, "\"%s\": IKE_SA in state %s, SPIs: 0x%.16llx 0x%.16llx",
+ name,
+ mapping_find(ike_sa_state_m, this->current_state->get_state(this->current_state)),
+ this->ike_sa_id->get_initiator_spi(this->ike_sa_id),
+ this->ike_sa_id->get_responder_spi(this->ike_sa_id));
+ logger->log(logger, CONTROL, "\"%s\": %s[%s]...%s[%s]",
+ name,
+ my_host->get_address(my_host),
+ my_id->get_string(my_id),
+ other_host->get_address(other_host),
+ other_id->get_string(other_id));
+
+ iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
+ while (iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void**)&child_sa);
+ child_sa->log_status(child_sa, logger, name);
+ }
+ iterator->destroy(iterator);
+}
+
+/**
+ * Implementation of protected_ike_sa_t.destroy.
+ */
+static void destroy (private_ike_sa_t *this)
+{
+ child_sa_t *child_sa;
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Going to destroy IKE SA %llu:%llu, role %s",
+ this->ike_sa_id->get_initiator_spi(this->ike_sa_id),
+ this->ike_sa_id->get_responder_spi(this->ike_sa_id),
+ this->ike_sa_id->is_initiator(this->ike_sa_id) ? "initiator" : "responder");
+
+ /* inform other peer of delete */
+ send_delete_ike_sa_request(this);
+ while (this->child_sas->remove_last(this->child_sas, (void**)&child_sa) == SUCCESS)
+ {
+ child_sa->destroy(child_sa);
+ }
+ this->child_sas->destroy(this->child_sas);
+
+ if (this->crypter_initiator)
+ {
+ this->crypter_initiator->destroy(this->crypter_initiator);
+ }
+ if (this->crypter_responder)
+ {
+ this->crypter_responder->destroy(this->crypter_responder);
+ }
+ if (this->signer_initiator)
+ {
+ this->signer_initiator->destroy(this->signer_initiator);
+ }
+ if (this->signer_responder)
+ {
+ this->signer_responder->destroy(this->signer_responder);
+ }
+ if (this->prf)
+ {
+ this->prf->destroy(this->prf);
+ }
+ if (this->child_prf)
+ {
+ this->child_prf->destroy(this->child_prf);
+ }
+ if (this->prf_auth_i)
+ {
+ this->prf_auth_i->destroy(this->prf_auth_i);
+ }
+ if (this->prf_auth_r)
+ {
+ this->prf_auth_r->destroy(this->prf_auth_r);
+ }
+ if (this->connection)
+ {
+ host_t *me, *other;
+ me = this->connection->get_my_host(this->connection);
+ other = this->connection->get_other_host(this->connection);
+
+ this->logger->log(this->logger, AUDIT, "IKE_SA deleted between %s - %s",
+ me->get_address(me), other->get_address(other));
+ this->connection->destroy(this->connection);
+ }
+ if (this->policy)
+ {
+ this->policy->destroy(this->policy);
+ }
+ if (this->last_requested_message)
+ {
+ this->last_requested_message->destroy(this->last_requested_message);
+ }
+ if (this->last_responded_message)
+ {
+ this->last_responded_message->destroy(this->last_responded_message);
+ }
+ this->ike_sa_id->destroy(this->ike_sa_id);
+ this->randomizer->destroy(this->randomizer);
+ this->current_state->destroy(this->current_state);
+
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
+{
+ private_ike_sa_t *this = malloc_thing(private_ike_sa_t);
+
+ /* Public functions */
+ this->protected.public.process_message = (status_t(*)(ike_sa_t*, message_t*)) process_message;
+ this->protected.public.initiate_connection = (status_t(*)(ike_sa_t*,connection_t*)) initiate_connection;
+ this->protected.public.get_id = (ike_sa_id_t*(*)(ike_sa_t*)) get_id;
+ this->protected.public.get_my_host = (host_t*(*)(ike_sa_t*)) get_my_host;
+ this->protected.public.get_other_host = (host_t*(*)(ike_sa_t*)) get_other_host;
+ this->protected.public.get_my_id = (identification_t*(*)(ike_sa_t*)) get_my_id;
+ this->protected.public.get_other_id = (identification_t*(*)(ike_sa_t*)) get_other_id;
+ this->protected.public.get_connection = (connection_t*(*)(ike_sa_t*)) get_connection;
+ this->protected.public.retransmit_request = (status_t (*) (ike_sa_t *, u_int32_t)) retransmit_request;
+ this->protected.public.get_state = (ike_sa_state_t (*) (ike_sa_t *this)) get_state;
+ this->protected.public.send_delete_ike_sa_request = (void (*)(ike_sa_t*)) send_delete_ike_sa_request;
+ this->protected.public.log_status = (void (*) (ike_sa_t*,logger_t*,char*))log_status;
+ this->protected.public.destroy = (void(*)(ike_sa_t*))destroy;
+
+ /* protected functions */
+ this->protected.build_message = (void (*) (protected_ike_sa_t *, exchange_type_t , bool , message_t **)) build_message;
+ this->protected.get_prf = (prf_t *(*) (protected_ike_sa_t *)) get_prf;
+ this->protected.get_child_prf = (prf_t *(*) (protected_ike_sa_t *)) get_child_prf;
+ this->protected.get_prf_auth_i = (prf_t *(*) (protected_ike_sa_t *)) get_prf_auth_i;
+ this->protected.get_prf_auth_r = (prf_t *(*) (protected_ike_sa_t *)) get_prf_auth_r;
+ this->protected.add_child_sa = (void (*) (protected_ike_sa_t*,child_sa_t*)) add_child_sa;
+ this->protected.set_connection = (void (*) (protected_ike_sa_t *,connection_t *)) set_connection;
+ this->protected.get_connection = (connection_t *(*) (protected_ike_sa_t *)) get_connection;
+ this->protected.set_policy = (void (*) (protected_ike_sa_t *,policy_t *)) set_policy;
+ this->protected.get_policy = (policy_t *(*) (protected_ike_sa_t *)) get_policy;
+ this->protected.get_randomizer = (randomizer_t *(*) (protected_ike_sa_t *)) get_randomizer;
+ this->protected.send_request = (status_t (*) (protected_ike_sa_t *,message_t *)) send_request;
+ this->protected.send_response = (status_t (*) (protected_ike_sa_t *,message_t *)) send_response;
+ this->protected.send_notify = (void (*)(protected_ike_sa_t*,exchange_type_t,notify_message_type_t,chunk_t)) send_notify;
+ this->protected.build_transforms = (status_t (*) (protected_ike_sa_t *,proposal_t*,diffie_hellman_t*,chunk_t,chunk_t)) build_transforms;
+ this->protected.set_new_state = (void (*) (protected_ike_sa_t *,state_t *)) set_new_state;
+ this->protected.get_crypter_initiator = (crypter_t *(*) (protected_ike_sa_t *)) get_crypter_initiator;
+ this->protected.get_signer_initiator = (signer_t *(*) (protected_ike_sa_t *)) get_signer_initiator;
+ this->protected.get_crypter_responder = (crypter_t *(*) (protected_ike_sa_t *)) get_crypter_responder;
+ this->protected.get_signer_responder = (signer_t *(*) (protected_ike_sa_t *)) get_signer_responder;
+ this->protected.reset_message_buffers = (void (*) (protected_ike_sa_t *)) reset_message_buffers;
+ this->protected.get_last_responded_message = (message_t * (*) (protected_ike_sa_t *this)) get_last_responded_message;
+ this->protected.get_last_requested_message = (message_t * (*) (protected_ike_sa_t *this)) get_last_requested_message;
+
+ this->protected.set_last_replied_message_id = (void (*) (protected_ike_sa_t *,u_int32_t)) set_last_replied_message_id;
+
+ /* private functions */
+ this->resend_last_reply = resend_last_reply;
+
+ /* initialize private fields */
+ this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
+
+ this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
+ this->child_sas = linked_list_create();
+ this->randomizer = randomizer_create();
+
+ this->last_requested_message = NULL;
+ this->last_responded_message = NULL;
+ this->message_id_out = 0;
+ this->message_id_in = 0;
+ this->last_replied_message_id = -1;
+ this->crypter_initiator = NULL;
+ this->crypter_responder = NULL;
+ this->signer_initiator = NULL;
+ this->signer_responder = NULL;
+ this->prf = NULL;
+ this->prf_auth_i = NULL;
+ this->prf_auth_r = NULL;
+ this->child_prf = NULL;
+ this->connection = NULL;
+ this->policy = NULL;
+
+ /* at creation time, IKE_SA is in a initiator state */
+ if (ike_sa_id->is_initiator(ike_sa_id))
+ {
+ this->logger->log(this->logger, CONTROL | LEVEL2, "Create first state_t object of type INITIATOR_INIT");
+ this->current_state = (state_t *) initiator_init_create(&(this->protected));
+ }
+ else
+ {
+ this->logger->log(this->logger, CONTROL | LEVEL2, "Create first state_t object of type RESPONDER_INIT");
+ this->current_state = (state_t *) responder_init_create(&(this->protected));
+ }
+ return &(this->protected.public);
+}
diff --git a/programs/charon/charon/sa/ike_sa.h b/programs/charon/charon/sa/ike_sa.h
new file mode 100644
index 000000000..c526c6347
--- /dev/null
+++ b/programs/charon/charon/sa/ike_sa.h
@@ -0,0 +1,462 @@
+/**
+ * @file ike_sa.h
+ *
+ * @brief Interface of ike_sa_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef IKE_SA_H_
+#define IKE_SA_H_
+
+#include <types.h>
+#include <encoding/message.h>
+#include <encoding/payloads/proposal_substructure.h>
+#include <sa/ike_sa_id.h>
+#include <sa/child_sa.h>
+#include <sa/states/state.h>
+#include <config/configuration.h>
+#include <utils/logger.h>
+#include <utils/randomizer.h>
+#include <crypto/prfs/prf.h>
+#include <crypto/crypters/crypter.h>
+#include <crypto/signers/signer.h>
+#include <config/connections/connection.h>
+#include <config/policies/policy.h>
+#include <utils/logger.h>
+
+/**
+ * Nonce size in bytes for nonces sending to other peer.
+ *
+ * @warning Nonce size MUST be between 16 and 256 bytes.
+ *
+ * @ingroup sa
+ */
+#define NONCE_SIZE 16
+
+
+typedef struct ike_sa_t ike_sa_t;
+
+/**
+ * @brief Class ike_sa_t representing an IKE_SA.
+ *
+ * An object of this type is managed by an ike_sa_manager_t object
+ * and represents an IKE_SA. Message processing is split up in different states.
+ * They will handle all related things for the state they represent.
+ *
+ * @b Constructors:
+ * - ike_sa_create()
+ *
+ * @ingroup sa
+ */
+struct ike_sa_t {
+
+ /**
+ * @brief Processes a incoming IKEv2-Message of type message_t.
+ *
+ * @param this ike_sa_t object object
+ * @param[in] message message_t object to process
+ * @return
+ * - SUCCESS
+ * - FAILED
+ * - DELETE_ME if this IKE_SA MUST be deleted
+ */
+ status_t (*process_message) (ike_sa_t *this,message_t *message);
+
+ /**
+ * @brief Initiate a new connection with given connection_t object.
+ *
+ * The connection_t object is owned by the IKE_SA after the call, so
+ * do not modify or destroy it.
+ *
+ * @param this calling object
+ * @param connection connection to initiate
+ * @return
+ * - SUCCESS if initialization started
+ * - FAILED if in wrong state
+ * - DELETE_ME if initialization failed and IKE_SA MUST be deleted
+ */
+ status_t (*initiate_connection) (ike_sa_t *this, connection_t *connection);
+
+ /**
+ * @brief Retransmits a request.
+ *
+ * @param this calling object
+ * @param message_id ID of the request to retransmit
+ * @return
+ * - SUCCESS
+ * - NOT_FOUND if request doesn't have to be retransmited
+ */
+ status_t (*retransmit_request) (ike_sa_t *this, u_int32_t message_id);
+
+ /**
+ * @brief Sends a request to delete IKE_SA.
+ *
+ * Only supported in state IKE_SA_ESTABLISHED
+ *
+ * @param this calling object
+ */
+ void (*send_delete_ike_sa_request) (ike_sa_t *this);
+
+ /**
+ * @brief 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 local peer address of the IKE_SA.
+ *
+ * @param this calling object
+ * @return local host_t
+ */
+ host_t* (*get_my_host) (ike_sa_t *this);
+
+ /**
+ * @brief Get remote peer address of the IKE_SA.
+ *
+ * @param this calling object
+ * @return remote host_t
+ */
+ host_t* (*get_other_host) (ike_sa_t *this);
+
+ /**
+ * @brief Get own ID of the IKE_SA.
+ *
+ * @param this calling object
+ * @return local identification_t
+ */
+ identification_t* (*get_my_id) (ike_sa_t *this);
+
+ /**
+ * @brief Get remote ID the IKE_SA.
+ *
+ * @param this calling object
+ * @return remote identification_t
+ */
+ identification_t* (*get_other_id) (ike_sa_t *this);
+
+ /**
+ * @brief Get the connection of the IKE_SA.
+ *
+ * The internal used connection specification
+ * can be queried to get some data of an IKE_SA.
+ * The connection is still owned to the IKE_SA
+ * and must not be manipulated.
+ *
+ * @param this calling object
+ * @return connection_t
+ */
+ connection_t* (*get_connection) (ike_sa_t *this);
+
+ /**
+ * @brief Get the state of type of associated state object.
+ *
+ * @param this calling object
+ * @return state of IKE_SA
+ */
+ ike_sa_state_t (*get_state) (ike_sa_t *this);
+
+ /**
+ * @brief Log the status of a the ike sa to a logger.
+ *
+ * The status of the IKE SA and all child SAs is logged.
+ * Supplying NULL as logger uses the internal child_sa logger
+ * to do the logging. The log is only done if the supplied
+ * connection name is NULL or matches the connections name.
+ *
+ * @param this calling object
+ * @param logger logger to use for logging
+ * @param name name of the connection
+ */
+ void (*log_status) (ike_sa_t *this, logger_t *logger, char *name);
+
+ /**
+ * @brief Destroys a ike_sa_t object.
+ *
+ * @param this calling object
+ */
+ void (*destroy) (ike_sa_t *this);
+};
+
+
+typedef struct protected_ike_sa_t protected_ike_sa_t;
+
+/**
+ * @brief Protected functions of an ike_sa_t object.
+ *
+ * This members are only accessed out from
+ * the various state_t implementations.
+ *
+ * @ingroup sa
+ */
+struct protected_ike_sa_t {
+
+ /**
+ * Public interface of an ike_sa_t object.
+ */
+ ike_sa_t public;
+
+ /**
+ * @brief Build an empty IKEv2-Message and fills in default informations.
+ *
+ * Depending on the type of message (request or response), the message id is
+ * either message_id_out or message_id_in.
+ *
+ * Used in state_t Implementation to build an empty IKEv2-Message.
+ *
+ * @param this calling object
+ * @param type exchange type of new message
+ * @param request TRUE, if message has to be a request
+ * @param message new message is stored at this location
+ */
+ void (*build_message) (protected_ike_sa_t *this, exchange_type_t type, bool request, message_t **message);
+
+ /**
+ * @brief Get the internal stored connection_t object.
+ *
+ * @param this calling object
+ * @return pointer to the internal stored connection_t object
+ */
+ connection_t *(*get_connection) (protected_ike_sa_t *this);
+
+ /**
+ * @brief Set the internal connection object.
+ *
+ * @param this calling object
+ * @param connection object of type connection_t
+ */
+ void (*set_connection) (protected_ike_sa_t *this, connection_t *connection);
+
+ /**
+ * @brief Get the internal stored policy object.
+ *
+ * @param this calling object
+ * @return pointer to the internal stored policy_t object
+ */
+ policy_t *(*get_policy) (protected_ike_sa_t *this);
+
+ /**
+ * @brief Set the internal policy_t object.
+ *
+ * @param this calling object
+ * @param policy object of type policy_t
+ */
+ void (*set_policy) (protected_ike_sa_t *this,policy_t *policy);
+
+ /**
+ * @brief Derive all keys and create the transforms for IKE communication.
+ *
+ * Keys are derived using the diffie hellman secret, nonces and internal
+ * stored SPIs.
+ * Allready existing objects get destroyed.
+ *
+ * @param this calling object
+ * @param proposal proposal which contains algorithms to use
+ * @param dh diffie hellman object with shared secret
+ * @param nonce_i initiators nonce
+ * @param nonce_r responders nonce
+ */
+ status_t (*build_transforms) (protected_ike_sa_t *this, proposal_t* proposal,
+ diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r);
+
+ /**
+ * @brief Send the next request message.
+ *
+ * Also the first retransmit job is created.
+ *
+ * Last stored requested message gets destroyed. Object gets not cloned!
+ *
+ * @param this calling object
+ * @param message pointer to the message which should be sent
+ * @return
+ * - SUCCESS
+ * - FAILED if message id is not next expected one
+ */
+ status_t (*send_request) (protected_ike_sa_t *this,message_t * message);
+
+ /**
+ * @brief Send the next response message.
+ *
+ * Last stored responded message gets destroyed. Object gets not cloned!
+ *
+ * @param this calling object
+ * @param message pointer to the message which should be sent
+ * return
+ * - SUCCESS
+ * - FAILED if message id is not next expected one
+ */
+ status_t (*send_response) (protected_ike_sa_t *this,message_t * message);
+
+ /**
+ * @brief Send a notify reply message.
+ *
+ * @param this calling object
+ * @param exchange_type type of exchange in which the notify should be wrapped
+ * @param type type of the notify message to send
+ * @param data notification data
+ */
+ void (*send_notify) (protected_ike_sa_t *this, exchange_type_t exchange_type, notify_message_type_t type, chunk_t data);
+
+ /**
+ * @brief Get the internal stored randomizer_t object.
+ *
+ * @param this calling object
+ * @return pointer to the internal randomizer_t object
+ */
+ randomizer_t *(*get_randomizer) (protected_ike_sa_t *this);
+
+ /**
+ * @brief Set the new state_t object of the IKE_SA object.
+ *
+ * The old state_t object gets not destroyed. It's the callers duty to
+ * make sure old state is destroyed (Normally the old state is the caller).
+ *
+ * @param this calling object
+ * @param state pointer to the new state_t object
+ */
+ void (*set_new_state) (protected_ike_sa_t *this,state_t *state);
+
+ /**
+ * @brief Set the last replied message id.
+ *
+ * @param this calling object
+ * @param message_id message id
+ */
+ void (*set_last_replied_message_id) (protected_ike_sa_t *this,u_int32_t message_id);
+
+ /**
+ * @brief Get the internal stored initiator crypter_t object.
+ *
+ * @param this calling object
+ * @return pointer to crypter_t object
+ */
+ crypter_t *(*get_crypter_initiator) (protected_ike_sa_t *this);
+
+ /**
+ * @brief Get the internal stored initiator signer_t object.
+ *
+ * @param this calling object
+ * @return pointer to signer_t object
+ */
+ signer_t *(*get_signer_initiator) (protected_ike_sa_t *this);
+
+ /**
+ * @brief Get the internal stored responder crypter_t object.
+ *
+ * @param this calling object
+ * @return pointer to crypter_t object
+ */
+ crypter_t *(*get_crypter_responder) (protected_ike_sa_t *this);
+
+ /**
+ * @brief Get the internal stored responder signer object.
+ *
+ * @param this calling object
+ * @return pointer to signer_t object
+ */
+ signer_t *(*get_signer_responder) (protected_ike_sa_t *this);
+
+ /**
+ * @brief Get the multi purpose prf.
+ *
+ * @param this calling object
+ * @return pointer to prf_t object
+ */
+ prf_t *(*get_prf) (protected_ike_sa_t *this);
+
+ /**
+ * @brief 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) (protected_ike_sa_t *this);
+
+ /**
+ * @brief Get the prf used for authentication of initiator.
+ *
+ * @param this calling object
+ * @return pointer to prf_t object
+ */
+ prf_t *(*get_prf_auth_i) (protected_ike_sa_t *this);
+
+ /**
+ * @brief Get the prf used for authentication of responder.
+ *
+ * @param this calling object
+ * @return pointer to prf_t object
+ */
+ prf_t *(*get_prf_auth_r) (protected_ike_sa_t *this);
+
+ /**
+ * @brief Associates a child SA to this IKE SA
+ *
+ * @param this calling object
+ * @param child_sa child_sa to add
+ */
+ void (*add_child_sa) (protected_ike_sa_t *this, child_sa_t *child_sa);
+
+ /**
+ * @brief Get the last responded message.
+ *
+ * @param this calling object
+ * @return
+ * - last received as message_t object
+ * - NULL if no last request available
+ */
+ message_t *(*get_last_responded_message) (protected_ike_sa_t *this);
+
+ /**
+ * @brief Get the last requested message.
+ *
+ * @param this calling object
+ * @return
+ * - last sent as message_t object
+ * - NULL if no last request available
+ */
+ message_t *(*get_last_requested_message) (protected_ike_sa_t *this);
+
+ /**
+ * @brief Resets message counters and does destroy stored received and sent messages.
+ *
+ * @param this calling object
+ */
+ void (*reset_message_buffers) (protected_ike_sa_t *this);
+};
+
+
+/**
+ * @brief Creates an ike_sa_t object with a specific ID.
+ *
+ * @warning the Content of internal ike_sa_id_t object can change over time
+ * e.g. when a IKE_SA_INIT has been finished.
+ *
+ * @param[in] ike_sa_id ike_sa_id_t object to associate with new IKE_SA.
+ * The object is internal getting cloned
+ * and so has to be destroyed by the caller.
+ * @return ike_sa_t object
+ *
+ * @ingroup sa
+ */
+ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id);
+
+#endif /*IKE_SA_H_*/
diff --git a/programs/charon/charon/sa/ike_sa_id.c b/programs/charon/charon/sa/ike_sa_id.c
new file mode 100644
index 000000000..bf3a05d11
--- /dev/null
+++ b/programs/charon/charon/sa/ike_sa_id.c
@@ -0,0 +1,185 @@
+/**
+ * @file ike_sa_id.c
+ *
+ * @brief Implementation of ike_sa_id_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#include "ike_sa_id.h"
+
+
+
+typedef struct private_ike_sa_id_t private_ike_sa_id_t;
+
+/**
+ * Private data of an ike_sa_id_t object.
+ */
+struct private_ike_sa_id_t {
+ /**
+ * Public interface of ike_sa_id_t.
+ */
+ ike_sa_id_t public;
+
+ /**
+ * SPI of Initiator.
+ */
+ u_int64_t initiator_spi;
+
+ /**
+ * SPI of Responder.
+ */
+ u_int64_t responder_spi;
+
+ /**
+ * Role for specific IKE_SA.
+ */
+ bool is_initiator_flag;
+};
+
+/**
+ * Implementation of ike_sa_id_t.set_responder_spi.
+ */
+static void set_responder_spi (private_ike_sa_id_t *this, u_int64_t responder_spi)
+{
+ this->responder_spi = responder_spi;
+}
+
+/**
+ * Implementation of ike_sa_id_t.set_initiator_spi.
+ */
+static void set_initiator_spi(private_ike_sa_id_t *this, u_int64_t initiator_spi)
+{
+ this->initiator_spi = initiator_spi;
+}
+
+/**
+ * Implementation of ike_sa_id_t.get_initiator_spi.
+ */
+static u_int64_t get_initiator_spi (private_ike_sa_id_t *this)
+{
+ return this->initiator_spi;
+}
+
+/**
+ * Implementation of ike_sa_id_t.get_responder_spi.
+ */
+static u_int64_t get_responder_spi (private_ike_sa_id_t *this)
+{
+ return this->responder_spi;
+}
+
+/**
+ * Implementation of ike_sa_id_t.equals.
+ */
+static bool equals (private_ike_sa_id_t *this, private_ike_sa_id_t *other)
+{
+ if (other == NULL)
+ {
+ return FALSE;
+ }
+ if ((this->is_initiator_flag == other->is_initiator_flag) &&
+ (this->initiator_spi == other->initiator_spi) &&
+ (this->responder_spi == other->responder_spi))
+ {
+ /* private_ike_sa_id's are equal */
+ return TRUE;
+ }
+ else
+ {
+ /* private_ike_sa_id's are not equal */
+ return FALSE;
+ }
+}
+
+/**
+ * Implementation of ike_sa_id_t.replace_values.
+ */
+static void replace_values(private_ike_sa_id_t *this, private_ike_sa_id_t *other)
+{
+ this->initiator_spi = other->initiator_spi;
+ this->responder_spi = other->responder_spi;
+ this->is_initiator_flag = other->is_initiator_flag;
+}
+
+/**
+ * Implementation of ike_sa_id_t.is_initiator.
+ */
+static bool is_initiator(private_ike_sa_id_t *this)
+{
+ return this->is_initiator_flag;
+}
+
+/**
+ * Implementation of ike_sa_id_t.switch_initiator.
+ */
+static bool switch_initiator(private_ike_sa_id_t *this)
+{
+ if (this->is_initiator_flag)
+ {
+ this->is_initiator_flag = FALSE;
+ }
+ else
+ {
+ this->is_initiator_flag = TRUE;
+ }
+ return this->is_initiator_flag;
+}
+
+/**
+ * Implementation of ike_sa_id_t.clone.
+ */
+static ike_sa_id_t* clone(private_ike_sa_id_t *this)
+{
+ return ike_sa_id_create(this->initiator_spi, this->responder_spi, this->is_initiator_flag);
+}
+
+/**
+ * Implementation of ike_sa_id_t.destroy.
+ */
+static void destroy(private_ike_sa_id_t *this)
+{
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+ike_sa_id_t * ike_sa_id_create(u_int64_t initiator_spi, u_int64_t responder_spi, bool is_initiator_flag)
+{
+ private_ike_sa_id_t *this = malloc_thing(private_ike_sa_id_t);
+
+ /* public functions */
+ this->public.set_responder_spi = (void(*)(ike_sa_id_t*,u_int64_t)) set_responder_spi;
+ this->public.set_initiator_spi = (void(*)(ike_sa_id_t*,u_int64_t)) set_initiator_spi;
+ this->public.get_responder_spi = (u_int64_t(*)(ike_sa_id_t*)) get_responder_spi;
+ this->public.get_initiator_spi = (u_int64_t(*)(ike_sa_id_t*)) get_initiator_spi;
+ this->public.equals = (bool(*)(ike_sa_id_t*,ike_sa_id_t*)) equals;
+ this->public.replace_values = (void(*)(ike_sa_id_t*,ike_sa_id_t*)) replace_values;
+ this->public.is_initiator = (bool(*)(ike_sa_id_t*)) is_initiator;
+ this->public.switch_initiator = (bool(*)(ike_sa_id_t*)) switch_initiator;
+ this->public.clone = (ike_sa_id_t*(*)(ike_sa_id_t*)) clone;
+ this->public.destroy = (void(*)(ike_sa_id_t*))destroy;
+
+ /* private data */
+ this->initiator_spi = initiator_spi;
+ this->responder_spi = responder_spi;
+ this->is_initiator_flag = is_initiator_flag;
+
+ return (&this->public);
+}
diff --git a/programs/charon/charon/sa/ike_sa_id.h b/programs/charon/charon/sa/ike_sa_id.h
new file mode 100644
index 000000000..0f16f7637
--- /dev/null
+++ b/programs/charon/charon/sa/ike_sa_id.h
@@ -0,0 +1,146 @@
+/**
+ * @file ike_sa_id.h
+ *
+ * @brief Interface of ike_sa_id_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#ifndef IKE_SA_ID_H_
+#define IKE_SA_ID_H_
+
+#include <types.h>
+
+
+typedef struct ike_sa_id_t ike_sa_id_t;
+
+/**
+ * @brief 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.
+ *
+ * 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.
+ *
+ * @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.
+ *
+ * @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.
+ *
+ * @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.
+ *
+ * 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.
+ * 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.
+ *
+ * @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.
+ *
+ * @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.
+ *
+ * @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
+ */
+ void (*destroy) (ike_sa_id_t *this);
+};
+
+/**
+ * @brief 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);
+
+#endif /*IKE_SA_ID_H_*/
diff --git a/programs/charon/charon/sa/ike_sa_manager.c b/programs/charon/charon/sa/ike_sa_manager.c
new file mode 100644
index 000000000..01f3f5ad2
--- /dev/null
+++ b/programs/charon/charon/sa/ike_sa_manager.c
@@ -0,0 +1,812 @@
+/**
+ * @file ike_sa_manager.c
+ *
+ * @brief Implementation of ike_sa_mananger_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <pthread.h>
+#include <string.h>
+
+#include "ike_sa_manager.h"
+
+#include <daemon.h>
+#include <sa/ike_sa_id.h>
+#include <utils/logger.h>
+#include <utils/logger_manager.h>
+#include <utils/linked_list.h>
+
+typedef struct ike_sa_entry_t ike_sa_entry_t;
+
+/**
+ * An entry in the linked list, contains IKE_SA, locking and lookup data.
+ */
+struct ike_sa_entry_t {
+ /**
+ * Destructor, also destroys associated ike_sa_t object.
+ */
+ status_t (*destroy) (ike_sa_entry_t *this);
+
+ /**
+ * Number of threads waiting for this ike_sa_t object.
+ */
+ int waiting_threads;
+
+ /**
+ * Condvar where threads can wait until ike_sa_t object is free for use again.
+ */
+ pthread_cond_t condvar;
+
+ /**
+ * Is this ike_sa currently checked out?
+ */
+ bool checked_out;
+
+ /**
+ * Does this SA drives out new threads?
+ */
+ bool driveout_new_threads;
+
+ /**
+ * Does this SA drives out waiting threads?
+ */
+ bool driveout_waiting_threads;
+
+ /**
+ * Identifiaction of an IKE_SA (SPIs).
+ */
+ ike_sa_id_t *ike_sa_id;
+
+ /**
+ * The contained ike_sa_t object.
+ */
+ ike_sa_t *ike_sa;
+};
+
+/**
+ * Implementation of ike_sa_entry_t.destroy.
+ */
+static status_t ike_sa_entry_destroy(ike_sa_entry_t *this)
+{
+ /* also destroy IKE SA */
+ this->ike_sa->destroy(this->ike_sa);
+ this->ike_sa_id->destroy(this->ike_sa_id);
+ free(this);
+ return SUCCESS;
+}
+
+/**
+ * @brief Creates a new entry for the ike_sa_t list.
+ *
+ * This constructor additionaly creates a new and empty SA.
+ *
+ * @param ike_sa_id The associated ike_sa_id_t, will be cloned
+ * @return ike_sa_entry_t object
+ */
+static ike_sa_entry_t *ike_sa_entry_create(ike_sa_id_t *ike_sa_id)
+{
+ ike_sa_entry_t *this = malloc_thing(ike_sa_entry_t);
+
+ /* destroy function */
+ this->destroy = ike_sa_entry_destroy;
+
+ this->waiting_threads = 0;
+ pthread_cond_init(&(this->condvar), NULL);
+
+ /* we set checkout flag when we really give it out */
+ this->checked_out = FALSE;
+ this->driveout_new_threads = FALSE;
+ this->driveout_waiting_threads = FALSE;
+
+ /* ike_sa_id is always cloned */
+ this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
+
+ /* create new ike_sa */
+ this->ike_sa = ike_sa_create(ike_sa_id);
+
+ return this;
+}
+
+
+typedef struct private_ike_sa_manager_t private_ike_sa_manager_t;
+
+/**
+ * Additional private members of ike_sa_manager_t.
+ */
+struct private_ike_sa_manager_t {
+ /**
+ * Public interface of ike_sa_manager_t.
+ */
+ ike_sa_manager_t public;
+
+ /**
+ * @brief Get next spi.
+ *
+ * We give out SPIs incremental starting at 1.
+ *
+ * @param this the ike_sa_manager
+ * @return the next spi
+ */
+ u_int64_t (*get_next_spi) (private_ike_sa_manager_t *this);
+
+ /**
+ * @brief Find the ike_sa_entry_t object in the list by SPIs.
+ *
+ * This function simply iterates over the linked list. A hash-table
+ * would be more efficient when storing a lot of IKE_SAs...
+ *
+ * @param this calling object
+ * @param ike_sa_id id of the ike_sa, containing SPIs
+ * @param[out] entry pointer to set to the found entry
+ * @return
+ * - SUCCESS when found,
+ * - NOT_FOUND when no such ike_sa_id in list
+ */
+ status_t (*get_entry_by_id) (private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, ike_sa_entry_t **entry);
+
+ /**
+ * @brief Find the ike_sa_entry_t in the list by pointer to SA.
+ *
+ * This function simply iterates over the linked list. A hash-table
+ * would be more efficient when storing a lot of IKE_SAs...
+ *
+ * @param this calling object
+ * @param ike_sa pointer to the ike_sa
+ * @param[out] entry pointer to set to the found entry
+ * @return
+ * - SUCCESS when found,
+ * - NOT_FOUND when no such ike_sa_id in list
+ */
+ status_t (*get_entry_by_sa) (private_ike_sa_manager_t *this, ike_sa_t *ike_sa, ike_sa_entry_t **entry);
+
+ /**
+ * @brief Felete an entry from the linked list.
+ *
+ * @param this calling object
+ * @param entry entry to delete
+ * @return
+ * - SUCCESS when found,
+ * - NOT_FOUND when no such ike_sa_id in list
+ */
+ status_t (*delete_entry) (private_ike_sa_manager_t *this, ike_sa_entry_t *entry);
+
+ /**
+ * Lock for exclusivly accessing the manager.
+ */
+ pthread_mutex_t mutex;
+
+ /**
+ * Logger used for this IKE SA Manager.
+ */
+ logger_t *logger;
+
+ /**
+ * Linked list with entries for the ike_sa_t objects.
+ */
+ linked_list_t *ike_sa_list;
+
+ /**
+ * Next SPI, needed for incremental creation of SPIs.
+ */
+ u_int64_t next_spi;
+};
+
+/**
+ * Implementation of private_ike_sa_manager_t.get_entry_by_id.
+ */
+static status_t get_entry_by_id(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, ike_sa_entry_t **entry)
+{
+ linked_list_t *list = this->ike_sa_list;
+ iterator_t *iterator;
+ status_t status;
+
+ /* create iterator over list of ike_sa's */
+ iterator = list->create_iterator(list, TRUE);
+
+ /* default status */
+ status = NOT_FOUND;
+
+ while (iterator->has_next(iterator))
+ {
+ ike_sa_entry_t *current;
+
+ iterator->current(iterator, (void**)&current);
+ if (current->ike_sa_id->get_responder_spi(current->ike_sa_id) == 0)
+ {
+ /* seems to be a half ready ike_sa */
+ if ((current->ike_sa_id->get_initiator_spi(current->ike_sa_id) == ike_sa_id->get_initiator_spi(ike_sa_id))
+ && (ike_sa_id->is_initiator(ike_sa_id) == current->ike_sa_id->is_initiator(current->ike_sa_id)))
+ {
+ this->logger->log(this->logger,CONTROL | LEVEL2,"Found entry by initiator spi %d",ike_sa_id->get_initiator_spi(ike_sa_id));
+ *entry = current;
+ status = SUCCESS;
+ break;
+ }
+ }
+ else if (ike_sa_id->get_responder_spi(ike_sa_id) == 0)
+ {
+ if ((current->ike_sa_id->get_initiator_spi(current->ike_sa_id) == ike_sa_id->get_initiator_spi(ike_sa_id))
+ && (ike_sa_id->is_initiator(ike_sa_id) == current->ike_sa_id->is_initiator(current->ike_sa_id)))
+ {
+ this->logger->log(this->logger,CONTROL | LEVEL2,"Found entry by initiator spi %d",ike_sa_id->get_initiator_spi(ike_sa_id));
+ *entry = current;
+ status = SUCCESS;
+ break;
+ }
+ }
+ if (current->ike_sa_id->equals(current->ike_sa_id, ike_sa_id))
+ {
+ this->logger->log(this->logger,CONTROL | LEVEL2,"Found entry by full ID");
+ *entry = current;
+ status = SUCCESS;
+ break;
+ }
+ }
+
+ iterator->destroy(iterator);
+ return status;
+}
+
+/**
+ * Implementation of private_ike_sa_manager_t.get_entry_by_sa.
+ */
+static status_t get_entry_by_sa(private_ike_sa_manager_t *this, ike_sa_t *ike_sa, ike_sa_entry_t **entry)
+{
+ linked_list_t *list = this->ike_sa_list;
+ iterator_t *iterator;
+ status_t status;
+
+ iterator = list->create_iterator(list, TRUE);
+
+ /* default status */
+ status = NOT_FOUND;
+
+ while (iterator->has_next(iterator))
+ {
+ ike_sa_entry_t *current;
+ iterator->current(iterator, (void**)&current);
+ /* only pointers are compared */
+ if (current->ike_sa == ike_sa)
+ {
+ this->logger->log(this->logger,CONTROL | LEVEL2,"Found entry by pointer");
+ *entry = current;
+ status = SUCCESS;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+
+ return status;
+}
+
+/**
+ * Implementation of private_ike_sa_manager_s.delete_entry.
+ */
+static status_t delete_entry(private_ike_sa_manager_t *this, ike_sa_entry_t *entry)
+{
+ linked_list_t *list = this->ike_sa_list;
+ iterator_t *iterator;
+ status_t status;
+
+ iterator = list->create_iterator(list, TRUE);
+
+ status = NOT_FOUND;
+
+ while (iterator->has_next(iterator))
+ {
+ ike_sa_entry_t *current;
+ iterator->current(iterator, (void**)&current);
+ if (current == entry)
+ {
+ this->logger->log(this->logger,CONTROL | LEVEL2,"Found entry by pointer. Going to delete it.");
+ iterator->remove(iterator);
+ entry->destroy(entry);
+ status = SUCCESS;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ return status;
+}
+
+
+/**
+ * Implementation of private_ike_sa_manager_t.get_next_spi.
+ */
+static u_int64_t get_next_spi(private_ike_sa_manager_t *this)
+{
+ this->next_spi++;
+ if (this->next_spi == 0) {
+ /* TODO handle overflow,
+ * delete all SAs or so
+ */
+ }
+ return this->next_spi;
+}
+
+/**
+ * Implementation of of ike_sa_manager.create_and_checkout.
+ */
+static void create_and_checkout(private_ike_sa_manager_t *this,ike_sa_t **ike_sa)
+{
+ u_int64_t initiator_spi;
+ ike_sa_entry_t *new_ike_sa_entry;
+ ike_sa_id_t *new_ike_sa_id;
+
+ initiator_spi = this->get_next_spi(this);
+ new_ike_sa_id = ike_sa_id_create(0, 0, TRUE);
+ new_ike_sa_id->set_initiator_spi(new_ike_sa_id, initiator_spi);
+
+ /* create entry */
+ new_ike_sa_entry = ike_sa_entry_create(new_ike_sa_id);
+ new_ike_sa_id->destroy(new_ike_sa_id);
+
+ /* each access is locked */
+ pthread_mutex_lock(&(this->mutex));
+
+ this->ike_sa_list->insert_last(this->ike_sa_list, new_ike_sa_entry);
+
+ /* check ike_sa out */
+ this->logger->log(this->logger,CONTROL | LEVEL1 ,"New IKE_SA created and added to list of known IKE_SA's");
+ new_ike_sa_entry->checked_out = TRUE;
+ *ike_sa = new_ike_sa_entry->ike_sa;
+
+ pthread_mutex_unlock(&(this->mutex));
+}
+
+/**
+ * Implementation of of ike_sa_manager.checkout.
+ */
+static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, ike_sa_t **ike_sa)
+{
+ bool responder_spi_set;
+ bool initiator_spi_set;
+ bool original_initiator;
+ status_t retval;
+
+ /* each access is locked */
+ pthread_mutex_lock(&(this->mutex));
+
+ responder_spi_set = (FALSE != ike_sa_id->get_responder_spi(ike_sa_id));
+ initiator_spi_set = (FALSE != ike_sa_id->get_initiator_spi(ike_sa_id));
+ original_initiator = ike_sa_id->is_initiator(ike_sa_id);
+
+ if ((initiator_spi_set && responder_spi_set) ||
+ ((initiator_spi_set && !responder_spi_set) && (original_initiator)))
+ {
+ /* we SHOULD have an IKE_SA for these SPIs in the list,
+ * if not, we can't handle the request...
+ */
+ ike_sa_entry_t *entry;
+ /* look for the entry */
+ if (this->get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS)
+ {
+ /* can we give this ike_sa out to new requesters?*/
+ if (entry->driveout_new_threads)
+ {
+ this->logger->log(this->logger,CONTROL|LEVEL1,"Drive out new thread for existing IKE_SA");
+ /* no we can't */
+ retval = NOT_FOUND;
+ }
+ else
+ {
+ /* is this IKE_SA already checked out ??
+ * are we welcome to get this SA ? */
+ while (entry->checked_out && !entry->driveout_waiting_threads)
+ {
+ /* so wait until we can get it for us.
+ * we register us as waiting.
+ */
+ entry->waiting_threads++;
+ pthread_cond_wait(&(entry->condvar), &(this->mutex));
+ entry->waiting_threads--;
+ }
+
+ /* hm, a deletion request forbids us to get this SA, go home */
+ if (entry->driveout_waiting_threads)
+ {
+ /* we must signal here, others are interested that we leave */
+ pthread_cond_signal(&(entry->condvar));
+ this->logger->log(this->logger,CONTROL|LEVEL1,"Drive out waiting thread for existing IKE_SA");
+ retval = NOT_FOUND;
+ }
+ else
+ {
+ this->logger->log(this->logger,CONTROL|LEVEL2,"IKE SA successfully checked out");
+ /* ok, this IKE_SA is finally ours */
+ entry->checked_out = TRUE;
+ *ike_sa = entry->ike_sa;
+ /* DON'T use return, we must unlock the mutex! */
+ retval = SUCCESS;
+ }
+ }
+ }
+ else
+ {
+ this->logger->log(this->logger,ERROR | LEVEL1,"IKE SA not stored in known IKE_SA list");
+ /* looks like there is no such IKE_SA, better luck next time... */
+ /* DON'T use return, we must unlock the mutex! */
+ retval = NOT_FOUND;
+ }
+ }
+ else if ((initiator_spi_set && !responder_spi_set) && (!original_initiator))
+ {
+ /* an IKE_SA_INIT from an another endpoint,
+ * he is the initiator.
+ * For simplicity, we do NOT check for retransmitted
+ * IKE_SA_INIT-Requests here, so EVERY single IKE_SA_INIT-
+ * Request (even a retransmitted one) will result in a
+ * IKE_SA. This could be improved...
+ */
+ u_int64_t responder_spi;
+ ike_sa_entry_t *new_ike_sa_entry;
+
+
+ /* set SPIs, we are the responder */
+ responder_spi = this->get_next_spi(this);
+
+ /* we also set arguments spi, so its still valid */
+ ike_sa_id->set_responder_spi(ike_sa_id, responder_spi);
+
+ /* create entry */
+ new_ike_sa_entry = ike_sa_entry_create(ike_sa_id);
+
+ this->ike_sa_list->insert_last(this->ike_sa_list, new_ike_sa_entry);
+
+ /* check ike_sa out */
+ this->logger->log(this->logger,CONTROL | LEVEL1 ,"IKE_SA added to list of known IKE_SA's");
+ new_ike_sa_entry->checked_out = TRUE;
+ *ike_sa = new_ike_sa_entry->ike_sa;
+
+ retval = CREATED;
+ }
+ else
+ {
+ /* responder set, initiator not: here is something seriously wrong! */
+ this->logger->log(this->logger,ERROR | LEVEL1, "Invalid IKE_SA SPI's");
+ /* DON'T use return, we must unlock the mutex! */
+ retval = INVALID_ARG;
+ }
+
+ pthread_mutex_unlock(&(this->mutex));
+ /* OK, unlocked... */
+ return retval;
+}
+
+/**
+ * Implementation of of ike_sa_manager.checkout_by_hosts.
+ */
+static status_t checkout_by_hosts(private_ike_sa_manager_t *this, host_t *me, host_t *other, ike_sa_t **ike_sa)
+{
+ iterator_t *iterator;
+ ike_sa_id_t *ike_sa_id = NULL;
+
+ pthread_mutex_lock(&(this->mutex));
+
+ iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
+ while (iterator->has_next(iterator))
+ {
+ ike_sa_entry_t *current;
+ host_t *sa_me, *sa_other;
+
+ iterator->current(iterator, (void**)&current);
+ sa_me = current->ike_sa->get_my_host(current->ike_sa);
+ sa_other = current->ike_sa->get_other_host(current->ike_sa);
+
+ /* one end may be default/any, but not both */
+ if (me->is_default_route(me))
+ {
+ if (other->is_default_route(other))
+ {
+ break;
+ }
+ if (other->equals(other, sa_other))
+ {
+ /* other matches */
+ ike_sa_id = current->ike_sa_id;
+ }
+ }
+ else if (other->is_default_route(other))
+ {
+ if (me->equals(me, sa_me))
+ {
+ /* ME matches */
+ ike_sa_id = current->ike_sa_id;
+ }
+ }
+ else
+ {
+ if (me->equals(me, sa_me) && other->equals(other, sa_other))
+ {
+ /* both matches */
+ ike_sa_id = current->ike_sa_id;
+ }
+ }
+ }
+ iterator->destroy(iterator);
+ pthread_mutex_unlock(&(this->mutex));
+
+ if (ike_sa_id)
+ {
+ /* checkout is done in the checkout function, since its rather complex */
+ return checkout(this, ike_sa_id, ike_sa);
+ }
+ return NOT_FOUND;
+}
+
+/**
+ * Implementation of ike_sa_manager_t.get_ike_sa_list.
+ */
+linked_list_t *get_ike_sa_list(private_ike_sa_manager_t* this)
+{
+ linked_list_t *list;
+ iterator_t *iterator;
+
+ pthread_mutex_lock(&(this->mutex));
+
+ list = linked_list_create();
+ iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
+ while (iterator->has_next(iterator))
+ {
+ ike_sa_entry_t *entry;
+ iterator->current(iterator, (void**)&entry);
+ list->insert_last(list, (void*)entry->ike_sa_id->clone(entry->ike_sa_id));
+ }
+ iterator->destroy(iterator);
+
+ pthread_mutex_unlock(&(this->mutex));
+ return list;
+}
+
+/**
+ * Implementation of ike_sa_manager_t.log_status.
+ */
+static void log_status(private_ike_sa_manager_t* this, logger_t* logger, char* name)
+{
+ iterator_t *iterator;
+
+ pthread_mutex_lock(&(this->mutex));
+
+ iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
+ while (iterator->has_next(iterator))
+ {
+ ike_sa_entry_t *entry;
+ iterator->current(iterator, (void**)&entry);
+ entry->ike_sa->log_status(entry->ike_sa, logger, name);
+ }
+ iterator->destroy(iterator);
+
+ pthread_mutex_unlock(&(this->mutex));
+}
+
+/**
+ * Implementation of ike_sa_manager_t.checkin.
+ */
+static status_t checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
+{
+ /* to check the SA back in, we look for the pointer of the ike_sa
+ * in all entries.
+ * We can't search by SPI's since the MAY have changed (e.g. on reception
+ * of a IKE_SA_INIT response). Updating of the SPI MAY be necessary...
+ */
+ status_t retval;
+ ike_sa_entry_t *entry;
+
+ pthread_mutex_lock(&(this->mutex));
+
+ /* look for the entry */
+ if (this->get_entry_by_sa(this, ike_sa, &entry) == SUCCESS)
+ {
+ /* ike_sa_id must be updated */
+ entry->ike_sa_id->replace_values(entry->ike_sa_id, ike_sa->get_id(ike_sa));
+ /* signal waiting threads */
+ entry->checked_out = FALSE;
+ this->logger->log(this->logger,CONTROL | LEVEL1,"Checkin of IKE_SA successful.");
+ pthread_cond_signal(&(entry->condvar));
+ retval = SUCCESS;
+ }
+ else
+ {
+ this->logger->log(this->logger,ERROR,"Fatal Error: Tried to checkin nonexisting IKE_SA");
+ /* this SA is no more, this REALLY should not happen */
+ retval = NOT_FOUND;
+ }
+ pthread_mutex_unlock(&(this->mutex));
+ return retval;
+}
+
+
+/**
+ * Implementation of ike_sa_manager_t.checkin_and_delete.
+ */
+static status_t checkin_and_delete(private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
+{
+ /* deletion is a bit complex, we must garant that no thread is waiting for
+ * this SA.
+ * We take this SA from the list, and start signaling while threads
+ * are in the condvar.
+ */
+ ike_sa_entry_t *entry;
+ status_t retval;
+
+ pthread_mutex_lock(&(this->mutex));
+
+ if (this->get_entry_by_sa(this, ike_sa, &entry) == SUCCESS)
+ {
+ /* mark it, so now new threads can acquire this SA */
+ entry->driveout_new_threads = TRUE;
+ /* additionaly, drive out waiting threads */
+ entry->driveout_waiting_threads = TRUE;
+
+ /* wait until all workers have done their work */
+ while (entry->waiting_threads > 0)
+ {
+ /* let the other threads do some work*/
+ pthread_cond_signal(&(entry->condvar));
+ /* and the nice thing, they will wake us again when their work is done */
+ pthread_cond_wait(&(entry->condvar), &(this->mutex));
+ }
+ /* ok, we are alone now, no threads waiting in the entry's condvar */
+ this->delete_entry(this, entry);
+ this->logger->log(this->logger,CONTROL | LEVEL1,"Checkin and delete of IKE_SA successful");
+ retval = SUCCESS;
+ }
+ else
+ {
+ this->logger->log(this->logger,ERROR,"Fatal Error: Tried to checkin and delete nonexisting IKE_SA");
+ retval = NOT_FOUND;
+ }
+
+ pthread_mutex_unlock(&(this->mutex));
+ return retval;
+}
+
+/**
+ * Implementation of ike_sa_manager_t.delete.
+ */
+static status_t delete(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
+{
+ /* deletion is a bit complex, we must garant that no thread is waiting for
+ * this SA.
+ * We take this SA from the list, and start signaling while threads
+ * are in the condvar.
+ */
+ ike_sa_entry_t *entry;
+ status_t retval;
+
+ pthread_mutex_lock(&(this->mutex));
+
+ if (this->get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS)
+ {
+ /* mark it, so now new threads can acquire this SA */
+ entry->driveout_new_threads = TRUE;
+
+ /* wait until all workers have done their work */
+ while (entry->waiting_threads)
+ {
+ /* wake up all */
+ pthread_cond_signal(&(entry->condvar));
+ /* and the nice thing, they will wake us again when their work is done */
+ pthread_cond_wait(&(entry->condvar), &(this->mutex));
+ }
+ /* ok, we are alone now, no threads waiting in the entry's condvar */
+ this->delete_entry(this, entry);
+ this->logger->log(this->logger,CONTROL | LEVEL1,"Delete of IKE_SA successful");
+ retval = SUCCESS;
+ }
+ else
+ {
+ this->logger->log(this->logger,ERROR,"Fatal Error: Tried to delete nonexisting IKE_SA");
+ retval = NOT_FOUND;
+ }
+
+ pthread_mutex_unlock(&(this->mutex));
+ return retval;
+}
+
+/**
+ * Implementation of ike_sa_manager_t.destroy.
+ */
+static void destroy(private_ike_sa_manager_t *this)
+{
+ /* destroy all list entries */
+ linked_list_t *list = this->ike_sa_list;
+ iterator_t *iterator;
+ ike_sa_entry_t *entry;
+
+ pthread_mutex_lock(&(this->mutex));
+
+ this->logger->log(this->logger,CONTROL | LEVEL1,"Going to destroy IKE_SA manager and all managed IKE_SA's");
+
+ /* Step 1: drive out all waiting threads */
+ iterator = list->create_iterator(list, TRUE);
+
+ this->logger->log(this->logger,CONTROL | LEVEL2,"Set driveout flags for all stored IKE_SA's");
+ while (iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void**)&entry);
+ /* do not accept new threads, drive out waiting threads */
+ entry->driveout_new_threads = TRUE;
+ entry->driveout_waiting_threads = TRUE;
+ }
+
+ this->logger->log(this->logger,CONTROL | LEVEL2,"Wait for all threads to leave IKE_SA's");
+ /* Step 2: wait until all are gone */
+ iterator->reset(iterator);
+ while (iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void**)&entry);
+ while (entry->waiting_threads)
+ {
+ /* wake up all */
+ pthread_cond_signal(&(entry->condvar));
+ /* go sleeping until they are gone */
+ pthread_cond_wait(&(entry->condvar), &(this->mutex));
+ }
+ }
+ this->logger->log(this->logger,CONTROL | LEVEL2,"Delete all IKE_SA's");
+ /* Step 3: delete all entries */
+ iterator->destroy(iterator);
+
+ while (list->get_count(list) > 0)
+ {
+ list->get_first(list, (void**)&entry);
+ this->delete_entry(this, entry);
+ }
+ list->destroy(list);
+ this->logger->log(this->logger,CONTROL | LEVEL2,"IKE_SA's deleted");
+ pthread_mutex_unlock(&(this->mutex));
+
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+ike_sa_manager_t *ike_sa_manager_create()
+{
+ private_ike_sa_manager_t *this = malloc_thing(private_ike_sa_manager_t);
+
+ /* assign public functions */
+ this->public.destroy = (void(*)(ike_sa_manager_t*))destroy;
+ this->public.create_and_checkout = (void(*)(ike_sa_manager_t*,ike_sa_t**))create_and_checkout;
+ this->public.checkout = (status_t(*)(ike_sa_manager_t*, ike_sa_id_t*,ike_sa_t**))checkout;
+ this->public.checkout_by_hosts = (status_t(*)(ike_sa_manager_t*,host_t*,host_t*,ike_sa_t**))checkout_by_hosts;
+ this->public.get_ike_sa_list = (linked_list_t*(*)(ike_sa_manager_t*))get_ike_sa_list;
+ this->public.log_status = (void(*)(ike_sa_manager_t*,logger_t*,char*))log_status;
+ this->public.checkin = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin;
+ this->public.delete = (status_t(*)(ike_sa_manager_t*,ike_sa_id_t*))delete;
+ this->public.checkin_and_delete = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin_and_delete;
+
+ /* initialize private functions */
+ this->get_next_spi = get_next_spi;
+ this->get_entry_by_sa = get_entry_by_sa;
+ this->get_entry_by_id = get_entry_by_id;
+ this->delete_entry = delete_entry;
+
+ /* initialize private variables */
+ this->logger = logger_manager->get_logger(logger_manager, IKE_SA_MANAGER);
+
+ this->ike_sa_list = linked_list_create();
+
+ pthread_mutex_init(&(this->mutex), NULL);
+
+ this->next_spi = 0;
+
+ return (ike_sa_manager_t*)this;
+}
diff --git a/programs/charon/charon/sa/ike_sa_manager.h b/programs/charon/charon/sa/ike_sa_manager.h
new file mode 100644
index 000000000..e2235b4b6
--- /dev/null
+++ b/programs/charon/charon/sa/ike_sa_manager.h
@@ -0,0 +1,185 @@
+/**
+ * @file ike_sa_manager.h
+ *
+ * @brief Interface of ike_sa_manager_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef IKE_SA_MANAGER_H_
+#define IKE_SA_MANAGER_H_
+
+#include <types.h>
+#include <sa/ike_sa.h>
+#include <utils/logger.h>
+
+
+typedef struct ike_sa_manager_t ike_sa_manager_t;
+
+/**
+ * @brief 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.
+ * The manager also handles deletion of SAs.
+ *
+ * @todo checking of double-checkouts from the same threads would be nice.
+ * 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 IKE_SA, create it when necesarry.
+ *
+ * Checks out a SA by its ID. An SA will be created, when:
+ * - Responder SPI is not set (when received an IKE_SA_INIT from initiator)
+ * Management of SPIs is the managers job, he will set it.
+ * This function blocks until SA is available for checkout.
+ *
+ * @warning checking out two times without checking in will
+ * result in a deadlock!
+ *
+ * @param this the manager object
+ * @param ike_sa_id[in/out] the SA identifier, will be updated
+ * @param ike_sa[out] checked out SA
+ * @returns
+ * - SUCCESS if checkout successful
+ * - NOT_FOUND when no such SA is available
+ * - CREATED if a new IKE_SA got created
+ */
+ status_t (*checkout) (ike_sa_manager_t* this, ike_sa_id_t *sa_id, ike_sa_t **ike_sa);
+
+ /**
+ * @brief Create and checkout an IKE_SA as original initator.
+ *
+ * Creates and checks out a SA as initiator.
+ * Management of SPIs is the managers job, he will set it.
+ *
+ * @param this the manager object
+ * @param ike_sa[out] checked out SA
+ */
+ void (*create_and_checkout) (ike_sa_manager_t* this,ike_sa_t **ike_sa);
+
+ /**
+ * @brief Check out an IKE_SA, defined be the two peers.
+ *
+ * Checking out an IKE_SA by their peer addresses may be necessary
+ * for kernel traps, status querying and so on... one of the hosts
+ * may be 0.0.0.0 (defaultroute/any), but not both.
+ *
+ * @param this the manager object
+ * @param me host on local side
+ * @param other host on remote side
+ * @param ike_sa[out] checked out SA
+ * @return
+ * - NOT_FOUND, if no such SA found
+ * - SUCCESS, if SA found and ike_sa set appropriatly
+ */
+ status_t (*checkout_by_hosts) (ike_sa_manager_t* this, host_t *me, host_t *other, ike_sa_t **ike_sa);
+
+ /**
+ * @brief Get a list of all IKE_SA SAs currently set up.
+ *
+ * The resulting list with all IDs must be destroyd by
+ * the caller. There is no guarantee an ike_sa with the
+ * corrensponding ID really exists, since it may be deleted
+ * in the meantime by another thread.
+ *
+ * @param this the manager object
+ * @return a list with ike_sa_id_t s
+ */
+ linked_list_t *(*get_ike_sa_list) (ike_sa_manager_t* this);
+
+ /**
+ * @brief Log the status of the IKE_SA's in the manager.
+ *
+ * A informational log is done to the supplied logger. If logger is
+ * NULL, an internal logger is used. If a name is supplied,
+ * only connections with the matching name will be logged.
+ *
+ * @param this the manager object
+ * @param logger logger to do the log, or NULL
+ * @param name name of a connection, or NULL
+ */
+ void (*log_status) (ike_sa_manager_t* this, logger_t* logger, char* name);
+
+ /**
+ * @brief 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[in/out] the SA identifier, will be updated
+ * @param ike_sa[out] checked out SA
+ * @returns
+ * - SUCCESS if checked in
+ * - NOT_FOUND when not found (shouldn't happen!)
+ */
+ status_t (*checkin) (ike_sa_manager_t* this, ike_sa_t *ike_sa);
+
+ /**
+ * @brief Delete a SA, which was not checked out.
+ *
+ * @warning do not use this when the SA is already checked out, this will
+ * deadlock!
+ *
+ * @param this the manager object
+ * @param ike_sa_id[in/out] the SA identifier
+ * @returns
+ * - SUCCESS if found
+ * - NOT_FOUND when no such SA is available
+ */
+ status_t (*delete) (ike_sa_manager_t* this, ike_sa_id_t *ike_sa_id);
+
+ /**
+ * @brief Delete a checked out SA.
+ *
+ * @param this the manager object
+ * @param ike_sa SA to delete
+ * @returns
+ * - SUCCESS if found
+ * - NOT_FOUND when no such SA is available
+ */
+ status_t (*checkin_and_delete) (ike_sa_manager_t* this, ike_sa_t *ike_sa);
+
+ /**
+ * @brief 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
+ *
+ * @ingroup sa
+ */
+ike_sa_manager_t *ike_sa_manager_create();
+
+#endif /*IKE_SA_MANAGER_H_*/
diff --git a/programs/charon/charon/sa/states/Makefile.states b/programs/charon/charon/sa/states/Makefile.states
new file mode 100644
index 000000000..a258ebef0
--- /dev/null
+++ b/programs/charon/charon/sa/states/Makefile.states
@@ -0,0 +1,43 @@
+# Copyright (C) 2005 Jan Hutter, Martin Willi
+# Hochschule fuer Technik Rapperswil
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+
+STATES_DIR= $(SA_DIR)states/
+
+CHARON_OBJS+= $(BUILD_DIR)ike_auth_requested.o
+$(BUILD_DIR)ike_auth_requested.o : $(STATES_DIR)ike_auth_requested.c $(STATES_DIR)ike_auth_requested.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)ike_sa_established.o
+$(BUILD_DIR)ike_sa_established.o : $(STATES_DIR)ike_sa_established.c $(STATES_DIR)ike_sa_established.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)ike_sa_init_requested.o
+$(BUILD_DIR)ike_sa_init_requested.o : $(STATES_DIR)ike_sa_init_requested.c $(STATES_DIR)ike_sa_init_requested.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)ike_sa_init_responded.o
+$(BUILD_DIR)ike_sa_init_responded.o : $(STATES_DIR)ike_sa_init_responded.c $(STATES_DIR)ike_sa_init_responded.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)initiator_init.o
+$(BUILD_DIR)initiator_init.o : $(STATES_DIR)initiator_init.c $(STATES_DIR)initiator_init.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)responder_init.o
+$(BUILD_DIR)responder_init.o : $(STATES_DIR)responder_init.c $(STATES_DIR)responder_init.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)state.o
+$(BUILD_DIR)state.o : $(STATES_DIR)state.c $(STATES_DIR)state.h
+ $(CC) $(CFLAGS) -c -o $@ $< \ No newline at end of file
diff --git a/programs/charon/charon/sa/states/ike_auth_requested.c b/programs/charon/charon/sa/states/ike_auth_requested.c
new file mode 100644
index 000000000..3d49f440f
--- /dev/null
+++ b/programs/charon/charon/sa/states/ike_auth_requested.c
@@ -0,0 +1,671 @@
+/**
+ * @file ike_auth_requested.c
+ *
+ * @brief Implementation of ike_auth_requested_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+
+#include "ike_auth_requested.h"
+
+#include <daemon.h>
+#include <encoding/payloads/ts_payload.h>
+#include <encoding/payloads/sa_payload.h>
+#include <encoding/payloads/id_payload.h>
+#include <encoding/payloads/auth_payload.h>
+#include <encoding/payloads/notify_payload.h>
+#include <crypto/signers/signer.h>
+#include <crypto/crypters/crypter.h>
+#include <sa/states/ike_sa_established.h>
+#include <sa/authenticator.h>
+#include <sa/child_sa.h>
+
+typedef struct private_ike_auth_requested_t private_ike_auth_requested_t;
+
+/**
+ * Private data of a ike_auth_requested_t object.
+ *
+ */
+struct private_ike_auth_requested_t {
+ /**
+ * Public interface of ike_auth_requested_t.
+ */
+ ike_auth_requested_t public;
+
+ /**
+ * Assigned IKE_SA.
+ */
+ protected_ike_sa_t *ike_sa;
+
+ /**
+ * SA config, just a copy of the one stored in the ike_sa.
+ */
+ policy_t *policy;
+
+ /**
+ * Received nonce from responder.
+ */
+ chunk_t received_nonce;
+
+ /**
+ * Sent nonce in IKE_SA_INIT request.
+ */
+ chunk_t sent_nonce;
+
+ /**
+ * IKE_SA_INIT-Request in binary form.
+ */
+ chunk_t ike_sa_init_reply_data;
+
+ /**
+ * Proposal to setup CHILD_SA
+ */
+ proposal_t *proposal;
+
+ /**
+ * Traffic selectors applicable at our site
+ */
+ linked_list_t *my_ts;
+
+ /**
+ * Traffic selectors applicable at remote site
+ */
+ linked_list_t *other_ts;
+
+ /**
+ * Child sa created in ike_sa_init_requested
+ */
+ child_sa_t *child_sa;
+
+ /**
+ * Assigned Logger.
+ *
+ * Is logger of ike_sa!
+ */
+ logger_t *logger;
+
+ /**
+ * Process the IDr payload (check if other id is valid)
+ *
+ * @param this calling object
+ * @param idr_payload ID payload of responder
+ * @return
+ * - SUCCESS
+ * - DELETE_ME
+ */
+ status_t (*process_idr_payload) (private_ike_auth_requested_t *this, id_payload_t *idr_payload);
+
+ /**
+ * Process the SA payload (check if selected proposals are valid, setup child sa)
+ *
+ * @param this calling object
+ * @param sa_payload SA payload of responder
+ *
+ * - SUCCESS
+ * - DELETE_ME
+ */
+ status_t (*process_sa_payload) (private_ike_auth_requested_t *this, sa_payload_t *sa_payload);
+
+ /**
+ * Process the AUTH payload (check authenticity of message)
+ *
+ * @param this calling object
+ * @param auth_payload AUTH payload of responder
+ * @param other_id_payload ID payload of responder
+ *
+ * - SUCCESS
+ * - DELETE_ME
+ */
+ status_t (*process_auth_payload) (private_ike_auth_requested_t *this, auth_payload_t *auth_payload, id_payload_t *other_id_payload);
+
+ /**
+ * Process the TS payload (check if selected traffic selectors are valid)
+ *
+ * @param this calling object
+ * @param ts_initiator TRUE if TS payload is TSi, FALSE for TSr
+ * @param ts_payload TS payload of responder
+ *
+ * - SUCCESS
+ * - DELETE_ME
+ */
+ status_t (*process_ts_payload) (private_ike_auth_requested_t *this, bool ts_initiator, ts_payload_t *ts_payload);
+
+ /**
+ * Process a notify payload
+ *
+ * @param this calling object
+ * @param notify_payload notify payload
+ *
+ * - SUCCESS
+ * - FAILED
+ * - DELETE_ME
+ */
+ status_t (*process_notify_payload) (private_ike_auth_requested_t *this, notify_payload_t *notify_payload);
+
+ /**
+ * Destroy function called internally of this class after state change to
+ * state IKE_SA_ESTABLISHED succeeded.
+ *
+ * This destroy function does not destroy objects which were passed to the new state.
+ *
+ * @param this calling object
+ */
+ void (*destroy_after_state_change) (private_ike_auth_requested_t *this);
+};
+
+
+/**
+ * Implements state_t.process_message
+ */
+static status_t process_message(private_ike_auth_requested_t *this, message_t *ike_auth_reply)
+{
+ ts_payload_t *tsi_payload = NULL, *tsr_payload = NULL;
+ id_payload_t *idr_payload = NULL;
+ auth_payload_t *auth_payload = NULL;
+ sa_payload_t *sa_payload = NULL;
+ iterator_t *payloads = NULL;
+ crypter_t *crypter = NULL;
+ signer_t *signer = NULL;
+ status_t status;
+ host_t *my_host, *other_host;
+ chunk_t seed;
+ prf_plus_t *prf_plus;
+ connection_t *connection;
+
+ if (ike_auth_reply->get_exchange_type(ike_auth_reply) != IKE_AUTH)
+ {
+ this->logger->log(this->logger, ERROR | LEVEL1, "Message of type %s not supported in state ike_auth_requested",
+ mapping_find(exchange_type_m,ike_auth_reply->get_exchange_type(ike_auth_reply)));
+ return FAILED;
+ }
+
+ if (ike_auth_reply->get_request(ike_auth_reply))
+ {
+ this->logger->log(this->logger, ERROR | LEVEL1, "IKE_AUTH requests not allowed state ike_sa_init_responded");
+ return FAILED;
+ }
+
+ /* get signer for verification and crypter for decryption */
+ signer = this->ike_sa->get_signer_responder(this->ike_sa);
+ crypter = this->ike_sa->get_crypter_responder(this->ike_sa);
+
+ /* parse incoming message */
+ status = ike_auth_reply->parse_body(ike_auth_reply, crypter, signer);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, AUDIT, "IKE_AUTH reply decryption failed. Ignoring message");
+ return status;
+ }
+
+ this->policy = this->ike_sa->get_policy(this->ike_sa);
+
+ /* we collect all payloads, which are processed later. Notify's are processed
+ * in place, since we don't know how may are there.
+ */
+ payloads = ike_auth_reply->get_payload_iterator(ike_auth_reply);
+ while (payloads->has_next(payloads))
+ {
+ payload_t *payload;
+ payloads->current(payloads, (void**)&payload);
+
+ switch (payload->get_type(payload))
+ {
+ case AUTHENTICATION:
+ {
+ auth_payload = (auth_payload_t*)payload;
+ break;
+ }
+ case ID_RESPONDER:
+ {
+ idr_payload = (id_payload_t*)payload;
+ break;
+ }
+ case SECURITY_ASSOCIATION:
+ {
+ sa_payload = (sa_payload_t*)payload;
+ break;
+ }
+ case TRAFFIC_SELECTOR_INITIATOR:
+ {
+ tsi_payload = (ts_payload_t*)payload;
+ break;
+ }
+ case TRAFFIC_SELECTOR_RESPONDER:
+ {
+ tsr_payload = (ts_payload_t*)payload;
+ break;
+ }
+ case NOTIFY:
+ {
+ notify_payload_t *notify_payload = (notify_payload_t *) payload;
+ /* handle the notify directly, abort if no further processing required */
+ status = this->process_notify_payload(this, notify_payload);
+ if (status != SUCCESS)
+ {
+ payloads->destroy(payloads);
+ return status;
+ }
+ }
+ case CERTIFICATE:
+ {
+ /* TODO handle cert payloads */
+ }
+ default:
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1, "Ignoring Payload %s (%d)",
+ mapping_find(payload_type_m, payload->get_type(payload)), payload->get_type(payload));
+ break;
+ }
+ }
+ }
+ /* iterator can be destroyed */
+ payloads->destroy(payloads);
+
+ /* check if we have all payloads */
+ if (!(idr_payload && sa_payload && auth_payload && tsi_payload && tsr_payload))
+ {
+ this->logger->log(this->logger, AUDIT, "IKE_AUTH reply did not contain all required payloads. Deleting IKE_SA");
+ return DELETE_ME;
+ }
+
+ /* process all payloads */
+ status = this->process_idr_payload(this, idr_payload);
+ if (status != SUCCESS)
+ {
+ return status;
+ }
+ status = this->process_auth_payload(this, auth_payload,idr_payload);
+ if (status != SUCCESS)
+ {
+ return status;
+ }
+ status = this->process_sa_payload(this, sa_payload);
+ if (status != SUCCESS)
+ {
+ return status;
+ }
+ status = this->process_ts_payload(this, TRUE, tsi_payload);
+ if (status != SUCCESS)
+ {
+ return status;
+ }
+ status = this->process_ts_payload(this, FALSE, tsr_payload);
+ if (status != SUCCESS)
+ {
+ return status;
+ }
+
+ /* install child SAs for AH and esp */
+ if (!this->child_sa)
+ {
+ this->logger->log(this->logger, CONTROL, "No CHILD_SA requested, no CHILD_SA built");
+ }
+ if (!this->proposal)
+ {
+ this->logger->log(this->logger, CONTROL, "Proposal negotiation failed, no CHILD_SA built");
+ this->child_sa->destroy(this->child_sa);
+ this->child_sa = NULL;
+ }
+ else if (this->my_ts->get_count(this->my_ts) == 0 || this->other_ts->get_count(this->other_ts) == 0)
+ {
+ this->logger->log(this->logger, CONTROL, "Traffic selector negotiation failed, no CHILD_SA built");
+ this->child_sa->destroy(this->child_sa);
+ this->child_sa = NULL;
+ }
+ else
+ {
+ seed = chunk_alloc(this->sent_nonce.len + this->received_nonce.len);
+ memcpy(seed.ptr, this->sent_nonce.ptr, this->sent_nonce.len);
+ memcpy(seed.ptr + this->sent_nonce.len, this->received_nonce.ptr, this->received_nonce.len);
+ prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed);
+ chunk_free(&seed);
+
+ status = this->child_sa->update(this->child_sa, this->proposal, prf_plus);
+ prf_plus->destroy(prf_plus);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA! Deleting IKE_SA");
+ return DELETE_ME;
+ }
+ status = this->child_sa->add_policies(this->child_sa, this->my_ts, this->other_ts);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA policy! Deleting IKE_SA");
+ return DELETE_ME;
+ }
+ this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
+ }
+
+ this->ike_sa->set_last_replied_message_id(this->ike_sa,ike_auth_reply->get_message_id(ike_auth_reply));
+
+ /* create new state */
+ this->ike_sa->set_new_state(this->ike_sa, (state_t*)ike_sa_established_create(this->ike_sa));
+ this->destroy_after_state_change(this);
+
+ connection = this->ike_sa->get_connection(this->ike_sa);
+ my_host = connection->get_my_host(connection);
+ other_host = connection->get_other_host(connection);
+ this->logger->log(this->logger, AUDIT, "IKE_SA established between %s - %s",
+ my_host->get_address(my_host), other_host->get_address(other_host));
+
+ return SUCCESS;
+}
+
+/**
+ * Implements private_ike_auth_requested_t.process_idr_payload
+ */
+static status_t process_idr_payload(private_ike_auth_requested_t *this, id_payload_t *idr_payload)
+{
+ identification_t *other_id, *configured_other_id;
+ connection_t *connection;
+
+ other_id = idr_payload->get_identification(idr_payload);
+ configured_other_id = this->policy->get_other_id(this->policy);
+
+ this->logger->log(this->logger, CONTROL|LEVEL1, "configured ID: %s, ID of responder: %s",
+ configured_other_id->get_string(configured_other_id),
+ other_id->get_string(other_id));
+
+ if (!other_id->belongs_to(other_id, configured_other_id))
+ {
+ other_id->destroy(other_id);
+ this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained a not acceptable ID. Deleting IKE_SA");
+ return DELETE_ME;
+ }
+
+ connection = this->ike_sa->get_connection(this->ike_sa);
+ connection->update_other_id(connection, other_id->clone(other_id));
+
+ this->policy->update_other_id(this->policy, other_id);
+ return SUCCESS;
+}
+
+/**
+ * Implements private_ike_auth_requested_t.process_sa_payload
+ */
+static status_t process_sa_payload(private_ike_auth_requested_t *this, sa_payload_t *sa_payload)
+{
+ proposal_t *proposal, *proposal_tmp;
+ linked_list_t *proposal_list;
+
+ /* get his selected proposal */
+ proposal_list = sa_payload->get_proposals(sa_payload);
+ /* check count of proposals */
+ if (proposal_list->get_count(proposal_list) == 0)
+ {
+ /* no proposal? we accept this, but no child sa is built */
+ this->logger->log(this->logger, AUDIT, "IKE_AUTH reply's SA_PAYLOAD didn't contain any proposals. No CHILD_SA created",
+ proposal_list->get_count(proposal_list));
+ proposal_list->destroy(proposal_list);
+ return SUCCESS;
+ }
+ if (proposal_list->get_count(proposal_list) > 1)
+ {
+ this->logger->log(this->logger, AUDIT, "IKE_AUTH reply's SA_PAYLOAD contained %d proposal. Deleting IKE_SA",
+ proposal_list->get_count(proposal_list));
+ while (proposal_list->remove_last(proposal_list, (void**)&proposal) == SUCCESS)
+ {
+ proposal->destroy(proposal);
+ }
+ proposal_list->destroy(proposal_list);
+ return DELETE_ME;
+ }
+
+ /* we have to re-check here if other's selection is valid */
+ proposal = this->policy->select_proposal(this->policy, proposal_list);
+ /* list not needed anymore */
+ while (proposal_list->remove_last(proposal_list, (void**)&proposal_tmp) == SUCCESS)
+ {
+ proposal_tmp->destroy(proposal_tmp);
+ }
+ proposal_list->destroy(proposal_list);
+ /* got a match? */
+ if (proposal == NULL)
+ {
+ this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained a not offered proposal. Deleting IKE_SA");
+ return DELETE_ME;
+ }
+
+ /* apply proposal */
+ this->proposal = proposal;
+
+ return SUCCESS;
+}
+
+/**
+ * Implements private_ike_auth_requested_t.process_auth_payload
+ */
+static status_t process_auth_payload(private_ike_auth_requested_t *this, auth_payload_t *auth_payload, id_payload_t *other_id_payload)
+{
+ authenticator_t *authenticator;
+ status_t status;
+
+ authenticator = authenticator_create(this->ike_sa);
+ status = authenticator->verify_auth_data(authenticator,auth_payload,this->ike_sa_init_reply_data,this->sent_nonce,other_id_payload,FALSE);
+ authenticator->destroy(authenticator);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, AUDIT, "Verification of IKE_AUTH reply failed. Deleting IKE_SA");
+ return DELETE_ME;
+ }
+
+ this->logger->log(this->logger, CONTROL|LEVEL1, "AUTH data verified successfully");
+ return SUCCESS;
+}
+
+/**
+ * Implements private_ike_auth_requested_t.process_ts_payload
+ */
+static status_t process_ts_payload(private_ike_auth_requested_t *this, bool ts_initiator, ts_payload_t *ts_payload)
+{
+ linked_list_t *ts_received, *ts_selected;
+ traffic_selector_t *ts;
+
+ /* get ts form payload */
+ ts_received = ts_payload->get_traffic_selectors(ts_payload);
+ /* select ts depending on payload type */
+ if (ts_initiator)
+ {
+ ts_selected = this->policy->select_my_traffic_selectors(this->policy, ts_received);
+ this->my_ts = ts_selected;
+ }
+ else
+ {
+ ts_selected = this->policy->select_other_traffic_selectors(this->policy, ts_received);
+ this->other_ts = ts_selected;
+ }
+ /* check if the responder selected valid proposals */
+ if (ts_selected->get_count(ts_selected) != ts_received->get_count(ts_received))
+ {
+ this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained not offered traffic selectors.");
+ }
+
+ /* cleanup */
+ while (ts_received->remove_last(ts_received, (void**)&ts) == SUCCESS)
+ {
+ ts->destroy(ts);
+ }
+ ts_received->destroy(ts_received);
+
+ return SUCCESS;
+}
+
+/**
+ * Implements private_ike_auth_requested_t.process_notify_payload
+ */
+static status_t process_notify_payload(private_ike_auth_requested_t *this, notify_payload_t *notify_payload)
+{
+ notify_message_type_t notify_message_type = notify_payload->get_notify_message_type(notify_payload);
+
+ this->logger->log(this->logger, CONTROL|LEVEL1, "Process notify type %s",
+ mapping_find(notify_message_type_m, notify_message_type));
+
+ switch (notify_message_type)
+ {
+ case INVALID_SYNTAX:
+ {
+ this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained an INVALID_SYNTAX notify. Deleting IKE_SA");
+ return DELETE_ME;
+
+ }
+ case AUTHENTICATION_FAILED:
+ {
+ this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained an AUTHENTICATION_FAILED notify. Deleting IKE_SA");
+ return DELETE_ME;
+
+ }
+ case SINGLE_PAIR_REQUIRED:
+ {
+ this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained a SINGLE_PAIR_REQUIRED notify. Deleting IKE_SA");
+ return DELETE_ME;
+ }
+ default:
+ {
+ /*
+ * - In case of unknown error: IKE_SA gets destroyed.
+ * - In case of unknown status: logging
+ */
+
+ if (notify_message_type < 16383)
+ {
+ this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained an unknown notify error (%d). Deleting IKE_SA",
+ notify_message_type);
+ return DELETE_ME;
+
+ }
+ else
+ {
+ this->logger->log(this->logger, CONTROL, "IKE_AUTH reply contained an unknown notify (%d), ignored.",
+ notify_message_type);
+ return SUCCESS;
+ }
+ }
+ }
+}
+
+/**
+ * Implements state_t.get_state
+ */
+static ike_sa_state_t get_state(private_ike_auth_requested_t *this)
+{
+ return IKE_AUTH_REQUESTED;
+}
+
+/**
+ * Implements state_t.get_state
+ */
+static void destroy(private_ike_auth_requested_t *this)
+{
+ chunk_free(&(this->received_nonce));
+ chunk_free(&(this->sent_nonce));
+ chunk_free(&(this->ike_sa_init_reply_data));
+ if (this->child_sa)
+ {
+ this->child_sa->destroy(this->child_sa);
+ }
+ if (this->my_ts)
+ {
+ traffic_selector_t *ts;
+ while (this->my_ts->remove_last(this->my_ts, (void**)&ts) == SUCCESS)
+ {
+ ts->destroy(ts);
+ }
+ this->my_ts->destroy(this->my_ts);
+ }
+ if (this->other_ts)
+ {
+ traffic_selector_t *ts;
+ while (this->other_ts->remove_last(this->other_ts, (void**)&ts) == SUCCESS)
+ {
+ ts->destroy(ts);
+ }
+ this->other_ts->destroy(this->other_ts);
+ }
+ if (this->proposal)
+ {
+ this->proposal->destroy(this->proposal);
+ }
+ free(this);
+}
+/**
+ * Implements protected_ike_sa_t.destroy_after_state_change
+ */
+static void destroy_after_state_change(private_ike_auth_requested_t *this)
+{
+ chunk_free(&(this->received_nonce));
+ chunk_free(&(this->sent_nonce));
+ chunk_free(&(this->ike_sa_init_reply_data));
+ if (this->my_ts)
+ {
+ traffic_selector_t *ts;
+ while (this->my_ts->remove_last(this->my_ts, (void**)&ts) == SUCCESS)
+ {
+ ts->destroy(ts);
+ }
+ this->my_ts->destroy(this->my_ts);
+ }
+ if (this->other_ts)
+ {
+ traffic_selector_t *ts;
+ while (this->other_ts->remove_last(this->other_ts, (void**)&ts) == SUCCESS)
+ {
+ ts->destroy(ts);
+ }
+ this->other_ts->destroy(this->other_ts);
+ }
+ if (this->proposal)
+ {
+ this->proposal->destroy(this->proposal);
+ }
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+ike_auth_requested_t *ike_auth_requested_create(protected_ike_sa_t *ike_sa,chunk_t sent_nonce,chunk_t received_nonce,chunk_t ike_sa_init_reply_data, child_sa_t *child_sa)
+{
+ private_ike_auth_requested_t *this = malloc_thing(private_ike_auth_requested_t);
+
+ /* interface functions */
+ this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
+ this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
+ this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
+
+ /* private functions */
+ this->process_idr_payload = process_idr_payload;
+ this->process_sa_payload = process_sa_payload;
+ this->process_auth_payload = process_auth_payload;
+ this->process_ts_payload = process_ts_payload;
+ this->process_notify_payload = process_notify_payload;
+ this->destroy_after_state_change = destroy_after_state_change;
+
+ /* private data */
+ this->ike_sa = ike_sa;
+ this->received_nonce = received_nonce;
+ this->sent_nonce = sent_nonce;
+ this->ike_sa_init_reply_data = ike_sa_init_reply_data;
+ this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
+ this->my_ts = NULL;
+ this->other_ts = NULL;
+ this->proposal = NULL;
+ this->child_sa = child_sa;
+
+ return &(this->public);
+}
diff --git a/programs/charon/charon/sa/states/ike_auth_requested.h b/programs/charon/charon/sa/states/ike_auth_requested.h
new file mode 100644
index 000000000..a8eef014c
--- /dev/null
+++ b/programs/charon/charon/sa/states/ike_auth_requested.h
@@ -0,0 +1,72 @@
+/**
+ * @file ike_auth_requested.h
+ *
+ * @brief Interface of ike_auth_requested_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef IKE_AUTH_REQUESTED_H_
+#define IKE_AUTH_REQUESTED_H_
+
+#include <sa/states/state.h>
+#include <sa/ike_sa.h>
+
+
+typedef struct ike_auth_requested_t ike_auth_requested_t;
+
+/**
+ * @brief This class represents an IKE_SA, which has requested an IKE_AUTH.
+ *
+ * The state accpets IKE_AUTH responses. It proves the authenticity
+ * and sets up the first child sa. After that, it changes IKE_SA state to
+ * IKE_SA_ESTABLISHED.
+ *
+ * @ Constructors:
+ * - ike_auth_requested_create()
+ *
+ * @todo handle certificate payloads
+ *
+ * @ingroup states
+ */
+struct ike_auth_requested_t {
+ /**
+ * The state_t interface.
+ */
+ state_t state_interface;
+
+};
+
+/**
+ * Constructor of class ike_auth_requested_t
+ *
+ * @param ike_sa assigned ike_sa object
+ * @param sent_nonce Sent nonce value in IKE_SA_INIT request
+ * @param received_nonce Received nonce value in IKE_SA_INIT response
+ * @param ike_sa_init_reply_data binary representation of IKE_SA_INIT reply
+ * @param child_sa opened but not completed child_sa
+ * @return created ike_auth_requested_t object
+ *
+ * @ingroup states
+ */
+ike_auth_requested_t *ike_auth_requested_create(protected_ike_sa_t *ike_sa,
+ chunk_t sent_nonce,
+ chunk_t received_nonce,
+ chunk_t ike_sa_init_reply_data,
+ child_sa_t *child_sa);
+
+#endif /*IKE_AUTH_REQUESTED_H_*/
diff --git a/programs/charon/charon/sa/states/ike_sa_established.c b/programs/charon/charon/sa/states/ike_sa_established.c
new file mode 100644
index 000000000..e91409f6a
--- /dev/null
+++ b/programs/charon/charon/sa/states/ike_sa_established.c
@@ -0,0 +1,239 @@
+/**
+ * @file ike_sa_established.c
+ *
+ * @brief Implementation of ike_sa_established_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "ike_sa_established.h"
+
+#include <daemon.h>
+#include <encoding/payloads/delete_payload.h>
+
+
+typedef struct private_ike_sa_established_t private_ike_sa_established_t;
+
+/**
+ * Private data of a ike_sa_established_t object.
+ */
+struct private_ike_sa_established_t {
+ /**
+ * methods of the state_t interface
+ */
+ ike_sa_established_t public;
+
+ /**
+ * Assigned IKE_SA.
+ */
+ protected_ike_sa_t *ike_sa;
+
+ /**
+ * Assigned logger. Use logger of IKE_SA.
+ */
+ logger_t *logger;
+
+ /**
+ * Process a notify payload
+ *
+ * @param this calling object
+ * @param notify_payload notify payload
+ * @param response response message of type INFORMATIONAL
+ *
+ * - SUCCESS
+ * - FAILED
+ * - DELETE_ME
+ */
+ status_t (*process_notify_payload) (private_ike_sa_established_t *this, notify_payload_t *notify_payload,message_t *response);
+};
+
+/**
+ * Implements state_t.get_state
+ */
+static status_t process_message(private_ike_sa_established_t *this, message_t *message)
+{
+ delete_payload_t *delete_request = NULL;
+ ike_sa_id_t *ike_sa_id;
+ iterator_t *payloads;
+ message_t *response;
+ crypter_t *crypter;
+ signer_t *signer;
+ status_t status;
+
+ if (message->get_exchange_type(message) != INFORMATIONAL)
+ {
+ this->logger->log(this->logger, ERROR | LEVEL1, "Message of type %s not supported in state ike_sa_established",
+ mapping_find(exchange_type_m,message->get_exchange_type(message)));
+ return FAILED;
+ }
+
+ if (!message->get_request(message))
+ {
+ this->logger->log(this->logger, ERROR | LEVEL1, "INFORMATIONAL responses not handled in state ike_sa_established");
+ return FAILED;
+ }
+
+ ike_sa_id = this->ike_sa->public.get_id(&(this->ike_sa->public));
+
+ /* get signer for verification and crypter for decryption */
+ if (!ike_sa_id->is_initiator(ike_sa_id))
+ {
+ crypter = this->ike_sa->get_crypter_initiator(this->ike_sa);
+ signer = this->ike_sa->get_signer_initiator(this->ike_sa);
+ }
+ else
+ {
+ crypter = this->ike_sa->get_crypter_responder(this->ike_sa);
+ signer = this->ike_sa->get_signer_responder(this->ike_sa);
+ }
+
+ /* parse incoming message */
+ status = message->parse_body(message, crypter, signer);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, AUDIT, "INFORMATIONAL request decryption failed. Ignoring message");
+ return status;
+ }
+
+ /* build empty INFORMATIONAL message */
+ this->ike_sa->build_message(this->ike_sa, INFORMATIONAL, FALSE, &response);
+
+ payloads = message->get_payload_iterator(message);
+
+ while (payloads->has_next(payloads))
+ {
+ payload_t *payload;
+ payloads->current(payloads, (void**)&payload);
+
+ switch (payload->get_type(payload))
+ {
+ case NOTIFY:
+ {
+ notify_payload_t *notify_payload = (notify_payload_t *) payload;
+ /* handle the notify directly, abort if no further processing required */
+ status = this->process_notify_payload(this, notify_payload,response);
+ if (status != SUCCESS)
+ {
+ payloads->destroy(payloads);
+ response->destroy(response);
+ return status;
+ }
+ }
+ case DELETE:
+ {
+ delete_request = (delete_payload_t *) payload;
+ break;
+ }
+ default:
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1, "Ignoring Payload %s (%d)",
+ mapping_find(payload_type_m, payload->get_type(payload)), payload->get_type(payload));
+ break;
+ }
+ }
+ }
+ /* iterator can be destroyed */
+ payloads->destroy(payloads);
+
+ if (delete_request)
+ {
+ if (delete_request->get_protocol_id(delete_request) == PROTO_IKE)
+ {
+ this->logger->log(this->logger, AUDIT, "DELETE request for IKE_SA received");
+ response->destroy(response);
+ return DELETE_ME;
+ }
+ else
+ {
+ this->logger->log(this->logger, AUDIT, "DELETE request for CHILD_SA received. Ignored");
+ response->destroy(response);
+ return SUCCESS;
+ }
+ }
+
+ status = this->ike_sa->send_response(this->ike_sa, response);
+ /* message can now be sent (must not be destroyed) */
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, AUDIT, "Unable to send INFORMATIONAL reply");
+ response->destroy(response);
+ return FAILED;
+ }
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of private_ike_sa_established_t.process_notify_payload;
+ */
+static status_t process_notify_payload (private_ike_sa_established_t *this, notify_payload_t *notify_payload, message_t *response)
+{
+ notify_message_type_t notify_message_type = notify_payload->get_notify_message_type(notify_payload);
+
+ this->logger->log(this->logger, CONTROL|LEVEL1, "Process notify type %s for protocol %s",
+ mapping_find(notify_message_type_m, notify_message_type),
+ mapping_find(protocol_id_m, notify_payload->get_protocol_id(notify_payload)));
+
+ switch (notify_message_type)
+ {
+ default:
+ {
+ this->logger->log(this->logger, AUDIT, "INFORMATIONAL request contained an unknown notify (%d), ignored.", notify_message_type);
+ }
+ }
+
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of state_t.get_state.
+ */
+static ike_sa_state_t get_state(private_ike_sa_established_t *this)
+{
+ return IKE_SA_ESTABLISHED;
+}
+
+/**
+ * Implementation of state_t.get_state
+ */
+static void destroy(private_ike_sa_established_t *this)
+{
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+ike_sa_established_t *ike_sa_established_create(protected_ike_sa_t *ike_sa)
+{
+ private_ike_sa_established_t *this = malloc_thing(private_ike_sa_established_t);
+
+ /* interface functions */
+ this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
+ this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
+ this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
+
+ /* private functions */
+ this->process_notify_payload = process_notify_payload;
+
+ /* private data */
+ this->ike_sa = ike_sa;
+ this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
+
+ return &(this->public);
+}
diff --git a/programs/charon/charon/sa/states/ike_sa_established.h b/programs/charon/charon/sa/states/ike_sa_established.h
new file mode 100644
index 000000000..8477ad5bc
--- /dev/null
+++ b/programs/charon/charon/sa/states/ike_sa_established.h
@@ -0,0 +1,64 @@
+/**
+ * @file ike_sa_established.h
+ *
+ * @brief Interface of ike_sa_established_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef IKE_SA_ESTABLISHED_H_
+#define IKE_SA_ESTABLISHED_H_
+
+#include <sa/states/state.h>
+#include <sa/ike_sa.h>
+
+typedef struct ike_sa_established_t ike_sa_established_t;
+
+/**
+ * @brief This class represents an the state of an established
+ * IKE_SA.
+ *
+ * @b Constructors:
+ * - ike_sa_established_create()
+ *
+ * @todo Implement handling of CREATE_CHILD_SA requests
+ *
+ * @todo Implement initialization of CREATE_CHILD_SA requests
+ *
+ * @todo Implement handling of any other message
+ *
+ * @ingroup states
+ */
+struct ike_sa_established_t {
+ /**
+ * methods of the state_t interface
+ */
+ state_t state_interface;
+
+};
+
+/**
+ * @brief Constructor of class ike_sa_established_t
+ *
+ * @param ike_sa assigned ike_sa
+ * @return created ike_sa_established_t object
+ *
+ * @ingroup states
+ */
+ike_sa_established_t *ike_sa_established_create(protected_ike_sa_t *ike_sa);
+
+#endif /*IKE_SA_ESTABLISHED_H_*/
diff --git a/programs/charon/charon/sa/states/ike_sa_init_requested.c b/programs/charon/charon/sa/states/ike_sa_init_requested.c
new file mode 100644
index 000000000..311cdf0a0
--- /dev/null
+++ b/programs/charon/charon/sa/states/ike_sa_init_requested.c
@@ -0,0 +1,798 @@
+/**
+ * @file ike_sa_init_requested.c
+ *
+ * @brief Implementation of ike_sa_init_requested_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "ike_sa_init_requested.h"
+
+#include <daemon.h>
+#include <encoding/payloads/sa_payload.h>
+#include <encoding/payloads/ke_payload.h>
+#include <encoding/payloads/nonce_payload.h>
+#include <encoding/payloads/notify_payload.h>
+#include <encoding/payloads/id_payload.h>
+#include <encoding/payloads/auth_payload.h>
+#include <encoding/payloads/ts_payload.h>
+#include <crypto/diffie_hellman.h>
+#include <sa/states/ike_auth_requested.h>
+#include <sa/states/initiator_init.h>
+#include <sa/authenticator.h>
+
+
+typedef struct private_ike_sa_init_requested_t private_ike_sa_init_requested_t;
+
+/**
+ * Private data of a ike_sa_init_requested_t object.
+ *
+ */
+struct private_ike_sa_init_requested_t {
+ /**
+ * Public interface of an ike_sa_init_requested_t object.
+ */
+ ike_sa_init_requested_t public;
+
+ /**
+ * Assigned IKE_SA
+ */
+ protected_ike_sa_t *ike_sa;
+
+ /**
+ * Diffie Hellman object used to compute shared secret.
+ */
+ diffie_hellman_t *diffie_hellman;
+
+ /**
+ * Sent nonce value.
+ */
+ chunk_t sent_nonce;
+
+ /**
+ * Received nonce
+ */
+ chunk_t received_nonce;
+
+ /**
+ * Selected proposal
+ */
+ proposal_t *proposal;
+
+ /**
+ * Packet data of ike_sa_init request
+ */
+ chunk_t ike_sa_init_request_data;
+
+ /**
+ * Created child sa, if any
+ */
+ child_sa_t *child_sa;
+
+ /**
+ * Assigned logger
+ *
+ * Is logger of ike_sa!
+ */
+ logger_t *logger;
+
+
+ /**
+ * Process NONCE payload of IKE_SA_INIT response.
+ *
+ * @param this calling object
+ * @param nonce_payload NONCE payload to process
+ * @return SUCCESS in any case
+ */
+ status_t (*process_nonce_payload) (private_ike_sa_init_requested_t *this, nonce_payload_t *nonce_payload);
+
+ /**
+ * Process SA payload of IKE_SA_INIT response.
+ *
+ * @param this calling object
+ * @param sa_payload SA payload to process
+ * @return
+ * - SUCCESS
+ * - FAILED
+ */
+ status_t (*process_sa_payload) (private_ike_sa_init_requested_t *this, sa_payload_t *sa_payload);
+
+ /**
+ * Process KE payload of IKE_SA_INIT response.
+ *
+ * @param this calling object
+ * @param sa_payload KE payload to process
+ * @return
+ * - SUCCESS
+ * - FAILED
+ */
+ status_t (*process_ke_payload) (private_ike_sa_init_requested_t *this, ke_payload_t *ke_payload);
+
+ /**
+ * Build ID payload for IKE_AUTH request.
+ *
+ * @param this calling object
+ * @param[out] id_payload buildet ID payload
+ * @param response created payload will be added to this message_t object
+ * @return
+ * - SUCCESS
+ * - FAILED
+ */
+ status_t (*build_id_payload) (private_ike_sa_init_requested_t *this,id_payload_t **id_payload, message_t *response);
+
+ /**
+ * Build IDr payload for IKE_AUTH request.
+ *
+ * Only built when the ID of the responder contains no wildcards.
+ *
+ * @param this calling object
+ * @param response created payload will be added to this message_t object
+ * @return
+ * - SUCCESS
+ * - FAILED
+ */
+ status_t (*build_idr_payload) (private_ike_sa_init_requested_t *this, message_t *response);
+
+ /**
+ * Build AUTH payload for IKE_AUTH request.
+ *
+ * @param this calling object
+ * @param my_id_payload buildet ID payload
+ * @param response created payload will be added to this message_t object
+ * @return
+ * - SUCCESS
+ * - FAILED
+ */
+ status_t (*build_auth_payload) (private_ike_sa_init_requested_t *this,id_payload_t *my_id_payload, message_t *response);
+
+ /**
+ * Build SA payload for IKE_AUTH request.
+ *
+ * @param this calling object
+ * @param response created payload will be added to this message_t object
+ * @return
+ * - SUCCESS
+ * - FAILED
+ */
+ status_t (*build_sa_payload) (private_ike_sa_init_requested_t *this, message_t *response);
+
+ /**
+ * Build TSi payload for IKE_AUTH request.
+ *
+ * @param this calling object
+ * @param response created payload will be added to this message_t object
+ * @return
+ * - SUCCESS
+ * - FAILED
+ */
+ status_t (*build_tsi_payload) (private_ike_sa_init_requested_t *this, message_t *response);
+
+ /**
+ * Build TSr payload for IKE_AUTH request.
+ *
+ * @param this calling object
+ * @param response created payload will be added to this message_t object
+ * @return
+ * - SUCCESS
+ * - FAILED
+ */
+ status_t (*build_tsr_payload) (private_ike_sa_init_requested_t *this, message_t *response);
+
+ /**
+ * Process a notify payload and react.
+ *
+ * @param this calling object
+ * @param notify_payload notify_payload to handle
+ */
+ status_t (*process_notify_payload) (private_ike_sa_init_requested_t *this, notify_payload_t *notify_payload);
+
+ /**
+ * Destroy function called internally of this class after state change to
+ * state IKE_AUTH_REQUESTED succeeded.
+ *
+ * This destroy function does not destroy objects which were passed to the new state.
+ *
+ * @param this calling object
+ */
+ void (*destroy_after_state_change) (private_ike_sa_init_requested_t *this);
+};
+
+/**
+ * Implementation of state_t.process_message.
+ */
+static status_t process_message(private_ike_sa_init_requested_t *this, message_t *ike_sa_init_reply)
+{
+ ike_auth_requested_t *next_state;
+ chunk_t ike_sa_init_reply_data;
+ sa_payload_t *sa_payload = NULL;
+ ke_payload_t *ke_payload = NULL;
+ id_payload_t *id_payload = NULL;
+ nonce_payload_t *nonce_payload = NULL;
+ u_int64_t responder_spi;
+ ike_sa_id_t *ike_sa_id;
+ iterator_t *payloads;
+ host_t *me;
+ connection_t *connection;
+ policy_t *policy;
+
+ message_t *request;
+ status_t status;
+
+ /*
+ * In this state a reply message of type IKE_SA_INIT is expected:
+ *
+ * <-- HDR, SAr1, KEr, Nr, [CERTREQ]
+ * or
+ * <-- HDR, N
+ */
+
+ if (ike_sa_init_reply->get_exchange_type(ike_sa_init_reply) != IKE_SA_INIT)
+ {
+ this->logger->log(this->logger, ERROR | LEVEL1, "Message of type %s not supported in state ike_sa_init_requested",
+ mapping_find(exchange_type_m,ike_sa_init_reply->get_exchange_type(ike_sa_init_reply)));
+ return FAILED;
+ }
+
+ if (ike_sa_init_reply->get_request(ike_sa_init_reply))
+ {
+ this->logger->log(this->logger, ERROR | LEVEL1, "IKE_SA_INIT requests not allowed state ike_sa_init_responded");
+ return FAILED;
+ }
+
+ /* parse incoming message */
+ status = ike_sa_init_reply->parse_body(ike_sa_init_reply, NULL, NULL);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, ERROR | LEVEL1, "IKE_SA_INIT reply parsing faild. Ignoring message");
+ return status;
+ }
+
+ /* because we are original initiator we have to update the responder SPI to the new one */
+ responder_spi = ike_sa_init_reply->get_responder_spi(ike_sa_init_reply);
+ if (responder_spi == 0)
+ {
+ this->logger->log(this->logger, ERROR | LEVEL1, "IKE_SA_INIT reply contained a SPI of zero");
+ return FAILED;
+ }
+ ike_sa_id = this->ike_sa->public.get_id(&(this->ike_sa->public));
+ ike_sa_id->set_responder_spi(ike_sa_id,responder_spi);
+
+ /* Iterate over all payloads.
+ *
+ * The message is allready checked for the right payload types.
+ */
+ payloads = ike_sa_init_reply->get_payload_iterator(ike_sa_init_reply);
+ while (payloads->has_next(payloads))
+ {
+ payload_t *payload;
+ payloads->current(payloads, (void**)&payload);
+
+ switch (payload->get_type(payload))
+ {
+ case SECURITY_ASSOCIATION:
+ {
+ sa_payload = (sa_payload_t*)payload;
+ break;
+ }
+ case KEY_EXCHANGE:
+ {
+ ke_payload = (ke_payload_t*)payload;
+ break;
+ }
+ case NONCE:
+ {
+ nonce_payload = (nonce_payload_t*)payload;
+ break;
+ }
+ case NOTIFY:
+ {
+ notify_payload_t *notify_payload = (notify_payload_t *) payload;
+
+ status = this->process_notify_payload(this, notify_payload);
+ if (status != SUCCESS)
+ {
+ payloads->destroy(payloads);
+ return status;
+ }
+ break;
+ }
+ default:
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1, "Ignoring payload %s (%d)",
+ mapping_find(payload_type_m, payload->get_type(payload)), payload->get_type(payload));
+ break;
+ }
+
+ }
+
+ }
+ payloads->destroy(payloads);
+
+ if (!(nonce_payload && sa_payload && ke_payload))
+ {
+ this->logger->log(this->logger, AUDIT, "IKE_SA_INIT reply did not contain all required payloads. Deleting IKE_SA");
+ return DELETE_ME;
+ }
+
+ status = this->process_nonce_payload (this,nonce_payload);
+ if (status != SUCCESS)
+ {
+ return status;
+ }
+
+ status = this->process_sa_payload (this,sa_payload);
+ if (status != SUCCESS)
+ {
+ return status;
+ }
+
+ status = this->process_ke_payload (this,ke_payload);
+ if (status != SUCCESS)
+ {
+ return status;
+ }
+
+ /* derive all the keys used in the IKE_SA */
+ status = this->ike_sa->build_transforms(this->ike_sa, this->proposal, this->diffie_hellman, this->sent_nonce, this->received_nonce);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, AUDIT, "Transform objects could not be created from selected proposal. Deleting IKE_SA");
+ return DELETE_ME;
+ }
+
+ /* apply the address on wich we really received the packet */
+ connection = this->ike_sa->get_connection(this->ike_sa);
+ me = ike_sa_init_reply->get_destination(ike_sa_init_reply);
+ connection->update_my_host(connection, me->clone(me));
+ policy = this->ike_sa->get_policy(this->ike_sa);
+ policy->update_my_ts(policy, me);
+
+ /* build empty message */
+ this->ike_sa->build_message(this->ike_sa, IKE_AUTH, TRUE, &request);
+
+ status = this->build_id_payload(this, &id_payload, request);
+ if (status != SUCCESS)
+ {
+ request->destroy(request);
+ return status;
+ }
+ status = this->build_idr_payload(this, request);
+ if (status != SUCCESS)
+ {
+ request->destroy(request);
+ return status;
+ }
+ status = this->build_auth_payload(this, (id_payload_t*)id_payload, request);
+ if (status != SUCCESS)
+ {
+ request->destroy(request);
+ return status;
+ }
+ status = this->build_sa_payload(this, request);
+ if (status != SUCCESS)
+ {
+ request->destroy(request);
+ return status;
+ }
+ status = this->build_tsi_payload(this, request);
+ if (status != SUCCESS)
+ {
+ request->destroy(request);
+ return status;
+ }
+ status = this->build_tsr_payload(this, request);
+ if (status != SUCCESS)
+ {
+ request->destroy(request);
+ return status;
+ }
+
+ /* message can now be sent (must not be destroyed) */
+ status = this->ike_sa->send_request(this->ike_sa, request);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, AUDIT, "Unable to send IKE_AUTH request. Deleting IKE_SA");
+ request->destroy(request);
+ return DELETE_ME;
+ }
+
+ this->ike_sa->set_last_replied_message_id(this->ike_sa,ike_sa_init_reply->get_message_id(ike_sa_init_reply));
+
+ ike_sa_init_reply_data = ike_sa_init_reply->get_packet_data(ike_sa_init_reply);
+
+ /* state can now be changed */
+ next_state = ike_auth_requested_create(this->ike_sa, this->sent_nonce, this->received_nonce,
+ ike_sa_init_reply_data, this->child_sa);
+ this->ike_sa->set_new_state(this->ike_sa,(state_t *) next_state);
+
+ this->destroy_after_state_change(this);
+ return SUCCESS;
+}
+
+
+/**
+ * Implementation of private_ike_sa_init_requested_t.process_nonce_payload.
+ */
+status_t process_nonce_payload (private_ike_sa_init_requested_t *this, nonce_payload_t *nonce_payload)
+{
+ free(this->received_nonce.ptr);
+ this->received_nonce = nonce_payload->get_nonce(nonce_payload);
+ return SUCCESS;
+}
+
+
+/**
+ * Implementation of private_ike_sa_init_requested_t.process_sa_payload.
+ */
+status_t process_sa_payload (private_ike_sa_init_requested_t *this, sa_payload_t *sa_payload)
+{
+ proposal_t *proposal;
+ linked_list_t *proposal_list;
+ connection_t *connection;
+
+ connection = this->ike_sa->get_connection(this->ike_sa);
+
+ /* get the list of selected proposals, the peer has to select only one proposal */
+ proposal_list = sa_payload->get_proposals (sa_payload);
+ if (proposal_list->get_count(proposal_list) != 1)
+ {
+ this->logger->log(this->logger, AUDIT, "IKE_SA_INIT response did not contain a single proposal. Deleting IKE_SA");
+ while (proposal_list->remove_last(proposal_list, (void**)&proposal) == SUCCESS)
+ {
+ proposal->destroy(proposal);
+ }
+ proposal_list->destroy(proposal_list);
+ return DELETE_ME;
+ }
+
+ /* we have to re-check if the others selection is valid */
+ this->proposal = connection->select_proposal(connection, proposal_list);
+ while (proposal_list->remove_last(proposal_list, (void**)&proposal) == SUCCESS)
+ {
+ proposal->destroy(proposal);
+ }
+ proposal_list->destroy(proposal_list);
+
+ if (this->proposal == NULL)
+ {
+ this->logger->log(this->logger, AUDIT, "IKE_SA_INIT response contained selected proposal we did not offer. Deleting IKE_SA");
+ return DELETE_ME;
+ }
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of private_ike_sa_init_requested_t.process_ke_payload.
+ */
+status_t process_ke_payload (private_ike_sa_init_requested_t *this, ke_payload_t *ke_payload)
+{
+ this->diffie_hellman->set_other_public_value(this->diffie_hellman, ke_payload->get_key_exchange_data(ke_payload));
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of private_ike_sa_init_requested_t.build_id_payload.
+ */
+static status_t build_id_payload (private_ike_sa_init_requested_t *this,id_payload_t **id_payload, message_t *request)
+{
+ policy_t *policy;
+ id_payload_t *new_id_payload;
+ identification_t *identification;
+
+ policy = this->ike_sa->get_policy(this->ike_sa);
+ identification = policy->get_my_id(policy);
+ new_id_payload = id_payload_create_from_identification(TRUE, identification);
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Add ID payload to message");
+ request->add_payload(request,(payload_t *) new_id_payload);
+
+ *id_payload = new_id_payload;
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of private_ike_sa_init_requested_t.build_idr_payload.
+ */
+static status_t build_idr_payload (private_ike_sa_init_requested_t *this, message_t *request)
+{
+ policy_t *policy;
+ id_payload_t *idr_payload;
+ identification_t *identification;
+
+ policy = this->ike_sa->get_policy(this->ike_sa);
+ identification = policy->get_other_id(policy);
+ if (!identification->contains_wildcards(identification))
+ {
+ idr_payload = id_payload_create_from_identification(FALSE, identification);
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Add IDr payload to message");
+ request->add_payload(request,(payload_t *) idr_payload);
+ }
+ return SUCCESS;
+}
+
+/**
+ * Implementation of private_ike_sa_init_requested_t.build_auth_payload.
+ */
+static status_t build_auth_payload (private_ike_sa_init_requested_t *this, id_payload_t *my_id_payload, message_t *request)
+{
+ authenticator_t *authenticator;
+ auth_payload_t *auth_payload;
+ status_t status;
+
+ authenticator = authenticator_create(this->ike_sa);
+ status = authenticator->compute_auth_data(authenticator,&auth_payload,this->ike_sa_init_request_data,this->received_nonce,my_id_payload,TRUE);
+ authenticator->destroy(authenticator);
+
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, AUDIT, "Could not generate AUTH data for IKE_AUTH request. Deleting IKE_SA");
+ return DELETE_ME;
+ }
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Add AUTH payload to message");
+ request->add_payload(request,(payload_t *) auth_payload);
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of private_ike_sa_init_requested_t.build_sa_payload.
+ */
+static status_t build_sa_payload (private_ike_sa_init_requested_t *this, message_t *request)
+{
+ linked_list_t *proposal_list;
+ sa_payload_t *sa_payload;
+ policy_t *policy;
+ connection_t *connection;
+
+ /* get proposals form config, add to payload */
+ policy = this->ike_sa->get_policy(this->ike_sa);
+ proposal_list = policy->get_proposals(policy);
+ /* build child sa */
+ connection = this->ike_sa->get_connection(this->ike_sa);
+ this->child_sa = child_sa_create(connection->get_my_host(connection),
+ connection->get_other_host(connection));
+ if (this->child_sa->alloc(this->child_sa, proposal_list) != SUCCESS)
+ {
+ this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA! Deleting IKE_SA");
+ return DELETE_ME;
+ }
+
+ sa_payload = sa_payload_create_from_proposal_list(proposal_list);
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Add SA payload to message");
+ request->add_payload(request,(payload_t *) sa_payload);
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of private_ike_sa_init_requested_t.build_tsi_payload.
+ */
+static status_t build_tsi_payload (private_ike_sa_init_requested_t *this, message_t *request)
+{
+ linked_list_t *ts_list;
+ ts_payload_t *ts_payload;
+ policy_t *policy;
+
+ policy = this->ike_sa->get_policy(this->ike_sa);
+ ts_list = policy->get_my_traffic_selectors(policy);
+ ts_payload = ts_payload_create_from_traffic_selectors(TRUE, ts_list);
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Add TSi payload to message");
+ request->add_payload(request,(payload_t *) ts_payload);
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of private_ike_sa_init_requested_t.build_tsr_payload.
+ */
+static status_t build_tsr_payload (private_ike_sa_init_requested_t *this, message_t *request)
+{
+ linked_list_t *ts_list;
+ ts_payload_t *ts_payload;
+ policy_t *policy;
+
+ policy = this->ike_sa->get_policy(this->ike_sa);
+ ts_list = policy->get_other_traffic_selectors(policy);
+ ts_payload = ts_payload_create_from_traffic_selectors(FALSE, ts_list);
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Add TSr payload to message");
+ request->add_payload(request,(payload_t *) ts_payload);
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of private_ike_sa_init_requested_t.process_notify_payload.
+ */
+static status_t process_notify_payload(private_ike_sa_init_requested_t *this, notify_payload_t *notify_payload)
+{
+ notify_message_type_t notify_message_type = notify_payload->get_notify_message_type(notify_payload);
+
+ this->logger->log(this->logger, CONTROL|LEVEL1, "Process notify type %s",
+ mapping_find(notify_message_type_m, notify_message_type));
+
+ switch (notify_message_type)
+ {
+ case NO_PROPOSAL_CHOSEN:
+ {
+ this->logger->log(this->logger, AUDIT, "IKE_SA_INIT response contained a NO_PROPOSAL_CHOSEN notify. Deleting IKE_SA");
+ return DELETE_ME;
+ }
+ case INVALID_MAJOR_VERSION:
+ {
+ this->logger->log(this->logger, AUDIT, "IKE_SA_INIT response contained a INVALID_MAJOR_VERSION notify. Deleting IKE_SA");
+ return DELETE_ME;
+ }
+ case INVALID_KE_PAYLOAD:
+ {
+ initiator_init_t *initiator_init_state;
+ chunk_t notify_data;
+ diffie_hellman_group_t dh_group, old_dh_group;
+ connection_t *connection;
+
+ connection = this->ike_sa->get_connection(this->ike_sa);
+ old_dh_group = connection->get_dh_group(connection);
+ notify_data = notify_payload->get_notification_data(notify_payload);
+ dh_group = ntohs(*((u_int16_t*)notify_data.ptr));
+
+ /* TODO:
+ * We are very restrictive here: If the other didn't accept
+ * our DH group, and we do not accept his offer, continuation
+ * is cancelled...
+ */
+
+ this->logger->log(this->logger, AUDIT, "Peer didn't accept %s, it requested %s!",
+ mapping_find(diffie_hellman_group_m, old_dh_group),
+ mapping_find(diffie_hellman_group_m, dh_group));
+ /* check if we can accept this dh group */
+ if (!connection->check_dh_group(connection, dh_group))
+ {
+ this->logger->log(this->logger, AUDIT,
+ "Peer does only accept DH group %s, which we do not accept! Aborting",
+ mapping_find(diffie_hellman_group_m, dh_group));
+ return DELETE_ME;
+ }
+
+ /* Going to change state back to initiator_init_t */
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Create next state object");
+ initiator_init_state = initiator_init_create(this->ike_sa);
+
+ /* buffer of sent and received messages has to get reseted */
+ this->ike_sa->reset_message_buffers(this->ike_sa);
+
+ /* state can now be changed */
+ this->ike_sa->set_new_state(this->ike_sa,(state_t *) initiator_init_state);
+
+ /* state has NOW changed :-) */
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Destroy old sate object");
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Going to retry initialization of connection");
+
+ this->public.state_interface.destroy(&(this->public.state_interface));
+ if (initiator_init_state->retry_initiate_connection (initiator_init_state, dh_group) != SUCCESS)
+ {
+ return DELETE_ME;
+ }
+ return FAILED;
+ }
+ default:
+ {
+ /*
+ * - In case of unknown error: IKE_SA gets destroyed.
+ * - In case of unknown status: logging
+ */
+ if (notify_message_type < 16383)
+ {
+ this->logger->log(this->logger, AUDIT, "IKE_SA_INIT reply contained an unknown notify error (%d). Deleting IKE_SA",
+ notify_message_type);
+ return DELETE_ME;
+ }
+ else
+ {
+ this->logger->log(this->logger, CONTROL, "IKE_SA_INIT reply contained an unknown notify (%d), ignored.",
+ notify_message_type);
+ return SUCCESS;
+ }
+ }
+ }
+}
+
+/**
+ * Implementation of state_t.get_state.
+ */
+static ike_sa_state_t get_state(private_ike_sa_init_requested_t *this)
+{
+ return IKE_SA_INIT_REQUESTED;
+}
+
+/**
+ * Implementation of private_ike_sa_init_requested_t.destroy_after_state_change.
+ */
+static void destroy_after_state_change (private_ike_sa_init_requested_t *this)
+{
+ this->diffie_hellman->destroy(this->diffie_hellman);
+ chunk_free(&(this->ike_sa_init_request_data));
+ if (this->proposal)
+ {
+ this->proposal->destroy(this->proposal);
+ }
+ free(this);
+}
+
+/**
+ * Implementation state_t.destroy.
+ */
+static void destroy(private_ike_sa_init_requested_t *this)
+{
+ this->diffie_hellman->destroy(this->diffie_hellman);
+ free(this->sent_nonce.ptr);
+ free(this->received_nonce.ptr);
+ chunk_free(&(this->ike_sa_init_request_data));
+ if (this->child_sa)
+ {
+ this->child_sa->destroy(this->child_sa);
+ }
+ if (this->proposal)
+ {
+ this->proposal->destroy(this->proposal);
+ }
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+ike_sa_init_requested_t *ike_sa_init_requested_create(protected_ike_sa_t *ike_sa, diffie_hellman_t *diffie_hellman, chunk_t sent_nonce,chunk_t ike_sa_init_request_data)
+{
+ private_ike_sa_init_requested_t *this = malloc_thing(private_ike_sa_init_requested_t);
+
+ /* interface functions */
+ this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
+ this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
+ this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
+
+ /* private functions */
+ this->destroy_after_state_change = destroy_after_state_change;
+ this->process_nonce_payload = process_nonce_payload;
+ this->process_sa_payload = process_sa_payload;
+ this->process_ke_payload = process_ke_payload;
+ this->build_auth_payload = build_auth_payload;
+ this->build_tsi_payload = build_tsi_payload;
+ this->build_tsr_payload = build_tsr_payload;
+ this->build_id_payload = build_id_payload;
+ this->build_idr_payload = build_idr_payload;
+ this->build_sa_payload = build_sa_payload;
+ this->process_notify_payload = process_notify_payload;
+
+ /* private data */
+ this->ike_sa = ike_sa;
+ this->received_nonce = CHUNK_INITIALIZER;
+ this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
+ this->diffie_hellman = diffie_hellman;
+ this->proposal = NULL;
+ this->sent_nonce = sent_nonce;
+ this->child_sa = NULL;
+ this->ike_sa_init_request_data = ike_sa_init_request_data;
+
+ return &(this->public);
+}
diff --git a/programs/charon/charon/sa/states/ike_sa_init_requested.h b/programs/charon/charon/sa/states/ike_sa_init_requested.h
new file mode 100644
index 000000000..0a43afad1
--- /dev/null
+++ b/programs/charon/charon/sa/states/ike_sa_init_requested.h
@@ -0,0 +1,68 @@
+/**
+ * @file ike_sa_init_requested.h
+ *
+ * @brief Interface of ike_sa_init_requestet_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#ifndef IKE_SA_INIT_REQUESTED_H_
+#define IKE_SA_INIT_REQUESTED_H_
+
+#include <types.h>
+#include <sa/ike_sa.h>
+#include <sa/states/state.h>
+#include <crypto/diffie_hellman.h>
+
+typedef struct ike_sa_init_requested_t ike_sa_init_requested_t;
+
+/**
+ * @brief This class represents an IKE_SA state when
+ * requested an IKE_SA_INIT as initiator.
+ *
+ * @b Constructors:
+ * - ike_sa_init_requested_create()
+ *
+ * @todo Include valid child sa SPIs in proposal
+ *
+ * @ingroup states
+ */
+struct ike_sa_init_requested_t {
+ /**
+ * The state_t interface.
+ */
+ state_t state_interface;
+};
+
+/**
+ * Constructor of class ike_sa_init_requested_t.
+ *
+ * @param ike_sa assigned ike_sa
+ * @param diffie_hellman diffie_hellman object use to retrieve shared secret
+ * @param sent_nonce Sent nonce value
+ * @param ike_sa_init_request_data the binary representation of the IKE_SA_INIT request message
+ * @return created ike_sa_init_request_t object
+ *
+ * @ingroup states
+ */
+ike_sa_init_requested_t *ike_sa_init_requested_create(protected_ike_sa_t *ike_sa,
+ diffie_hellman_t *diffie_hellman,
+ chunk_t sent_nonce,
+ chunk_t ike_sa_init_request_data);
+
+#endif /*IKE_SA_INIT_REQUESTED_H_*/
diff --git a/programs/charon/charon/sa/states/ike_sa_init_responded.c b/programs/charon/charon/sa/states/ike_sa_init_responded.c
new file mode 100644
index 000000000..e40b0cf22
--- /dev/null
+++ b/programs/charon/charon/sa/states/ike_sa_init_responded.c
@@ -0,0 +1,695 @@
+/**
+ * @file ike_sa_init_responded.c
+ *
+ * @brief State of a IKE_SA after responding to an IKE_SA_INIT request
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+
+#include "ike_sa_init_responded.h"
+
+#include <daemon.h>
+#include <sa/authenticator.h>
+#include <sa/child_sa.h>
+#include <encoding/payloads/ts_payload.h>
+#include <encoding/payloads/sa_payload.h>
+#include <encoding/payloads/id_payload.h>
+#include <encoding/payloads/auth_payload.h>
+#include <encoding/payloads/notify_payload.h>
+#include <crypto/signers/signer.h>
+#include <crypto/crypters/crypter.h>
+#include <sa/states/ike_sa_established.h>
+
+
+typedef struct private_ike_sa_init_responded_t private_ike_sa_init_responded_t;
+
+/**
+ * Private data of a ike_sa_init_responded_t object.
+ *
+ */
+struct private_ike_sa_init_responded_t {
+ /**
+ * Public interface of ike_sa_init_responded_t.
+ */
+ ike_sa_init_responded_t public;
+
+ /**
+ * Assigned IKE_SA.
+ */
+ protected_ike_sa_t *ike_sa;
+
+ /**
+ * Received nonce.
+ */
+ chunk_t received_nonce;
+
+ /**
+ * Sent nonce.
+ */
+ chunk_t sent_nonce;
+
+ /**
+ * Binary representation of the IKE_SA_INIT response.
+ */
+ chunk_t ike_sa_init_response_data;
+
+ /**
+ * Binary representation of the IKE_SA_INIT request.
+ */
+ chunk_t ike_sa_init_request_data;
+
+ /**
+ * SA config to use.
+ */
+ policy_t *policy;
+
+ /**
+ * CHILD_SA, if set up
+ */
+ child_sa_t *child_sa;
+
+ /**
+ * Traffic selectors applicable at our site
+ */
+ linked_list_t *my_ts;
+
+ /**
+ * Traffic selectors applicable at remote site
+ */
+ linked_list_t *other_ts;
+
+ /**
+ * Assigned logger.
+ *
+ * Is logger of ike_sa!
+ */
+ logger_t *logger;
+
+ /**
+ * Process received IDi and IDr payload and build IDr payload for IKE_AUTH response.
+ *
+ * @param this calling object
+ * @param request_idi ID payload representing initiator
+ * @param request_idr ID payload representing responder (May be zero)
+ * @param response The created IDr payload is added to this message_t object
+ * @param response_idr The created IDr payload is also written to this location
+ */
+ status_t (*build_idr_payload) (private_ike_sa_init_responded_t *this,
+ id_payload_t *request_idi,
+ id_payload_t *request_idr,
+ message_t *response,
+ id_payload_t **response_idr);
+
+ /**
+ * Process received SA payload and build SA payload for IKE_AUTH response.
+ *
+ * @param this calling object
+ * @param request SA payload received in IKE_AUTH request
+ * @param response The created SA payload is added to this message_t object
+ */
+ status_t (*build_sa_payload) (private_ike_sa_init_responded_t *this, sa_payload_t *request, message_t *response);
+
+ /**
+ * Process received AUTH payload and build AUTH payload for IKE_AUTH response.
+ *
+ * @param this calling object
+ * @param request AUTH payload received in IKE_AUTH request
+ * @param other_id_payload other ID payload needed to verify AUTH data
+ * @param my_id_payload my ID payload needed to compute AUTH data
+ * @param response The created AUTH payload is added to this message_t object
+ */
+ status_t (*build_auth_payload) (private_ike_sa_init_responded_t *this, auth_payload_t *request,id_payload_t *other_id_payload,id_payload_t *my_id_payload, message_t* response);
+
+ /**
+ * Process received TS payload and build TS payload for IKE_AUTH response.
+ *
+ * @param this calling object
+ * @param is_initiator type of TS payload. TRUE for TSi, FALSE for TSr
+ * @param request TS payload received in IKE_AUTH request
+ * @param response the created TS payload is added to this message_t object
+ */
+ status_t (*build_ts_payload) (private_ike_sa_init_responded_t *this, bool ts_initiator, ts_payload_t *request, message_t *response);
+
+ /**
+ * Sends a IKE_AUTH reply containing a notify payload.
+ *
+ * @param this calling object
+ * @param notify_payload payload to process
+ * @return
+ * - DELETE_ME if IKE_SA should be deleted
+ * - SUCCSS if processed successfull
+ */
+ status_t (*process_notify_payload) (private_ike_sa_init_responded_t *this, notify_payload_t* notify_payload);
+
+ /**
+ * Destroy function called internally of this class after state change to
+ * state IKE_SA_ESTABLISHED succeeded.
+ *
+ * This destroy function does not destroy objects which were passed to the new state.
+ *
+ * @param this calling object
+ */
+ void (*destroy_after_state_change) (private_ike_sa_init_responded_t *this);
+};
+
+/**
+ * Implements state_t.get_state
+ */
+static status_t process_message(private_ike_sa_init_responded_t *this, message_t *request)
+{
+ id_payload_t *idi_request = NULL, *idr_request = NULL,*idr_response;
+ ts_payload_t *tsi_request = NULL, *tsr_request = NULL;
+ auth_payload_t *auth_request = NULL;
+ sa_payload_t *sa_request = NULL;
+ iterator_t *payloads;
+ message_t *response;
+ crypter_t *crypter;
+ signer_t *signer;
+ status_t status;
+ host_t *my_host, *other_host;
+ connection_t *connection;
+
+ if (request->get_exchange_type(request) != IKE_AUTH)
+ {
+ this->logger->log(this->logger, ERROR | LEVEL1, "Message of type %s not supported in state ike_sa_init_responded",
+ mapping_find(exchange_type_m,request->get_exchange_type(request)));
+ return FAILED;
+ }
+
+ if (!request->get_request(request))
+ {
+ this->logger->log(this->logger, ERROR | LEVEL1, "IKE_AUTH responses not allowed state ike_sa_init_responded");
+ return FAILED;
+ }
+
+ /* get signer for verification and crypter for decryption */
+ signer = this->ike_sa->get_signer_initiator(this->ike_sa);
+ crypter = this->ike_sa->get_crypter_initiator(this->ike_sa);
+
+ status = request->parse_body(request, crypter, signer);
+ if (status != SUCCESS)
+ {
+ if (status == NOT_SUPPORTED)
+ {
+ this->logger->log(this->logger, ERROR | LEVEL1, "IKE_AUTH request contains unsupported payload with critical flag set."
+ "Deleting IKE_SA");
+ this->ike_sa->send_notify(this->ike_sa, IKE_AUTH, UNSUPPORTED_CRITICAL_PAYLOAD, CHUNK_INITIALIZER);
+ return DELETE_ME;
+ }
+ else
+ {
+ this->logger->log(this->logger, AUDIT, "IKE_AUTH request decryption faild. Ignoring message");
+ }
+ return status;
+ }
+
+ /* iterate over incoming payloads. Message is verified, we can be sure there are the required payloads */
+ payloads = request->get_payload_iterator(request);
+ while (payloads->has_next(payloads))
+ {
+ payload_t *payload;
+ payloads->current(payloads, (void**)&payload);
+
+ switch (payload->get_type(payload))
+ {
+ case ID_INITIATOR:
+ {
+ idi_request = (id_payload_t*)payload;
+ break;
+ }
+ case AUTHENTICATION:
+ {
+ auth_request = (auth_payload_t*)payload;
+ break;
+ }
+ case ID_RESPONDER:
+ {
+ idr_request = (id_payload_t*)payload;
+ break;
+ }
+ case SECURITY_ASSOCIATION:
+ {
+ sa_request = (sa_payload_t*)payload;
+ break;
+ }
+ case TRAFFIC_SELECTOR_INITIATOR:
+ {
+ tsi_request = (ts_payload_t*)payload;
+ break;
+ }
+ case TRAFFIC_SELECTOR_RESPONDER:
+ {
+ tsr_request = (ts_payload_t*)payload;
+ break;
+ }
+ case NOTIFY:
+ {
+ notify_payload_t *notify_payload = (notify_payload_t *) payload;
+ status = this->process_notify_payload(this, notify_payload);
+ if (status != SUCCESS)
+ {
+ payloads->destroy(payloads);
+ return status;
+ }
+ }
+ case CERTIFICATE:
+ {
+ /* TODO handle cert payloads */
+ }
+ case CERTIFICATE_REQUEST:
+ {
+ /* TODO handle certrequest payloads */
+ }
+ default:
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1, "Ignoring payload %s (%d)",
+ mapping_find(payload_type_m, payload->get_type(payload)), payload->get_type(payload));
+ break;
+ }
+ }
+ }
+ /* iterator can be destroyed */
+ payloads->destroy(payloads);
+
+ /* check if we have all payloads */
+ if (!(idi_request && sa_request && auth_request && tsi_request && tsr_request))
+ {
+ this->logger->log(this->logger, AUDIT, "IKE_AUTH reply did not contain all required payloads. Deleting IKE_SA");
+ return DELETE_ME;
+ }
+
+ /* build response */
+ this->ike_sa->build_message(this->ike_sa, IKE_AUTH, FALSE, &response);
+
+ /* add payloads to it */
+ status = this->build_idr_payload(this, idi_request, idr_request, response,&idr_response);
+ if (status != SUCCESS)
+ {
+ response->destroy(response);
+ return status;
+ }
+ status = this->build_auth_payload(this, auth_request,idi_request, idr_response,response);
+ if (status != SUCCESS)
+ {
+ response->destroy(response);
+ return status;
+ }
+ status = this->build_sa_payload(this, sa_request, response);
+ if (status != SUCCESS)
+ {
+ response->destroy(response);
+ return status;
+ }
+ status = this->build_ts_payload(this, TRUE, tsi_request, response);
+ if (status != SUCCESS)
+ {
+ response->destroy(response);
+ return status;
+ }
+ status = this->build_ts_payload(this, FALSE, tsr_request, response);
+ if (status != SUCCESS)
+ {
+ response->destroy(response);
+ return status;
+ }
+
+ status = this->ike_sa->send_response(this->ike_sa, response);
+ /* message can now be sent (must not be destroyed) */
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, AUDIT, "Unable to send IKE_AUTH reply. Deleting IKE_SA");
+ response->destroy(response);
+ return DELETE_ME;
+ }
+
+ /* install child SA policies */
+ if (!this->child_sa)
+ {
+ this->logger->log(this->logger, CONTROL, "Proposal negotiation failed, no CHILD_SA built");
+ }
+ else if (this->my_ts->get_count(this->my_ts) == 0 || this->other_ts->get_count(this->other_ts) == 0)
+ {
+ this->logger->log(this->logger, CONTROL, "Traffic selector negotiation failed, no CHILD_SA built");
+ this->child_sa->destroy(this->child_sa);
+ this->child_sa = NULL;
+ }
+ else
+ {
+ status = this->child_sa->add_policies(this->child_sa, this->my_ts, this->other_ts);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA policy! Deleting IKE_SA");
+ return DELETE_ME;
+ }
+ this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
+ }
+
+ /* create new state */
+ this->ike_sa->set_new_state(this->ike_sa, (state_t*)ike_sa_established_create(this->ike_sa));
+ this->destroy_after_state_change(this);
+
+ connection = this->ike_sa->get_connection(this->ike_sa);
+ my_host = connection->get_my_host(connection);
+ other_host = connection->get_other_host(connection);
+ this->logger->log(this->logger, AUDIT, "IKE_SA established between %s - %s",
+ my_host->get_address(my_host), other_host->get_address(other_host));
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of private_ike_sa_init_responded_t.build_idr_payload.
+ */
+static status_t build_idr_payload(private_ike_sa_init_responded_t *this, id_payload_t *request_idi, id_payload_t *request_idr, message_t *response,id_payload_t **response_idr)
+{
+ identification_t *other_id, *my_id = NULL;
+ connection_t *connection;
+ id_payload_t *idr_response;
+
+ connection = this->ike_sa->get_connection(this->ike_sa);
+
+ /* update adresses, as connection may contain wildcards, or wrong IDs */
+ other_id = request_idi->get_identification(request_idi);
+ if (request_idr)
+ {
+ my_id = request_idr->get_identification(request_idr);
+ connection->update_my_id(connection, my_id);
+ }
+ else
+ {
+ my_id = connection->get_my_id(connection);
+ }
+ connection->update_other_id(connection, other_id);
+
+ /* build new sa config */
+ this->policy = charon->policies->get_policy(charon->policies, my_id, other_id);
+ if (this->policy == NULL)
+ {
+ this->logger->log(this->logger, AUDIT, "We don't have a policy for IDs %s - %s. Deleting IKE_SA",
+ my_id->get_string(my_id), other_id->get_string(other_id));
+ return DELETE_ME;
+ }
+
+ /* get my id from policy, which must contain a fully qualified valid id */
+ my_id = this->policy->get_my_id(this->policy);
+
+ /* update others traffic selectors with actually used address */
+ this->policy->update_other_ts(this->policy, response->get_destination(response));
+
+ /* set policy in ike_sa for other states */
+ this->ike_sa->set_policy(this->ike_sa, this->policy);
+
+ /* build response */
+ idr_response = id_payload_create_from_identification(FALSE, my_id);
+ response->add_payload(response, (payload_t*)idr_response);
+ *response_idr = idr_response;
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of private_ike_sa_init_responded_t.build_sa_payload.
+ */
+static status_t build_sa_payload(private_ike_sa_init_responded_t *this, sa_payload_t *request, message_t *response)
+{
+ proposal_t *proposal, *proposal_tmp;
+ linked_list_t *proposal_list;
+ sa_payload_t *sa_response;
+ chunk_t seed;
+ prf_plus_t *prf_plus;
+ status_t status;
+ connection_t *connection;
+
+ /* get proposals from request */
+ proposal_list = request->get_proposals(request);
+ if (proposal_list->get_count(proposal_list) == 0)
+ {
+ /* if the other side did not offer any proposals, we do not create child sa's */
+ this->logger->log(this->logger, AUDIT, "IKE_AUH request did not contain any proposals. No CHILD_SA created");
+ sa_response = sa_payload_create();
+ response->add_payload(response, (payload_t*)sa_response);
+ proposal_list->destroy(proposal_list);
+ return SUCCESS;
+ }
+
+ /* now select a proposal */
+ this->logger->log(this->logger, CONTROL|LEVEL1, "Selecting proposals:");
+ proposal = this->policy->select_proposal(this->policy, proposal_list);
+ /* list is not needed anymore */
+ while (proposal_list->remove_last(proposal_list, (void**)&proposal_tmp) == SUCCESS)
+ {
+ proposal_tmp->destroy(proposal_tmp);
+ }
+ proposal_list->destroy(proposal_list);
+ /* do we have a proposal */
+ if (proposal == NULL)
+ {
+ this->logger->log(this->logger, AUDIT, "IKE_AUTH request did not contain any proposals we accept. Deleting IKE_SA");
+ this->ike_sa->send_notify(this->ike_sa, IKE_AUTH, NO_PROPOSAL_CHOSEN, CHUNK_INITIALIZER);
+ return DELETE_ME;
+ }
+
+ /* set up child sa */
+ seed = chunk_alloc(this->received_nonce.len + this->sent_nonce.len);
+ memcpy(seed.ptr, this->received_nonce.ptr, this->received_nonce.len);
+ memcpy(seed.ptr + this->received_nonce.len, this->sent_nonce.ptr, this->sent_nonce.len);
+ prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed);
+ chunk_free(&seed);
+
+ connection = this->ike_sa->get_connection(this->ike_sa);
+ this->child_sa = child_sa_create(connection->get_my_host(connection),
+ connection->get_other_host(connection));
+
+ status = this->child_sa->add(this->child_sa, proposal, prf_plus);
+ prf_plus->destroy(prf_plus);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA! Deleting IKE_SA");
+ return DELETE_ME;
+ }
+
+ /* create payload with selected propsal */
+ sa_response = sa_payload_create_from_proposal(proposal);
+ response->add_payload(response, (payload_t*)sa_response);
+ proposal->destroy(proposal);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of private_ike_sa_init_responded_t.build_auth_payload.
+ */
+static status_t build_auth_payload(private_ike_sa_init_responded_t *this, auth_payload_t *auth_request,id_payload_t *other_id_payload,id_payload_t *my_id_payload, message_t* response)
+{
+ authenticator_t *authenticator;
+ auth_payload_t *auth_reply;
+ status_t status;
+
+ authenticator = authenticator_create(this->ike_sa);
+ status = authenticator->verify_auth_data(authenticator,auth_request, this->ike_sa_init_request_data,this->sent_nonce,other_id_payload,TRUE);
+
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, AUDIT, "IKE_AUTH request verification failed. Deleting IKE_SA");
+ this->ike_sa->send_notify(this->ike_sa, IKE_AUTH, AUTHENTICATION_FAILED, CHUNK_INITIALIZER);
+ authenticator->destroy(authenticator);
+ return DELETE_ME;
+ }
+
+ status = authenticator->compute_auth_data(authenticator,&auth_reply, this->ike_sa_init_response_data,this->received_nonce,my_id_payload,FALSE);
+ authenticator->destroy(authenticator);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, AUDIT, "Unable to build authentication data for IKE_AUTH reply. Deleting IKE_SA");
+ return DELETE_ME;
+
+ }
+
+ response->add_payload(response, (payload_t *)auth_reply);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of private_ike_sa_init_responded_t.build_ts_payload.
+ */
+static status_t build_ts_payload(private_ike_sa_init_responded_t *this, bool ts_initiator, ts_payload_t *request, message_t* response)
+{
+ linked_list_t *ts_received, *ts_selected;
+ traffic_selector_t *ts;
+ status_t status = SUCCESS;
+ ts_payload_t *ts_response;
+
+ /* build a reply payload with selected traffic selectors */
+ ts_received = request->get_traffic_selectors(request);
+ /* select ts depending on payload type */
+ if (ts_initiator)
+ {
+ ts_selected = this->policy->select_other_traffic_selectors(this->policy, ts_received);
+ this->other_ts = ts_selected;
+ }
+ else
+ {
+ ts_selected = this->policy->select_my_traffic_selectors(this->policy, ts_received);
+ this->my_ts = ts_selected;
+ }
+
+ ts_response = ts_payload_create_from_traffic_selectors(ts_initiator, ts_selected);
+ response->add_payload(response, (payload_t*)ts_response);
+
+ /* cleanup */
+ while (ts_received->remove_last(ts_received, (void**)&ts) == SUCCESS)
+ {
+ ts->destroy(ts);
+ }
+ ts_received->destroy(ts_received);
+
+ return status;
+}
+
+static status_t process_notify_payload(private_ike_sa_init_responded_t *this, notify_payload_t *notify_payload)
+{
+ notify_message_type_t notify_message_type = notify_payload->get_notify_message_type(notify_payload);
+
+ this->logger->log(this->logger, CONTROL|LEVEL1, "Process notify type %s",
+ mapping_find(notify_message_type_m, notify_message_type));
+
+ switch (notify_message_type)
+ {
+ case SET_WINDOW_SIZE:
+ /*
+ * TODO Increase window size.
+ */
+ case INITIAL_CONTACT:
+ /*
+ * TODO Delete existing IKE_SA's with other Identity.
+ */
+ default:
+ {
+ this->logger->log(this->logger, AUDIT, "IKE_AUTH request contained an unknown notify (%d), ignored.", notify_message_type);
+ }
+ }
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of state_t.get_state.
+ */
+static ike_sa_state_t get_state(private_ike_sa_init_responded_t *this)
+{
+ return IKE_SA_INIT_RESPONDED;
+}
+
+/**
+ * Implementation of state_t.destroy.
+ */
+static void destroy(private_ike_sa_init_responded_t *this)
+{
+ chunk_free(&(this->received_nonce));
+ chunk_free(&(this->sent_nonce));
+ chunk_free(&(this->ike_sa_init_response_data));
+ chunk_free(&(this->ike_sa_init_request_data));
+ if (this->my_ts)
+ {
+ traffic_selector_t *ts;
+ while (this->my_ts->remove_last(this->my_ts, (void**)&ts) == SUCCESS)
+ {
+ ts->destroy(ts);
+ }
+ this->my_ts->destroy(this->my_ts);
+ }
+ if (this->other_ts)
+ {
+ traffic_selector_t *ts;
+ while (this->other_ts->remove_last(this->other_ts, (void**)&ts) == SUCCESS)
+ {
+ ts->destroy(ts);
+ }
+ this->other_ts->destroy(this->other_ts);
+ }
+ if (this->child_sa)
+ {
+ this->child_sa->destroy(this->child_sa);
+ }
+
+ free(this);
+}
+/**
+ * Implementation of private_ike_sa_init_responded.destroy_after_state_change.
+ */
+static void destroy_after_state_change(private_ike_sa_init_responded_t *this)
+{
+ chunk_free(&(this->received_nonce));
+ chunk_free(&(this->sent_nonce));
+ chunk_free(&(this->ike_sa_init_response_data));
+ chunk_free(&(this->ike_sa_init_request_data));
+ if (this->my_ts)
+ {
+ traffic_selector_t *ts;
+ while (this->my_ts->remove_last(this->my_ts, (void**)&ts) == SUCCESS)
+ {
+ ts->destroy(ts);
+ }
+ this->my_ts->destroy(this->my_ts);
+ }
+ if (this->other_ts)
+ {
+ traffic_selector_t *ts;
+ while (this->other_ts->remove_last(this->other_ts, (void**)&ts) == SUCCESS)
+ {
+ ts->destroy(ts);
+ }
+ this->other_ts->destroy(this->other_ts);
+ }
+
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+ike_sa_init_responded_t *ike_sa_init_responded_create(protected_ike_sa_t *ike_sa, chunk_t received_nonce, chunk_t sent_nonce,chunk_t ike_sa_init_request_data, chunk_t ike_sa_init_response_data)
+{
+ private_ike_sa_init_responded_t *this = malloc_thing(private_ike_sa_init_responded_t);
+
+ /* interface functions */
+ this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
+ this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
+ this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
+
+ /* private functions */
+ this->build_idr_payload = build_idr_payload;
+ this->build_sa_payload = build_sa_payload;
+ this->build_auth_payload = build_auth_payload;
+ this->build_ts_payload = build_ts_payload;
+ this->process_notify_payload = process_notify_payload;
+ this->destroy_after_state_change = destroy_after_state_change;
+
+ /* private data */
+ this->ike_sa = ike_sa;
+ this->received_nonce = received_nonce;
+ this->sent_nonce = sent_nonce;
+ this->ike_sa_init_response_data = ike_sa_init_response_data;
+ this->ike_sa_init_request_data = ike_sa_init_request_data;
+ this->my_ts = NULL;
+ this->other_ts = NULL;
+ this->child_sa = NULL;
+ this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
+
+ return &(this->public);
+}
diff --git a/programs/charon/charon/sa/states/ike_sa_init_responded.h b/programs/charon/charon/sa/states/ike_sa_init_responded.h
new file mode 100644
index 000000000..43aecf26f
--- /dev/null
+++ b/programs/charon/charon/sa/states/ike_sa_init_responded.h
@@ -0,0 +1,73 @@
+/**
+ * @file ike_sa_init_responded.h
+ *
+ * @brief Interface of ike_sa_init_responded_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef IKE_SA_INIT_RESPONDED_H_
+#define IKE_SA_INIT_RESPONDED_H_
+
+#include <sa/ike_sa.h>
+#include <sa/states/state.h>
+
+typedef struct ike_sa_init_responded_t ike_sa_init_responded_t;
+
+/**
+ * @brief This class represents an IKE_SA state when
+ * responded to an IKE_SA_INIT request.
+ *
+ * The state accpets IKE_AUTH requests. It proves the authenticity
+ * and sets up the first child sa. Then it sends back an IKE_AUTH
+ * reply and changes to the IKE_SA_ESTABLISHED state.
+ *
+ * @b Constructors:
+ * - ike_sa_init_response_data()
+ *
+ * @todo Implement handling of SET_WINDOW_SIZE notify
+ *
+ * @todo Implement handling of INITIAL_CONTACT notify
+ *
+ * @ingroup states
+ */
+struct ike_sa_init_responded_t {
+ /**
+ * The state_t interface.
+ */
+ state_t state_interface;
+
+};
+
+/**
+ * @brief Constructor of class ike_sa_init_responded_t
+ *
+ * @param ike_sa assigned IKE_SA
+ * @param received_nonce received nonce data in IKE_SA_INIT request
+ * @param sent_nonce sent nonce data in IKE_SA_INIT response
+ * @param ike_sa_init_request_data binary representation of received IKE_SA_INIT request
+ * @param ike_sa_init_response_data binary representation of sent IKE_SA_INIT response
+ *
+ * @ingroup states
+ */
+ike_sa_init_responded_t *ike_sa_init_responded_create(protected_ike_sa_t *ike_sa,
+ chunk_t received_nonce,
+ chunk_t sent_nonce,
+ chunk_t ike_sa_init_request_data,
+ chunk_t ike_sa_init_response_data);
+
+#endif /*IKE_SA_INIT_RESPONDED_H_*/
diff --git a/programs/charon/charon/sa/states/initiator_init.c b/programs/charon/charon/sa/states/initiator_init.c
new file mode 100644
index 000000000..35d15235d
--- /dev/null
+++ b/programs/charon/charon/sa/states/initiator_init.c
@@ -0,0 +1,360 @@
+/**
+ * @file initiator_init.c
+ *
+ * @brief Implementation of initiator_init_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "initiator_init.h"
+
+
+#include <daemon.h>
+#include <sa/states/state.h>
+#include <sa/states/ike_sa_init_requested.h>
+#include <queues/jobs/retransmit_request_job.h>
+#include <crypto/diffie_hellman.h>
+#include <encoding/payloads/sa_payload.h>
+#include <encoding/payloads/ke_payload.h>
+#include <encoding/payloads/nonce_payload.h>
+
+
+typedef struct private_initiator_init_t private_initiator_init_t;
+
+/**
+ * Private data of a initiator_init_t object..
+ *
+ */
+struct private_initiator_init_t {
+ /**
+ * Methods of the state_t interface.
+ */
+ initiator_init_t public;
+
+ /**
+ * Assigned IKE_SA.
+ */
+ protected_ike_sa_t *ike_sa;
+
+ /**
+ * Diffie hellman object used to generate public DH value.
+ * This objet is passed to the next state of type IKE_SA_INIT_REQUESTED.
+ */
+ diffie_hellman_t *diffie_hellman;
+
+ /**
+ * Sent nonce.
+ * This nonce is passed to the next state of type IKE_SA_INIT_REQUESTED.
+ */
+ chunk_t sent_nonce;
+
+ /**
+ * Assigned logger.
+ *
+ * Is logger of ike_sa!
+ */
+ logger_t *logger;
+
+ /**
+ * Builds the SA payload for this state.
+ *
+ * @param this calling object
+ * @param request message_t object to add the SA payload
+ */
+ void (*build_sa_payload) (private_initiator_init_t *this, message_t *request);
+
+ /**
+ * Builds the KE payload for this state.
+ *
+ * @param this calling object
+ * @param request message_t object to add the KE payload
+ */
+ void (*build_ke_payload) (private_initiator_init_t *this, message_t *request);
+
+ /**
+ * Builds the NONCE payload for this state.
+ *
+ * @param this calling object
+ * @param request message_t object to add the NONCE payload
+ */
+ status_t (*build_nonce_payload) (private_initiator_init_t *this,message_t *request);
+
+ /**
+ * Destroy function called internally of this class after state change to state
+ * IKE_SA_INIT_REQUESTED succeeded.
+ *
+ * This destroy function does not destroy objects which were passed to the new state.
+ *
+ * @param this calling object
+ */
+ void (*destroy_after_state_change) (private_initiator_init_t *this);
+};
+
+/**
+ * Implementation of initiator_init_t.initiate_connection.
+ */
+static status_t initiate_connection (private_initiator_init_t *this, connection_t *connection)
+{
+ policy_t *policy;
+ diffie_hellman_group_t dh_group;
+ host_t *my_host, *other_host;
+ identification_t *my_id, *other_id;
+
+ my_host = connection->get_my_host(connection);
+ other_host = connection->get_other_host(connection);
+ my_id = connection->get_my_id(connection);
+ other_id = connection->get_other_id(connection);
+
+ this->logger->log(this->logger, CONTROL, "Initiating connection between %s (%s) - %s (%s)",
+ my_id->get_string(my_id), my_host->get_address(my_host),
+ other_id->get_string(other_id), other_host->get_address(other_host));
+
+ this->ike_sa->set_connection(this->ike_sa, connection);
+
+ /* get policy */
+ policy = charon->policies->get_policy(charon->policies, my_id, other_id);
+ if (policy == NULL)
+ {
+ this->logger->log(this->logger, ERROR | LEVEL1, "Could not get a policy for '%s - %s', aborting",
+ my_id->get_string(my_id), other_id->get_string(other_id));
+ return DELETE_ME;
+ }
+ this->ike_sa->set_policy(this->ike_sa,policy);
+
+ /* we must guess now a DH group. For that we choose our most preferred group */
+ dh_group = connection->get_dh_group(connection);
+
+ /* next step is done in retry_initiate_connection */
+ return this->public.retry_initiate_connection(&this->public, dh_group);
+}
+
+/**
+ * Implementation of initiator_init_t.retry_initiate_connection.
+ */
+status_t retry_initiate_connection (private_initiator_init_t *this, diffie_hellman_group_t dh_group)
+{
+ ike_sa_init_requested_t *next_state;
+ chunk_t ike_sa_init_request_data;
+ connection_t *connection;
+ ike_sa_id_t *ike_sa_id;
+ message_t *message;
+ status_t status;
+
+ if (dh_group == MODP_UNDEFINED)
+ {
+ this->logger->log(this->logger, AUDIT, "No DH group acceptable for initialization, Aborting");
+ return DELETE_ME;
+ }
+
+ connection = this->ike_sa->get_connection(this->ike_sa);
+ this->diffie_hellman = diffie_hellman_create(dh_group);
+ ike_sa_id = this->ike_sa->public.get_id(&(this->ike_sa->public));
+ ike_sa_id->set_responder_spi(ike_sa_id,0);
+
+ /* going to build message */
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Going to build message");
+ this->ike_sa->build_message(this->ike_sa, IKE_SA_INIT, TRUE, &message);
+
+ /* build SA payload */
+ this->build_sa_payload(this, message);
+
+ /* build KE payload */
+ this->build_ke_payload(this, message);
+
+ /* build Nonce payload */
+ status = this->build_nonce_payload(this, message);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, ERROR, "Building nonce payload failed. Aborting");
+ message->destroy(message);
+ return DELETE_ME;
+ }
+
+ /* message can now be sent (must not be destroyed) */
+ status = this->ike_sa->send_request(this->ike_sa, message);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, AUDIT, "Unable to initiate connection, could not send message. Aborting");
+ message->destroy(message);
+ return DELETE_ME;
+ }
+
+ message = this->ike_sa->get_last_requested_message(this->ike_sa);
+
+ ike_sa_init_request_data = message->get_packet_data(message);
+
+ /* state can now be changed */
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Create next state object");
+ next_state = ike_sa_init_requested_create(this->ike_sa, this->diffie_hellman, this->sent_nonce,ike_sa_init_request_data);
+ this->ike_sa->set_new_state(this->ike_sa,(state_t *) next_state);
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Destroy old sate object");
+ this->destroy_after_state_change(this);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of private_initiator_init_t.build_sa_payload.
+ */
+static void build_sa_payload(private_initiator_init_t *this, message_t *request)
+{
+ sa_payload_t* sa_payload;
+ linked_list_t *proposal_list;
+ connection_t *connection;
+
+ this->logger->log(this->logger, CONTROL|LEVEL1, "Building SA payload");
+
+ connection = this->ike_sa->get_connection(this->ike_sa);
+
+ proposal_list = connection->get_proposals(connection);
+
+ sa_payload = sa_payload_create_from_proposal_list(proposal_list);
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Add SA payload to message");
+ request->add_payload(request, (payload_t *) sa_payload);
+}
+
+/**
+ * Implementation of private_initiator_init_t.build_ke_payload.
+ */
+static void build_ke_payload(private_initiator_init_t *this, message_t *request)
+{
+ ke_payload_t *ke_payload;
+ chunk_t key_data;
+ diffie_hellman_group_t dh_group;
+
+ this->logger->log(this->logger, CONTROL|LEVEL1, "Building KE payload");
+
+ this->diffie_hellman->get_my_public_value(this->diffie_hellman,&key_data);
+ dh_group = this->diffie_hellman->get_dh_group(this->diffie_hellman);
+
+ ke_payload = ke_payload_create();
+ ke_payload->set_dh_group_number(ke_payload, dh_group);
+ ke_payload->set_key_exchange_data(ke_payload, key_data);
+
+ chunk_free(&key_data);
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Add KE payload to message");
+ request->add_payload(request, (payload_t *) ke_payload);
+}
+
+/**
+ * Implementation of private_initiator_init_t.build_nonce_payload.
+ */
+static status_t build_nonce_payload(private_initiator_init_t *this, message_t *request)
+{
+ nonce_payload_t *nonce_payload;
+ randomizer_t *randomizer;
+ status_t status;
+
+ this->logger->log(this->logger, CONTROL|LEVEL1, "Building NONCE payload");
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Get pseudo random bytes for NONCE");
+ randomizer = this->ike_sa->get_randomizer(this->ike_sa);
+
+ status = randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE, &(this->sent_nonce));
+ if (status != SUCCESS)
+ {
+ return status;
+ }
+
+ this->logger->log(this->logger, RAW|LEVEL2, "Initiator NONCE",&(this->sent_nonce));
+
+ nonce_payload = nonce_payload_create();
+
+ nonce_payload->set_nonce(nonce_payload, this->sent_nonce);
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Add NONCE payload to message");
+ request->add_payload(request, (payload_t *) nonce_payload);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of state_t.process_message.
+ */
+static status_t process_message(private_initiator_init_t *this, message_t *message)
+{
+ this->logger->log(this->logger, ERROR, "In state INITIATOR_INIT, no message is processed");
+ return FAILED;
+}
+
+/**
+ * Implementation of state_t.get_state.
+ */
+static ike_sa_state_t get_state(private_initiator_init_t *this)
+{
+ return INITIATOR_INIT;
+}
+
+/**
+ * Implementation of state_t.destroy.
+ */
+static void destroy(private_initiator_init_t *this)
+{
+ this->logger->log(this->logger, CONTROL | LEVEL3, "Going to destroy initiator_init_t state object");
+
+ /* destroy diffie hellman object */
+ if (this->diffie_hellman != NULL)
+ {
+ this->diffie_hellman->destroy(this->diffie_hellman);
+ }
+ if (this->sent_nonce.ptr != NULL)
+ {
+ free(this->sent_nonce.ptr);
+ }
+ free(this);
+}
+
+/**
+ * Implementation of private_initiator_init_t.destroy_after_state_change
+ */
+static void destroy_after_state_change (private_initiator_init_t *this)
+{
+ this->logger->log(this->logger, CONTROL | LEVEL3, "Going to destroy initiator_init_t state object");
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+initiator_init_t *initiator_init_create(protected_ike_sa_t *ike_sa)
+{
+ private_initiator_init_t *this = malloc_thing(private_initiator_init_t);
+
+ /* interface functions */
+ this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
+ this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
+ this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
+
+ /* public functions */
+ this->public.initiate_connection = (status_t (*)(initiator_init_t *, connection_t*)) initiate_connection;
+ this->public.retry_initiate_connection = (status_t (*)(initiator_init_t *, int )) retry_initiate_connection;
+
+ /* private functions */
+ this->destroy_after_state_change = destroy_after_state_change;
+ this->build_nonce_payload = build_nonce_payload;
+ this->build_sa_payload = build_sa_payload;
+ this->build_ke_payload = build_ke_payload;
+
+ /* private data */
+ this->ike_sa = ike_sa;
+ this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
+ this->sent_nonce = CHUNK_INITIALIZER;
+ this->diffie_hellman = NULL;
+
+ return &(this->public);
+}
diff --git a/programs/charon/charon/sa/states/initiator_init.h b/programs/charon/charon/sa/states/initiator_init.h
new file mode 100644
index 000000000..6b4940a73
--- /dev/null
+++ b/programs/charon/charon/sa/states/initiator_init.h
@@ -0,0 +1,84 @@
+/**
+ * @file initiator_init.h
+ *
+ * @brief Interface of initiator_init_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#ifndef INITIATOR_INIT_H_
+#define INITIATOR_INIT_H_
+
+#include <sa/ike_sa.h>
+#include <sa/states/state.h>
+
+
+typedef struct initiator_init_t initiator_init_t;
+
+/**
+ * @brief This class represents an IKE_SA state when
+ * initializing a connection as initiator.
+ *
+ * @b Constructors:
+ * - initiator_init_create()
+ *
+ * @ingroup states
+ */
+struct initiator_init_t {
+ /**
+ * The state_t interface.
+ */
+ state_t state_interface;
+
+ /**
+ * Initiate a new connection with given connection_t object.
+ *
+ * @param this calling object
+ * @param connection connection to initiate
+ * @return
+ * - SUCCESS
+ * - DELETE_ME if something failed
+ */
+ status_t (*initiate_connection) (initiator_init_t *this, connection_t *connection);
+
+ /**
+ * Retry to initiate a new connection with a specific dh_group_priority.
+ *
+ * The dh_group_priority is starting at 1.
+ *
+ * @param this calling object
+ * @param dh_group_priority dh group priority to try with
+ * @return
+ * - SUCCESS
+ * - DELETE_ME if something failed (see log for error)
+ */
+ status_t (*retry_initiate_connection) (initiator_init_t *this, int dh_group_priority);
+};
+
+/**
+ * @brief Constructor of class initiator_init_t.
+ *
+ * @param ike_sa assigned IKE_SA
+ * @return created initiator_init_t object
+ *
+ * @ingroup states
+ */
+initiator_init_t *initiator_init_create(protected_ike_sa_t *ike_sa);
+
+
+#endif /*INITIATOR_INIT_H_*/
diff --git a/programs/charon/charon/sa/states/responder_init.c b/programs/charon/charon/sa/states/responder_init.c
new file mode 100644
index 000000000..10acf645c
--- /dev/null
+++ b/programs/charon/charon/sa/states/responder_init.c
@@ -0,0 +1,568 @@
+/**
+ * @file responder_init.c
+ *
+ * @brief Implementation of responder_init_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "responder_init.h"
+
+#include <daemon.h>
+#include <sa/states/state.h>
+#include <sa/states/ike_sa_init_responded.h>
+#include <encoding/payloads/sa_payload.h>
+#include <encoding/payloads/ke_payload.h>
+#include <encoding/payloads/nonce_payload.h>
+#include <encoding/payloads/notify_payload.h>
+#include <crypto/diffie_hellman.h>
+
+
+typedef struct private_responder_init_t private_responder_init_t;
+
+/**
+ * Private data of a responder_init_t object.
+ *
+ */
+struct private_responder_init_t {
+ /**
+ * Methods of the state_t interface.
+ */
+ responder_init_t public;
+
+ /**
+ * Assigned IKE_SA.
+ */
+ protected_ike_sa_t *ike_sa;
+
+ /**
+ * Diffie Hellman object used to compute shared secret.
+ */
+ diffie_hellman_t *diffie_hellman;
+
+ /**
+ * Diffie Hellman group number from selected IKE proposal.
+ */
+ u_int16_t dh_group_number;
+
+ /**
+ * Priority used to get matching dh_group number.
+ */
+ u_int16_t dh_group_priority;
+
+ /**
+ * Sent nonce value.
+ *
+ * This value is passed to the next state of type IKE_SA_INIT_RESPONDED.
+ */
+ chunk_t sent_nonce;
+
+ /**
+ * Received nonce value
+ *
+ * This value is passed to the next state of type IKE_SA_INIT_RESPONDED.
+ */
+ chunk_t received_nonce;
+
+ /**
+ * Selected proposal
+ */
+ proposal_t *proposal;
+
+ /**
+ * Logger used to log data .
+ *
+ * Is logger of ike_sa!
+ */
+ logger_t *logger;
+
+ /**
+ * Handles received SA payload and builds the SA payload for the response.
+ *
+ * @param this calling object
+ * @param sa_request The received SA payload
+ * @param response the SA payload is added to this response message_t object.
+ * @return
+ * - DELETE_ME
+ * - SUCCESS
+ */
+ status_t (*build_sa_payload) (private_responder_init_t *this,sa_payload_t *sa_request, message_t *response);
+
+ /**
+ * Handles received KE payload and builds the KE payload for the response.
+ *
+ * @param this calling object
+ * @param ke_request The received KE payload
+ * @param response the KE payload is added to this response message_t object.
+ * - DELETE_ME
+ * - SUCCESS
+ */
+ status_t (*build_ke_payload) (private_responder_init_t *this,ke_payload_t *ke_request, message_t *response);
+
+ /**
+ * Handles received NONCE payload and builds the NONCE payload for the response.
+ *
+ * @param this calling object
+ * @param nonce_request The received NONCE payload
+ * @param response the NONCE payload is added to this response message_t object.
+ * - DELETE_ME
+ * - SUCCESS
+ */
+ status_t (*build_nonce_payload) (private_responder_init_t *this,nonce_payload_t *nonce_request, message_t *response);
+
+ /**
+ * Sends a IKE_SA_INIT reply containing a notify payload.
+ *
+ * @param this calling object
+ * @param notify_payload notify_payload to process
+ */
+ status_t (*process_notify_payload) (private_responder_init_t *this, notify_payload_t *notify_payload);
+
+ /**
+ * Destroy function called internally of this class after change
+ * to state IKE_SA_INIT_RESPONDED succeeded.
+ *
+ * This destroy function does not destroy objects which were passed to the new state.
+ *
+ * @param this calling object
+ */
+ void (*destroy_after_state_change) (private_responder_init_t *this);
+
+};
+
+/**
+ * Implementation of state_t.process_message.
+ */
+static status_t process_message(private_responder_init_t *this, message_t *message)
+{
+ ike_sa_init_responded_t *next_state;
+ chunk_t ike_sa_init_response_data;
+ chunk_t ike_sa_init_request_data;
+ sa_payload_t *sa_request = NULL;
+ ke_payload_t *ke_request = NULL;
+ nonce_payload_t *nonce_request = NULL;
+ host_t *source, *destination;
+ connection_t *connection;
+ iterator_t *payloads;
+ message_t *response;
+ status_t status;
+
+ if (message->get_exchange_type(message) != IKE_SA_INIT)
+ {
+ this->logger->log(this->logger, ERROR | LEVEL1, "Message of type %s not supported in state responder_init",mapping_find(exchange_type_m,message->get_exchange_type(message)));
+ return DELETE_ME;
+ }
+ if (!message->get_request(message))
+ {
+ this->logger->log(this->logger, ERROR | LEVEL1, "IKE_SA_INIT responses not allowed state ike_sa_init_responded");
+ return DELETE_ME;
+ }
+
+ /* this is the first message to process, so get host infos */
+ source = message->get_source(message);
+ destination = message->get_destination(message);
+
+ connection = charon->connections->get_connection_by_hosts(charon->connections, destination, source);
+ if (connection == NULL)
+ {
+ /* no configuration matches given hosts */
+ this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request does not match any available connection. Deleting IKE_SA");
+ /* TODO: inform requestor */
+ return DELETE_ME;
+ }
+ this->ike_sa->set_connection(this->ike_sa,connection);
+
+ /* parse incoming message */
+ status = message->parse_body(message, NULL, NULL);
+ if (status != SUCCESS)
+ {
+ if (status == NOT_SUPPORTED)
+ {
+ this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request contains unsupported payload with critical flag set. "
+ "Deleting IKE_SA");
+ this->ike_sa->send_notify(this->ike_sa, IKE_SA_INIT, UNSUPPORTED_CRITICAL_PAYLOAD, CHUNK_INITIALIZER);
+ }
+ else
+ {
+ this->logger->log(this->logger, AUDIT, "Unable to parse IKE_SA_INIT request. Deleting IKE_SA");
+ }
+ return DELETE_ME;
+ }
+
+ payloads = message->get_payload_iterator(message);
+ while (payloads->has_next(payloads))
+ {
+ payload_t *payload;
+
+ payloads->current(payloads, (void**)&payload);
+
+ switch (payload->get_type(payload))
+ {
+ case SECURITY_ASSOCIATION:
+ {
+ sa_request = (sa_payload_t*)payload;
+ break;
+ }
+ case KEY_EXCHANGE:
+ {
+ ke_request = (ke_payload_t*)payload;
+ break;
+ }
+ case NONCE:
+ {
+ nonce_request = (nonce_payload_t*)payload;
+ break;
+ }
+ case NOTIFY:
+ {
+ notify_payload_t *notify_payload = (notify_payload_t *) payload;
+ status = this->process_notify_payload(this, notify_payload);
+ if (status != SUCCESS)
+ {
+ payloads->destroy(payloads);
+ return status;
+ }
+ }
+ default:
+ {
+ this->logger->log(this->logger, ERROR|LEVEL1, "Ignoring payload %s (%d)",
+ mapping_find(payload_type_m, payload->get_type(payload)), payload->get_type(payload));
+ break;
+ }
+ }
+ }
+ payloads->destroy(payloads);
+
+ /* check if we have all payloads */
+ if (!(sa_request && ke_request && nonce_request))
+ {
+ this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request did not contain all required payloads. Deleting IKE_SA");
+ return DELETE_ME;
+ }
+
+ this->ike_sa->build_message(this->ike_sa, IKE_SA_INIT, FALSE, &response);
+
+ status = this->build_sa_payload(this, sa_request, response);
+ if (status != SUCCESS)
+ {
+ response->destroy(response);
+ return status;
+ }
+
+ status = this->build_ke_payload(this, ke_request, response);
+ if (status != SUCCESS)
+ {
+ response->destroy(response);
+ return status;
+ }
+
+ status = this->build_nonce_payload(this, nonce_request, response);
+ if (status != SUCCESS)
+ {
+ response->destroy(response);
+ return status;
+ }
+
+ /* derive all the keys used in the IKE_SA */
+ status = this->ike_sa->build_transforms(this->ike_sa, this->proposal, this->diffie_hellman, this->received_nonce, this->sent_nonce);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, AUDIT, "Transform objects could not be created from selected proposal. Deleting IKE_SA");
+ return DELETE_ME;
+ }
+
+ /* message can now be sent (must not be destroyed) */
+ status = this->ike_sa->send_response(this->ike_sa, response);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, AUDIT, "Unable to send IKE_SA_INIT response. Deleting IKE_SA");
+ response->destroy(response);
+ return DELETE_ME;
+ }
+
+ /* state can now be changed */
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Create next state object of type IKE_SA_INIT_RESPONDED");
+
+ response = this->ike_sa->get_last_responded_message(this->ike_sa);
+ ike_sa_init_response_data = response->get_packet_data(response);
+ ike_sa_init_request_data = message->get_packet_data(message);
+
+ next_state = ike_sa_init_responded_create(this->ike_sa, this->received_nonce, this->sent_nonce,ike_sa_init_request_data,
+ ike_sa_init_response_data);
+
+ /* state can now be changed */
+ this->ike_sa->set_new_state(this->ike_sa, (state_t *) next_state);
+ this->destroy_after_state_change(this);
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of private_initiator_init_t.build_sa_payload.
+ */
+static status_t build_sa_payload(private_responder_init_t *this,sa_payload_t *sa_request, message_t *response)
+{
+ proposal_t *proposal;
+ linked_list_t *proposal_list;
+ connection_t *connection;
+ sa_payload_t* sa_payload;
+ algorithm_t *algo;
+
+ connection = this->ike_sa->get_connection(this->ike_sa);
+
+ this->logger->log(this->logger, CONTROL | LEVEL2, "Process received SA payload");
+
+ /* get the list of suggested proposals */
+ proposal_list = sa_request->get_proposals (sa_request);
+
+ /* select proposal */
+ this->proposal = connection->select_proposal(connection, proposal_list);
+ while(proposal_list->remove_last(proposal_list, (void**)&proposal) == SUCCESS)
+ {
+ proposal->destroy(proposal);
+ }
+ proposal_list->destroy(proposal_list);
+ if (this->proposal == NULL)
+ {
+ this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request did not contain any acceptable proposals. Deleting IKE_SA");
+ this->ike_sa->send_notify(this->ike_sa, IKE_SA_INIT, NO_PROPOSAL_CHOSEN, CHUNK_INITIALIZER);
+ return DELETE_ME;
+ }
+ /* get selected DH group to force policy, this is very restrictive!? */
+ this->proposal->get_algorithm(this->proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, &algo);
+ this->dh_group_number = algo->algorithm;
+
+ this->logger->log(this->logger, CONTROL | LEVEL2, "SA Payload processed");
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Building SA payload");
+ sa_payload = sa_payload_create_from_proposal(this->proposal);
+ this->logger->log(this->logger, CONTROL|LEVEL2, "add SA payload to message");
+ response->add_payload(response,(payload_t *) sa_payload);
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of private_initiator_init_t.build_ke_payload.
+ */
+static status_t build_ke_payload(private_responder_init_t *this,ke_payload_t *ke_request, message_t *response)
+{
+ diffie_hellman_group_t group;
+ ke_payload_t *ke_payload;
+ diffie_hellman_t *dh;
+ chunk_t key_data;
+
+ this->logger->log(this->logger, CONTROL | LEVEL2, "Process received KE payload");
+ group = ke_request->get_dh_group_number(ke_request);
+
+ if (group == MODP_UNDEFINED)
+ {
+ this->logger->log(this->logger, AUDIT, "No diffie hellman group to select. Deleting IKE_SA");
+ return DELETE_ME;
+ }
+
+ if (this->dh_group_number != group)
+ {
+ u_int16_t accepted_group;
+ chunk_t accepted_group_chunk;
+ /* group not same as selected one
+ * Maybe key exchange payload is before SA payload */
+ this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request did not contain a acceptable diffie hellman group. Deleting IKE_SA");
+
+ accepted_group = htons(this->dh_group_number);
+ accepted_group_chunk.ptr = (u_int8_t*) &(accepted_group);
+ accepted_group_chunk.len = 2;
+ this->ike_sa->send_notify(this->ike_sa,IKE_SA_INIT,INVALID_KE_PAYLOAD,accepted_group_chunk);
+ return DELETE_ME;
+ }
+
+ /* create diffie hellman object to handle DH exchange */
+ dh = diffie_hellman_create(group);
+ if (dh == NULL)
+ {
+ this->logger->log(this->logger, AUDIT, "Could not generate DH object with group %d. Deleting IKE_SA",
+ mapping_find(diffie_hellman_group_m,group) );
+ return DELETE_ME;
+ }
+ this->logger->log(this->logger, CONTROL | LEVEL2, "Set other DH public value");
+
+ dh->set_other_public_value(dh, ke_request->get_key_exchange_data(ke_request));
+
+ this->diffie_hellman = dh;
+
+ this->logger->log(this->logger, CONTROL | LEVEL2, "KE Payload processed.");
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Building KE payload");
+ this->diffie_hellman->get_my_public_value(this->diffie_hellman,&key_data);
+
+ ke_payload = ke_payload_create();
+ ke_payload->set_key_exchange_data(ke_payload,key_data);
+ ke_payload->set_dh_group_number(ke_payload, this->dh_group_number);
+ chunk_free(&key_data);
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Add KE payload to message");
+ response->add_payload(response,(payload_t *) ke_payload);
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of private_responder_init_t.build_nonce_payload.
+ */
+static status_t build_nonce_payload(private_responder_init_t *this,nonce_payload_t *nonce_request, message_t *response)
+{
+ nonce_payload_t *nonce_payload;
+ randomizer_t *randomizer;
+ status_t status;
+
+ this->logger->log(this->logger, CONTROL | LEVEL2, "Process received NONCE payload");
+ free(this->received_nonce.ptr);
+ this->received_nonce = CHUNK_INITIALIZER;
+
+ this->logger->log(this->logger, CONTROL | LEVEL2, "Get NONCE value and store it");
+ this->received_nonce = nonce_request->get_nonce(nonce_request);
+
+ this->logger->log(this->logger, CONTROL | LEVEL2, "Create new NONCE value.");
+
+ randomizer = this->ike_sa->get_randomizer(this->ike_sa);
+ status = randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE, &(this->sent_nonce));
+ if (status != SUCCESS)
+ {
+ return status;
+ }
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Building NONCE payload");
+ nonce_payload = nonce_payload_create();
+ nonce_payload->set_nonce(nonce_payload, this->sent_nonce);
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Add NONCE payload to message");
+ response->add_payload(response,(payload_t *) nonce_payload);
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of private_responder_init_t.process_notify_payload.
+ */
+static status_t process_notify_payload(private_responder_init_t *this, notify_payload_t *notify_payload)
+{
+ notify_message_type_t notify_message_type = notify_payload->get_notify_message_type(notify_payload);
+
+ this->logger->log(this->logger, CONTROL|LEVEL1, "Process notify type %s",
+ mapping_find(notify_message_type_m, notify_message_type));
+
+ if (notify_payload->get_protocol_id(notify_payload) != PROTO_IKE)
+ {
+ this->logger->log(this->logger, ERROR | LEVEL1, "Notify reply not for IKE protocol.");
+ return FAILED;
+ }
+ switch (notify_message_type)
+ {
+ default:
+ {
+ this->logger->log(this->logger, CONTROL, "IKE_SA_INIT request contained a notify (%d), ignored.",
+ notify_message_type);
+ return SUCCESS;
+ }
+ }
+}
+
+/**
+ * Implementation of state_t.get_state.
+ */
+static ike_sa_state_t get_state(private_responder_init_t *this)
+{
+ return RESPONDER_INIT;
+}
+
+/**
+ * Implementation of state_t.destroy.
+ */
+static void destroy(private_responder_init_t *this)
+{
+ this->logger->log(this->logger, CONTROL | LEVEL1, "Going to destroy responder init state object");
+
+ this->logger->log(this->logger, CONTROL | LEVEL2, "Destroy sent nonce");
+ chunk_free(&(this->sent_nonce));
+ this->logger->log(this->logger, CONTROL | LEVEL2, "Destroy received nonce");
+ chunk_free(&(this->received_nonce));
+
+ if (this->diffie_hellman != NULL)
+ {
+ this->logger->log(this->logger, CONTROL | LEVEL2, "Destroy diffie_hellman_t hellman object");
+ this->diffie_hellman->destroy(this->diffie_hellman);
+ }
+ if (this->proposal)
+ {
+ this->proposal->destroy(this->proposal);
+ }
+ this->logger->log(this->logger, CONTROL | LEVEL2, "Destroy object");
+ free(this);
+}
+
+/**
+ * Implementation of private_responder_init_t.destroy_after_state_change
+ */
+static void destroy_after_state_change (private_responder_init_t *this)
+{
+ this->logger->log(this->logger, CONTROL | LEVEL1, "Going to destroy responder_init_t state object");
+
+ /* destroy diffie hellman object */
+ if (this->diffie_hellman != NULL)
+ {
+ this->logger->log(this->logger, CONTROL | LEVEL2, "Destroy diffie_hellman_t object");
+ this->diffie_hellman->destroy(this->diffie_hellman);
+ }
+ if (this->proposal)
+ {
+ this->proposal->destroy(this->proposal);
+ }
+
+ this->logger->log(this->logger, CONTROL | LEVEL2, "Destroy object");
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+responder_init_t *responder_init_create(protected_ike_sa_t *ike_sa)
+{
+ private_responder_init_t *this = malloc_thing(private_responder_init_t);
+
+ /* interface functions */
+ this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
+ this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
+ this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
+
+ /* private functions */
+ this->build_sa_payload = build_sa_payload;
+ this->build_ke_payload = build_ke_payload;
+ this->build_nonce_payload = build_nonce_payload;
+ this->destroy_after_state_change = destroy_after_state_change;
+ this->process_notify_payload = process_notify_payload;
+
+ /* private data */
+ this->ike_sa = ike_sa;
+ this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
+ this->sent_nonce = CHUNK_INITIALIZER;
+ this->received_nonce = CHUNK_INITIALIZER;
+ this->dh_group_number = MODP_UNDEFINED;
+ this->diffie_hellman = NULL;
+ this->proposal = NULL;
+
+ return &(this->public);
+}
diff --git a/programs/charon/charon/sa/states/responder_init.h b/programs/charon/charon/sa/states/responder_init.h
new file mode 100644
index 000000000..c8ba73ea3
--- /dev/null
+++ b/programs/charon/charon/sa/states/responder_init.h
@@ -0,0 +1,68 @@
+/**
+ * @file responder_init.h
+ *
+ * @brief Interface of responder_init_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef RESPONDER_INIT_H_
+#define RESPONDER_INIT_H_
+
+#include <sa/ike_sa.h>
+#include <sa/states/state.h>
+
+
+typedef struct responder_init_t responder_init_t;
+
+/**
+ * @brief This class represents an IKE_SA state when
+ * initializing a connection as responder.
+ *
+ * @b Constructors:
+ * - responder_init_create()
+ *
+ * @ingroup states
+ */
+struct responder_init_t {
+ /**
+ * The state_t interface.
+ */
+ state_t state_interface;
+};
+
+/**
+ * Constructor of class responder_init_t.
+ *
+ * The following functions of the assigned protected_ike_sa_t object are being called with
+ * valid values after successfully processing a received message and before changing
+ * to next state IKE_SA_INIT_RESPONDED:
+ * - protected_ike_sa_t.set_connection()
+ * - protected_ike_sa_t.set_my_host()
+ * - protected_ike_sa_t.set_other_host()
+ * - protected_ike_sa_t.compute_secrets()
+ * - protected_ike_sa_t.create_transforms_from_proposal()
+ *
+ * @param ike_sa assigned IKE_SA
+ *
+ * @return responder_init_t object
+ *
+ * @ingroup states
+ */
+responder_init_t *responder_init_create(protected_ike_sa_t *ike_sa);
+
+#endif /*RESPONDER_INIT_H_*/
diff --git a/programs/charon/charon/sa/states/state.c b/programs/charon/charon/sa/states/state.c
new file mode 100644
index 000000000..595f5abbb
--- /dev/null
+++ b/programs/charon/charon/sa/states/state.c
@@ -0,0 +1,37 @@
+/**
+ * @file state.c
+ *
+ * @brief Interface state_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "state.h"
+
+
+/**
+ * String mappings for ike_sa_state_t.
+ */
+mapping_t ike_sa_state_m[] = {
+ {INITIATOR_INIT, "INITIATOR_INIT"},
+ {RESPONDER_INIT, "RESPONDER_INIT"},
+ {IKE_SA_INIT_REQUESTED, "IKE_SA_INIT_REQUESTED"},
+ {IKE_SA_INIT_RESPONDED, "IKE_SA_INIT_RESPONDED"},
+ {IKE_AUTH_REQUESTED, "IKE_AUTH_REQUESTED"},
+ {IKE_SA_ESTABLISHED, "IKE_SA_ESTABLISHED"},
+ {MAPPING_END, NULL}
+};
diff --git a/programs/charon/charon/sa/states/state.h b/programs/charon/charon/sa/states/state.h
new file mode 100644
index 000000000..c93068d35
--- /dev/null
+++ b/programs/charon/charon/sa/states/state.h
@@ -0,0 +1,166 @@
+/**
+ * @file state.h
+ *
+ * @brief Interface state_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef STATE_H_
+#define STATE_H_
+
+#include <definitions.h>
+#include <types.h>
+#include <encoding/message.h>
+
+typedef enum ike_sa_state_t ike_sa_state_t;
+
+/**
+ * States in which a IKE_SA can be.
+ *
+ * @todo Support of more states (CHILD_SA_REQUESTED, etc...)
+ *
+ * @ingroup states
+ */
+enum ike_sa_state_t {
+
+ /**
+ * @brief IKE_SA is in initial state as initiator and is going to initiate a new connection.
+ *
+ * Next state following this state is IKE_SA_INIT_REQUESTED.
+ *
+ * Implemented in class initiator_init_t.
+ */
+ INITIATOR_INIT = 1,
+
+ /**
+ * @brief IKE_SA is in initial state as responder and is going to respond to a initiated connection.
+ *
+ * Next state following this state is IKE_SA_INIT_RESPONDED.
+ *
+ * Implemented in class responder_init_t.
+ */
+ RESPONDER_INIT = 2,
+
+ /**
+ * @brief A IKE_SA_INIT request was sent. In this state a reply of type IKE_SA_INIT is expected.
+ *
+ * Two states are possible as next states:
+ * - IKE_AUTH_REQUESTED if IKE_SA_INIT reply could successfully processed and IKE_AUTH request could be sent.
+ * - INITIATOR_INIT if selected DH group was not the one selected by other peer.
+ *
+ * Implemented in class ike_sa_init_requested_t.
+ */
+ IKE_SA_INIT_REQUESTED = 3,
+
+ /**
+ * @brief A IKE_SA_INIT response was sent. In this state a request of type IKE_AUTH is expected.
+ *
+ * Next state following this state is IKE_SA_ESTABLISHED.
+ *
+ * Implemented in class ike_sa_init_responded_t.
+ */
+ IKE_SA_INIT_RESPONDED = 4,
+
+ /**
+ * @brief An IKE_AUTH request was sent after a successful IKE_SA_INIT-exchange.
+ *
+ * Next state following this state is IKE_SA_ESTABLISHED.
+ *
+ * Implemented in class ike_auth_requested_t.
+ */
+ IKE_AUTH_REQUESTED = 5,
+
+ /**
+ * @brief An IKE_AUTH exchange was successfuly handled either as initiator or responder.
+ *
+ * In this state, all the informations for an IKE_SA and one CHILD_SA are known.
+ *
+ * Implemented in class ike_sa_established_t.
+ */
+ IKE_SA_ESTABLISHED = 6
+};
+
+
+/**
+ * String mappings for ike_sa_state_t.
+ */
+extern mapping_t ike_sa_state_m[];
+
+
+typedef struct state_t state_t;
+
+/**
+ * @brief This interface represents an IKE_SA state.
+ *
+ * A state_t object is responsible to handle incoming messages.
+ *
+ * It's the responsibility of the state_t object to parse the body of the message and to process each
+ * payload.
+ *
+ * Needed Configurations and transform objects can be retrieved over an internal stored protected_ike_sa_t object
+ * which is passed to a state_t object when creating it (see different constructors).
+ *
+ * The following states are supported and implemented:
+ * - INITIATOR_INIT: implemented in initiator_init_t
+ * - RESPONDER_INIT: implemented in responder_init_t
+ * - IKE_SA_INIT_REQUESTED: implemented in ike_sa_init_requested_t
+ * - IKE_SA_INIT_RESPONDED: implemented in ike_sa_init_responded_t
+ * - IKE_AUTH_REQUESTED: implemented in ike_auth_requested_t
+ * - IKE_SA_ESTABLISHED: implemented in ike_sa_established_t
+ *
+ * @b Constructors:
+ * - initiator_init_create()
+ * - responder_init_create()
+ * - ike_sa_init_requested_create()
+ * - ike_sa_init_responded_create()
+ * - ike_auth_requested_create()
+ * - ike_sa_established_create()
+ *
+ * @ingroup states
+ */
+struct state_t {
+
+ /**
+ * @brief Processes a incoming IKEv2-Message of type message_t.
+ *
+ * @param this calling object
+ * @param[in] message message_t object to process
+ * @return
+ * - SUCCESSFUL
+ * - FAILED
+ * - DELETE_ME if belonging IKE_SA should be deleted
+ */
+ status_t (*process_message) (state_t *this,message_t *message);
+
+ /**
+ * @brief Get the current state representing by this state_t object.
+ *
+ * @param this calling object
+ * @return state
+ */
+ ike_sa_state_t (*get_state) (state_t *this);
+
+ /**
+ * @brief Destroys a state_t object.
+ *
+ * @param this calling object
+ */
+ void (*destroy) (state_t *this);
+};
+
+#endif /*STATE_H_*/
diff --git a/programs/charon/charon/threads/Makefile.threads b/programs/charon/charon/threads/Makefile.threads
new file mode 100644
index 000000000..949c1ad24
--- /dev/null
+++ b/programs/charon/charon/threads/Makefile.threads
@@ -0,0 +1,39 @@
+# Copyright (C) 2005 Jan Hutter, Martin Willi
+# Hochschule fuer Technik Rapperswil
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+
+THREADS_DIR= $(CHARON_DIR)threads/
+
+CHARON_OBJS+= $(BUILD_DIR)receiver.o
+$(BUILD_DIR)receiver.o : $(THREADS_DIR)receiver.c $(THREADS_DIR)receiver.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)scheduler.o
+$(BUILD_DIR)scheduler.o : $(THREADS_DIR)scheduler.c $(THREADS_DIR)scheduler.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)sender.o
+$(BUILD_DIR)sender.o : $(THREADS_DIR)sender.c $(THREADS_DIR)sender.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)thread_pool.o
+$(BUILD_DIR)thread_pool.o : $(THREADS_DIR)thread_pool.c $(THREADS_DIR)thread_pool.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)kernel_interface.o
+$(BUILD_DIR)kernel_interface.o :$(THREADS_DIR)kernel_interface.c $(THREADS_DIR)kernel_interface.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+CHARON_OBJS+= $(BUILD_DIR)stroke_interface.o
+$(BUILD_DIR)stroke_interface.o :$(THREADS_DIR)stroke_interface.c $(THREADS_DIR)stroke_interface.h
+ $(CC) $(CFLAGS) -c -o $@ $<
diff --git a/programs/charon/charon/threads/kernel_interface.c b/programs/charon/charon/threads/kernel_interface.c
new file mode 100644
index 000000000..679cf69ee
--- /dev/null
+++ b/programs/charon/charon/threads/kernel_interface.c
@@ -0,0 +1,729 @@
+/**
+ * @file kernel_interface.c
+ *
+ * @brief Implementation of kernel_interface_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2003 Herbert Xu.
+ *
+ * Contains modified parts from pluto.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
+#include "kernel_interface.h"
+
+#include <daemon.h>
+#include <utils/linked_list.h>
+
+
+#define KERNEL_ESP 50
+#define KERNEL_AH 51
+
+#define SPD_PRIORITY 1024
+
+#define XFRM_DATA_LENGTH 512
+
+
+typedef struct xfrm_data_t xfrm_data_t;
+
+/**
+ * Lenght/Type/data struct for userdata in xfrm
+ * We dont use the "I-don't-know-where-they-come-from"-structs
+ * used in the kernel.
+ */
+struct xfrm_data_t {
+ /**
+ * length of the data
+ */
+ u_int16_t length;
+
+ /**
+ * type of data
+ */
+ u_int16_t type;
+
+ /**
+ * and the data itself, for different purposes
+ */
+ union {
+ /** algorithm */
+ struct xfrm_algo algo;
+ /** policy tmpl */
+ struct xfrm_user_tmpl tmpl[2];
+ };
+};
+
+
+typedef struct netlink_message_t netlink_message_t;
+
+/**
+ * Representation of ANY netlink message used
+ */
+struct netlink_message_t {
+
+ /**
+ * header of the netlink message
+ */
+ struct nlmsghdr hdr;
+
+ union {
+ /** error message */
+ struct nlmsgerr e;
+ /** message for spi allocation */
+ struct xfrm_userspi_info spi;
+ /** message for SA manipulation */
+ struct xfrm_usersa_id sa_id;
+ /** message for SA installation */
+ struct xfrm_usersa_info sa;
+ /** message for policy manipulation */
+ struct xfrm_userpolicy_id policy_id;
+ /** message for policy installation */
+ struct xfrm_userpolicy_info policy;
+ };
+ u_int8_t data[XFRM_DATA_LENGTH];
+};
+
+
+typedef struct private_kernel_interface_t private_kernel_interface_t;
+
+ /**
+ * @brief Private Variables and Functions of kernel_interface class.
+ *
+ */
+struct private_kernel_interface_t {
+ /**
+ * Public part of the kernel_interface_t object.
+ */
+ kernel_interface_t public;
+
+ /**
+ * Netlink communication socket.
+ */
+ int socket;
+
+ /**
+ * Process id of kernel thread
+ */
+ pid_t pid;
+
+ /**
+ * Sequence number for messages.
+ */
+ u_int32_t seq;
+
+ /**
+ * List of responded messages.
+ */
+ linked_list_t *responses;
+
+ /**
+ * Thread which receives messages.
+ */
+ pthread_t thread;
+
+ /**
+ * Mutex locks access to replies list.
+ */
+ pthread_mutex_t mutex;
+
+ /**
+ * Condvar allows signaling of threads waiting for a reply.
+ */
+ pthread_cond_t condvar;
+
+ /**
+ * Logger for XFRM stuff
+ */
+ logger_t *logger;
+
+ /**
+ * Function for the thread, receives messages.
+ */
+ void (*receive_messages) (private_kernel_interface_t *this);
+
+ /**
+ * Sends a netlink_message_t down to the kernel and wait for reply.
+ */
+ status_t (*send_message) (private_kernel_interface_t *this, netlink_message_t *request, netlink_message_t **response);
+};
+
+/**
+ * In the kernel, algorithms are identified as strings, we use our
+ * mapping functions...
+ * Algorithms for encryption.
+ * TODO: Add missing algorithm strings
+ */
+mapping_t kernel_encryption_algs_m[] = {
+ {ENCR_DES_IV64, ""},
+ {ENCR_DES, "des"},
+ {ENCR_3DES, "des3_ede"},
+ {ENCR_RC5, ""},
+ {ENCR_IDEA, "idea"},
+ {ENCR_CAST, "cast128"},
+ {ENCR_BLOWFISH, "blowfish"},
+ {ENCR_3IDEA, ""},
+ {ENCR_DES_IV32, ""},
+ {ENCR_NULL, ""},
+ {ENCR_AES_CBC, "aes"},
+ {ENCR_AES_CTR, ""},
+ {MAPPING_END, NULL}
+};
+/**
+ * In the kernel, algorithms are identified as strings, we use our
+ * mapping functions...
+ * Algorithms for integrity protection.
+ * TODO: Add missing algorithm strings
+ */
+mapping_t kernel_integrity_algs_m[] = {
+ {AUTH_HMAC_MD5_96, "md5"},
+ {AUTH_HMAC_SHA1_96, "sha1"},
+ {AUTH_DES_MAC, ""},
+ {AUTH_KPDK_MD5, ""},
+ {AUTH_AES_XCBC_96, ""},
+ {MAPPING_END, NULL}
+};
+
+
+/**
+ * Implementation of kernel_interface_t.get_spi.
+ */
+static status_t get_spi(private_kernel_interface_t *this,
+ host_t *src, host_t *dest,
+ protocol_id_t protocol, u_int32_t reqid,
+ u_int32_t *spi)
+{
+ netlink_message_t request, *response;
+ status_t status = SUCCESS;
+
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "getting spi");
+
+ memset(&request, 0, sizeof(request));
+ request.hdr.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(request.spi)));
+ request.hdr.nlmsg_flags = NLM_F_REQUEST;
+ request.hdr.nlmsg_type = XFRM_MSG_ALLOCSPI;
+ request.spi.info.saddr = src->get_xfrm_addr(src);
+ request.spi.info.id.daddr = dest->get_xfrm_addr(dest);
+ request.spi.info.mode = TRUE; /* tunnel mode */
+ request.spi.info.reqid = reqid;
+ request.spi.info.id.proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH;
+ request.spi.info.family = PF_INET;
+ request.spi.min = 0xc0000000;
+ request.spi.max = 0xcFFFFFFF;
+
+ if (this->send_message(this, &request, &response) != SUCCESS)
+ {
+ this->logger->log(this->logger, ERROR, "netlink communication failed");
+ return FAILED;
+ }
+ else if (response->hdr.nlmsg_type == NLMSG_ERROR)
+ {
+ this->logger->log(this->logger, ERROR, "netlink request XFRM_MSG_ALLOCSPI got an error: %s",
+ strerror(-response->e.error));
+ status = FAILED;
+ }
+ else if (response->hdr.nlmsg_type != XFRM_MSG_NEWSA)
+ {
+ this->logger->log(this->logger, ERROR, "netlink request XFRM_MSG_ALLOCSPI got a unknown reply");
+ status = FAILED;
+ }
+ else if (response->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(response->sa)))
+ {
+ this->logger->log(this->logger, ERROR, "netlink request XFRM_MSG_ALLOCSPI got an invalid reply");
+ status = FAILED;
+ }
+ else
+ {
+ *spi = response->sa.id.spi;
+ }
+ free(response);
+
+ return status;
+}
+
+/**
+ * Implementation of kernel_interface_t.add_sa.
+ */
+static status_t add_sa( private_kernel_interface_t *this,
+ host_t *me,
+ host_t *other,
+ u_int32_t spi,
+ int protocol,
+ u_int32_t reqid,
+ encryption_algorithm_t enc_alg,
+ chunk_t encryption_key,
+ integrity_algorithm_t int_alg,
+ chunk_t integrity_key,
+ bool replace)
+{
+ netlink_message_t request, *response;
+ memset(&request, 0, sizeof(request));
+ status_t status = SUCCESS;
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "adding SA");
+
+ request.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ request.hdr.nlmsg_type = replace ? XFRM_MSG_UPDSA : XFRM_MSG_NEWSA;
+
+ request.sa.saddr = me->get_xfrm_addr(me);
+ request.sa.id.daddr = other->get_xfrm_addr(other);
+
+ request.sa.id.spi = spi;
+ request.sa.id.proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH;
+ request.sa.family = me->get_family(me);
+ request.sa.mode = TRUE; /* tunnel mode */
+ request.sa.replay_window = 32;
+ request.sa.reqid = reqid;
+ request.sa.lft.soft_byte_limit = XFRM_INF;
+ request.sa.lft.soft_packet_limit = XFRM_INF;
+ request.sa.lft.hard_byte_limit = XFRM_INF;
+ request.sa.lft.hard_packet_limit = XFRM_INF;
+
+ request.hdr.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(request.sa)));
+
+ if (enc_alg != ENCR_UNDEFINED)
+ {
+ xfrm_data_t *data = (xfrm_data_t*)(((u_int8_t*)&request) + request.hdr.nlmsg_len);
+
+ data->type = XFRMA_ALG_CRYPT;
+ data->length = 4 + sizeof(data->algo) + encryption_key.len;
+ data->algo.alg_key_len = encryption_key.len * 8;
+ request.hdr.nlmsg_len += data->length;
+ if (request.hdr.nlmsg_len > sizeof(request))
+ {
+ return FAILED;
+ }
+ strcpy(data->algo.alg_name, mapping_find(kernel_encryption_algs_m, enc_alg));
+ memcpy(data->algo.alg_key, encryption_key.ptr, encryption_key.len);
+ }
+
+ if (int_alg != AUTH_UNDEFINED)
+ {
+ xfrm_data_t *data = (xfrm_data_t*)(((u_int8_t*)&request) + request.hdr.nlmsg_len);
+
+ data->type = XFRMA_ALG_AUTH;
+ data->length = 4 + sizeof(data->algo) + integrity_key.len;
+ data->algo.alg_key_len = integrity_key.len * 8;
+ request.hdr.nlmsg_len += data->length;
+ if (request.hdr.nlmsg_len > sizeof(request))
+ {
+ return FAILED;
+ }
+ strcpy(data->algo.alg_name, mapping_find(kernel_integrity_algs_m, int_alg));
+ memcpy(data->algo.alg_key, integrity_key.ptr, integrity_key.len);
+ }
+
+ /* TODO: add IPComp here*/
+
+ if (this->send_message(this, &request, &response) != SUCCESS)
+ {
+ this->logger->log(this->logger, ERROR, "netlink communication failed");
+ return FAILED;
+ }
+ else if (response->hdr.nlmsg_type != NLMSG_ERROR)
+ {
+ this->logger->log(this->logger, ERROR, "netlink request XFRM_MSG_NEWSA not acknowledged");
+ status = FAILED;
+ }
+ else if (response->e.error)
+ {
+ this->logger->log(this->logger, ERROR, "netlink request XFRM_MSG_NEWSA got error %s",
+ strerror(-response->e.error));
+ status = FAILED;
+ }
+
+ free(response);
+ return status;
+}
+
+static status_t del_sa( private_kernel_interface_t *this,
+ host_t *dst,
+ u_int32_t spi,
+ protocol_id_t protocol)
+{
+ netlink_message_t request, *response;
+ memset(&request, 0, sizeof(request));
+ status_t status = SUCCESS;
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "deleting SA");
+
+ request.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ request.hdr.nlmsg_type = XFRM_MSG_DELSA;
+
+ request.sa_id.daddr = dst->get_xfrm_addr(dst);
+
+ request.sa_id.spi = spi;
+ request.sa_id.proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH;
+ request.sa_id.family = dst->get_family(dst);
+
+ request.hdr.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(request.sa_id)));
+
+ if (this->send_message(this, &request, &response) != SUCCESS)
+ {
+ return FAILED;
+ }
+ else if (response->hdr.nlmsg_type != NLMSG_ERROR)
+ {
+ status = FAILED;
+ }
+ else if (response->e.error)
+ {
+ status = FAILED;
+ }
+
+ free(response);
+ return status;
+}
+
+/**
+ * Implementation of kernel_interface_t.add_policy.
+ */
+static status_t add_policy(private_kernel_interface_t *this,
+ host_t *me, host_t *other,
+ host_t *src, host_t *dst,
+ u_int8_t src_hostbits, u_int8_t dst_hostbits,
+ int direction, int upper_proto,
+ bool ah, bool esp,
+ u_int32_t reqid)
+{
+ netlink_message_t request, *response;
+ status_t status = SUCCESS;
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "adding policy");
+
+ memset(&request, 0, sizeof(request));
+ request.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+
+ request.policy.sel.sport = htons(src->get_port(src));
+ request.policy.sel.dport = htons(dst->get_port(dst));
+ request.policy.sel.sport_mask = (request.policy.sel.sport) ? ~0 : 0;
+ request.policy.sel.dport_mask = (request.policy.sel.dport) ? ~0 : 0;
+ request.policy.sel.saddr = src->get_xfrm_addr(src);
+ request.policy.sel.daddr = dst->get_xfrm_addr(dst);
+ request.policy.sel.prefixlen_s = src_hostbits;
+ request.policy.sel.prefixlen_d = dst_hostbits;
+ request.policy.sel.proto = upper_proto;
+ request.policy.sel.family = src->get_family(src);
+
+ request.hdr.nlmsg_type = XFRM_MSG_NEWPOLICY;
+ request.hdr.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(request.policy)));
+
+ request.policy.dir = direction;
+ request.policy.priority = SPD_PRIORITY;
+ request.policy.action = XFRM_POLICY_ALLOW;
+ request.policy.share = XFRM_SHARE_ANY;
+
+ request.policy.lft.soft_byte_limit = XFRM_INF;
+ request.policy.lft.soft_packet_limit = XFRM_INF;
+ request.policy.lft.hard_byte_limit = XFRM_INF;
+ request.policy.lft.hard_packet_limit = XFRM_INF;
+
+ if (esp || ah)
+ {
+ xfrm_data_t *data;
+ int tmpl_pos = 0;
+ data = (xfrm_data_t*)(((u_int8_t*)&request) + request.hdr.nlmsg_len);
+ data->type = XFRMA_TMPL;
+ if (esp)
+ {
+ data->tmpl[tmpl_pos].reqid = reqid;
+ data->tmpl[tmpl_pos].id.proto = KERNEL_ESP;
+ data->tmpl[tmpl_pos].aalgos = data->tmpl[tmpl_pos].ealgos = data->tmpl[tmpl_pos].calgos = ~0;
+ data->tmpl[tmpl_pos].mode = TRUE;
+
+ data->tmpl[tmpl_pos].saddr = me->get_xfrm_addr(me);
+ data->tmpl[tmpl_pos].id.daddr = me->get_xfrm_addr(other);
+
+ tmpl_pos++;
+ }
+ if (ah)
+ {
+ data->tmpl[tmpl_pos].reqid = reqid;
+ data->tmpl[tmpl_pos].id.proto = KERNEL_AH;
+ data->tmpl[tmpl_pos].aalgos = data->tmpl[tmpl_pos].ealgos = data->tmpl[tmpl_pos].calgos = ~0;
+ data->tmpl[tmpl_pos].mode = TRUE;
+
+ data->tmpl[tmpl_pos].saddr = me->get_xfrm_addr(me);
+ data->tmpl[tmpl_pos].id.daddr = other->get_xfrm_addr(other);
+
+ tmpl_pos++;
+ }
+ data->length = 4 + sizeof(struct xfrm_user_tmpl) * tmpl_pos;
+ request.hdr.nlmsg_len += data->length;
+ }
+
+ if (this->send_message(this, &request, &response) != SUCCESS)
+ {
+ this->logger->log(this->logger, ERROR, "netlink communication failed");
+ return FAILED;
+ }
+ else if (response->hdr.nlmsg_type != NLMSG_ERROR)
+ {
+ this->logger->log(this->logger, ERROR, "netlink request XFRM_MSG_NEWPOLICY not acknowledged");
+ status = FAILED;
+ }
+ else if (response->e.error)
+ {
+ this->logger->log(this->logger, ERROR, "netlink request XFRM_MSG_NEWPOLICY got error %s",
+ strerror(-response->e.error));
+ status = FAILED;
+ }
+
+ free(response);
+ return status;
+}
+
+/**
+ * Implementation of kernel_interface_t.del_policy.
+ */
+static status_t del_policy(private_kernel_interface_t *this,
+ host_t *me, host_t *other,
+ host_t *src, host_t *dst,
+ u_int8_t src_hostbits, u_int8_t dst_hostbits,
+ int direction, int upper_proto)
+{
+ netlink_message_t request, *response;
+ status_t status = SUCCESS;
+
+
+ this->logger->log(this->logger, CONTROL|LEVEL2, "deleting policy");
+
+ memset(&request, 0, sizeof(request));
+ request.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+
+ request.policy_id.sel.sport = htons(src->get_port(src));
+ request.policy_id.sel.dport = htons(dst->get_port(dst));
+ request.policy_id.sel.sport_mask = (request.policy.sel.sport) ? ~0 : 0;
+ request.policy_id.sel.dport_mask = (request.policy.sel.dport) ? ~0 : 0;
+ request.policy_id.sel.saddr = src->get_xfrm_addr(src);
+ request.policy_id.sel.daddr = dst->get_xfrm_addr(dst);
+ request.policy_id.sel.prefixlen_s = src_hostbits;
+ request.policy_id.sel.prefixlen_d = dst_hostbits;
+ request.policy_id.sel.proto = upper_proto;
+ request.policy_id.sel.family = src->get_family(src);
+
+ request.policy_id.dir = direction;
+
+ request.hdr.nlmsg_type = XFRM_MSG_DELPOLICY;
+ request.hdr.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(request.policy_id)));
+
+ if (this->send_message(this, &request, &response) != SUCCESS)
+ {
+ return FAILED;
+ }
+ else if (response->hdr.nlmsg_type != NLMSG_ERROR)
+ {
+ status = FAILED;
+ }
+ else if (response->e.error)
+ {
+ status = FAILED;
+ }
+
+ free(response);
+ return status;
+}
+
+/**
+ * Implementation of private_kernel_interface_t.send_message.
+ */
+static status_t send_message(private_kernel_interface_t *this, netlink_message_t *request, netlink_message_t **response)
+{
+ size_t length;
+ struct sockaddr_nl addr;
+
+ request->hdr.nlmsg_seq = ++this->seq;
+ request->hdr.nlmsg_pid = this->pid;
+
+ memset(&addr, 0, sizeof(struct sockaddr_nl));
+ addr.nl_family = AF_NETLINK;
+ addr.nl_pid = 0;
+ addr.nl_groups = 0;
+
+ length = sendto(this->socket,(void *)request, request->hdr.nlmsg_len, 0, (struct sockaddr *)&addr, sizeof(addr));
+
+ if (length < 0)
+ {
+ return FAILED;
+ }
+ else if (length != request->hdr.nlmsg_len)
+ {
+ return FAILED;
+ }
+
+ pthread_mutex_lock(&(this->mutex));
+
+ while (TRUE)
+ {
+ iterator_t *iterator;
+ bool found = FALSE;
+ /* search list, break if found */
+ iterator = this->responses->create_iterator(this->responses, TRUE);
+ while (iterator->has_next(iterator))
+ {
+ netlink_message_t *listed_response;
+ iterator->current(iterator, (void**)&listed_response);
+ if (listed_response->hdr.nlmsg_seq == request->hdr.nlmsg_seq)
+ {
+ /* matches our request, this is the reply */
+ *response = listed_response;
+ found = TRUE;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+
+ if (found)
+ {
+ break;
+ }
+ /* TODO: we should time out, if something goes wrong!??? */
+ pthread_cond_wait(&(this->condvar), &(this->mutex));
+ }
+
+ pthread_mutex_unlock(&(this->mutex));
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of private_kernel_interface_t.receive_messages.
+ */
+static void receive_messages(private_kernel_interface_t *this)
+{
+ while(TRUE)
+ {
+ netlink_message_t response, *listed_response;
+ while (TRUE)
+ {
+ struct sockaddr_nl addr;
+ socklen_t addr_length;
+ size_t length;
+
+ addr_length = sizeof(addr);
+
+ response.hdr.nlmsg_type = XFRM_MSG_NEWSA;
+ length = recvfrom(this->socket, &response, sizeof(response), 0, (struct sockaddr*)&addr, &addr_length);
+ if (length < 0)
+ {
+ if (errno == EINTR)
+ {
+ /* interrupted, try again */
+ continue;
+ }
+ charon->kill(charon, "receiving from netlink socket failed");
+ }
+ if (!NLMSG_OK(&response.hdr, length))
+ {
+ /* bad netlink message */
+ continue;
+ }
+ if (addr.nl_pid != 0)
+ {
+ /* not from kernel. not interested, try another one */
+ continue;
+ }
+ break;
+ }
+
+ /* got a valid message.
+ * requests are handled on our own,
+ * responses are listed for the requesters
+ */
+ if (response.hdr.nlmsg_flags & NLM_F_REQUEST)
+ {
+ /* handle request */
+ }
+ else
+ {
+ /* add response to queue */
+ listed_response = malloc(sizeof(response));
+ memcpy(listed_response, &response, sizeof(response));
+
+ pthread_mutex_lock(&(this->mutex));
+ this->responses->insert_last(this->responses, (void*)listed_response);
+ pthread_mutex_unlock(&(this->mutex));
+ /* signal ALL waiting threads */
+ pthread_cond_broadcast(&(this->condvar));
+ }
+ /* get the next one */
+ }
+}
+
+/**
+ * Implementation of kernel_interface_t.destroy.
+ */
+static void destroy(private_kernel_interface_t *this)
+{
+ pthread_cancel(this->thread);
+ pthread_join(this->thread, NULL);
+ close(this->socket);
+ this->responses->destroy(this->responses);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+kernel_interface_t *kernel_interface_create()
+{
+ private_kernel_interface_t *this = malloc_thing(private_kernel_interface_t);
+
+ /* public functions */
+ this->public.get_spi = (status_t(*)(kernel_interface_t*,host_t*,host_t*,protocol_id_t,u_int32_t,u_int32_t*))get_spi;
+ this->public.add_sa = (status_t(*)(kernel_interface_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,encryption_algorithm_t,chunk_t,integrity_algorithm_t,chunk_t,bool))add_sa;
+ this->public.add_policy = (status_t(*)(kernel_interface_t*,host_t*, host_t*,host_t*,host_t*,u_int8_t,u_int8_t,int,int,bool,bool,u_int32_t))add_policy;
+ this->public.del_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t))del_sa;
+ this->public.del_policy = (status_t(*)(kernel_interface_t*,host_t*,host_t*,host_t*,host_t*,u_int8_t,u_int8_t,int,int))del_policy;
+
+ this->public.destroy = (void(*)(kernel_interface_t*)) destroy;
+
+ /* private members */
+ this->receive_messages = receive_messages;
+ this->send_message = send_message;
+ this->pid = getpid();
+ this->responses = linked_list_create();
+ this->logger = logger_manager->get_logger(logger_manager, XFRM);
+ pthread_mutex_init(&(this->mutex),NULL);
+ pthread_cond_init(&(this->condvar),NULL);
+ this->seq = 0;
+ this->socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_XFRM);
+ if (this->socket <= 0)
+ {
+ this->responses->destroy(this->responses);
+ free(this);
+ charon->kill(charon, "Unable to create netlink socket");
+ }
+
+ if (pthread_create(&(this->thread), NULL, (void*(*)(void*))this->receive_messages, this) != 0)
+ {
+ this->responses->destroy(this->responses);
+ close(this->socket);
+ free(this);
+ charon->kill(charon, "Unable to create netlink thread");
+ }
+
+ return (&this->public);
+}
diff --git a/programs/charon/charon/threads/kernel_interface.h b/programs/charon/charon/threads/kernel_interface.h
new file mode 100644
index 000000000..ceafa6468
--- /dev/null
+++ b/programs/charon/charon/threads/kernel_interface.h
@@ -0,0 +1,185 @@
+/**
+ * @file kernel_interface.h
+ *
+ * @brief Interface of kernel_interface_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef KERNEL_INTERFACE_H_
+#define KERNEL_INTERFACE_H_
+
+#include <linux/xfrm.h>
+
+#include <utils/host.h>
+#include <encoding/payloads/proposal_substructure.h>
+
+typedef struct kernel_interface_t kernel_interface_t;
+
+/**
+ * @brief 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
+ * further the handling of kernel events.
+ *
+ * @b Constructors:
+ * - kernel_interface_create()
+ *
+ * @ingroup threads
+ */
+struct kernel_interface_t {
+
+ /**
+ * @brief Get a SPI from the kernel.
+ *
+ * @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
+ */
+ 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_sa() may update an already allocated
+ * SPI (via get_spi). In this case, the replace
+ * flag must be set.
+ * This function does install a single SA for a
+ * single protocol in one direction.
+ *
+ * @param 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
+ * @param protocol protocol for this SA (ESP/AH)
+ * @param reqid unique ID for this SA
+ * @param enc_alg Algorithm to use for encryption (ESP only)
+ * @param enc_key Key to use for encryption
+ * @param int_alg Algorithm to use for integrity protection
+ * @param int_key Key for integrity protection
+ * @param replace Should an already installed SA be updated?
+ * @return
+ * - SUCCESS
+ * - FAILED if kernel comm failed
+ */
+ status_t (*add_sa)(kernel_interface_t *this,
+ host_t *src, host_t *dst,
+ u_int32_t spi,
+ protocol_id_t protocol,
+ u_int32_t reqid,
+ encryption_algorithm_t enc_alg,
+ chunk_t enc_key,
+ integrity_algorithm_t int_alg,
+ chunk_t int_key,
+ bool replace);
+ /**
+ * @brief 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
+ */
+ 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.
+ *
+ * A policy is always associated to an SA, so
+ * traffic applied to a policy. Traffic which
+ * matches a policy is handled by the SA with the same
+ * reqid.
+ *
+ * @param this calling object
+ * @param me address of local peer
+ * @param other address of remote peer
+ * @param src src address of traffic this policy applies
+ * @param dst dest address of traffic this policy applies
+ * @param src_hostbits subnetmask to use for src address
+ * @param dst_hostbits subnetmask to use for dst address
+ * @param direction direction of traffic, XFRM_POLICY_OUT, XFRM_POLICY_IN, XFRM_POLICY_FWD
+ * @param upper_proto upper layer protocol of traffic for this policy (TCP, UDP, ICMP, ...)
+ * @param ah protect traffic with AH?
+ * @param esp protect traffic with ESP?
+ * @param reqid uniqe ID of an SA to use to enforce policy
+ * @return
+ * - SUCCESS
+ * - FAILED if kernel comm failed
+ */
+ status_t (*add_policy) (kernel_interface_t *this,
+ host_t *me, host_t *other,
+ host_t *src, host_t *dst,
+ u_int8_t src_hostbits, u_int8_t dst_hostbits,
+ int direction, int upper_proto,
+ bool ah, bool esp,
+ u_int32_t reqid);
+
+ /**
+ * @brief Remove a policy from the SPD.
+ *
+ * @param this calling object
+ * @param me address of local peer
+ * @param other address of remote peer
+ * @param src src address of traffic this policy applies
+ * @param dst dest address of traffic this policy applies
+ * @param src_hostbits subnetmask to use for src address
+ * @param dst_hostbits subnetmask to use for dst address
+ * @param direction direction of traffic, XFRM_POLICY_OUT, XFRM_POLICY_IN, XFRM_POLICY_FWD
+ * @param upper_proto upper layer protocol of traffic for this policy (TCP, UDP, ICMP, ...)
+ * @return
+ * - SUCCESS
+ * - FAILED if kernel comm failed
+ */
+ status_t (*del_policy) (kernel_interface_t *this,
+ host_t *me, host_t *other,
+ host_t *src, host_t *dst,
+ u_int8_t src_hostbits, u_int8_t dst_hostbits,
+ int direction, int upper_proto);
+
+ /**
+ * @brief Destroys a kernel_interface object.
+ *
+ * @param kernel_interface_t calling object
+ */
+ void (*destroy) (kernel_interface_t *kernel_interface);
+};
+
+/**
+ * @brief Creates an object of type kernel_interface_t.
+ *
+ * @ingroup threads
+ */
+kernel_interface_t *kernel_interface_create();
+
+#endif /*KERNEL_INTERFACE_H_*/
diff --git a/programs/charon/charon/threads/receiver.c b/programs/charon/charon/threads/receiver.c
new file mode 100644
index 000000000..0cf8b7bde
--- /dev/null
+++ b/programs/charon/charon/threads/receiver.c
@@ -0,0 +1,128 @@
+/**
+ * @file receiver.c
+ *
+ * @brief Implementation of receiver_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stdlib.h>
+#include <pthread.h>
+
+#include "receiver.h"
+
+#include <daemon.h>
+#include <network/socket.h>
+#include <network/packet.h>
+#include <queues/job_queue.h>
+#include <queues/jobs/job.h>
+#include <queues/jobs/incoming_packet_job.h>
+#include <utils/logger_manager.h>
+
+
+typedef struct private_receiver_t private_receiver_t;
+
+/**
+ * Private data of a receiver_t object.
+ */
+struct private_receiver_t {
+ /**
+ * Public part of a receiver_t object.
+ */
+ receiver_t public;
+
+ /**
+ * @brief Thread function started at creation of the receiver object.
+ *
+ * @param this calling object
+ */
+ void (*receive_packets) (private_receiver_t *this);
+
+ /**
+ * Assigned thread.
+ */
+ pthread_t assigned_thread;
+
+ /**
+ * A logger for the receiver_t object.
+ */
+ logger_t *logger;
+};
+
+/**
+ * Implementation of receiver_t.receive_packets.
+ */
+static void receive_packets(private_receiver_t * this)
+{
+ packet_t * current_packet;
+ job_t *current_job;
+
+ /* cancellation disabled by default */
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+
+ this->logger->log(this->logger, CONTROL, "Receiver thread running, thread_id %u", (int)pthread_self());
+
+ while (1)
+ {
+ while (charon->socket->receive(charon->socket,&current_packet) == SUCCESS)
+ {
+ this->logger->log(this->logger, CONTROL | LEVEL1, "Creating job from packet");
+ current_job = (job_t *) incoming_packet_job_create(current_packet);
+
+ charon->job_queue->add(charon->job_queue,current_job);
+
+ }
+ /* bad bad, rebuild the socket ? */
+ this->logger->log(this->logger, ERROR, "Receiving from socket failed!");
+ }
+}
+
+/**
+ * Implementation of receiver_t.destroy.
+ */
+static void destroy(private_receiver_t *this)
+{
+ this->logger->log(this->logger, CONTROL | LEVEL1, "Going to terminate receiver thread");
+ pthread_cancel(this->assigned_thread);
+
+ pthread_join(this->assigned_thread, NULL);
+ this->logger->log(this->logger, CONTROL | LEVEL1, "Receiver thread terminated");
+
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+receiver_t * receiver_create()
+{
+ private_receiver_t *this = malloc_thing(private_receiver_t);
+
+ this->public.destroy = (void(*)(receiver_t*)) destroy;
+ this->receive_packets = receive_packets;
+
+ this->logger = logger_manager->get_logger(logger_manager, RECEIVER);
+
+ if (pthread_create(&(this->assigned_thread), NULL, (void*(*)(void*))this->receive_packets, this) != 0)
+ {
+ this->logger->log(this->logger, ERROR, "Receiver thread could not be started");
+ free(this);
+ charon->kill(charon, "Unable to create receiver thread");
+ }
+
+ return &(this->public);
+}
diff --git a/programs/charon/charon/threads/receiver.h b/programs/charon/charon/threads/receiver.h
new file mode 100644
index 000000000..932774f5f
--- /dev/null
+++ b/programs/charon/charon/threads/receiver.h
@@ -0,0 +1,67 @@
+/**
+ * @file receiver.h
+ *
+ * @brief Interface of receiver_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef RECEIVER_H_
+#define RECEIVER_H_
+
+#include <types.h>
+
+
+typedef struct receiver_t receiver_t;
+
+/**
+ * @brief Receives packets from the socket and adds them to the job queue.
+ *
+ * The receiver starts a thread, wich reads on the blocking socket. If
+ * data is available, a packet_t object is created , wrapped
+ * in an incoming_packet_job_t and added to the job queue.
+ *
+ * @b Constructors:
+ * - receiver_create()
+ *
+ * @ingroup threads
+ */
+struct receiver_t {
+
+ /**
+ * @brief Destroys a receiver_t object.
+ *
+ * @param receiver receiver object
+ */
+ void (*destroy) (receiver_t *receiver);
+};
+
+/**
+ * @brief Create a receiver_t object.
+ *
+ * The receiver thread will start working, get data
+ * from the socket and add those packets to the job queue.
+ *
+ * @return
+ * - receiver_t object
+ * - NULL of thread could not be started
+ *
+ * @ingroup threads
+ */
+receiver_t * receiver_create();
+
+#endif /*RECEIVER_H_*/
diff --git a/programs/charon/charon/threads/scheduler.c b/programs/charon/charon/threads/scheduler.c
new file mode 100644
index 000000000..47c5d6fb9
--- /dev/null
+++ b/programs/charon/charon/threads/scheduler.c
@@ -0,0 +1,124 @@
+/**
+ * @file scheduler.c
+ *
+ * @brief Implementation of scheduler_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stdlib.h>
+#include <pthread.h>
+
+#include "scheduler.h"
+
+#include <daemon.h>
+#include <definitions.h>
+#include <utils/logger_manager.h>
+#include <queues/job_queue.h>
+
+
+typedef struct private_scheduler_t private_scheduler_t;
+
+/**
+ * Private data of a scheduler_t object.
+ */
+struct private_scheduler_t {
+ /**
+ * Public part of a scheduler_t object.
+ */
+ scheduler_t public;
+
+ /**
+ * @brief Get events from the event queue and add them to to job queue.
+ *
+ * Thread function started at creation of the scheduler object.
+ *
+ * @param this calling object
+ */
+ void (*get_events) (private_scheduler_t *this);
+
+ /**
+ * Assigned thread.
+ */
+ pthread_t assigned_thread;
+
+ /**
+ * A logger.
+ */
+ logger_t *logger;
+};
+
+/**
+ * Implementation of private_scheduler_t.get_events.
+ */
+static void get_events(private_scheduler_t * this)
+{
+ job_t *current_job;
+
+ /* cancellation disabled by default */
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+
+ this->logger->log(this->logger, CONTROL, "Scheduler thread running, thread_id %u", (int)pthread_self());
+
+ for (;;)
+ {
+ this->logger->log(this->logger, CONTROL|LEVEL2, "Waiting for next event...");
+ /* get a job, this block until one is available */
+ current_job = charon->event_queue->get(charon->event_queue);
+ /* queue the job in the job queue, workers will eat them */
+ charon->job_queue->add(charon->job_queue, current_job);
+ this->logger->log(this->logger, CONTROL | LEVEL1, "Got event, added job %s to job-queue.",
+ mapping_find(job_type_m, current_job->get_type(current_job)));
+ }
+}
+
+/**
+ * Implementation of scheduler_t.destroy.
+ */
+static void destroy(private_scheduler_t *this)
+{
+ this->logger->log(this->logger, CONTROL | LEVEL1, "Going to terminate scheduler thread");
+ pthread_cancel(this->assigned_thread);
+
+ pthread_join(this->assigned_thread, NULL);
+ this->logger->log(this->logger, CONTROL | LEVEL1, "Scheduler thread terminated");
+
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+scheduler_t * scheduler_create()
+{
+ private_scheduler_t *this = malloc_thing(private_scheduler_t);
+
+ this->public.destroy = (void(*)(scheduler_t*)) destroy;
+ this->get_events = get_events;
+
+ this->logger = logger_manager->get_logger(logger_manager, SCHEDULER);
+
+ if (pthread_create(&(this->assigned_thread), NULL, (void*(*)(void*))this->get_events, this) != 0)
+ {
+ /* thread could not be created */
+ this->logger->log(this->logger, ERROR, "Scheduler thread could not be created!");
+ free(this);
+ charon->kill(charon, "Unable to create scheduler thread");
+ }
+
+ return &(this->public);
+}
diff --git a/programs/charon/charon/threads/scheduler.h b/programs/charon/charon/threads/scheduler.h
new file mode 100644
index 000000000..0165a718b
--- /dev/null
+++ b/programs/charon/charon/threads/scheduler.h
@@ -0,0 +1,67 @@
+/**
+ * @file scheduler.h
+ *
+ * @brief Interface of scheduler_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef SCHEDULER_H_
+#define SCHEDULER_H_
+
+#include <types.h>
+
+typedef struct scheduler_t scheduler_t;
+
+/**
+ * @brief The scheduler thread is responsible for timed events.
+ *
+ * The scheduler thread takes out jobs from the event-queue and adds them
+ * to the job-queue.
+ *
+ * Starts a thread which does the work, since event-queue is blocking.
+ *
+ * @b Constructors:
+ * - scheduler_create()
+ *
+ * @ingroup threads
+ */
+struct scheduler_t {
+
+ /**
+ * @brief Destroys a scheduler object.
+ *
+ * @param scheduler calling object
+ */
+ void (*destroy) (scheduler_t *scheduler);
+};
+
+/**
+ * @brief Create a scheduler with its associated thread.
+ *
+ * The thread will start to get jobs form the event queue
+ * and adds them to the job queue.
+ *
+ * @return
+ * - scheduler_t object
+ * - NULL if thread could not be started
+ *
+ * @ingroup threads
+ */
+scheduler_t * scheduler_create();
+
+#endif /*SCHEDULER_H_*/
diff --git a/programs/charon/charon/threads/sender.c b/programs/charon/charon/threads/sender.c
new file mode 100644
index 000000000..42d11beb9
--- /dev/null
+++ b/programs/charon/charon/threads/sender.c
@@ -0,0 +1,126 @@
+/**
+ * @file sender.c
+ *
+ * @brief Implementation of sender_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stdlib.h>
+#include <pthread.h>
+
+#include "sender.h"
+
+#include <daemon.h>
+#include <network/socket.h>
+#include <network/packet.h>
+#include <queues/send_queue.h>
+#include <utils/logger_manager.h>
+
+
+typedef struct private_sender_t private_sender_t;
+
+/**
+ * Private data of a sender_t object.
+ */
+struct private_sender_t {
+ /**
+ * Public part of a sender_t object.
+ */
+ sender_t public;
+
+ /**
+ * Assigned thread.
+ */
+ pthread_t assigned_thread;
+
+ /**
+ * @brief The thread function, sends out packets.
+ *
+ * @param this calling object
+ */
+ void (*send_packets) (private_sender_t * this);
+
+ /**
+ * A logger for this sender_t object.
+ */
+ logger_t *logger;
+
+};
+
+/**
+ * Implementation of private_sender_t.send_packets.
+ */
+static void send_packets(private_sender_t * this)
+{
+ packet_t * current_packet;
+ status_t status;
+
+ /* cancellation disabled by default */
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+
+ this->logger->log(this->logger, CONTROL, "Sender thread running, thread_id %u", (int)pthread_self());
+
+ while (1)
+ {
+ current_packet = charon->send_queue->get(charon->send_queue);
+ this->logger->log(this->logger, CONTROL|LEVEL1, "Got a packet, sending it");
+ status = charon->socket->send(charon->socket,current_packet);
+ if (status != SUCCESS)
+ {
+ this->logger->log(this->logger, ERROR, "Sending failed, socket returned %s",
+ mapping_find(status_m, status));
+ }
+ current_packet->destroy(current_packet);
+ }
+}
+
+/**
+ * Implementation of sender_t.destroy.
+ */
+static void destroy(private_sender_t *this)
+{
+ this->logger->log(this->logger, CONTROL | LEVEL1, "Going to terminate sender thread");
+ pthread_cancel(this->assigned_thread);
+
+ pthread_join(this->assigned_thread, NULL);
+ this->logger->log(this->logger, CONTROL | LEVEL1, "Sender thread terminated");
+
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+sender_t * sender_create()
+{
+ private_sender_t *this = malloc_thing(private_sender_t);
+
+ this->send_packets = send_packets;
+ this->public.destroy = (void(*)(sender_t*)) destroy;
+
+ this->logger = logger_manager->get_logger(logger_manager, SENDER);
+
+ if (pthread_create(&(this->assigned_thread), NULL, (void*(*)(void*))this->send_packets, this) != 0)
+ {
+ this->logger->log(this->logger, ERROR, "Sender thread could not be created");
+ free(this);
+ charon->kill(charon, "Unable to create sender thread");
+ }
+
+ return &(this->public);
+}
diff --git a/programs/charon/charon/threads/sender.h b/programs/charon/charon/threads/sender.h
new file mode 100644
index 000000000..ea8124147
--- /dev/null
+++ b/programs/charon/charon/threads/sender.h
@@ -0,0 +1,63 @@
+/**
+ * @file sender.h
+ *
+ * @brief Interface of sender_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef SENDER_H_
+#define SENDER_H_
+
+#include <types.h>
+
+typedef struct sender_t sender_t;
+
+/**
+ * @brief Thread responsible for sending packets over the socket.
+ *
+ * @b Constructors:
+ * - sender_create()
+ *
+ * @ingroup threads
+ */
+struct sender_t {
+
+ /**
+ * @brief Destroys a sender object.
+ *
+ * @param sender calling object
+ */
+ void (*destroy) (sender_t *sender);
+};
+
+
+/**
+ * @brief Create the sender thread.
+ *
+ * The thread will start to work, getting packets
+ * from the send queue and sends them out.
+ *
+ * @return
+ * - sender_t object
+ * - NULL of thread could not be started
+ *
+ * @ingroup threads
+ */
+sender_t * sender_create();
+
+#endif /*SENDER_H_*/
diff --git a/programs/charon/charon/threads/stroke_interface.c b/programs/charon/charon/threads/stroke_interface.c
new file mode 100755
index 000000000..ef5d5f1f6
--- /dev/null
+++ b/programs/charon/charon/threads/stroke_interface.c
@@ -0,0 +1,661 @@
+/**
+ * @file stroke.c
+ *
+ * @brief Implementation 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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <pthread.h>
+
+#include "stroke_interface.h"
+
+#include <stroke.h>
+#include <types.h>
+#include <daemon.h>
+#include <crypto/x509.h>
+#include <queues/jobs/initiate_ike_sa_job.h>
+
+
+struct sockaddr_un socket_addr = { AF_UNIX, STROKE_SOCKET};
+
+
+typedef struct private_stroke_t private_stroke_t;
+
+/**
+ * Private data of an stroke_t object.
+ */
+struct private_stroke_t {
+
+ /**
+ * Public part of stroke_t object.
+ */
+ stroke_t public;
+
+ /**
+ * Assigned logger_t object in charon.
+ */
+ logger_t *logger;
+
+ /**
+ * Logger which logs to stroke
+ */
+ logger_t *stroke_logger;
+
+ /**
+ * Unix socket to listen for strokes
+ */
+ int socket;
+
+ /**
+ * Thread which reads from the socket
+ */
+ pthread_t assigned_thread;
+
+ /**
+ * Read from the socket and handle stroke messages
+ */
+ void (*stroke_receive) (private_stroke_t *this);
+};
+
+/**
+ * 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)
+{
+ /* check for sanity of string pointer and string */
+ if (*string == NULL)
+ {
+ *string = "";
+ }
+ else if (string < (char**)msg ||
+ string > (char**)msg + sizeof(stroke_msg_t) ||
+ *string < (char*)msg->buffer - (u_int)msg ||
+ *string > (char*)(u_int)msg->length)
+ {
+ *string = "(invalid char* in stroke msg)";
+ }
+ else
+ {
+ *string = (char*)msg + (u_int)*string;
+ }
+}
+
+/**
+ * Add a connection to the configuration list
+ */
+static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg)
+{
+ connection_t *connection;
+ policy_t *policy;
+ identification_t *my_id, *other_id;
+ host_t *my_host, *other_host, *my_subnet, *other_subnet;
+ proposal_t *proposal;
+ traffic_selector_t *my_ts, *other_ts;
+ x509_t *cert;
+
+ pop_string(msg, &msg->add_conn.name);
+ pop_string(msg, &msg->add_conn.me.address);
+ pop_string(msg, &msg->add_conn.other.address);
+ pop_string(msg, &msg->add_conn.me.id);
+ pop_string(msg, &msg->add_conn.other.id);
+ pop_string(msg, &msg->add_conn.me.cert);
+ pop_string(msg, &msg->add_conn.other.cert);
+ pop_string(msg, &msg->add_conn.me.subnet);
+ pop_string(msg, &msg->add_conn.other.subnet);
+
+ this->logger->log(this->logger, CONTROL, "received stroke: add connection \"%s\"", msg->add_conn.name);
+
+ my_host = host_create(AF_INET, msg->add_conn.me.address, 500);
+ if (my_host == NULL)
+ {
+ this->stroke_logger->log(this->stroke_logger, ERROR, "invalid host: %s", msg->add_conn.me.address);
+ return;
+ }
+ other_host = host_create(AF_INET, msg->add_conn.other.address, 500);
+ if (other_host == NULL)
+ {
+ this->stroke_logger->log(this->stroke_logger, ERROR, "invalid host: %s", msg->add_conn.other.address);
+ my_host->destroy(my_host);
+ return;
+ }
+ 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)
+ {
+ this->stroke_logger->log(this->stroke_logger, ERROR, "invalid id: %s", msg->add_conn.me.id);
+ my_host->destroy(my_host);
+ other_host->destroy(other_host);
+ return;
+ }
+ 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)
+ {
+ my_host->destroy(my_host);
+ other_host->destroy(other_host);
+ my_id->destroy(my_id);
+ this->stroke_logger->log(this->stroke_logger, ERROR, "invalid id: %s", msg->add_conn.other.id);
+ return;
+ }
+
+ my_subnet = host_create(AF_INET, *msg->add_conn.me.subnet ? msg->add_conn.me.subnet : msg->add_conn.me.address, 500);
+ if (my_subnet == NULL)
+ {
+ my_host->destroy(my_host);
+ other_host->destroy(other_host);
+ my_id->destroy(my_id);
+ other_id->destroy(other_id);
+ this->stroke_logger->log(this->stroke_logger, ERROR, "invalid subnet: %s", msg->add_conn.me.subnet);
+ return;
+ }
+
+ other_subnet = host_create(AF_INET, *msg->add_conn.other.subnet ? msg->add_conn.other.subnet : msg->add_conn.other.address, 500);
+ if (other_subnet == NULL)
+ {
+ my_host->destroy(my_host);
+ other_host->destroy(other_host);
+ my_id->destroy(my_id);
+ other_id->destroy(other_id);
+ my_subnet->destroy(my_subnet);
+ this->stroke_logger->log(this->stroke_logger, ERROR, "invalid subnet: %s", msg->add_conn.me.subnet);
+ return;
+ }
+
+ my_ts = traffic_selector_create_from_subnet(my_subnet, *msg->add_conn.me.subnet ? msg->add_conn.me.subnet_mask : 32);
+ my_subnet->destroy(my_subnet);
+ other_ts = traffic_selector_create_from_subnet(other_subnet, *msg->add_conn.other.subnet ? msg->add_conn.other.subnet_mask : 32);
+ other_subnet->destroy(other_subnet);
+
+ if (charon->socket->is_listening_on(charon->socket, other_host))
+ {
+ this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1, "left is other host, switching");
+
+ host_t *tmp_host = my_host;
+ identification_t *tmp_id = my_id;
+ traffic_selector_t *tmp_ts = my_ts;
+ char *tmp_cert = msg->add_conn.me.cert;
+
+ my_host = other_host;
+ other_host = tmp_host;
+ my_id = other_id;
+ other_id = tmp_id;
+ my_ts = other_ts;
+ other_ts = tmp_ts;
+ msg->add_conn.me.cert = msg->add_conn.other.cert;
+ msg->add_conn.other.cert = tmp_cert;
+ }
+ else if (charon->socket->is_listening_on(charon->socket, my_host))
+ {
+ this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1, "left is own host, not switching");
+ }
+ else
+ {
+ this->stroke_logger->log(this->stroke_logger, ERROR, "left nor right host is our, aborting");
+
+ my_host->destroy(my_host);
+ other_host->destroy(other_host);
+ my_id->destroy(my_id);
+ other_id->destroy(other_id);
+ my_ts->destroy(my_ts);
+ other_ts->destroy(other_ts);
+ return;
+ }
+
+ if (msg->add_conn.me.cert)
+ {
+ char file[128];
+ snprintf(file, sizeof(file), "%s%s", CERTIFICATE_DIR, msg->add_conn.me.cert);
+ cert = x509_create_from_file(file);
+ if (cert)
+ {
+ my_id->destroy(my_id);
+ my_id = cert->get_subject(cert);
+ my_id = my_id->clone(my_id);
+ cert->destroy(cert);
+ this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1,
+ "defined a valid certificate, using its ID \"%s\"",
+ my_id->get_string(my_id));
+ }
+ }
+ if (msg->add_conn.other.cert)
+ {
+ char file[128];
+ snprintf(file, sizeof(file), "%s%s", CERTIFICATE_DIR, msg->add_conn.other.cert);
+ cert = x509_create_from_file(file);
+ if (cert)
+ {
+ other_id->destroy(other_id);
+ other_id = cert->get_subject(cert);
+ other_id = other_id->clone(other_id);
+ cert->destroy(cert);
+ this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1,
+ "defined a valid certificate, using its ID \"%s\"",
+ other_id->get_string(other_id));
+ }
+ }
+
+ connection = connection_create(msg->add_conn.name,
+ my_host, other_host,
+ my_id->clone(my_id), other_id->clone(other_id),
+ RSA_DIGITAL_SIGNATURE);
+ proposal = proposal_create(1);
+ proposal->add_algorithm(proposal, PROTO_IKE, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16);
+ proposal->add_algorithm(proposal, PROTO_IKE, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
+ proposal->add_algorithm(proposal, PROTO_IKE, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
+ proposal->add_algorithm(proposal, PROTO_IKE, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA1, 0);
+ proposal->add_algorithm(proposal, PROTO_IKE, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_MD5, 0);
+ proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0);
+ proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_1536_BIT, 0);
+ proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0);
+ proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_4096_BIT, 0);
+ proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_8192_BIT, 0);
+ connection->add_proposal(connection, proposal);
+ /* add to global connection list */
+ charon->connections->add_connection(charon->connections, connection);
+
+ policy = policy_create(my_id, other_id);
+ proposal = proposal_create(1);
+ proposal->add_algorithm(proposal, PROTO_ESP, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16);
+ proposal->add_algorithm(proposal, PROTO_ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
+ proposal->add_algorithm(proposal, PROTO_ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
+ policy->add_proposal(policy, proposal);
+ policy->add_my_traffic_selector(policy, my_ts);
+ policy->add_other_traffic_selector(policy, other_ts);
+ /* add to global policy list */
+ charon->policies->add_policy(charon->policies, policy);
+
+ this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1, "connection \"%s\" added", msg->add_conn.name);
+}
+
+/**
+ * initiate a connection by name
+ */
+static void stroke_initiate(private_stroke_t *this, stroke_msg_t *msg)
+{
+ initiate_ike_sa_job_t *job;
+ connection_t *connection;
+
+ pop_string(msg, &(msg->initiate.name));
+ this->logger->log(this->logger, CONTROL, "received stroke: initiate \"%s\"", msg->initiate.name);
+ connection = charon->connections->get_connection_by_name(charon->connections, msg->initiate.name);
+ if (connection == NULL)
+ {
+ this->stroke_logger->log(this->stroke_logger, ERROR, "could not find a connection named \"%s\"", msg->initiate.name);
+ }
+ else
+ {
+ job = initiate_ike_sa_job_create(connection);
+ charon->job_queue->add(charon->job_queue, (job_t*)job);
+ }
+}
+
+/**
+ * terminate a connection by name
+ */
+static void stroke_terminate(private_stroke_t *this, stroke_msg_t *msg)
+{
+ connection_t *connection;
+ ike_sa_t *ike_sa;
+ host_t *my_host, *other_host;
+ status_t status;
+
+ pop_string(msg, &(msg->terminate.name));
+ this->logger->log(this->logger, CONTROL, "received stroke: terminate \"%s\"", msg->terminate.name);
+ connection = charon->connections->get_connection_by_name(charon->connections, msg->terminate.name);
+
+ if (connection)
+ {
+ my_host = connection->get_my_host(connection);
+ other_host = connection->get_other_host(connection);
+
+ /* TODO: Do this directly by name now */
+ /* TODO: terminate any instance of the name */
+ status = charon->ike_sa_manager->checkout_by_hosts(charon->ike_sa_manager,
+ my_host, other_host, &ike_sa);
+
+ if (status == SUCCESS)
+ {
+ this->stroke_logger->log(this->stroke_logger, CONTROL, "deleting IKE SA between %s - %s",
+ my_host->get_address(my_host), other_host->get_address(other_host));
+
+ charon->ike_sa_manager->checkin_and_delete(charon->ike_sa_manager, ike_sa);
+ }
+ else
+ {
+ this->stroke_logger->log(this->stroke_logger, ERROR, "no active connection found between %s - %s",
+ my_host->get_address(my_host), other_host->get_address(other_host));
+ }
+ }
+ else
+ {
+ this->stroke_logger->log(this->stroke_logger, ERROR, "could not find a connection named \"%s\"", msg->terminate.name);
+ }
+
+}
+
+/**
+ * show status of (established) connections
+ */
+static void stroke_status(private_stroke_t *this, stroke_msg_t *msg)
+{
+ if (msg->status.name)
+ {
+ pop_string(msg, &(msg->status.name));
+ }
+ charon->ike_sa_manager->log_status(charon->ike_sa_manager, this->stroke_logger, msg->status.name);
+}
+
+logger_context_t get_context(char *context)
+{
+ if (strcasecmp(context, "ALL") == 0) return ALL_LOGGERS;
+ else if (strcasecmp(context, "PARSR") == 0) return PARSER;
+ else if (strcasecmp(context, "GNRAT") == 0) return GENERATOR;
+ else if (strcasecmp(context, "IKESA") == 0) return IKE_SA;
+ else if (strcasecmp(context, "SAMGR") == 0) return IKE_SA_MANAGER;
+ else if (strcasecmp(context, "CHDSA") == 0) return CHILD_SA;
+ else if (strcasecmp(context, "MESSG") == 0) return MESSAGE;
+ else if (strcasecmp(context, "TPOOL") == 0) return THREAD_POOL;
+ else if (strcasecmp(context, "WORKR") == 0) return WORKER;
+ else if (strcasecmp(context, "SCHED") == 0) return SCHEDULER;
+ else if (strcasecmp(context, "SENDR") == 0) return SENDER;
+ else if (strcasecmp(context, "RECVR") == 0) return RECEIVER;
+ else if (strcasecmp(context, "SOCKT") == 0) return SOCKET;
+ else if (strcasecmp(context, "TESTR") == 0) return TESTER;
+ else if (strcasecmp(context, "DAEMN") == 0) return DAEMON;
+ else if (strcasecmp(context, "CONFG") == 0) return CONFIG;
+ else if (strcasecmp(context, "ENCPL") == 0) return ENCRYPTION_PAYLOAD;
+ else if (strcasecmp(context, "PAYLD") == 0) return PAYLOAD;
+ else return -2;
+}
+
+/**
+ * set the type of logged messages in a context
+ */
+static void stroke_logtype(private_stroke_t *this, stroke_msg_t *msg)
+{
+ pop_string(msg, &(msg->logtype.context));
+ pop_string(msg, &(msg->logtype.type));
+
+ this->logger->log(this->logger, CONTROL, "received stroke: logtype for %s", msg->logtype.context);
+
+ log_level_t level;
+ logger_context_t context = get_context(msg->logtype.context);
+ if (context == -2)
+ {
+ this->stroke_logger->log(this->stroke_logger, ERROR, "invalid context (%s)!", msg->logtype.context);
+ return;
+ }
+
+ if (strcasecmp(msg->logtype.type, "CONTROL") == 0) level = CONTROL;
+ else if (strcasecmp(msg->logtype.type, "ERROR") == 0) level = ERROR;
+ else if (strcasecmp(msg->logtype.type, "AUDIT") == 0) level = AUDIT;
+ else if (strcasecmp(msg->logtype.type, "RAW") == 0) level = RAW;
+ else if (strcasecmp(msg->logtype.type, "PRIVATE") == 0) level = PRIVATE;
+ else
+ {
+ this->stroke_logger->log(this->stroke_logger, ERROR, "invalid type (%s)!", msg->logtype.type);
+ return;
+ }
+
+ if (msg->logtype.enable)
+ {
+ logger_manager->enable_log_level(logger_manager, context, level);
+ }
+ else
+ {
+ logger_manager->disable_log_level(logger_manager, context, level);
+ }
+}
+
+/**
+ * set the verbosity of a logger
+ */
+static void stroke_loglevel(private_stroke_t *this, stroke_msg_t *msg)
+{
+ pop_string(msg, &(msg->loglevel.context));
+
+ this->logger->log(this->logger, CONTROL, "received stroke: loglevel for %s", msg->loglevel.context);
+
+ log_level_t level;
+ logger_context_t context = get_context(msg->loglevel.context);
+
+ if (context == -2)
+ {
+ this->stroke_logger->log(this->stroke_logger, ERROR, "invalid context (%s)!", msg->loglevel.context);
+ return;
+ }
+
+ if (msg->loglevel.level == 0)
+ {
+ level = LEVEL0;
+ }
+ else if (msg->loglevel.level == 1)
+ {
+ level = LEVEL1;
+ }
+ else if (msg->loglevel.level == 2)
+ {
+ level = LEVEL2;
+ }
+ else if (msg->loglevel.level == 3)
+ {
+ level = LEVEL3;
+ }
+ else
+ {
+ this->stroke_logger->log(this->stroke_logger, ERROR, "invalid level (%d)!", msg->loglevel.level);
+ return;
+ }
+
+ logger_manager->enable_log_level(logger_manager, context, level);
+}
+
+/**
+ * Implementation of private_stroke_t.stroke_receive.
+ */
+static void stroke_receive(private_stroke_t *this)
+{
+ stroke_msg_t *msg;
+ u_int16_t msg_length;
+ struct sockaddr_un strokeaddr;
+ int strokeaddrlen = sizeof(strokeaddr);
+ ssize_t bytes_read;
+ int strokefd;
+ FILE *strokefile;
+ int oldstate;
+
+ /* disable cancellation by default */
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+
+ while (1)
+ {
+ /* wait for connections, but allow thread to terminate */
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
+ strokefd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen);
+ pthread_setcancelstate(oldstate, NULL);
+
+ if (strokefd < 0)
+ {
+ this->logger->log(this->logger, ERROR, "accepting stroke connection failed: %s", strerror(errno));
+ continue;
+ }
+
+ /* peek the length */
+ bytes_read = recv(strokefd, &msg_length, sizeof(msg_length), MSG_PEEK);
+ if (bytes_read != sizeof(msg_length))
+ {
+ this->logger->log(this->logger, ERROR, "reading lenght of stroke message failed");
+ close(strokefd);
+ continue;
+ }
+
+ /* read message */
+ msg = malloc(msg_length);
+ bytes_read = recv(strokefd, msg, msg_length, 0);
+ if (bytes_read != msg_length)
+ {
+ this->logger->log(this->logger, ERROR, "reading stroke message failed: %s");
+ close(strokefd);
+ continue;
+ }
+
+ strokefile = fdopen(dup(strokefd), "w");
+ if (strokefile == NULL)
+ {
+ this->logger->log(this->logger, ERROR, "opening stroke output channel failed:", strerror(errno));
+ close(strokefd);
+ free(msg);
+ continue;
+ }
+
+ this->stroke_logger = logger_create("-", CONTROL|ERROR, FALSE, strokefile);
+
+ this->logger->log_bytes(this->logger, RAW, "stroke message", (void*)msg, msg_length);
+
+ switch (msg->type)
+ {
+ case STR_INITIATE:
+ {
+ stroke_initiate(this, msg);
+ break;
+ }
+ case STR_TERMINATE:
+ {
+ stroke_terminate(this, msg);
+ break;
+ }
+ case STR_STATUS:
+ {
+ stroke_status(this, msg);
+ break;
+ }
+ case STR_STATUS_ALL:
+ {
+ this->stroke_logger->enable_level(this->stroke_logger, LEVEL1);
+ stroke_status(this, msg);
+ break;
+ }
+ case STR_ADD_CONN:
+ {
+ stroke_add_conn(this, msg);
+ break;
+ }
+ case STR_LOGTYPE:
+ {
+ stroke_logtype(this, msg);
+ break;
+ }
+ case STR_LOGLEVEL:
+ {
+ stroke_loglevel(this, msg);
+ break;
+ }
+ default:
+ this->logger->log(this->logger, ERROR, "received invalid stroke");
+ }
+ this->stroke_logger->destroy(this->stroke_logger);
+ fclose(strokefile);
+ close(strokefd);
+ free(msg);
+ }
+}
+
+/**
+ * Implementation of stroke_t.destroy.
+ */
+static void destroy(private_stroke_t *this)
+{
+
+ pthread_cancel(this->assigned_thread);
+ pthread_join(this->assigned_thread, NULL);
+
+ close(this->socket);
+ unlink(socket_addr.sun_path);
+ free(this);
+}
+
+
+/*
+ * Described in header-file
+ */
+stroke_t *stroke_create()
+{
+ private_stroke_t *this = malloc_thing(private_stroke_t);
+ mode_t old;
+
+ /* public functions */
+ this->public.destroy = (void (*)(stroke_t*))destroy;
+
+ /* private functions */
+ this->stroke_receive = stroke_receive;
+
+ this->logger = logger_manager->get_logger(logger_manager, CONFIG);
+
+ /* set up unix socket */
+ this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (this->socket == -1)
+ {
+ this->logger->log(this->logger, ERROR, "could not create whack socket");
+ free(this);
+ return NULL;
+ }
+
+ old = umask(~S_IRWXU);
+ if (bind(this->socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0)
+ {
+ this->logger->log(this->logger, ERROR, "could not bind stroke socket: %s", strerror(errno));
+ close(this->socket);
+ free(this);
+ return NULL;
+ }
+ umask(old);
+
+ if (listen(this->socket, 0) < 0)
+ {
+ this->logger->log(this->logger, ERROR, "could not listen on stroke socket: %s", strerror(errno));
+ close(this->socket);
+ unlink(socket_addr.sun_path);
+ free(this);
+ return NULL;
+ }
+
+ /* start a thread reading from the socket */
+ if (pthread_create(&(this->assigned_thread), NULL, (void*(*)(void*))this->stroke_receive, this) != 0)
+ {
+ this->logger->log(this->logger, ERROR, "Could not spawn stroke thread");
+ close(this->socket);
+ unlink(socket_addr.sun_path);
+ free(this);
+ return NULL;
+ }
+
+ return (&this->public);
+}
diff --git a/programs/charon/charon/threads/stroke_interface.h b/programs/charon/charon/threads/stroke_interface.h
new file mode 100644
index 000000000..f8efc9c67
--- /dev/null
+++ b/programs/charon/charon/threads/stroke_interface.h
@@ -0,0 +1,86 @@
+/**
+ * @file stroke.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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef STROKE_INTERFACE_H_
+#define STROKE_INTERFACE_H_
+
+#include <config/policies/policy_store.h>
+#include <config/connections/connection_store.h>
+#include <config/credentials/credential_store.h>
+
+
+typedef struct stroke_t stroke_t;
+
+/**
+ * @brief Stroke is a configuration and control interface which
+ * allows other processes to modify charons behavior.
+ *
+ * stroke_t allows config manipulation (as whack in pluto).
+ * Messages of type stroke_msg_t's are sent over a unix socket
+ * (/var/run/charon.ctl). stroke_t implements the connections_t
+ * and the policies_t interface, which means it acts as a
+ * configuration backend for those too. stroke_t uses an own
+ * thread to read from the socket.
+ *
+ * @warning DO NOT cast stroke_t to any of the implemented interfaces!
+ * stroke_t implements multiple interfaces, so you must use
+ * stroke_t.interface_xy to access the specific interface! You have
+ * been warned...
+ *
+ * @todo Add clean thread cancellation
+ *
+ * @b Constructors:
+ * - stroke_create()
+ *
+ * @ingroup threads
+ */
+struct stroke_t {
+
+ /**
+ * Implements policy_store_t interface
+ */
+ policy_store_t policies;
+
+ /**
+ * Implements credential_store_t interfacce
+ */
+ credential_store_t credentials;
+
+ /**
+ * @brief Destroy a stroke_t instance.
+ *
+ * @param this stroke_t objec to destroy
+ */
+ void (*destroy) (stroke_t *this);
+};
+
+
+/**
+ * @brief Create the stroke interface and listen on the socket.
+ *
+ * @return stroke_t object
+ *
+ * @ingroup threads
+ */
+stroke_t *stroke_create();
+
+#endif /* STROKE_INTERFACE_H_ */
diff --git a/programs/charon/charon/threads/thread_pool.c b/programs/charon/charon/threads/thread_pool.c
new file mode 100644
index 000000000..4482e795f
--- /dev/null
+++ b/programs/charon/charon/threads/thread_pool.c
@@ -0,0 +1,623 @@
+/**
+ * @file thread_pool.c
+ *
+ * @brief Implementation of thread_pool_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stdlib.h>
+#include <pthread.h>
+#include <string.h>
+#include <errno.h>
+
+#include "thread_pool.h"
+
+#include <daemon.h>
+#include <queues/job_queue.h>
+#include <queues/jobs/delete_half_open_ike_sa_job.h>
+#include <queues/jobs/delete_established_ike_sa_job.h>
+#include <queues/jobs/incoming_packet_job.h>
+#include <queues/jobs/initiate_ike_sa_job.h>
+#include <queues/jobs/retransmit_request_job.h>
+#include <encoding/payloads/notify_payload.h>
+#include <utils/logger.h>
+
+
+typedef struct private_thread_pool_t private_thread_pool_t;
+
+/**
+ * @brief Private data of thread_pool_t class.
+ */
+struct private_thread_pool_t {
+ /**
+ * Public thread_pool_t interface.
+ */
+ thread_pool_t public;
+
+ /**
+ * @brief Main processing function for worker threads.
+ *
+ * Gets a job from the job queue and calls corresponding
+ * function for processing.
+ *
+ * @param this calling object
+ */
+ void (*process_jobs) (private_thread_pool_t *this);
+
+ /**
+ * @brief Process a INCOMING_PACKET job.
+ *
+ * @param this calling object
+ * @param job incoming_packet_job_t object
+ */
+ void (*process_incoming_packet_job) (private_thread_pool_t *this, incoming_packet_job_t *job);
+
+ /**
+ * @brief Process a INITIATE_IKE_SA job.
+ *
+ * @param this calling object
+ * @param job initiate_ike_sa_job_t object
+ */
+ void (*process_initiate_ike_sa_job) (private_thread_pool_t *this, initiate_ike_sa_job_t *job);
+
+ /**
+ * @brief Process a DELETE_HALF_OPEN_IKE_SA job.
+ *
+ * @param this calling object
+ * @param job delete__half_open_ike_sa_job_t object
+ */
+ void (*process_delete_half_open_ike_sa_job) (private_thread_pool_t *this, delete_half_open_ike_sa_job_t *job);
+
+ /**
+ * @brief Process a DELETE_ESTABLISHED_IKE_SA job.
+ *
+ * @param this calling object
+ * @param job delete_established_ike_sa_job_t object
+ */
+ void (*process_delete_established_ike_sa_job) (private_thread_pool_t *this, delete_established_ike_sa_job_t *job);
+
+ /**
+ * @brief Process a RETRANSMIT_REQUEST job.
+ *
+ * @param this calling object
+ * @param job retransmit_request_job_t object
+ */
+ void (*process_retransmit_request_job) (private_thread_pool_t *this, retransmit_request_job_t *job);
+
+ /**
+ * Creates a job of type DELETE_HALF_OPEN_IKE_SA.
+ *
+ * This job is used to delete IKE_SA's which are still in state INITIATOR_INIT,
+ * RESPONDER_INIT, IKE_AUTH_REQUESTED, IKE_INIT_REQUESTED or IKE_INIT_RESPONDED.
+ *
+ * @param ike_sa_id ID of IKE_SA to delete
+ * @param delay Delay in ms after a half open IKE_SA gets deleted!
+ */
+ void (*create_delete_half_open_ike_sa_job) (private_thread_pool_t *this,ike_sa_id_t *ike_sa_id, u_int32_t delay);
+
+ /**
+ * Number of running threads.
+ */
+ size_t pool_size;
+
+ /**
+ * Array of thread ids.
+ */
+ pthread_t *threads;
+
+ /**
+ * Logger of the thread pool.
+ */
+ logger_t *pool_logger;
+
+ /**
+ * Logger of the worker threads.
+ */
+ logger_t *worker_logger;
+} ;
+
+/**
+ * Implementation of private_thread_pool_t.process_jobs.
+ */
+static void process_jobs(private_thread_pool_t *this)
+{
+ job_t *job;
+ job_type_t job_type;
+ timeval_t start_time;
+ timeval_t end_time;
+
+ /* cancellation disabled by default */
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+
+ this->worker_logger->log(this->worker_logger, CONTROL, "Worker thread running, thread_id: %u", (int)pthread_self());
+
+ for (;;) {
+
+ job = charon->job_queue->get(charon->job_queue);
+ job_type = job->get_type(job);
+ this->worker_logger->log(this->worker_logger, CONTROL|LEVEL2, "Process job of type %s",
+ mapping_find(job_type_m,job_type));
+ gettimeofday(&start_time,NULL);
+ switch (job_type)
+ {
+ case INCOMING_PACKET:
+ {
+ this->process_incoming_packet_job(this, (incoming_packet_job_t*)job);
+ job->destroy(job);
+ break;
+ }
+ case INITIATE_IKE_SA:
+ {
+ this->process_initiate_ike_sa_job(this, (initiate_ike_sa_job_t*)job);
+ job->destroy(job);
+ break;
+ }
+ case DELETE_HALF_OPEN_IKE_SA:
+ {
+ this->process_delete_half_open_ike_sa_job(this, (delete_half_open_ike_sa_job_t*)job);
+ job->destroy(job);
+ break;
+ }
+ case DELETE_ESTABLISHED_IKE_SA:
+ {
+ this->process_delete_established_ike_sa_job(this, (delete_established_ike_sa_job_t*)job);
+ job->destroy(job);
+ break;
+ }
+ case RETRANSMIT_REQUEST:
+ {
+ this->process_retransmit_request_job(this, (retransmit_request_job_t*)job);
+ break;
+ }
+ default:
+ {
+ this->worker_logger->log(this->worker_logger, ERROR, "Job of type %s not supported!",
+ mapping_find(job_type_m,job_type));
+ job->destroy(job);
+ break;
+ }
+ }
+ gettimeofday(&end_time,NULL);
+
+ this->worker_logger->log(this->worker_logger, CONTROL | LEVEL2, "Processed job of type %s in %d us",
+ mapping_find(job_type_m,job_type),
+ (((end_time.tv_sec - start_time.tv_sec) * 1000000) + (end_time.tv_usec - start_time.tv_usec)));
+
+
+ }
+}
+
+/**
+ * Implementation of private_thread_pool_t.process_incoming_packet_job.
+ */
+static void process_incoming_packet_job(private_thread_pool_t *this, incoming_packet_job_t *job)
+{
+ packet_t *packet;
+ message_t *message;
+ ike_sa_t *ike_sa;
+ ike_sa_id_t *ike_sa_id;
+ status_t status;
+
+
+ packet = job->get_packet(job);
+
+ message = message_create_from_packet(packet);
+
+ status = message->parse_header(message);
+ if (status != SUCCESS)
+ {
+ this->worker_logger->log(this->worker_logger, ERROR, "Message header could not be verified!");
+ message->destroy(message);
+ return;
+ }
+
+ this->worker_logger->log(this->worker_logger, CONTROL|LEVEL2, "Message is a %s %s",
+ mapping_find(exchange_type_m, message->get_exchange_type(message)),
+ message->get_request(message) ? "request" : "reply");
+
+ if ((message->get_major_version(message) != IKE_MAJOR_VERSION) ||
+ (message->get_minor_version(message) != IKE_MINOR_VERSION))
+ {
+ this->worker_logger->log(this->worker_logger, ERROR | LEVEL2, "IKE version %d.%d not supported",
+ message->get_major_version(message),
+ message->get_minor_version(message));
+ /*
+ * This check is not handled in state_t object of IKE_SA to increase speed.
+ */
+ if ((message->get_exchange_type(message) == IKE_SA_INIT) && (message->get_request(message)))
+ {
+ message_t *response;
+ message->get_ike_sa_id(message, &ike_sa_id);
+ ike_sa_id->switch_initiator(ike_sa_id);
+ response = message_create_notify_reply(message->get_destination(message),
+ message->get_source(message),
+ IKE_SA_INIT,
+ FALSE,ike_sa_id,INVALID_MAJOR_VERSION);
+ message->destroy(message);
+ ike_sa_id->destroy(ike_sa_id);
+ status = response->generate(response, NULL, NULL, &packet);
+ if (status != SUCCESS)
+ {
+ this->worker_logger->log(this->worker_logger, ERROR, "Could not generate packet from message");
+ response->destroy(response);
+ return;
+ }
+ this->worker_logger->log(this->worker_logger, ERROR, "Send notify reply of type INVALID_MAJOR_VERSION");
+ charon->send_queue->add(charon->send_queue, packet);
+ response->destroy(response);
+ return;
+ }
+ message->destroy(message);
+ return;
+ }
+
+ message->get_ike_sa_id(message, &ike_sa_id);
+
+ ike_sa_id->switch_initiator(ike_sa_id);
+
+ this->worker_logger->log(this->worker_logger, CONTROL|LEVEL3, "Checking out IKE SA %lld:%lld, role %s",
+ ike_sa_id->get_initiator_spi(ike_sa_id),
+ ike_sa_id->get_responder_spi(ike_sa_id),
+ ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder");
+
+ status = charon->ike_sa_manager->checkout(charon->ike_sa_manager,ike_sa_id, &ike_sa);
+ if ((status != SUCCESS) && (status != CREATED))
+ {
+ this->worker_logger->log(this->worker_logger, ERROR, "IKE SA could not be checked out");
+ ike_sa_id->destroy(ike_sa_id);
+ message->destroy(message);
+
+ /*
+ * TODO send notify reply of type INVALID_IKE_SPI if SPI could not be found ?
+ */
+
+ return;
+ }
+
+ if (status == CREATED)
+ {
+ this->worker_logger->log(this->worker_logger, CONTROL|LEVEL3,
+ "Create Job to delete half open IKE_SA.");
+ this->create_delete_half_open_ike_sa_job(this,ike_sa_id,
+ charon->configuration->get_half_open_ike_sa_timeout(charon->configuration));
+ }
+
+ status = ike_sa->process_message(ike_sa, message);
+
+ this->worker_logger->log(this->worker_logger, CONTROL|LEVEL3, "%s IKE SA %lld:%lld, role %s",
+ (status == DELETE_ME) ? "Checkin and delete" : "Checkin",
+ ike_sa_id->get_initiator_spi(ike_sa_id),
+ ike_sa_id->get_responder_spi(ike_sa_id),
+ ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder");
+ ike_sa_id->destroy(ike_sa_id);
+
+ if (status == DELETE_ME)
+ {
+ status = charon->ike_sa_manager->checkin_and_delete(charon->ike_sa_manager, ike_sa);
+ }
+ else
+ {
+ status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ }
+
+ if (status != SUCCESS)
+ {
+ this->worker_logger->log(this->worker_logger, ERROR, "Checkin of IKE SA failed!");
+ }
+ message->destroy(message);
+}
+
+/**
+ * Implementation of private_thread_pool_t.process_initiate_ike_sa_job.
+ */
+static void process_initiate_ike_sa_job(private_thread_pool_t *this, initiate_ike_sa_job_t *job)
+{
+ /*
+ * Initiatie an IKE_SA:
+ * - is defined by a name of a configuration
+ * - create an empty IKE_SA via manager
+ * - call initiate_connection on this sa
+ */
+ ike_sa_t *ike_sa;
+ status_t status;
+
+
+ this->worker_logger->log(this->worker_logger, CONTROL|LEVEL2, "Creating and checking out IKE SA");
+ charon->ike_sa_manager->create_and_checkout(charon->ike_sa_manager, &ike_sa);
+
+ status = ike_sa->initiate_connection(ike_sa, job->get_connection(job));
+ if (status != SUCCESS)
+ {
+ this->worker_logger->log(this->worker_logger, ERROR, "Initiation returned %s, going to delete IKE_SA.",
+ mapping_find(status_m, status));
+ charon->ike_sa_manager->checkin_and_delete(charon->ike_sa_manager, ike_sa);
+ return;
+ }
+
+ this->worker_logger->log(this->worker_logger, CONTROL|LEVEL3, "Create Job to delete half open IKE_SA.");
+ this->create_delete_half_open_ike_sa_job(this,ike_sa->get_id(ike_sa),
+ charon->configuration->get_half_open_ike_sa_timeout(charon->configuration));
+
+ this->worker_logger->log(this->worker_logger, CONTROL|LEVEL2, "Checking in IKE SA");
+ status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ if (status != SUCCESS)
+ {
+ this->worker_logger->log(this->worker_logger, ERROR, "Could not checkin IKE_SA (%s)",
+ mapping_find(status_m, status));
+ }
+}
+
+/**
+ * Implementation of private_thread_pool_t.process_delete_ike_sa_job.
+ */
+static void process_delete_half_open_ike_sa_job(private_thread_pool_t *this, delete_half_open_ike_sa_job_t *job)
+{
+ ike_sa_id_t *ike_sa_id = job->get_ike_sa_id(job);
+ ike_sa_t *ike_sa;
+ status_t status;
+ status = charon->ike_sa_manager->checkout(charon->ike_sa_manager,ike_sa_id, &ike_sa);
+ if ((status != SUCCESS) && (status != CREATED))
+ {
+ this->worker_logger->log(this->worker_logger, CONTROL | LEVEL3, "IKE SA seems to be allready deleted and so doesn't have to be deleted");
+ return;
+ }
+
+
+ switch (ike_sa->get_state(ike_sa))
+ {
+ case INITIATOR_INIT:
+ case RESPONDER_INIT:
+ case IKE_SA_INIT_REQUESTED:
+ case IKE_SA_INIT_RESPONDED:
+ case IKE_AUTH_REQUESTED:
+ {
+ /* IKE_SA is half open and gets deleted! */
+ status = charon->ike_sa_manager->checkin_and_delete(charon->ike_sa_manager, ike_sa);
+ if (status != SUCCESS)
+ {
+ this->worker_logger->log(this->worker_logger, ERROR, "Could not checkin and delete checked out IKE_SA!");
+ }
+ break;
+ }
+ default:
+ {
+ /* IKE_SA is established and so is not getting deleted! */
+ status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ if (status != SUCCESS)
+ {
+ this->worker_logger->log(this->worker_logger, ERROR, "Could not checkin a checked out IKE_SA!");
+ }
+ break;
+ }
+ }
+}
+
+/**
+ * Implementation of private_thread_pool_t.process_delete_established_ike_sa_job.
+ */
+static void process_delete_established_ike_sa_job(private_thread_pool_t *this, delete_established_ike_sa_job_t *job)
+{
+ ike_sa_id_t *ike_sa_id = job->get_ike_sa_id(job);
+ ike_sa_t *ike_sa;
+ status_t status;
+ status = charon->ike_sa_manager->checkout(charon->ike_sa_manager,ike_sa_id, &ike_sa);
+ if ((status != SUCCESS) && (status != CREATED))
+ {
+ this->worker_logger->log(this->worker_logger, CONTROL | LEVEL3, "IKE SA seems to be allready deleted and so doesn't have to be deleted");
+ return;
+ }
+
+ switch (ike_sa->get_state(ike_sa))
+ {
+ case INITIATOR_INIT:
+ case RESPONDER_INIT:
+ case IKE_SA_INIT_REQUESTED:
+ case IKE_SA_INIT_RESPONDED:
+ case IKE_AUTH_REQUESTED:
+ {
+ break;
+ }
+ default:
+ {
+ this->worker_logger->log(this->worker_logger, CONTROL, "Send delete request for IKE_SA.");
+ ike_sa->send_delete_ike_sa_request(ike_sa);
+ break;
+ }
+ }
+ this->worker_logger->log(this->worker_logger, CONTROL, "Delete established IKE_SA.");
+ status = charon->ike_sa_manager->checkin_and_delete(charon->ike_sa_manager, ike_sa);
+ if (status != SUCCESS)
+ {
+ this->worker_logger->log(this->worker_logger, ERROR, "Could not checkin and delete checked out IKE_SA!");
+ }
+}
+
+
+/**
+ * Implementation of private_thread_pool_t.process_retransmit_request_job.
+ */
+static void process_retransmit_request_job(private_thread_pool_t *this, retransmit_request_job_t *job)
+{
+
+ ike_sa_id_t *ike_sa_id = job->get_ike_sa_id(job);
+ u_int32_t message_id = job->get_message_id(job);
+ bool stop_retransmitting = FALSE;
+ u_int32_t timeout;
+ ike_sa_t *ike_sa;
+ status_t status;
+
+ this->worker_logger->log(this->worker_logger, CONTROL|LEVEL2, "Checking out IKE SA %lld:%lld, role %s",
+ ike_sa_id->get_initiator_spi(ike_sa_id),
+ ike_sa_id->get_responder_spi(ike_sa_id),
+ ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder");
+
+ status = charon->ike_sa_manager->checkout(charon->ike_sa_manager,ike_sa_id, &ike_sa);
+ if ((status != SUCCESS) && (status != CREATED))
+ {
+ job->destroy(job);
+ this->worker_logger->log(this->worker_logger, ERROR, "IKE SA could not be checked out. Allready deleted?");
+ return;
+ }
+
+ status = ike_sa->retransmit_request(ike_sa, message_id);
+
+ if (status != SUCCESS)
+ {
+ this->worker_logger->log(this->worker_logger, CONTROL | LEVEL3, "Message doesn't have to be retransmitted");
+ stop_retransmitting = TRUE;
+ }
+
+ this->worker_logger->log(this->worker_logger, CONTROL|LEVEL2, "Checkin IKE SA %lld:%lld, role %s",
+ ike_sa_id->get_initiator_spi(ike_sa_id),
+ ike_sa_id->get_responder_spi(ike_sa_id),
+ ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder");
+
+ status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ if (status != SUCCESS)
+ {
+ this->worker_logger->log(this->worker_logger, ERROR, "Checkin of IKE SA failed!");
+ }
+
+ if (stop_retransmitting)
+ {
+ job->destroy(job);
+ return;
+ }
+
+ job->increase_retransmit_count(job);
+ status = charon->configuration->get_retransmit_timeout (charon->configuration,job->get_retransmit_count(job),&timeout);
+ if (status != SUCCESS)
+ {
+ this->worker_logger->log(this->worker_logger, CONTROL | LEVEL2, "Message will not be anymore retransmitted");
+ job->destroy(job);
+ /*
+ * TODO delete IKE_SA ?
+ */
+ return;
+ }
+ charon->event_queue->add_relative(charon->event_queue,(job_t *) job,timeout);
+}
+
+
+
+/**
+ * Implementation of private_thread_pool_t.create_delete_half_open_ike_sa_job.
+ */
+static void create_delete_half_open_ike_sa_job(private_thread_pool_t *this,ike_sa_id_t *ike_sa_id, u_int32_t delay)
+{
+ job_t *delete_job;
+
+ this->worker_logger->log(this->worker_logger, CONTROL | LEVEL2, "Going to create job to delete half open IKE_SA in %d ms", delay);
+
+ delete_job = (job_t *) delete_half_open_ike_sa_job_create(ike_sa_id);
+ charon->event_queue->add_relative(charon->event_queue,delete_job, delay);
+}
+
+
+/**
+ * Implementation of thread_pool_t.get_pool_size.
+ */
+static size_t get_pool_size(private_thread_pool_t *this)
+{
+ return this->pool_size;
+}
+
+/**
+ * Implementation of thread_pool_t.destroy.
+ */
+static void destroy(private_thread_pool_t *this)
+{
+ int current;
+ /* flag thread for termination */
+ for (current = 0; current < this->pool_size; current++) {
+ this->pool_logger->log(this->pool_logger, CONTROL, "cancelling worker thread #%d", current+1);
+ pthread_cancel(this->threads[current]);
+ }
+
+ /* wait for all threads */
+ for (current = 0; current < this->pool_size; current++) {
+ if (pthread_join(this->threads[current], NULL) == 0)
+ {
+ this->pool_logger->log(this->pool_logger, CONTROL, "worker thread #%d terminated", current+1);
+ }
+ else
+ {
+ this->pool_logger->log(this->pool_logger, ERROR, "could not terminate worker thread #%d", current+1);
+ }
+ }
+
+ /* free mem */
+ free(this->threads);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+thread_pool_t *thread_pool_create(size_t pool_size)
+{
+ int current;
+
+ private_thread_pool_t *this = malloc_thing(private_thread_pool_t);
+
+ /* fill in public fields */
+ this->public.destroy = (void(*)(thread_pool_t*))destroy;
+ this->public.get_pool_size = (size_t(*)(thread_pool_t*))get_pool_size;
+
+ this->process_jobs = process_jobs;
+ this->process_initiate_ike_sa_job = process_initiate_ike_sa_job;
+ this->process_delete_half_open_ike_sa_job = process_delete_half_open_ike_sa_job;
+ this->process_delete_established_ike_sa_job = process_delete_established_ike_sa_job;
+ this->process_incoming_packet_job = process_incoming_packet_job;
+ this->process_retransmit_request_job = process_retransmit_request_job;
+ this->create_delete_half_open_ike_sa_job = create_delete_half_open_ike_sa_job;
+
+ this->pool_size = pool_size;
+
+ this->threads = malloc(sizeof(pthread_t) * pool_size);
+
+ this->pool_logger = logger_manager->get_logger(logger_manager, THREAD_POOL);
+
+ this->worker_logger = logger_manager->get_logger(logger_manager, WORKER);
+
+ /* try to create as many threads as possible, up tu pool_size */
+ for (current = 0; current < pool_size; current++)
+ {
+ if (pthread_create(&(this->threads[current]), NULL, (void*(*)(void*))this->process_jobs, this) == 0)
+ {
+ this->pool_logger->log(this->pool_logger, CONTROL, "Created worker thread #%d", current+1);
+ }
+ else
+ {
+ /* creation failed, is it the first one? */
+ if (current == 0)
+ {
+ this->pool_logger->log(this->pool_logger, ERROR, "Could not create any thread");
+ free(this->threads);
+ free(this);
+ return NULL;
+ }
+ /* not all threads could be created, but at least one :-/ */
+ this->pool_logger->log(this->pool_logger, ERROR, "Could only create %d from requested %d threads!", current, pool_size);
+
+ this->pool_size = current;
+ return (thread_pool_t*)this;
+ }
+ }
+ return (thread_pool_t*)this;
+}
diff --git a/programs/charon/charon/threads/thread_pool.h b/programs/charon/charon/threads/thread_pool.h
new file mode 100644
index 000000000..b33be08e3
--- /dev/null
+++ b/programs/charon/charon/threads/thread_pool.h
@@ -0,0 +1,78 @@
+/**
+ * @file thread_pool.h
+ *
+ * @brief Interface of thread_pool_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef THREAD_POOL_H_
+#define THREAD_POOL_H_
+
+#include <stdlib.h>
+
+#include <types.h>
+
+
+typedef struct thread_pool_t thread_pool_t;
+
+/**
+ * @brief A thread_pool consists of a pool of threads processing jobs from the job queue.
+ *
+ * Current implementation uses as many threads as specified in constructor.
+ * A more improved version would dynamically increase thread count if necessary.
+ *
+ * @b Constructors:
+ * - thread_pool_create()
+ *
+ * @todo Add support for dynamic thread handling
+ *
+ * @ingroup threads
+ */
+struct thread_pool_t {
+ /**
+ * @brief Return currently instanciated thread count.
+ *
+ * @param thread_pool calling object
+ * @return size of thread pool
+ */
+ size_t (*get_pool_size) (thread_pool_t *thread_pool);
+
+ /**
+ * @brief Destroy a thread_pool_t object.
+ *
+ * Sends cancellation request to all threads and AWAITS their termination.
+ *
+ * @param thread_pool calling object
+ */
+ void (*destroy) (thread_pool_t *thread_pool);
+};
+
+/**
+ * @brief Create the thread pool using using pool_size of threads.
+ *
+ * @param pool_size desired pool size
+ * @return
+ * - thread_pool_t object if one ore more threads could be started, or
+ * - NULL if no threads could be created
+ *
+ * @ingroup threads
+ */
+thread_pool_t *thread_pool_create(size_t pool_size);
+
+
+#endif /*THREAD_POOL_H_*/
diff --git a/programs/charon/doc/Architecture.txt b/programs/charon/doc/Architecture.txt
new file mode 100644
index 000000000..14b99274c
--- /dev/null
+++ b/programs/charon/doc/Architecture.txt
@@ -0,0 +1,56 @@
+/** @mainpage
+
+@section design strongSwans overall design
+
+IKEv1 and IKEv2 is handled in different keying daemons. The ole IKEv1 stuff is
+completely handled in pluto, as it was all the times. IKEv2 is handled in the
+new keying daemon, which is called #charon.
+Daemon control is done over unix sockets. Pluto uses whack, as it did for years.
+Charon uses another socket interface, called stroke. Stroke uses another
+format as whack and therefore is not compatible to whack. The starter utility,
+wich does fast configuration parsing, speaks both the protocols, whack and
+stroke. It also handles daemon startup and termination.
+Pluto uses starter for some commands, for other it uses the whack utility. To be
+as close to pluto as possible, charon has the same split up of commands to
+starter and stroke. All commands are wrapped together in the ipsec script, which
+allows transparent control of both daemons.
+@verbatim
+
+ +-----------------------------------------+
+ | ipsec |
+ +-----+--------------+---------------+----+
+ | | |
+ | | |
+ | +-----+-----+ |
+ +-----+----+ | | +-----+----+
+ | | | starter | | |
+ | stroke | | | | whack |
+ | | +---+--+----+ | |
+ +------+---+ | | +--+-------+
+ | | | |
+ +---+------+ | | +------+--+
+ | | | | | |
+ | charon +----+ +----+ pluto |
+ | | | |
+ +-----+----+ +----+----+
+ | |
+ +-----+----+ |
+ | LSF | |
+ +-----+----+ |
+ | |
+ +-----+----+ +----+----+
+ | RAW Sock | | UDP/500 |
+ +----------+ +---------+
+
+@endverbatim
+Since IKEv2 uses the same port as IKEv1, both daemons must listen to UDP port
+500. Under Linux, there is no clean way to set up two sockets at the same port.
+To reslove this problem, charon uses a RAW socket, as they are used in network
+sniffers. An installed Linux Socket Filter (LSF) filters out all none-IKEv2
+traffic. Pluto receives any IKE message, independant of charons behavior.
+Therefore plutos behavior is changed to discard any IKEv2 traffic silently.
+
+To gain some reusability of the code, generic crypto and utility functions are
+separeted in a shared library, libstrongswan.
+
+*/ \ No newline at end of file
diff --git a/programs/charon/doc/Known-bugs.txt b/programs/charon/doc/Known-bugs.txt
new file mode 100644
index 000000000..3f594ad79
--- /dev/null
+++ b/programs/charon/doc/Known-bugs.txt
@@ -0,0 +1,6 @@
+ Known bugs in charon
+======================
+
+- intiating the same connection twice makes trouble
+- leak_detective gets confused from libpthread (invalid frees)
+- installing to many SAs in the kernel at the same time causes troubles. Threading issue?
diff --git a/programs/charon/doc/Todo-list.txt b/programs/charon/doc/Todo-list.txt
new file mode 100644
index 000000000..11b30fb7d
--- /dev/null
+++ b/programs/charon/doc/Todo-list.txt
@@ -0,0 +1,49 @@
+ Todo-List for charon
+======================
+
++ = done, / = partial, - = todo, ordered by priority
+
+
++ private key loading: der, without passphrase
++ load all private keys from ipsec.d/private/ in stroke.c
++ handle leftcert and rightcert in starterstroke.c/stroke.c
++ load specified certs in stroke.c
++ extract public keys from certs
++ public key authentication
++ release for Andreas
+
++ stroke loglevels
++ stroke up
++ ike_sa_manager checkout_by_hosts
++ stroke down
++ stroke output redirection
++ stroke status
+
++ libx509
+ + new charon build - libstrong?
+ + transforms
+ + utils (plus host)
+ + logger_manager instance in lib
+ + leak detective usable for charon and pluto and anything else
+ + integrate asn1 parser/oid (asn1/oid)
+ + integrate basic PEM loading
+ + port x509 stuff
+
++ doxygen cleanup (charon/lib)
+
+/ useable certificate support
+ + more id types (use atodn from pluto)
+ + rewrite certificate storage the clean way
+ - further subjectAltName support
+ - certificate validation/chaining
+ - certificate exchange
+
+- implement 3DES to load encrypted pem files
+- ipsec.secrets parsing
+
+- trapping
+- delete notify, when to send?
+- notifys on connection setup failure
+- create child sa message/rekeying
+
+- new build environment (autotools?)
diff --git a/programs/charon/lib/Makefile.lib b/programs/charon/lib/Makefile.lib
new file mode 100644
index 000000000..80a44ff69
--- /dev/null
+++ b/programs/charon/lib/Makefile.lib
@@ -0,0 +1,31 @@
+# Copyright (C) 2006 Martin Willi
+# Hochschule fuer Technik Rapperswil
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+
+LIB_DIR= $(MAIN_DIR)lib/
+
+include $(MAIN_DIR)lib/utils/Makefile.utils
+include $(MAIN_DIR)lib/crypto/Makefile.transforms
+include $(MAIN_DIR)lib/asn1/Makefile.asn1
+
+LIB_OBJS+= $(BUILD_DIR)types.o
+$(BUILD_DIR)types.o : $(LIB_DIR)types.c $(LIB_DIR)types.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+LIB_OBJS+= $(BUILD_DIR)definitions.o
+$(BUILD_DIR)definitions.o : $(LIB_DIR)definitions.c $(LIB_DIR)definitions.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+LIB_OBJS+= $(BUILD_DIR)library.o
+$(BUILD_DIR)library.o : $(LIB_DIR)library.c $(LIB_DIR)library.h
+ $(CC) $(CFLAGS) -c -o $@ $<
diff --git a/programs/charon/lib/asn1/Makefile.asn1 b/programs/charon/lib/asn1/Makefile.asn1
new file mode 100644
index 000000000..3a5450d50
--- /dev/null
+++ b/programs/charon/lib/asn1/Makefile.asn1
@@ -0,0 +1,29 @@
+# Copyright (C) 2006 Martin Willi
+# Hochschule fuer Technik Rapperswil
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+
+ASN1_DIR= $(LIB_DIR)asn1/
+
+
+LIB_OBJS+= $(BUILD_DIR)oid.o
+$(BUILD_DIR)oid.o : $(ASN1_DIR)oid.c $(ASN1_DIR)oid.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+LIB_OBJS+= $(BUILD_DIR)asn1.o
+$(BUILD_DIR)asn1.o : $(ASN1_DIR)asn1.c $(ASN1_DIR)asn1.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+LIB_OBJS+= $(BUILD_DIR)pem.o
+$(BUILD_DIR)pem.o : $(ASN1_DIR)pem.c $(ASN1_DIR)pem.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+LIB_OBJS+= $(BUILD_DIR)ttodata.o
+$(BUILD_DIR)ttodata.o : $(ASN1_DIR)ttodata.c $(ASN1_DIR)ttodata.h
+ $(CC) $(CFLAGS) -c -o $@ $< \ No newline at end of file
diff --git a/programs/charon/lib/asn1/asn1.c b/programs/charon/lib/asn1/asn1.c
new file mode 100644
index 000000000..c847461b6
--- /dev/null
+++ b/programs/charon/lib/asn1/asn1.c
@@ -0,0 +1,738 @@
+/* Simple ASN.1 parser
+ * Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+ * Copyright (C) 2006 Martin Will, Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "asn1.h"
+
+#include <utils/logger_manager.h>
+
+static logger_t *logger;
+
+/* Names of the months */
+static const char* months[] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+/* some common prefabricated ASN.1 constants */
+static u_char ASN1_INTEGER_0_str[] = { 0x02, 0x00 };
+static u_char ASN1_INTEGER_1_str[] = { 0x02, 0x01, 0x01 };
+static u_char ASN1_INTEGER_2_str[] = { 0x02, 0x01, 0x02 };
+
+const chunk_t ASN1_INTEGER_0 = chunk_from_buf(ASN1_INTEGER_0_str);
+const chunk_t ASN1_INTEGER_1 = chunk_from_buf(ASN1_INTEGER_1_str);
+const chunk_t ASN1_INTEGER_2 = chunk_from_buf(ASN1_INTEGER_2_str);
+
+/* some popular algorithmIdentifiers */
+
+static u_char ASN1_md5_id_str[] = {
+ 0x30, 0x0C,
+ 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05,
+ 0x05, 0x00
+};
+
+static u_char ASN1_sha1_id_str[] = {
+ 0x30, 0x09,
+ 0x06, 0x05, 0x2B, 0x0E,0x03, 0x02, 0x1A,
+ 0x05, 0x00
+};
+
+static u_char ASN1_md5WithRSA_id_str[] = {
+ 0x30, 0x0D,
+ 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x04,
+ 0x05, 0x00
+};
+
+static u_char ASN1_sha1WithRSA_id_str[] = {
+ 0x30, 0x0D,
+ 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05,
+ 0x05, 0x00
+};
+
+static u_char ASN1_rsaEncryption_id_str[] = {
+ 0x30, 0x0D,
+ 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01,
+ 0x05, 0x00
+};
+
+const chunk_t ASN1_md5_id = chunk_from_buf(ASN1_md5_id_str);
+const chunk_t ASN1_sha1_id = chunk_from_buf(ASN1_sha1_id_str);
+const chunk_t ASN1_rsaEncryption_id = chunk_from_buf(ASN1_rsaEncryption_id_str);
+const chunk_t ASN1_md5WithRSA_id = chunk_from_buf(ASN1_md5WithRSA_id_str);
+const chunk_t ASN1_sha1WithRSA_id = chunk_from_buf(ASN1_sha1WithRSA_id_str);
+
+/* ASN.1 definiton of an algorithmIdentifier */
+static const asn1Object_t algorithmIdentifierObjects[] = {
+ { 0, "algorithmIdentifier", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "algorithm", ASN1_OID, ASN1_BODY }, /* 1 */
+ { 1, "parameters", ASN1_EOC, ASN1_RAW } /* 2 */
+};
+
+#define ALGORITHM_ID_ALG 1
+#define ALGORITHM_ID_PARAMETERS 2
+#define ALGORITHM_ID_ROOF 3
+
+/*
+ * return the ASN.1 encoded algorithm identifier
+ */
+chunk_t asn1_algorithmIdentifier(int oid)
+{
+ switch (oid)
+ {
+ case OID_RSA_ENCRYPTION:
+ return ASN1_rsaEncryption_id;
+ case OID_MD5_WITH_RSA:
+ return ASN1_md5WithRSA_id;
+ case OID_SHA1_WITH_RSA:
+ return ASN1_sha1WithRSA_id;
+ case OID_MD5:
+ return ASN1_md5_id;
+ case OID_SHA1:
+ return ASN1_sha1_id;
+ default:
+ return CHUNK_INITIALIZER;
+ }
+}
+
+/*
+ * If the oid is listed in the oid_names table then the corresponding
+ * position in the oid_names table is returned otherwise -1 is returned
+ */
+int known_oid(chunk_t object)
+{
+ int oid = 0;
+
+ while (object.len)
+ {
+ if (oid_names[oid].octet == *object.ptr)
+ {
+ if (--object.len == 0 || oid_names[oid].down == 0)
+ {
+ return oid; /* found terminal symbol */
+ }
+ else
+ {
+ object.ptr++; oid++; /* advance to next hex octet */
+ }
+ }
+ else
+ {
+ if (oid_names[oid].next)
+ oid = oid_names[oid].next;
+ else
+ return OID_UNKNOWN;
+ }
+ }
+ return -1;
+}
+
+/*
+ * Decodes the length in bytes of an ASN.1 object
+ */
+u_int asn1_length(chunk_t *blob)
+{
+ u_char n;
+ size_t len;
+
+ /* advance from tag field on to length field */
+ blob->ptr++;
+ blob->len--;
+
+ /* read first octet of length field */
+ n = *blob->ptr++;
+ blob->len--;
+
+ if ((n & 0x80) == 0)
+ {/* single length octet */
+ return n;
+ }
+
+ /* composite length, determine number of length octets */
+ n &= 0x7f;
+
+ if (n > blob->len)
+ {
+ logger->log(logger, ERROR|LEVEL1, "number of length octets is larger than ASN.1 object");
+ return ASN1_INVALID_LENGTH;
+ }
+
+ if (n > sizeof(len))
+ {
+ logger->log(logger, ERROR|LEVEL1, "number of length octets is larger than limit of %d octets",
+ (int)sizeof(len));
+ return ASN1_INVALID_LENGTH;
+ }
+
+ len = 0;
+
+ while (n-- > 0)
+ {
+ len = 256*len + *blob->ptr++;
+ blob->len--;
+ }
+ return len;
+}
+
+/*
+ * determines if a character string is of type ASN.1 printableString
+ */
+bool is_printablestring(chunk_t str)
+{
+ const char printablestring_charset[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 '()+,-./:=?";
+ u_int i;
+
+ for (i = 0; i < str.len; i++)
+ {
+ if (strchr(printablestring_charset, str.ptr[i]) == NULL)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ * Display a date either in local or UTC time
+ * TODO: Does not seem to be thread save
+ */
+char* timetoa(const time_t *time, bool utc)
+{
+ static char buf[30];
+
+ if (*time == 0)
+ sprintf(buf, "--- -- --:--:--%s----", (utc)?" UTC ":" ");
+ else
+ {
+ struct tm *t = (utc)? gmtime(time) : localtime(time);
+ sprintf(buf, "%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);
+ }
+ return buf;
+}
+
+/*
+ * Converts ASN.1 UTCTIME or GENERALIZEDTIME into calender time
+ */
+time_t asn1totime(const chunk_t *utctime, asn1_t type)
+{
+ struct tm t;
+ time_t tz_offset;
+ u_char *eot = NULL;
+
+ if ((eot = memchr(utctime->ptr, 'Z', utctime->len)) != NULL)
+ {
+ tz_offset = 0; /* Zulu time with a zero time zone offset */
+ }
+ else if ((eot = memchr(utctime->ptr, '+', utctime->len)) != NULL)
+ {
+ int tz_hour, tz_min;
+
+ sscanf(eot+1, "%2d%2d", &tz_hour, &tz_min);
+ tz_offset = 3600*tz_hour + 60*tz_min; /* positive time zone offset */
+ }
+ else if ((eot = memchr(utctime->ptr, '-', utctime->len)) != NULL)
+ {
+ int tz_hour, tz_min;
+
+ sscanf(eot+1, "%2d%2d", &tz_hour, &tz_min);
+ tz_offset = -3600*tz_hour - 60*tz_min; /* negative time zone offset */
+ }
+ else
+ {
+ return 0; /* error in time format */
+ }
+
+ {
+ const char* format = (type == ASN1_UTCTIME)? "%2d%2d%2d%2d%2d":
+ "%4d%2d%2d%2d%2d";
+
+ sscanf(utctime->ptr, format, &t.tm_year, &t.tm_mon, &t.tm_mday,
+ &t.tm_hour, &t.tm_min);
+ }
+
+ /* is there a seconds field? */
+ if ((eot - utctime->ptr) == ((type == ASN1_UTCTIME)?12:14))
+ {
+ sscanf(eot-2, "%2d", &t.tm_sec);
+ }
+ else
+ {
+ t.tm_sec = 0;
+ }
+
+ /* representation of year */
+ if (t.tm_year >= 1900)
+ {
+ t.tm_year -= 1900;
+ }
+ else if (t.tm_year >= 100)
+ {
+ return 0;
+ }
+ else if (t.tm_year < 50)
+ {
+ t.tm_year += 100;
+ }
+
+ /* representation of month 0..11*/
+ t.tm_mon--;
+
+ /* set daylight saving time to off */
+ t.tm_isdst = 0;
+
+ /* compensate timezone */
+
+ return mktime(&t) - timezone - tz_offset;
+}
+
+/*
+ * Initializes the internal context of the ASN.1 parser
+ */
+void asn1_init(asn1_ctx_t *ctx, chunk_t blob, u_int level0, bool implicit)
+{
+ logger = logger_manager->get_logger(logger_manager, ASN1);
+ ctx->blobs[0] = blob;
+ ctx->level0 = level0;
+ ctx->implicit = implicit;
+ memset(ctx->loopAddr, '\0', sizeof(ctx->loopAddr));
+}
+
+/*
+ * print the value of an ASN.1 simple object
+ */
+static void debug_asn1_simple_object(chunk_t object, asn1_t type)
+{
+ int oid;
+ time_t time;
+
+ switch (type)
+ {
+ case ASN1_OID:
+ oid = known_oid(object);
+ if (oid != OID_UNKNOWN)
+ {
+ logger->log(logger, CONTROL|LEVEL1, " '%s'", oid_names[oid].name);
+ return;
+ }
+ break;
+ case ASN1_UTF8STRING:
+ case ASN1_IA5STRING:
+ case ASN1_PRINTABLESTRING:
+ case ASN1_T61STRING:
+ case ASN1_VISIBLESTRING:
+ logger->log(logger, CONTROL|LEVEL1, " '%.*s'", (int)object.len, object.ptr);
+ return;
+ case ASN1_UTCTIME:
+ case ASN1_GENERALIZEDTIME:
+ time = asn1totime(&object, type);
+ logger->log(logger, CONTROL|LEVEL1, " '%s'", timetoa(&time, TRUE));
+ return;
+ default:
+ break;
+ }
+ logger->log_chunk(logger, RAW|LEVEL1, "", object);
+}
+
+/*
+ * Parses and extracts the next ASN.1 object
+ */
+bool extract_object(asn1Object_t const *objects, u_int *objectID, chunk_t *object, u_int *level, asn1_ctx_t *ctx)
+{
+ asn1Object_t obj = objects[*objectID];
+ chunk_t *blob;
+ chunk_t *blob1;
+ u_char *start_ptr;
+
+ *object = CHUNK_INITIALIZER;
+
+ if (obj.flags & ASN1_END) /* end of loop or option found */
+ {
+ if (ctx->loopAddr[obj.level] && ctx->blobs[obj.level+1].len > 0)
+ {
+ *objectID = ctx->loopAddr[obj.level]; /* another iteration */
+ obj = objects[*objectID];
+ }
+ else
+ {
+ ctx->loopAddr[obj.level] = 0; /* exit loop or option*/
+ return TRUE;
+ }
+ }
+
+ *level = ctx->level0 + obj.level;
+ blob = ctx->blobs + obj.level;
+ blob1 = blob + 1;
+ start_ptr = blob->ptr;
+
+ /* handle ASN.1 defaults values */
+ if ((obj.flags & ASN1_DEF) && (blob->len == 0 || *start_ptr != obj.type) )
+ {
+ /* field is missing */
+ logger->log(logger, CONTROL|LEVEL1, "L%d - %s:", *level, obj.name);
+ if (obj.type & ASN1_CONSTRUCTED)
+ {
+ (*objectID)++ ; /* skip context-specific tag */
+ }
+ return TRUE;
+ }
+
+ /* handle ASN.1 options */
+
+ if ((obj.flags & ASN1_OPT)
+ && (blob->len == 0 || *start_ptr != obj.type))
+ {
+ /* advance to end of missing option field */
+ do
+ (*objectID)++;
+ while (!((objects[*objectID].flags & ASN1_END)
+ && (objects[*objectID].level == obj.level)));
+ return TRUE;
+ }
+
+ /* an ASN.1 object must possess at least a tag and length field */
+
+ if (blob->len < 2)
+ {
+ logger->log(logger, ERROR|LEVEL1, "L%d - %s: ASN.1 object smaller than 2 octets",
+ *level, obj.name);
+ return FALSE;
+ }
+
+ blob1->len = asn1_length(blob);
+
+ if (blob1->len == ASN1_INVALID_LENGTH || blob->len < blob1->len)
+ {
+ logger->log(logger, ERROR|LEVEL1, "L%d - %s: length of ASN.1 object invalid or too large",
+ *level, obj.name);
+ return FALSE;
+ }
+
+ blob1->ptr = blob->ptr;
+ blob->ptr += blob1->len;
+ blob->len -= blob1->len;
+
+ /* return raw ASN.1 object without prior type checking */
+
+ if (obj.flags & ASN1_RAW)
+ {
+ logger->log(logger, CONTROL|LEVEL1, "L%d - %s:", *level, obj.name);
+ object->ptr = start_ptr;
+ object->len = (size_t)(blob->ptr - start_ptr);
+ return TRUE;
+ }
+
+ if (*start_ptr != obj.type && !(ctx->implicit && *objectID == 0))
+ {
+ logger->log(logger, ERROR|LEVEL1, "L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x",
+ *level, obj.name, obj.type, *start_ptr);
+ logger->log_bytes(logger, RAW|LEVEL1, "", start_ptr, (u_int)(blob->ptr - start_ptr));
+ return FALSE;
+ }
+
+ logger->log(logger, CONTROL|LEVEL1, "L%d - %s:", ctx->level0+obj.level, obj.name);
+
+ /* In case of "SEQUENCE OF" or "SET OF" start a loop */
+ if (obj.flags & ASN1_LOOP)
+ {
+ if (blob1->len > 0)
+ {
+ /* at least one item, start the loop */
+ ctx->loopAddr[obj.level] = *objectID + 1;
+ }
+ else
+ {
+ /* no items, advance directly to end of loop */
+ do
+ (*objectID)++;
+ while (!((objects[*objectID].flags & ASN1_END)
+ && (objects[*objectID].level == obj.level)));
+ return TRUE;
+ }
+ }
+
+ if (obj.flags & ASN1_OBJ)
+ {
+ object->ptr = start_ptr;
+ object->len = (size_t)(blob->ptr - start_ptr);
+ logger->log_chunk(logger, RAW|LEVEL1, "", *object);
+ }
+ else if (obj.flags & ASN1_BODY)
+ {
+ *object = *blob1;
+ debug_asn1_simple_object(*object, obj.type);
+ }
+ return TRUE;
+}
+
+/*
+ * parse an ASN.1 simple type
+ */
+bool parse_asn1_simple_object(chunk_t *object, asn1_t type, u_int level, const char* name)
+{
+ size_t len;
+
+ /* an ASN.1 object must possess at least a tag and length field */
+ if (object->len < 2)
+ {
+ logger->log(logger, ERROR|LEVEL1, "L%d - %s: ASN.1 object smaller than 2 octets",
+ level, name);
+ return FALSE;
+ }
+
+ if (*object->ptr != type)
+ {
+ logger->log(logger, ERROR|LEVEL1, "L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x",
+ level, name, type, *object->ptr);
+ return FALSE;
+ }
+
+ len = asn1_length(object);
+
+ if (len == ASN1_INVALID_LENGTH || object->len < len)
+ {
+ logger->log(logger, ERROR|LEVEL1, "L%d - %s: length of ASN.1 object invalid or too large",
+ level, name);
+ return FALSE;
+ }
+
+ logger->log(logger, CONTROL|LEVEL1, "L%d - %s:", level, name);
+ debug_asn1_simple_object(*object, type);
+ return TRUE;
+}
+
+/*
+ * extracts an algorithmIdentifier
+ */
+int parse_algorithmIdentifier(chunk_t blob, int level0, chunk_t *parameters)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int alg = OID_UNKNOWN;
+ int objectID = 0;
+
+ asn1_init(&ctx, blob, level0, FALSE);
+
+ while (objectID < ALGORITHM_ID_ROOF)
+ {
+ if (!extract_object(algorithmIdentifierObjects, &objectID, &object, &level, &ctx))
+ return OID_UNKNOWN;
+
+ switch (objectID)
+ {
+ case ALGORITHM_ID_ALG:
+ alg = known_oid(object);
+ break;
+ case ALGORITHM_ID_PARAMETERS:
+ if (parameters != NULL)
+ *parameters = object;
+ break;
+ default:
+ break;
+ }
+ objectID++;
+ }
+ return alg;
+ }
+
+/*
+ * tests if a blob contains a valid ASN.1 set or sequence
+ */
+bool is_asn1(chunk_t blob)
+{
+ u_int len;
+ u_char tag = *blob.ptr;
+
+ if (tag != ASN1_SEQUENCE && tag != ASN1_SET)
+ {
+ logger->log(logger, ERROR|LEVEL2, " file content is not binary ASN.1");
+ return FALSE;
+ }
+ len = asn1_length(&blob);
+ if (len != blob.len)
+ {
+ logger->log(logger, ERROR|LEVEL2, " file size does not match ASN.1 coded length");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ * codes ASN.1 lengths up to a size of 16'777'215 bytes
+ */
+void code_asn1_length(size_t length, chunk_t *code)
+{
+ if (length < 128)
+ {
+ code->ptr[0] = length;
+ code->len = 1;
+ }
+ else if (length < 256)
+ {
+ code->ptr[0] = 0x81;
+ code->ptr[1] = (u_char) length;
+ code->len = 2;
+ }
+ else if (length < 65536)
+ {
+ code->ptr[0] = 0x82;
+ code->ptr[1] = length >> 8;
+ code->ptr[2] = length & 0x00ff;
+ code->len = 3;
+ }
+ else
+ {
+ code->ptr[0] = 0x83;
+ code->ptr[1] = length >> 16;
+ code->ptr[2] = (length >> 8) & 0x00ff;
+ code->ptr[3] = length & 0x0000ff;
+ code->len = 4;
+ }
+}
+
+/*
+ * build an empty asn.1 object with tag and length fields already filled in
+ */
+u_char* build_asn1_object(chunk_t *object, asn1_t type, size_t datalen)
+{
+ u_char length_buf[4];
+ chunk_t length = { length_buf, 0 };
+ u_char *pos;
+
+ /* code the asn.1 length field */
+ code_asn1_length(datalen, &length);
+
+ /* allocate memory for the asn.1 TLV object */
+ object->len = 1 + length.len + datalen;
+ object->ptr = malloc(object->len);
+
+ /* set position pointer at the start of the object */
+ pos = object->ptr;
+
+ /* copy the asn.1 tag field and advance the pointer */
+ *pos++ = type;
+
+ /* copy the asn.1 length field and advance the pointer */
+ memcpy(pos, length.ptr, length.len);
+ pos += length.len;
+
+ return pos;
+}
+
+/*
+ * build a simple ASN.1 object
+ */
+chunk_t asn1_simple_object(asn1_t tag, chunk_t content)
+{
+ chunk_t object;
+
+ u_char *pos = build_asn1_object(&object, tag, content.len);
+ memcpy(pos, content.ptr, content.len);
+ pos += content.len;
+
+ return object;
+}
+
+/* Build an ASN.1 object from a variable number of individual chunks.
+ * Depending on the mode, chunks either are moved ('m') or copied ('c').
+ */
+chunk_t asn1_wrap(asn1_t type, const char *mode, ...)
+{
+ chunk_t construct;
+ va_list chunks;
+ u_char *pos;
+ int i;
+ int count = strlen(mode);
+
+ /* sum up lengths of individual chunks */
+ va_start(chunks, mode);
+ construct.len = 0;
+ for (i = 0; i < count; i++)
+ {
+ chunk_t ch = va_arg(chunks, chunk_t);
+ construct.len += ch.len;
+ }
+ va_end(chunks);
+
+ /* allocate needed memory for construct */
+ pos = build_asn1_object(&construct, type, construct.len);
+
+ /* copy or move the chunks */
+ va_start(chunks, mode);
+ for (i = 0; i < count; i++)
+ {
+ chunk_t ch = va_arg(chunks, chunk_t);
+
+ switch (*mode++)
+ {
+ case 'm':
+ memcpy(pos, ch.ptr, ch.len);
+ pos += ch.len;
+ free(ch.ptr);
+ break;
+ case 'c':
+ default:
+ memcpy(pos, ch.ptr, ch.len);
+ pos += ch.len;
+ }
+ }
+ va_end(chunks);
+
+ 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);
+}
+
+/*
+ * convert a date into ASN.1 UTCTIME or GENERALIZEDTIME format
+ */
+chunk_t timetoasn1(const time_t *time, asn1_t type)
+{
+ int offset;
+ const char *format;
+ char buf[TIMETOA_BUF];
+ chunk_t formatted_time;
+ struct tm *t = gmtime(time);
+
+ if (type == ASN1_GENERALIZEDTIME)
+ {
+ format = "%04d%02d%02d%02d%02d%02dZ";
+ offset = 1900;
+ }
+ else /* ASN1_UTCTIME */
+ {
+ format = "%02d%02d%02d%02d%02d%02dZ";
+ offset = (t->tm_year < 100)? 0 : -100;
+ }
+ sprintf(buf, format, t->tm_year + offset, t->tm_mon + 1, t->tm_mday
+ , t->tm_hour, t->tm_min, t->tm_sec);
+ formatted_time.ptr = buf;
+ formatted_time.len = strlen(buf);
+ return asn1_simple_object(type, formatted_time);
+}
diff --git a/programs/charon/lib/asn1/asn1.h b/programs/charon/lib/asn1/asn1.h
new file mode 100644
index 000000000..556bb2b05
--- /dev/null
+++ b/programs/charon/lib/asn1/asn1.h
@@ -0,0 +1,137 @@
+/* Simple ASN.1 parser
+ * Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+ * Copyright (C) 2006 Martin Will, Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef _ASN1_H
+#define _ASN1_H
+
+#include <stdarg.h>
+#include <gmp.h>
+
+#include <types.h>
+#include <asn1/oid.h>
+
+
+/* Defines some primitive ASN1 types */
+typedef enum {
+ ASN1_EOC = 0x00,
+ ASN1_BOOLEAN = 0x01,
+ ASN1_INTEGER = 0x02,
+ ASN1_BIT_STRING = 0x03,
+ ASN1_OCTET_STRING = 0x04,
+ ASN1_NULL = 0x05,
+ ASN1_OID = 0x06,
+ ASN1_ENUMERATED = 0x0A,
+ ASN1_UTF8STRING = 0x0C,
+ ASN1_NUMERICSTRING = 0x12,
+ ASN1_PRINTABLESTRING = 0x13,
+ ASN1_T61STRING = 0x14,
+ ASN1_VIDEOTEXSTRING = 0x15,
+ ASN1_IA5STRING = 0x16,
+ ASN1_UTCTIME = 0x17,
+ ASN1_GENERALIZEDTIME = 0x18,
+ ASN1_GRAPHICSTRING = 0x19,
+ ASN1_VISIBLESTRING = 0x1A,
+ ASN1_GENERALSTRING = 0x1B,
+ ASN1_UNIVERSALSTRING = 0x1C,
+ ASN1_BMPSTRING = 0x1E,
+
+ ASN1_CONSTRUCTED = 0x20,
+
+ ASN1_SEQUENCE = 0x30,
+
+ ASN1_SET = 0x31,
+
+ ASN1_CONTEXT_S_0 = 0x80,
+ ASN1_CONTEXT_S_1 = 0x81,
+ ASN1_CONTEXT_S_2 = 0x82,
+ ASN1_CONTEXT_S_3 = 0x83,
+ ASN1_CONTEXT_S_4 = 0x84,
+ ASN1_CONTEXT_S_5 = 0x85,
+ ASN1_CONTEXT_S_6 = 0x86,
+ ASN1_CONTEXT_S_7 = 0x87,
+ ASN1_CONTEXT_S_8 = 0x88,
+
+ ASN1_CONTEXT_C_0 = 0xA0,
+ ASN1_CONTEXT_C_1 = 0xA1,
+ ASN1_CONTEXT_C_2 = 0xA2,
+ ASN1_CONTEXT_C_3 = 0xA3,
+ ASN1_CONTEXT_C_4 = 0xA4,
+ ASN1_CONTEXT_C_5 = 0xA5
+} asn1_t;
+
+/* Definition of ASN1 flags */
+
+#define ASN1_NONE 0x00
+#define ASN1_DEF 0x01
+#define ASN1_OPT 0x02
+#define ASN1_LOOP 0x04
+#define ASN1_END 0x08
+#define ASN1_OBJ 0x10
+#define ASN1_BODY 0x20
+#define ASN1_RAW 0x40
+
+#define ASN1_INVALID_LENGTH 0xffffffff
+
+/* definition of an ASN.1 object */
+
+typedef struct {
+ u_int level;
+ const u_char *name;
+ asn1_t type;
+ u_char flags;
+} asn1Object_t;
+
+#define ASN1_MAX_LEVEL 10
+
+typedef struct {
+ bool implicit;
+ u_int level0;
+ u_int loopAddr[ASN1_MAX_LEVEL+1];
+ chunk_t blobs[ASN1_MAX_LEVEL+2];
+} asn1_ctx_t;
+
+/* some common prefabricated ASN.1 constants */
+extern const chunk_t ASN1_INTEGER_0;
+extern const chunk_t ASN1_INTEGER_1;
+extern const chunk_t ASN1_INTEGER_2;
+
+/* some popular algorithmIdentifiers */
+extern const chunk_t ASN1_md5_id;
+extern const chunk_t ASN1_sha1_id;
+extern const chunk_t ASN1_rsaEncryption_id;
+extern const chunk_t ASN1_md5WithRSA_id;
+extern const chunk_t ASN1_sha1WithRSA_id;
+
+#define TIMETOA_BUF 30
+
+extern chunk_t asn1_algorithmIdentifier(int oid);
+extern int known_oid(chunk_t object);
+extern u_int asn1_length(chunk_t *blob);
+extern bool is_printablestring(chunk_t str);
+extern time_t asn1totime(const chunk_t *utctime, asn1_t type);
+extern void asn1_init(asn1_ctx_t *ctx, chunk_t blob, u_int level0, bool implicit);
+extern bool extract_object(asn1Object_t const *objects, u_int *objectID, chunk_t *object, u_int *level, asn1_ctx_t *ctx);
+extern bool parse_asn1_simple_object(chunk_t *object, asn1_t type, u_int level, const char* name);
+extern int parse_algorithmIdentifier(chunk_t blob, int level0, chunk_t *parameters);
+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_wrap(asn1_t type, const char *mode, ...);
+extern chunk_t timetoasn1(const time_t *time, asn1_t type);
+
+#endif /* _ASN1_H */
diff --git a/programs/charon/lib/asn1/oid.c b/programs/charon/lib/asn1/oid.c
new file mode 100644
index 000000000..4b0632de2
--- /dev/null
+++ b/programs/charon/lib/asn1/oid.c
@@ -0,0 +1,197 @@
+/* List of some useful object identifiers (OIDs)
+ * Copyright (C) 2003-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+ *
+ * This file has been automatically generated by the script oid.pl
+ * Do not edit manually!
+ */
+
+#include <stdlib.h>
+
+#include "oid.h"
+
+const oid_t oid_names[] = {
+ {0x02, 7, 1, "ITU-T Administration" }, /* 0 */
+ { 0x82, 0, 1, "" }, /* 1 */
+ { 0x06, 0, 1, "Germany ITU-T member" }, /* 2 */
+ { 0x01, 0, 1, "Deutsche Telekom AG" }, /* 3 */
+ { 0x0A, 0, 1, "" }, /* 4 */
+ { 0x07, 0, 1, "" }, /* 5 */
+ { 0x14, 0, 0, "ND" }, /* 6 */
+ {0x09, 18, 1, "data" }, /* 7 */
+ { 0x92, 0, 1, "" }, /* 8 */
+ { 0x26, 0, 1, "" }, /* 9 */
+ { 0x89, 0, 1, "" }, /* 10 */
+ { 0x93, 0, 1, "" }, /* 11 */
+ { 0xF2, 0, 1, "" }, /* 12 */
+ { 0x2C, 0, 1, "" }, /* 13 */
+ { 0x64, 0, 1, "pilot" }, /* 14 */
+ { 0x01, 0, 1, "pilotAttributeType" }, /* 15 */
+ { 0x01, 17, 0, "UID" }, /* 16 */
+ { 0x19, 0, 0, "DC" }, /* 17 */
+ {0x55, 51, 1, "X.500" }, /* 18 */
+ { 0x04, 36, 1, "X.509" }, /* 19 */
+ { 0x03, 21, 0, "CN" }, /* 20 */
+ { 0x04, 22, 0, "S" }, /* 21 */
+ { 0x05, 23, 0, "SN" }, /* 22 */
+ { 0x06, 24, 0, "C" }, /* 23 */
+ { 0x07, 25, 0, "L" }, /* 24 */
+ { 0x08, 26, 0, "ST" }, /* 25 */
+ { 0x0A, 27, 0, "O" }, /* 26 */
+ { 0x0B, 28, 0, "OU" }, /* 27 */
+ { 0x0C, 29, 0, "T" }, /* 28 */
+ { 0x0D, 30, 0, "D" }, /* 29 */
+ { 0x24, 31, 0, "userCertificate" }, /* 30 */
+ { 0x29, 32, 0, "N" }, /* 31 */
+ { 0x2A, 33, 0, "G" }, /* 32 */
+ { 0x2B, 34, 0, "I" }, /* 33 */
+ { 0x2D, 35, 0, "ID" }, /* 34 */
+ { 0x48, 0, 0, "role" }, /* 35 */
+ { 0x1D, 0, 1, "id-ce" }, /* 36 */
+ { 0x09, 38, 0, "subjectDirectoryAttrs" }, /* 37 */
+ { 0x0E, 39, 0, "subjectKeyIdentifier" }, /* 38 */
+ { 0x0F, 40, 0, "keyUsage" }, /* 39 */
+ { 0x10, 41, 0, "privateKeyUsagePeriod" }, /* 40 */
+ { 0x11, 42, 0, "subjectAltName" }, /* 41 */
+ { 0x12, 43, 0, "issuerAltName" }, /* 42 */
+ { 0x13, 44, 0, "basicConstraints" }, /* 43 */
+ { 0x15, 45, 0, "reasonCode" }, /* 44 */
+ { 0x1F, 46, 0, "crlDistributionPoints" }, /* 45 */
+ { 0x20, 47, 0, "certificatePolicies" }, /* 46 */
+ { 0x23, 48, 0, "authorityKeyIdentifier" }, /* 47 */
+ { 0x25, 49, 0, "extendedKeyUsage" }, /* 48 */
+ { 0x37, 50, 0, "targetInformation" }, /* 49 */
+ { 0x38, 0, 0, "noRevAvail" }, /* 50 */
+ {0x2A, 88, 1, "" }, /* 51 */
+ { 0x86, 0, 1, "" }, /* 52 */
+ { 0x48, 0, 1, "" }, /* 53 */
+ { 0x86, 0, 1, "" }, /* 54 */
+ { 0xF7, 0, 1, "" }, /* 55 */
+ { 0x0D, 0, 1, "RSADSI" }, /* 56 */
+ { 0x01, 83, 1, "PKCS" }, /* 57 */
+ { 0x01, 66, 1, "PKCS-1" }, /* 58 */
+ { 0x01, 60, 0, "rsaEncryption" }, /* 59 */
+ { 0x02, 61, 0, "md2WithRSAEncryption" }, /* 60 */
+ { 0x04, 62, 0, "md5WithRSAEncryption" }, /* 61 */
+ { 0x05, 63, 0, "sha-1WithRSAEncryption" }, /* 62 */
+ { 0x0B, 64, 0, "sha256WithRSAEncryption"}, /* 63 */
+ { 0x0C, 65, 0, "sha384WithRSAEncryption"}, /* 64 */
+ { 0x0D, 0, 0, "sha512WithRSAEncryption"}, /* 65 */
+ { 0x07, 73, 1, "PKCS-7" }, /* 66 */
+ { 0x01, 68, 0, "data" }, /* 67 */
+ { 0x02, 69, 0, "signedData" }, /* 68 */
+ { 0x03, 70, 0, "envelopedData" }, /* 69 */
+ { 0x04, 71, 0, "signedAndEnvelopedData" }, /* 70 */
+ { 0x05, 72, 0, "digestedData" }, /* 71 */
+ { 0x06, 0, 0, "encryptedData" }, /* 72 */
+ { 0x09, 0, 1, "PKCS-9" }, /* 73 */
+ { 0x01, 75, 0, "E" }, /* 74 */
+ { 0x02, 76, 0, "unstructuredName" }, /* 75 */
+ { 0x03, 77, 0, "contentType" }, /* 76 */
+ { 0x04, 78, 0, "messageDigest" }, /* 77 */
+ { 0x05, 79, 0, "signingTime" }, /* 78 */
+ { 0x06, 80, 0, "counterSignature" }, /* 79 */
+ { 0x07, 81, 0, "challengePassword" }, /* 80 */
+ { 0x08, 82, 0, "unstructuredAddress" }, /* 81 */
+ { 0x0E, 0, 0, "extensionRequest" }, /* 82 */
+ { 0x02, 86, 1, "digestAlgorithm" }, /* 83 */
+ { 0x02, 85, 0, "md2" }, /* 84 */
+ { 0x05, 0, 0, "md5" }, /* 85 */
+ { 0x03, 0, 1, "encryptionAlgorithm" }, /* 86 */
+ { 0x07, 0, 0, "3des-ede-cbc" }, /* 87 */
+ {0x2B, 149, 1, "" }, /* 88 */
+ { 0x06, 136, 1, "dod" }, /* 89 */
+ { 0x01, 0, 1, "internet" }, /* 90 */
+ { 0x04, 105, 1, "private" }, /* 91 */
+ { 0x01, 0, 1, "enterprise" }, /* 92 */
+ { 0x82, 98, 1, "" }, /* 93 */
+ { 0x37, 0, 1, "Microsoft" }, /* 94 */
+ { 0x0A, 0, 1, "" }, /* 95 */
+ { 0x03, 0, 1, "" }, /* 96 */
+ { 0x03, 0, 0, "msSGC" }, /* 97 */
+ { 0x89, 0, 1, "" }, /* 98 */
+ { 0x31, 0, 1, "" }, /* 99 */
+ { 0x01, 0, 1, "" }, /* 100 */
+ { 0x01, 0, 1, "" }, /* 101 */
+ { 0x02, 0, 1, "" }, /* 102 */
+ { 0x02, 104, 0, "" }, /* 103 */
+ { 0x4B, 0, 0, "TCGID" }, /* 104 */
+ { 0x05, 0, 1, "security" }, /* 105 */
+ { 0x05, 0, 1, "mechanisms" }, /* 106 */
+ { 0x07, 0, 1, "id-pkix" }, /* 107 */
+ { 0x01, 110, 1, "id-pe" }, /* 108 */
+ { 0x01, 0, 0, "authorityInfoAccess" }, /* 109 */
+ { 0x03, 120, 1, "id-kp" }, /* 110 */
+ { 0x01, 112, 0, "serverAuth" }, /* 111 */
+ { 0x02, 113, 0, "clientAuth" }, /* 112 */
+ { 0x03, 114, 0, "codeSigning" }, /* 113 */
+ { 0x04, 115, 0, "emailProtection" }, /* 114 */
+ { 0x05, 116, 0, "ipsecEndSystem" }, /* 115 */
+ { 0x06, 117, 0, "ipsecTunnel" }, /* 116 */
+ { 0x07, 118, 0, "ipsecUser" }, /* 117 */
+ { 0x08, 119, 0, "timeStamping" }, /* 118 */
+ { 0x09, 0, 0, "ocspSigning" }, /* 119 */
+ { 0x08, 122, 1, "id-otherNames" }, /* 120 */
+ { 0x05, 0, 0, "xmppAddr" }, /* 121 */
+ { 0x0A, 127, 1, "id-aca" }, /* 122 */
+ { 0x01, 124, 0, "authenticationInfo" }, /* 123 */
+ { 0x02, 125, 0, "accessIdentity" }, /* 124 */
+ { 0x03, 126, 0, "chargingIdentity" }, /* 125 */
+ { 0x04, 0, 0, "group" }, /* 126 */
+ { 0x30, 0, 1, "id-ad" }, /* 127 */
+ { 0x01, 0, 1, "ocsp" }, /* 128 */
+ { 0x01, 130, 0, "basic" }, /* 129 */
+ { 0x02, 131, 0, "nonce" }, /* 130 */
+ { 0x03, 132, 0, "crl" }, /* 131 */
+ { 0x04, 133, 0, "response" }, /* 132 */
+ { 0x05, 134, 0, "noCheck" }, /* 133 */
+ { 0x06, 135, 0, "archiveCutoff" }, /* 134 */
+ { 0x07, 0, 0, "serviceLocator" }, /* 135 */
+ { 0x0E, 142, 1, "oiw" }, /* 136 */
+ { 0x03, 0, 1, "secsig" }, /* 137 */
+ { 0x02, 0, 1, "algorithms" }, /* 138 */
+ { 0x07, 140, 0, "des-cbc" }, /* 139 */
+ { 0x1A, 141, 0, "sha-1" }, /* 140 */
+ { 0x1D, 0, 0, "sha-1WithRSASignature" }, /* 141 */
+ { 0x24, 0, 1, "TeleTrusT" }, /* 142 */
+ { 0x03, 0, 1, "algorithm" }, /* 143 */
+ { 0x03, 0, 1, "signatureAlgorithm" }, /* 144 */
+ { 0x01, 0, 1, "rsaSignature" }, /* 145 */
+ { 0x02, 147, 0, "rsaSigWithripemd160" }, /* 146 */
+ { 0x03, 148, 0, "rsaSigWithripemd128" }, /* 147 */
+ { 0x04, 0, 0, "rsaSigWithripemd256" }, /* 148 */
+ {0x60, 0, 1, "" }, /* 149 */
+ { 0x86, 0, 1, "" }, /* 150 */
+ { 0x48, 0, 1, "" }, /* 151 */
+ { 0x01, 0, 1, "organization" }, /* 152 */
+ { 0x65, 160, 1, "gov" }, /* 153 */
+ { 0x03, 0, 1, "csor" }, /* 154 */
+ { 0x04, 0, 1, "nistalgorithm" }, /* 155 */
+ { 0x02, 0, 1, "hashalgs" }, /* 156 */
+ { 0x01, 158, 0, "id-SHA-256" }, /* 157 */
+ { 0x02, 159, 0, "id-SHA-384" }, /* 158 */
+ { 0x03, 0, 0, "id-SHA-512" }, /* 159 */
+ { 0x86, 0, 1, "" }, /* 160 */
+ { 0xf8, 0, 1, "" }, /* 161 */
+ { 0x42, 174, 1, "netscape" }, /* 162 */
+ { 0x01, 169, 1, "" }, /* 163 */
+ { 0x01, 165, 0, "nsCertType" }, /* 164 */
+ { 0x03, 166, 0, "nsRevocationUrl" }, /* 165 */
+ { 0x04, 167, 0, "nsCaRevocationUrl" }, /* 166 */
+ { 0x08, 168, 0, "nsCaPolicyUrl" }, /* 167 */
+ { 0x0d, 0, 0, "nsComment" }, /* 168 */
+ { 0x03, 172, 1, "directory" }, /* 169 */
+ { 0x01, 0, 1, "" }, /* 170 */
+ { 0x03, 0, 0, "employeeNumber" }, /* 171 */
+ { 0x04, 0, 1, "policy" }, /* 172 */
+ { 0x01, 0, 0, "nsSGC" }, /* 173 */
+ { 0x45, 0, 1, "verisign" }, /* 174 */
+ { 0x01, 0, 1, "pki" }, /* 175 */
+ { 0x09, 0, 1, "attributes" }, /* 176 */
+ { 0x02, 178, 0, "messageType" }, /* 177 */
+ { 0x03, 179, 0, "pkiStatus" }, /* 178 */
+ { 0x04, 180, 0, "failInfo" }, /* 179 */
+ { 0x05, 181, 0, "senderNonce" }, /* 180 */
+ { 0x06, 182, 0, "recipientNonce" }, /* 181 */
+ { 0x07, 183, 0, "transID" }, /* 182 */
+ { 0x08, 0, 0, "extensionReq" } /* 183 */
+};
diff --git a/programs/charon/lib/asn1/oid.h b/programs/charon/lib/asn1/oid.h
new file mode 100644
index 000000000..a9265d43f
--- /dev/null
+++ b/programs/charon/lib/asn1/oid.h
@@ -0,0 +1,80 @@
+/* Object identifiers (OIDs) used by FreeS/WAN
+ * Copyright (C) 2003-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+ *
+ * This file has been automatically generated by the script oid.pl
+ * Do not edit manually!
+ */
+
+#ifndef OID_H_
+#define OID_H_
+
+typedef struct {
+ u_char octet;
+ u_int next;
+ u_int down;
+ const u_char *name;
+} oid_t;
+
+extern const oid_t oid_names[];
+
+#define OID_UNKNOWN -1
+#define OID_ROLE 35
+#define OID_SUBJECT_KEY_ID 38
+#define OID_SUBJECT_ALT_NAME 41
+#define OID_BASIC_CONSTRAINTS 43
+#define OID_CRL_REASON_CODE 44
+#define OID_CRL_DISTRIBUTION_POINTS 45
+#define OID_AUTHORITY_KEY_ID 47
+#define OID_EXTENDED_KEY_USAGE 48
+#define OID_TARGET_INFORMATION 49
+#define OID_NO_REV_AVAIL 50
+#define OID_RSA_ENCRYPTION 59
+#define OID_MD2_WITH_RSA 60
+#define OID_MD5_WITH_RSA 61
+#define OID_SHA1_WITH_RSA 62
+#define OID_SHA256_WITH_RSA 63
+#define OID_SHA384_WITH_RSA 64
+#define OID_SHA512_WITH_RSA 65
+#define OID_PKCS7_DATA 67
+#define OID_PKCS7_SIGNED_DATA 68
+#define OID_PKCS7_ENVELOPED_DATA 69
+#define OID_PKCS7_SIGNED_ENVELOPED_DATA 70
+#define OID_PKCS7_DIGESTED_DATA 71
+#define OID_PKCS7_ENCRYPTED_DATA 72
+#define OID_PKCS9_EMAIL 74
+#define OID_PKCS9_CONTENT_TYPE 76
+#define OID_PKCS9_MESSAGE_DIGEST 77
+#define OID_PKCS9_SIGNING_TIME 78
+#define OID_MD2 84
+#define OID_MD5 85
+#define OID_3DES_EDE_CBC 87
+#define OID_AUTHORITY_INFO_ACCESS 109
+#define OID_OCSP_SIGNING 119
+#define OID_XMPP_ADDR 121
+#define OID_AUTHENTICATION_INFO 123
+#define OID_ACCESS_IDENTITY 124
+#define OID_CHARGING_IDENTITY 125
+#define OID_GROUP 126
+#define OID_OCSP 128
+#define OID_BASIC 129
+#define OID_NONCE 130
+#define OID_CRL 131
+#define OID_RESPONSE 132
+#define OID_NO_CHECK 133
+#define OID_ARCHIVE_CUTOFF 134
+#define OID_SERVICE_LOCATOR 135
+#define OID_DES_CBC 139
+#define OID_SHA1 140
+#define OID_SHA1_WITH_RSA_OIW 141
+#define OID_NS_REVOCATION_URL 165
+#define OID_NS_CA_REVOCATION_URL 166
+#define OID_NS_CA_POLICY_URL 167
+#define OID_NS_COMMENT 168
+#define OID_PKI_MESSAGE_TYPE 177
+#define OID_PKI_STATUS 178
+#define OID_PKI_FAIL_INFO 179
+#define OID_PKI_SENDER_NONCE 180
+#define OID_PKI_RECIPIENT_NONCE 181
+#define OID_PKI_TRANS_ID 182
+
+#endif /* OID_H_ */
diff --git a/programs/charon/lib/asn1/oid.pl b/programs/charon/lib/asn1/oid.pl
new file mode 100644
index 000000000..a3725e57d
--- /dev/null
+++ b/programs/charon/lib/asn1/oid.pl
@@ -0,0 +1,127 @@
+#!/usr/bin/perl
+# Generates oid.h and oid.c out of oid.txt
+# Copyright (C) 2003-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+
+$copyright="Copyright (C) 2003-2004 Andreas Steffen, Zuercher Hochschule Winterthur";
+$automatic="This file has been automatically generated by the script oid.pl";
+$warning="Do not edit manually!";
+
+print "oid.pl generating oid.h and oid.c\n";
+
+# Generate oid.h
+
+open(OID_H, ">oid.h")
+ or die "could not open 'oid.h': $!";
+
+print OID_H "/* Object identifiers (OIDs) used by FreeS/WAN\n",
+ " * ", $copyright, "\n",
+ " * \n",
+ " * ", $automatic, "\n",
+ " * ", $warning, "\n",
+ " */\n\n",
+ "#ifndef OID_H_\n",
+ "#define OID_H_\n\n",
+ "typedef struct {\n",
+ " u_char octet;\n",
+ " u_int next;\n",
+ " u_int down;\n",
+ " const u_char *name;\n",
+ "} oid_t;\n",
+ "\n",
+ "extern const oid_t oid_names[];\n",
+ "\n",
+ "#define OID_UNKNOWN -1\n";
+
+# parse oid.txt
+
+open(SRC, "<oid.txt")
+ or die "could not open 'oid.txt': $!";
+
+$counter = 0;
+$max_name = 0;
+$max_order = 0;
+
+while ($line = <SRC>)
+{
+ $line =~ m/( *?)(0x\w{2})\s+(".*?")[ \t]*?([\w_]*?)\Z/;
+
+ @order[$counter] = length($1);
+ @octet[$counter] = $2;
+ @name[$counter] = $3;
+
+ if (length($1) > $max_order)
+ {
+ $max_order = length($1);
+ }
+ if (length($3) > $max_name)
+ {
+ $max_name = length($3);
+ }
+ if (length($4) > 0)
+ {
+ printf OID_H "#define %s%s%d\n", $4, "\t" x ((39-length($4))/8), $counter;
+ }
+ $counter++;
+}
+
+print OID_H "\n#endif /* OID_H_ */\n";
+
+close SRC;
+close OID_H;
+
+# Generate oid.c
+
+open(OID_C, ">oid.c")
+ or die "could not open 'oid.c': $!";
+
+print OID_C "/* List of some useful object identifiers (OIDs)\n",
+ " * ", $copyright, "\n",
+ " * \n",
+ " * ", $automatic, "\n",
+ " * ", $warning, "\n",
+ " */\n",
+ "\n",
+ "#include <stdlib.h>\n",
+ "\n",
+ "#include \"oid.h\"\n",
+ "\n",
+ "const oid_t oid_names[] = {\n";
+
+for ($c = 0; $c < $counter; $c++)
+{
+ $next = 0;
+
+ for ($d = $c+1; $d < $counter && @order[$d] >= @order[$c]; $d++)
+ {
+ if (@order[$d] == @order[$c])
+ {
+ @next[$c] = $d;
+ last;
+ }
+ }
+
+ printf OID_C " {%s%s,%s%3d, %d, %s%s}%s /* %3d */\n"
+ ,' ' x @order[$c]
+ , @octet[$c]
+ , ' ' x (1 + $max_order - @order[$c])
+ , @next[$c]
+ , @order[$c+1] > @order[$c]
+ , @name[$c]
+ , ' ' x ($max_name - length(@name[$c]))
+ , $c != $counter-1 ? "," : " "
+ , $c;
+}
+
+print OID_C "};\n" ;
+close OID_C;
diff --git a/programs/charon/lib/asn1/oid.txt b/programs/charon/lib/asn1/oid.txt
new file mode 100644
index 000000000..eed46d59d
--- /dev/null
+++ b/programs/charon/lib/asn1/oid.txt
@@ -0,0 +1,184 @@
+0x02 "ITU-T Administration"
+ 0x82 ""
+ 0x06 "Germany ITU-T member"
+ 0x01 "Deutsche Telekom AG"
+ 0x0A ""
+ 0x07 ""
+ 0x14 "ND"
+0x09 "data"
+ 0x92 ""
+ 0x26 ""
+ 0x89 ""
+ 0x93 ""
+ 0xF2 ""
+ 0x2C ""
+ 0x64 "pilot"
+ 0x01 "pilotAttributeType"
+ 0x01 "UID"
+ 0x19 "DC"
+0x55 "X.500"
+ 0x04 "X.509"
+ 0x03 "CN"
+ 0x04 "S"
+ 0x05 "SN"
+ 0x06 "C"
+ 0x07 "L"
+ 0x08 "ST"
+ 0x0A "O"
+ 0x0B "OU"
+ 0x0C "T"
+ 0x0D "D"
+ 0x24 "userCertificate"
+ 0x29 "N"
+ 0x2A "G"
+ 0x2B "I"
+ 0x2D "ID"
+ 0x48 "role" OID_ROLE
+ 0x1D "id-ce"
+ 0x09 "subjectDirectoryAttrs"
+ 0x0E "subjectKeyIdentifier" OID_SUBJECT_KEY_ID
+ 0x0F "keyUsage"
+ 0x10 "privateKeyUsagePeriod"
+ 0x11 "subjectAltName" OID_SUBJECT_ALT_NAME
+ 0x12 "issuerAltName"
+ 0x13 "basicConstraints" OID_BASIC_CONSTRAINTS
+ 0x15 "reasonCode" OID_CRL_REASON_CODE
+ 0x1F "crlDistributionPoints" OID_CRL_DISTRIBUTION_POINTS
+ 0x20 "certificatePolicies"
+ 0x23 "authorityKeyIdentifier" OID_AUTHORITY_KEY_ID
+ 0x25 "extendedKeyUsage" OID_EXTENDED_KEY_USAGE
+ 0x37 "targetInformation" OID_TARGET_INFORMATION
+ 0x38 "noRevAvail" OID_NO_REV_AVAIL
+0x2A ""
+ 0x86 ""
+ 0x48 ""
+ 0x86 ""
+ 0xF7 ""
+ 0x0D "RSADSI"
+ 0x01 "PKCS"
+ 0x01 "PKCS-1"
+ 0x01 "rsaEncryption" OID_RSA_ENCRYPTION
+ 0x02 "md2WithRSAEncryption" OID_MD2_WITH_RSA
+ 0x04 "md5WithRSAEncryption" OID_MD5_WITH_RSA
+ 0x05 "sha-1WithRSAEncryption" OID_SHA1_WITH_RSA
+ 0x0B "sha256WithRSAEncryption" OID_SHA256_WITH_RSA
+ 0x0C "sha384WithRSAEncryption" OID_SHA384_WITH_RSA
+ 0x0D "sha512WithRSAEncryption" OID_SHA512_WITH_RSA
+ 0x07 "PKCS-7"
+ 0x01 "data" OID_PKCS7_DATA
+ 0x02 "signedData" OID_PKCS7_SIGNED_DATA
+ 0x03 "envelopedData" OID_PKCS7_ENVELOPED_DATA
+ 0x04 "signedAndEnvelopedData" OID_PKCS7_SIGNED_ENVELOPED_DATA
+ 0x05 "digestedData" OID_PKCS7_DIGESTED_DATA
+ 0x06 "encryptedData" OID_PKCS7_ENCRYPTED_DATA
+ 0x09 "PKCS-9"
+ 0x01 "E" OID_PKCS9_EMAIL
+ 0x02 "unstructuredName"
+ 0x03 "contentType" OID_PKCS9_CONTENT_TYPE
+ 0x04 "messageDigest" OID_PKCS9_MESSAGE_DIGEST
+ 0x05 "signingTime" OID_PKCS9_SIGNING_TIME
+ 0x06 "counterSignature"
+ 0x07 "challengePassword"
+ 0x08 "unstructuredAddress"
+ 0x0E "extensionRequest"
+ 0x02 "digestAlgorithm"
+ 0x02 "md2" OID_MD2
+ 0x05 "md5" OID_MD5
+ 0x03 "encryptionAlgorithm"
+ 0x07 "3des-ede-cbc" OID_3DES_EDE_CBC
+0x2B ""
+ 0x06 "dod"
+ 0x01 "internet"
+ 0x04 "private"
+ 0x01 "enterprise"
+ 0x82 ""
+ 0x37 "Microsoft"
+ 0x0A ""
+ 0x03 ""
+ 0x03 "msSGC"
+ 0x89 ""
+ 0x31 ""
+ 0x01 ""
+ 0x01 ""
+ 0x02 ""
+ 0x02 ""
+ 0x4B "TCGID"
+ 0x05 "security"
+ 0x05 "mechanisms"
+ 0x07 "id-pkix"
+ 0x01 "id-pe"
+ 0x01 "authorityInfoAccess" OID_AUTHORITY_INFO_ACCESS
+ 0x03 "id-kp"
+ 0x01 "serverAuth"
+ 0x02 "clientAuth"
+ 0x03 "codeSigning"
+ 0x04 "emailProtection"
+ 0x05 "ipsecEndSystem"
+ 0x06 "ipsecTunnel"
+ 0x07 "ipsecUser"
+ 0x08 "timeStamping"
+ 0x09 "ocspSigning" OID_OCSP_SIGNING
+ 0x08 "id-otherNames"
+ 0x05 "xmppAddr" OID_XMPP_ADDR
+ 0x0A "id-aca"
+ 0x01 "authenticationInfo" OID_AUTHENTICATION_INFO
+ 0x02 "accessIdentity" OID_ACCESS_IDENTITY
+ 0x03 "chargingIdentity" OID_CHARGING_IDENTITY
+ 0x04 "group" OID_GROUP
+ 0x30 "id-ad"
+ 0x01 "ocsp" OID_OCSP
+ 0x01 "basic" OID_BASIC
+ 0x02 "nonce" OID_NONCE
+ 0x03 "crl" OID_CRL
+ 0x04 "response" OID_RESPONSE
+ 0x05 "noCheck" OID_NO_CHECK
+ 0x06 "archiveCutoff" OID_ARCHIVE_CUTOFF
+ 0x07 "serviceLocator" OID_SERVICE_LOCATOR
+ 0x0E "oiw"
+ 0x03 "secsig"
+ 0x02 "algorithms"
+ 0x07 "des-cbc" OID_DES_CBC
+ 0x1A "sha-1" OID_SHA1
+ 0x1D "sha-1WithRSASignature" OID_SHA1_WITH_RSA_OIW
+ 0x24 "TeleTrusT"
+ 0x03 "algorithm"
+ 0x03 "signatureAlgorithm"
+ 0x01 "rsaSignature"
+ 0x02 "rsaSigWithripemd160"
+ 0x03 "rsaSigWithripemd128"
+ 0x04 "rsaSigWithripemd256"
+0x60 ""
+ 0x86 ""
+ 0x48 ""
+ 0x01 "organization"
+ 0x65 "gov"
+ 0x03 "csor"
+ 0x04 "nistalgorithm"
+ 0x02 "hashalgs"
+ 0x01 "id-SHA-256"
+ 0x02 "id-SHA-384"
+ 0x03 "id-SHA-512"
+ 0x86 ""
+ 0xf8 ""
+ 0x42 "netscape"
+ 0x01 ""
+ 0x01 "nsCertType"
+ 0x03 "nsRevocationUrl" OID_NS_REVOCATION_URL
+ 0x04 "nsCaRevocationUrl" OID_NS_CA_REVOCATION_URL
+ 0x08 "nsCaPolicyUrl" OID_NS_CA_POLICY_URL
+ 0x0d "nsComment" OID_NS_COMMENT
+ 0x03 "directory"
+ 0x01 ""
+ 0x03 "employeeNumber"
+ 0x04 "policy"
+ 0x01 "nsSGC"
+ 0x45 "verisign"
+ 0x01 "pki"
+ 0x09 "attributes"
+ 0x02 "messageType" OID_PKI_MESSAGE_TYPE
+ 0x03 "pkiStatus" OID_PKI_STATUS
+ 0x04 "failInfo" OID_PKI_FAIL_INFO
+ 0x05 "senderNonce" OID_PKI_SENDER_NONCE
+ 0x06 "recipientNonce" OID_PKI_RECIPIENT_NONCE
+ 0x07 "transID" OID_PKI_TRANS_ID
+ 0x08 "extensionReq"
diff --git a/programs/charon/lib/asn1/pem.c b/programs/charon/lib/asn1/pem.c
new file mode 100755
index 000000000..b02268dd9
--- /dev/null
+++ b/programs/charon/lib/asn1/pem.c
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#include "pem.h"
+#include "ttodata.h"
+
+#include <crypto/hashers/hasher.h>
+#include <crypto/crypters/crypter.h>
+
+
+/*
+ * check the presence of a pattern in a character string
+ */
+static bool present(const char* pattern, chunk_t* ch)
+{
+ u_int pattern_len = strlen(pattern);
+
+ if (ch->len >= pattern_len && strncmp(ch->ptr, pattern, pattern_len) == 0)
+ {
+ ch->ptr += pattern_len;
+ ch->len -= pattern_len;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * compare string with chunk
+ */
+static bool match(const char *pattern, const chunk_t *ch)
+{
+ return ch->len == strlen(pattern) && strncmp(pattern, ch->ptr, ch->len) == 0;
+}
+
+/*
+ * find a boundary of the form -----tag name-----
+ */
+static bool find_boundary(const char* tag, chunk_t *line)
+{
+ chunk_t name = CHUNK_INITIALIZER;
+
+ if (!present("-----", line))
+ return FALSE;
+ if (!present(tag, line))
+ return FALSE;
+ if (*line->ptr != ' ')
+ return FALSE;
+ line->ptr++; line->len--;
+
+ /* extract name */
+ name.ptr = line->ptr;
+ while (line->len > 0)
+ {
+ if (present("-----", line))
+ {
+ return TRUE;
+ }
+ line->ptr++; line->len--; name.len++;
+ }
+ return FALSE;
+}
+
+/*
+ * eat whitespace
+ */
+static void eat_whitespace(chunk_t *src)
+{
+ while (src->len > 0 && (*src->ptr == ' ' || *src->ptr == '\t'))
+ {
+ src->ptr++; src->len--;
+ }
+}
+
+/*
+ * extracts a token ending with a given termination symbol
+ */
+static bool extract_token(chunk_t *token, char termination, chunk_t *src)
+{
+ u_char *eot = memchr(src->ptr, termination, src->len);
+
+ /* initialize empty token */
+ *token = CHUNK_INITIALIZER;
+
+ if (eot == NULL) /* termination symbol not found */
+ {
+ return FALSE;
+ }
+
+ /* extract token */
+ token->ptr = src->ptr;
+ token->len = (u_int)(eot - src->ptr);
+
+ /* advance src pointer after termination symbol */
+ src->ptr = eot + 1;
+ src->len -= (token->len + 1);
+
+ return TRUE;
+}
+
+/*
+ * extracts a name: value pair from the PEM header
+ */
+static bool extract_parameter(chunk_t *name, chunk_t *value, chunk_t *line)
+{
+ /* extract name */
+ if (!extract_token(name,':', line))
+ {
+ return FALSE;
+ }
+
+ eat_whitespace(line);
+
+ /* extract value */
+ *value = *line;
+ return TRUE;
+}
+
+/*
+ * fetches a new line terminated by \n or \r\n
+ */
+static bool fetchline(chunk_t *src, chunk_t *line)
+{
+ if (src->len == 0) /* end of src reached */
+ return FALSE;
+
+ if (extract_token(line, '\n', src))
+ {
+ if (line->len > 0 && *(line->ptr + line->len -1) == '\r')
+ line->len--; /* remove optional \r */
+ }
+ else /*last line ends without newline */
+ {
+ *line = *src;
+ src->ptr += src->len;
+ src->len = 0;
+ }
+ return TRUE;
+}
+
+/*
+ * decrypts a DES-EDE-CBC encrypted data block
+ */
+static status_t pem_decrypt(chunk_t *blob, chunk_t *iv, char *passphrase)
+{
+ hasher_t *hasher;
+ crypter_t *crypter;
+ chunk_t hash;
+ chunk_t decrypted;
+ chunk_t pass = {passphrase, strlen(passphrase)};
+ chunk_t key = {alloca(24), 24};
+ u_int8_t padding, *last_padding_pos, *first_padding_pos;
+
+ /* build key from passphrase and IV */
+ hasher = hasher_create(HASH_MD5);
+ hash.len = hasher->get_hash_size(hasher);
+ hash.ptr = alloca(hash.len);
+ hasher->get_hash(hasher, pass, NULL);
+ hasher->get_hash(hasher, *iv, hash.ptr);
+
+ memcpy(key.ptr, hash.ptr, hash.len);
+
+ hasher->get_hash(hasher, hash, NULL);
+ hasher->get_hash(hasher, pass, NULL);
+ hasher->get_hash(hasher, *iv, hash.ptr);
+
+ memcpy(key.ptr + hash.len, hash.ptr, key.len - hash.len);
+
+ hasher->destroy(hasher);
+
+ /* decrypt blob */
+ crypter = crypter_create(ENCR_3DES, 0);
+ crypter->set_key(crypter, key);
+ crypter->decrypt(crypter, *blob, *iv, &decrypted);
+ memcpy(blob->ptr, decrypted.ptr, blob->len);
+ chunk_free(&decrypted);
+
+ /* determine amount of padding */
+ last_padding_pos = blob->ptr + blob->len - 1;
+ padding = *last_padding_pos;
+ first_padding_pos = (padding > blob->len) ? blob->ptr : last_padding_pos - padding;
+
+ /* check the padding pattern */
+ while (--last_padding_pos > first_padding_pos)
+ {
+ if (*last_padding_pos != padding)
+ return FALSE;
+ }
+ /* remove padding */
+ blob->len -= padding;
+ return TRUE;
+}
+
+/* Converts a PEM encoded file into its binary form
+ *
+ * RFC 1421 Privacy Enhancement for Electronic Mail, February 1993
+ * RFC 934 Message Encapsulation, January 1985
+ */
+status_t pemtobin(chunk_t *blob, char *pass)
+{
+ typedef enum {
+ PEM_PRE = 0,
+ PEM_MSG = 1,
+ PEM_HEADER = 2,
+ PEM_BODY = 3,
+ PEM_POST = 4,
+ PEM_ABORT = 5
+ } state_t;
+
+ bool encrypted = FALSE;
+
+ state_t state = PEM_PRE;
+
+ chunk_t src = *blob;
+ chunk_t dst = *blob;
+ chunk_t line = CHUNK_INITIALIZER;
+ chunk_t iv = CHUNK_INITIALIZER;
+
+ u_char iv_buf[16]; /* MD5 digest size */
+
+ /* zero size of converted blob */
+ dst.len = 0;
+
+ /* zero size of IV */
+ iv.ptr = iv_buf;
+ iv.len = 0;
+
+ while (fetchline(&src, &line))
+ {
+ if (state == PEM_PRE)
+ {
+ if (find_boundary("BEGIN", &line))
+ {
+ state = PEM_MSG;
+ }
+ continue;
+ }
+ else
+ {
+ if (find_boundary("END", &line))
+ {
+ state = PEM_POST;
+ break;
+ }
+ if (state == PEM_MSG)
+ {
+ state = (memchr(line.ptr, ':', line.len) == NULL) ? PEM_BODY : PEM_HEADER;
+ }
+ if (state == PEM_HEADER)
+ {
+ chunk_t name = CHUNK_INITIALIZER;
+ chunk_t value = CHUNK_INITIALIZER;
+
+ /* an empty line separates HEADER and BODY */
+ if (line.len == 0)
+ {
+ state = PEM_BODY;
+ continue;
+ }
+
+ /* we are looking for a name: value pair */
+ if (!extract_parameter(&name, &value, &line))
+ continue;
+
+ if (match("Proc-Type", &name) && *value.ptr == '4')
+ encrypted = TRUE;
+ else if (match("DEK-Info", &name))
+ {
+ const char *ugh = NULL;
+ size_t len = 0;
+ chunk_t dek;
+
+ if (!extract_token(&dek, ',', &value))
+ dek = value;
+
+ /* we support DES-EDE3-CBC encrypted files, only */
+ if (!match("DES-EDE3-CBC", &dek))
+ return NOT_SUPPORTED;
+
+ eat_whitespace(&value);
+ ugh = ttodata(value.ptr, value.len, 16, iv.ptr, 16, &len);
+ if (ugh)
+ return PARSE_ERROR;
+
+ iv.len = len;
+ }
+ }
+ else /* state is PEM_BODY */
+ {
+ const char *ugh = NULL;
+ size_t len = 0;
+ chunk_t data;
+
+ /* remove any trailing whitespace */
+ if (!extract_token(&data ,' ', &line))
+ {
+ data = line;
+ }
+
+ ugh = ttodata(data.ptr, data.len, 64, dst.ptr, blob->len - dst.len, &len);
+ if (ugh)
+ {
+ state = PEM_ABORT;
+ break;
+ }
+ else
+ {
+ dst.ptr += len;
+ dst.len += len;
+ }
+ }
+ }
+ }
+ /* set length to size of binary blob */
+ blob->len = dst.len;
+
+ if (state != PEM_POST)
+ return PARSE_ERROR;
+
+ if (encrypted)
+ return pem_decrypt(blob, &iv, pass);
+ else
+ return SUCCESS;
+}
diff --git a/programs/charon/lib/asn1/pem.h b/programs/charon/lib/asn1/pem.h
new file mode 100755
index 000000000..a4332fd34
--- /dev/null
+++ b/programs/charon/lib/asn1/pem.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2006 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef PEM_H_
+#define PEM_H_
+
+#include <stdio.h>
+
+#include <types.h>
+
+status_t pemtobin(chunk_t *blob, char *pass);
+
+#endif /*PEM_H_*/
diff --git a/programs/charon/lib/asn1/ttodata.c b/programs/charon/lib/asn1/ttodata.c
new file mode 100644
index 000000000..5e8149955
--- /dev/null
+++ b/programs/charon/lib/asn1/ttodata.c
@@ -0,0 +1,374 @@
+/*
+ * convert from text form of arbitrary data (e.g., keys) to binary
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * 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.
+ */
+
+#include "ttodata.h"
+
+#include <string.h>
+#include <ctype.h>
+
+/* converters and misc */
+static int unhex(const char *, char *, size_t);
+static int unb64(const char *, char *, size_t);
+static int untext(const char *, char *, size_t);
+static const char *badch(const char *, int, char *, size_t);
+
+/* internal error codes for converters */
+#define SHORT (-2) /* internal buffer too short */
+#define BADPAD (-3) /* bad base64 padding */
+#define BADCH0 (-4) /* invalid character 0 */
+#define BADCH1 (-5) /* invalid character 1 */
+#define BADCH2 (-6) /* invalid character 2 */
+#define BADCH3 (-7) /* invalid character 3 */
+#define BADOFF(code) (BADCH0-(code))
+
+/*
+ - ttodatav - 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.
+ */
+const char * /* NULL on success, else literal or errp */
+ttodatav(src, srclen, base, dst, dstlen, lenp, errp, errlen, flags)
+const char *src;
+size_t srclen; /* 0 means apply strlen() */
+int base; /* 0 means figure it out */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+size_t *lenp; /* where to record length (NULL is nowhere) */
+char *errp; /* error buffer */
+size_t errlen;
+unsigned int flags;
+{
+ size_t ingroup; /* number of input bytes converted at once */
+ char buf[4]; /* output from conversion */
+ int nbytes; /* size of output */
+ int (*decode)(const char *, char *, size_t);
+ char *stop;
+ int ndone;
+ int i;
+ int underscoreok;
+ int skipSpace = 0;
+
+ if (srclen == 0)
+ srclen = strlen(src);
+ if (dstlen == 0)
+ dst = buf; /* point it somewhere valid */
+ stop = dst + dstlen;
+
+ if (base == 0) {
+ if (srclen < 2)
+ return "input too short to be valid";
+ if (*src++ != '0')
+ return "input does not begin with format prefix";
+ switch (*src++) {
+ case 'x':
+ case 'X':
+ base = 16;
+ break;
+ case 's':
+ case 'S':
+ base = 64;
+ break;
+ case 't':
+ case 'T':
+ base = 256;
+ break;
+ default:
+ return "unknown format prefix";
+ }
+ srclen -= 2;
+ }
+ switch (base) {
+ case 16:
+ decode = unhex;
+ underscoreok = 1;
+ ingroup = 2;
+ break;
+ case 64:
+ decode = unb64;
+ underscoreok = 0;
+ ingroup = 4;
+ if(flags & TTODATAV_IGNORESPACE) {
+ skipSpace = 1;
+ }
+ break;
+
+ case 256:
+ decode = untext;
+ ingroup = 1;
+ underscoreok = 0;
+ break;
+ default:
+ return "unknown base";
+ }
+
+ /* proceed */
+ ndone = 0;
+ while (srclen > 0) {
+ char stage[4]; /* staging area for group */
+ size_t sl = 0;
+
+ /* Grab ingroup characters into stage,
+ * squeezing out blanks if we are supposed to ignore them.
+ */
+ for (sl = 0; sl < ingroup; src++, srclen--) {
+ if (srclen == 0)
+ return "input ends in mid-byte, perhaps truncated";
+ else if (!(skipSpace && (*src == ' ' || *src == '\t')))
+ stage[sl++] = *src;
+ }
+
+ nbytes = (*decode)(stage, buf, sizeof(buf));
+ switch (nbytes) {
+ case BADCH0:
+ case BADCH1:
+ case BADCH2:
+ case BADCH3:
+ return badch(stage, nbytes, errp, errlen);
+ case SHORT:
+ return "internal buffer too short (\"can't happen\")";
+ case BADPAD:
+ return "bad (non-zero) padding at end of base64 input";
+ }
+ if (nbytes <= 0)
+ return "unknown internal error";
+ for (i = 0; i < nbytes; i++) {
+ if (dst < stop)
+ *dst++ = buf[i];
+ ndone++;
+ }
+ while (srclen >= 1 && skipSpace && (*src == ' ' || *src == '\t')){
+ src++;
+ srclen--;
+ }
+ if (underscoreok && srclen > 1 && *src == '_') {
+ /* srclen > 1 means not last character */
+ src++;
+ srclen--;
+ }
+ }
+
+ if (ndone == 0)
+ return "no data bytes specified by input";
+ if (lenp != NULL)
+ *lenp = ndone;
+ return NULL;
+}
+
+/*
+ - ttodata - convert text to data
+ */
+const char * /* NULL on success, else literal */
+ttodata(src, srclen, base, dst, dstlen, lenp)
+const char *src;
+size_t srclen; /* 0 means apply strlen() */
+int base; /* 0 means figure it out */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+size_t *lenp; /* where to record length (NULL is nowhere) */
+{
+ return ttodatav(src, srclen, base, dst, dstlen, lenp, (char *)NULL,
+ (size_t)0, TTODATAV_SPACECOUNTS);
+}
+
+/*
+ - atodata - convert ASCII to data
+ * backward-compatibility interface
+ */
+size_t /* 0 for failure, true length for success */
+atodata(src, srclen, dst, dstlen)
+const char *src;
+size_t srclen;
+char *dst;
+size_t dstlen;
+{
+ size_t len;
+ const char *err;
+
+ err = ttodata(src, srclen, 0, dst, dstlen, &len);
+ if (err != NULL)
+ return 0;
+ return len;
+}
+
+/*
+ - atobytes - convert ASCII to data bytes
+ * another backward-compatibility interface
+ */
+const char *
+atobytes(src, srclen, dst, dstlen, lenp)
+const char *src;
+size_t srclen;
+char *dst;
+size_t dstlen;
+size_t *lenp;
+{
+ return ttodata(src, srclen, 0, dst, dstlen, lenp);
+}
+
+/*
+ - unhex - convert two ASCII hex digits to byte
+ */
+static int /* number of result bytes, or error code */
+unhex(src, dst, dstlen)
+const char *src; /* known to be full length */
+char *dst;
+size_t dstlen; /* not large enough is a failure */
+{
+ char *p;
+ unsigned byte;
+ static char hex[] = "0123456789abcdef";
+
+ if (dstlen < 1)
+ return SHORT;
+
+ p = strchr(hex, *src);
+ if (p == NULL)
+ p = strchr(hex, tolower(*src));
+ if (p == NULL)
+ return BADCH0;
+ byte = (p - hex) << 4;
+ src++;
+
+ p = strchr(hex, *src);
+ if (p == NULL)
+ p = strchr(hex, tolower(*src));
+ if (p == NULL)
+ return BADCH1;
+ byte |= (p - hex);
+
+ *dst = byte;
+ return 1;
+}
+
+/*
+ - 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.
+ */
+static int /* number of result bytes, or error code */
+unb64(src, dst, dstlen)
+const char *src; /* known to be full length */
+char *dst;
+size_t dstlen;
+{
+ char *p;
+ unsigned byte1;
+ unsigned byte2;
+ static char base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+ if (dstlen < 3)
+ return SHORT;
+
+ p = strchr(base64, *src++);
+
+ if (p == NULL)
+ return BADCH0;
+ byte1 = (p - base64) << 2; /* first six bits */
+
+ p = strchr(base64, *src++);
+ if (p == NULL) {
+ return BADCH1;
+ }
+
+ byte2 = p - base64; /* next six: two plus four */
+ *dst++ = byte1 | (byte2 >> 4);
+ byte1 = (byte2 & 0xf) << 4;
+
+ p = strchr(base64, *src++);
+ if (p == NULL) {
+ if (*(src-1) == '=' && *src == '=') {
+ if (byte1 != 0) /* bad padding */
+ return BADPAD;
+ return 1;
+ }
+ return BADCH2;
+ }
+
+ byte2 = p - base64; /* next six: four plus two */
+ *dst++ = byte1 | (byte2 >> 2);
+ byte1 = (byte2 & 0x3) << 6;
+
+ p = strchr(base64, *src++);
+ if (p == NULL) {
+ if (*(src-1) == '=') {
+ if (byte1 != 0) /* bad padding */
+ return BADPAD;
+ return 2;
+ }
+ return BADCH3;
+ }
+ byte2 = p - base64; /* last six */
+ *dst++ = byte1 | byte2;
+
+ return 3;
+}
+
+/*
+ - untext - convert one ASCII character to byte
+ */
+static int /* number of result bytes, or error code */
+untext(src, dst, dstlen)
+const char *src; /* known to be full length */
+char *dst;
+size_t dstlen; /* not large enough is a failure */
+{
+ if (dstlen < 1)
+ return SHORT;
+
+ *dst = *src;
+ return 1;
+}
+
+/*
+ - 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.
+ */
+static const char * /* literal or errp */
+badch(src, errcode, errp, errlen)
+const char *src;
+int errcode;
+char *errp; /* might be NULL */
+size_t errlen;
+{
+ static const char pre[] = "unknown character (`";
+ static const char suf[] = "') in input";
+ char buf[5];
+# define REQD (sizeof(pre) - 1 + sizeof(buf) - 1 + sizeof(suf))
+ struct sizecheck {
+ char bigenough[TTODATAV_BUF - REQD]; /* see above */
+ };
+ char ch;
+
+ if (errp == NULL || errlen < REQD)
+ return "unknown character in input";
+ strcpy(errp, pre);
+ ch = *(src + BADOFF(errcode));
+ if (isprint(ch)) {
+ buf[0] = ch;
+ buf[1] = '\0';
+ } else {
+ buf[0] = '\\';
+ buf[1] = ((ch & 0700) >> 6) + '0';
+ buf[2] = ((ch & 0070) >> 3) + '0';
+ buf[3] = ((ch & 0007) >> 0) + '0';
+ buf[4] = '\0';
+ }
+ strcat(errp, buf);
+ strcat(errp, suf);
+ return (const char *)errp;
+}
diff --git a/programs/charon/lib/asn1/ttodata.h b/programs/charon/lib/asn1/ttodata.h
new file mode 100644
index 000000000..d57244ef5
--- /dev/null
+++ b/programs/charon/lib/asn1/ttodata.h
@@ -0,0 +1,30 @@
+/*
+ * convert from text form of arbitrary data (e.g., keys) to binary
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * 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.
+ */
+
+#ifndef TTODATA_H_
+#define TTODATA_H_
+
+#include <types.h>
+
+#define TTODATAV_BUF 40 /* ttodatav's largest non-literal message */
+#define TTODATAV_IGNORESPACE (1<<1) /* ignore spaces in base64 encodings*/
+#define TTODATAV_SPACECOUNTS 0 /* do not ignore spaces in base64 */
+
+typedef const char *err_t; /* error message, or NULL for success */
+
+err_t ttodata(const char *src, size_t srclen, int base, char *buf, size_t buflen, size_t *needed);
+
+
+#endif /* TTODATA_H_ */
diff --git a/programs/charon/lib/crypto/Makefile.transforms b/programs/charon/lib/crypto/Makefile.transforms
new file mode 100644
index 000000000..af0b147da
--- /dev/null
+++ b/programs/charon/lib/crypto/Makefile.transforms
@@ -0,0 +1,37 @@
+# Copyright (C) 2005 Jan Hutter, Martin Willi
+# Hochschule fuer Technik Rapperswil
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+
+CRYPTO_DIR= $(LIB_DIR)crypto/
+
+include $(CRYPTO_DIR)crypters/Makefile.crypters
+include $(CRYPTO_DIR)hashers/Makefile.hashers
+include $(CRYPTO_DIR)prfs/Makefile.prfs
+include $(CRYPTO_DIR)signers/Makefile.signers
+include $(CRYPTO_DIR)rsa/Makefile.rsa
+
+LIB_OBJS+= $(BUILD_DIR)diffie_hellman.o
+$(BUILD_DIR)diffie_hellman.o : $(CRYPTO_DIR)diffie_hellman.c $(CRYPTO_DIR)diffie_hellman.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+LIB_OBJS+= $(BUILD_DIR)hmac.o
+$(BUILD_DIR)hmac.o : $(CRYPTO_DIR)hmac.c $(CRYPTO_DIR)hmac.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+LIB_OBJS+= $(BUILD_DIR)prf_plus.o
+$(BUILD_DIR)prf_plus.o : $(CRYPTO_DIR)prf_plus.c $(CRYPTO_DIR)prf_plus.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+LIB_OBJS+= $(BUILD_DIR)x509.o
+$(BUILD_DIR)x509.o : $(CRYPTO_DIR)x509.c $(CRYPTO_DIR)x509.h
+ $(CC) $(CFLAGS) -c -o $@ $<
diff --git a/programs/charon/lib/crypto/crypters/Makefile.crypters b/programs/charon/lib/crypto/crypters/Makefile.crypters
new file mode 100644
index 000000000..612477de8
--- /dev/null
+++ b/programs/charon/lib/crypto/crypters/Makefile.crypters
@@ -0,0 +1,23 @@
+# Copyright (C) 2005 Jan Hutter, Martin Willi
+# Hochschule fuer Technik Rapperswil
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+
+CRYPTERS_DIR= $(CRYPTO_DIR)crypters/
+
+LIB_OBJS+= $(BUILD_DIR)crypter.o
+$(BUILD_DIR)crypter.o : $(CRYPTERS_DIR)crypter.c $(CRYPTERS_DIR)crypter.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+LIB_OBJS+= $(BUILD_DIR)aes_cbc_crypter.o
+$(BUILD_DIR)aes_cbc_crypter.o : $(CRYPTERS_DIR)aes_cbc_crypter.c $(CRYPTERS_DIR)aes_cbc_crypter.h
+ $(CC) $(CFLAGS) -c -o $@ $<
diff --git a/programs/charon/lib/crypto/crypters/aes_cbc_crypter.c b/programs/charon/lib/crypto/crypters/aes_cbc_crypter.c
new file mode 100644
index 000000000..9b7b07c62
--- /dev/null
+++ b/programs/charon/lib/crypto/crypters/aes_cbc_crypter.c
@@ -0,0 +1,1627 @@
+/**
+ * @file aes_cbc_crypter.c
+ *
+ * @brief Implementation of aes_cbc_crypter_t
+ *
+ */
+
+ /*
+ * Copyright (C) 2001 Dr B. R. Gladman <brg@gladman.uk.net>
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "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];
+
+ /**
+ * The number of columns in the cipher state.
+ */
+ u_int32_t aes_Ncol;
+
+ /**
+ * 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 (this->aes_Ncol)
+
+// 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(pos<data.len)
+ {
+ if (pos==0)
+ iv_i=(const u_int32_t*) iv.ptr;
+ else
+ iv_i=(const u_int32_t*) (out-16);
+ *((u_int32_t *)(&out[ 0])) = iv_i[0]^*((const u_int32_t *)(&in[ 0]));
+ *((u_int32_t *)(&out[ 4])) = iv_i[1]^*((const u_int32_t *)(&in[ 4]));
+ *((u_int32_t *)(&out[ 8])) = iv_i[2]^*((const u_int32_t *)(&in[ 8]));
+ *((u_int32_t *)(&out[12])) = iv_i[3]^*((const u_int32_t *)(&in[12]));
+ this->encrypt_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 > (this->aes_Ncol) ? this->aes_Nkey : (this->aes_Ncol)) + 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_Ncol = 8;
+ this->aes_Nkey = 8;
+ break;
+ case 24: /* bytes */
+ this->aes_Ncol = 6;
+ this->aes_Nkey = 6;
+ break;
+ case 16: /* bytes */
+ this->aes_Ncol = 4;
+ 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/programs/charon/lib/crypto/crypters/aes_cbc_crypter.h b/programs/charon/lib/crypto/crypters/aes_cbc_crypter.h
new file mode 100644
index 000000000..d7a3c0f5b
--- /dev/null
+++ b/programs/charon/lib/crypto/crypters/aes_cbc_crypter.h
@@ -0,0 +1,61 @@
+/**
+ * @file aes_cbc_crypter.h
+ *
+ * @brief Interface of aes_cbc_crypter_t
+ *
+ */
+
+/*
+ * Copyright (C) 2001 Dr B. R. Gladman <brg@gladman.uk.net>
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef AES_CBC_CRYPTER_H_
+#define AES_CBC_CRYPTER_H_
+
+#include <crypto/crypters/crypter.h>
+
+
+typedef struct aes_cbc_crypter_t aes_cbc_crypter_t;
+
+/**
+ * @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/programs/charon/lib/crypto/crypters/crypter.c b/programs/charon/lib/crypto/crypters/crypter.c
new file mode 100644
index 000000000..827d10228
--- /dev/null
+++ b/programs/charon/lib/crypto/crypters/crypter.c
@@ -0,0 +1,63 @@
+/**
+ * @file crypter.c
+ *
+ * @brief Generic constructor for crypter_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#include "crypter.h"
+
+#include <crypto/crypters/aes_cbc_crypter.h>
+
+
+/**
+ * String mappings for encryption_algorithm_t.
+ */
+mapping_t encryption_algorithm_m[] = {
+{ENCR_UNDEFINED, "ENCR_UNDEFINED"},
+{ENCR_DES_IV64, "ENCR_DES_IV64"},
+{ENCR_DES, "ENCR_DES"},
+{ENCR_3DES, "ENCR_3DES"},
+{ENCR_RC5, "ENCR_RC5"},
+{ENCR_IDEA, "ENCR_IDEA"},
+{ENCR_CAST, "ENCR_CAST"},
+{ENCR_BLOWFISH, "ENCR_BLOWFISH"},
+{ENCR_3IDEA, "ENCR_3IDEA"},
+{ENCR_DES_IV32, "ENCR_DES_IV32"},
+{ENCR_NULL, "ENCR_NULL"},
+{ENCR_AES_CBC, "ENCR_AES_CBC"},
+{ENCR_AES_CTR, "ENCR_AES_CTR"},
+{MAPPING_END, NULL}
+};
+
+/*
+ * 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);
+ }
+ default:
+ return NULL;
+ }
+}
diff --git a/programs/charon/lib/crypto/crypters/crypter.h b/programs/charon/lib/crypto/crypters/crypter.h
new file mode 100644
index 000000000..9c219f5cc
--- /dev/null
+++ b/programs/charon/lib/crypto/crypters/crypter.h
@@ -0,0 +1,153 @@
+/**
+ * @file crypter.h
+ *
+ * @brief Interface crypter_t
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef CRYPTER_H_
+#define CRYPTER_H_
+
+#include <types.h>
+
+typedef enum encryption_algorithm_t encryption_algorithm_t;
+
+/**
+ * @brief Encryption algorithm, as in IKEv2 RFC 3.3.2.
+ *
+ * Currently only the following algorithms are implemented and therefore supported:
+ * - ENCR_AES_CBC
+ *
+ * @todo Implement more enryption algorithms, such as 3DES
+ *
+ * @ingroup crypters
+ */
+enum encryption_algorithm_t {
+ ENCR_UNDEFINED = 1024,
+ ENCR_DES_IV64 = 1,
+ ENCR_DES = 2,
+ ENCR_3DES = 3,
+ ENCR_RC5 = 4,
+ ENCR_IDEA = 5,
+ ENCR_CAST = 6,
+ ENCR_BLOWFISH = 7,
+ 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
+};
+
+/**
+ * String mappings for encryption_algorithm_t.
+ */
+extern mapping_t encryption_algorithm_m[];
+
+
+typedef struct crypter_t crypter_t;
+
+/**
+ * @brief Generic interface for symmetric encryption algorithms.
+ *
+ * @b Constructors:
+ * - crypter_create()
+ *
+ * @ingroup crypters
+ */
+struct crypter_t {
+ /**
+ * @brief 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
+ */
+ 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.
+ *
+ * @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
+ */
+ 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.
+ *
+ * @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.
+ *
+ * @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.
+ *
+ * @param this calling object
+ * @param key key to set
+ * @return
+ * - SUCCESS
+ * - 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
+ */
+ void (*destroy) (crypter_t *this);
+};
+
+/**
+ * @brief Generic constructor for crypter_t objects.
+ *
+ * Currently only the following algorithms are implemented and therefore supported:
+ * - ENCR_AES_CBC
+ *
+ * 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_*/
diff --git a/programs/charon/lib/crypto/diffie_hellman.c b/programs/charon/lib/crypto/diffie_hellman.c
new file mode 100644
index 000000000..e458fb80f
--- /dev/null
+++ b/programs/charon/lib/crypto/diffie_hellman.c
@@ -0,0 +1,615 @@
+/**
+ * @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 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <gmp.h>
+#include <stdio.h>
+
+#include "diffie_hellman.h"
+
+#include <daemon.h>
+#include <utils/randomizer.h>
+
+
+/**
+ * String mappings for diffie_hellman_group_t.
+ */
+mapping_t diffie_hellman_group_m[] = {
+ {MODP_UNDEFINED, "MODP_UNDEFINED"},
+ {MODP_768_BIT, "MODP_768_BIT"},
+ {MODP_1024_BIT, "MODP_1024_BIT"},
+ {MODP_1536_BIT, "MODP_1536_BIT"},
+ {MODP_2048_BIT, "MODP_2048_BIT"},
+ {MODP_3072_BIT, "MODP_3072_BIT"},
+ {MODP_4096_BIT, "MODP_4096_BIT"},
+ {MODP_6144_BIT, "MODP_6144_BIT"},
+ {MODP_8192_BIT, "MODP_8192_BIT"},
+ {MAPPING_END, NULL}
+};
+
+
+/**
+ * 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_info_entry_t modulus_info_entry_t;
+
+/**
+ * Entry of the modulus list.
+ */
+struct modulus_info_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_length;
+
+ /*
+ * Generator value.
+ */
+ u_int16_t generator;
+};
+
+
+/**
+ * All supported modulus values.
+ */
+static modulus_info_entry_t modulus_info_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 dh_group_number;
+
+ /**
+ * Modulus.
+ */
+ mpz_t modulus;
+
+ /**
+ * Modulus length.
+ */
+ size_t modulus_length;
+
+ /*
+ * Generator value.
+ */
+ u_int16_t generator;
+
+ /**
+ * My private value .
+ */
+ mpz_t my_private_value;
+
+ /**
+ * My public value.
+ */
+ mpz_t my_public_value;
+
+ /**
+ * Other public value.
+ */
+ mpz_t other_public_value;
+
+ /**
+ * Shared secret.
+ */
+ mpz_t shared_secret;
+
+ /**
+ * True if shared secret is computed and stored in my_public_value.
+ */
+ bool shared_secret_is_computed;
+
+ /**
+ * Sets the modulus for a specific diffie hellman group.
+ *
+ * @param this calling object
+ * @return
+ * SUCCESS if modulus could be found
+ * NOT_FOUND if modulus not supported
+ */
+ status_t (*set_modulus) (private_diffie_hellman_t *this);
+
+ /**
+ * Makes sure my public value is computed.
+ *
+ * @param this calling object
+ */
+ void (*compute_public_value) (private_diffie_hellman_t *this);
+
+ /**
+ * Computes shared secret (other public value must be available).
+ *
+ * @param this calling object
+ */
+ void (*compute_shared_secret) (private_diffie_hellman_t *this);
+};
+
+/**
+ * Implementation of private_diffie_hellman_t.set_modulus.
+ */
+static status_t set_modulus(private_diffie_hellman_t *this)
+{
+ int i;
+ status_t status = NOT_FOUND;
+
+ for (i = 0; i < (sizeof(modulus_info_entries) / sizeof(modulus_info_entry_t)); i++)
+ {
+ if (modulus_info_entries[i].group == this->dh_group_number)
+ {
+ chunk_t modulus_chunk;
+ modulus_chunk.ptr = modulus_info_entries[i].modulus;
+ modulus_chunk.len = modulus_info_entries[i].modulus_length;
+ mpz_import(this->modulus, modulus_chunk.len, 1, 1, 1, 0, modulus_chunk.ptr);
+ this->modulus_length = modulus_chunk.len;
+ this->generator = modulus_info_entries[i].generator;
+ status = SUCCESS;
+ break;
+ }
+ }
+ return status;
+}
+
+/**
+ * Implementation of diffie_hellman_t.set_other_public_value.
+ */
+static void set_other_public_value(private_diffie_hellman_t *this,chunk_t public_value)
+{
+ mpz_import(this->other_public_value, public_value.len, 1, 1, 1, 0, public_value.ptr);
+ this->compute_shared_secret(this);
+}
+
+/**
+ * Implementation of diffie_hellman_t.get_other_public_value.
+ */
+static status_t get_other_public_value(private_diffie_hellman_t *this,chunk_t *public_value)
+{
+ if (!this->shared_secret_is_computed)
+ {
+ return FAILED;
+ }
+ public_value->len = this->modulus_length;
+ public_value->ptr = mpz_export(NULL, NULL, 1, public_value->len, 1, 0, this->other_public_value);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of private_diffie_hellman_t.compute_shared_secret.
+ */
+static void compute_shared_secret (private_diffie_hellman_t *this)
+{
+ /* initialize my public value */
+ mpz_init(this->shared_secret);
+ /* calculate my public value */
+ mpz_powm(this->shared_secret,this->other_public_value,this->my_private_value,this->modulus);
+
+ this->shared_secret_is_computed = TRUE;
+}
+
+/**
+ * Implementation of private_diffie_hellman_t.compute_public_value.
+ */
+static void compute_public_value (private_diffie_hellman_t *this)
+{
+ mpz_t generator;
+ /* initialize generator and set it*/
+ mpz_init_set_ui (generator,this->generator);
+ /* initialize my public value */
+ mpz_init(this->my_public_value);
+ /* calculate my public value */
+ mpz_powm(this->my_public_value,generator,this->my_private_value,this->modulus);
+ /* generator not used anymore */
+ mpz_clear(generator);
+}
+
+/**
+ * Implementation of diffie_hellman_t.get_my_public_value.
+ */
+static void get_my_public_value(private_diffie_hellman_t *this,chunk_t *public_value)
+{
+ public_value->len = this->modulus_length;
+ public_value->ptr = mpz_export(NULL, NULL, 1, public_value->len, 1, 0, this->my_public_value);
+}
+
+/**
+ * Implementation of diffie_hellman_t.get_shared_secret.
+ */
+static status_t get_shared_secret(private_diffie_hellman_t *this,chunk_t *secret)
+{
+ if (!this->shared_secret_is_computed)
+ {
+ return FAILED;
+ }
+ secret->len = this->modulus_length;
+ secret->ptr = mpz_export(NULL, NULL, 1, secret->len, 1, 0, this->shared_secret);
+ 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->dh_group_number;
+}
+
+/**
+ * Implementation of diffie_hellman_t.destroy.
+ */
+static void destroy(private_diffie_hellman_t *this)
+{
+ mpz_clear(this->modulus);
+ mpz_clear(this->my_private_value);
+ mpz_clear(this->my_public_value);
+ mpz_clear(this->other_public_value);
+
+ if (this->shared_secret_is_computed)
+ {
+ /* other public value gets initialized together with shared secret */
+ mpz_clear(this->shared_secret);
+ }
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+diffie_hellman_t *diffie_hellman_create(diffie_hellman_group_t dh_group_number)
+{
+ private_diffie_hellman_t *this = malloc_thing(private_diffie_hellman_t);
+ randomizer_t *randomizer;
+ chunk_t random_bytes;
+
+ /* 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 functions */
+ this->set_modulus = set_modulus;
+ this->compute_public_value = compute_public_value;
+ this->compute_shared_secret = compute_shared_secret;
+
+ /* private variables */
+ this->dh_group_number = dh_group_number;
+ mpz_init(this->modulus);
+ mpz_init(this->other_public_value);
+ mpz_init(this->my_private_value);
+
+ /* set this->modulus */
+ if (this->set_modulus(this) != SUCCESS)
+ {
+ free(this);
+ return NULL;
+ }
+ randomizer = randomizer_create();
+ if (randomizer == NULL)
+ {
+ free(this);
+ return NULL;
+ }
+ if (randomizer->allocate_pseudo_random_bytes(randomizer, this->modulus_length, &random_bytes) != SUCCESS)
+ {
+ randomizer->destroy(randomizer);
+ free(this);
+ return NULL;
+ }
+
+ mpz_import(this->my_private_value, random_bytes.len, 1, 1, 1, 0, random_bytes.ptr);
+ chunk_free(&random_bytes);
+
+ randomizer->destroy(randomizer);
+
+ this->compute_public_value(this);
+
+ this->shared_secret_is_computed = FALSE;
+
+ return &(this->public);
+}
diff --git a/programs/charon/lib/crypto/diffie_hellman.h b/programs/charon/lib/crypto/diffie_hellman.h
new file mode 100644
index 000000000..48a165557
--- /dev/null
+++ b/programs/charon/lib/crypto/diffie_hellman.h
@@ -0,0 +1,149 @@
+/**
+ * @file diffie_hellman.h
+ *
+ * @brief Interface of diffie_hellman_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef DIFFIE_HELLMAN_H_
+#define DIFFIE_HELLMAN_H_
+
+#include <types.h>
+
+
+typedef enum diffie_hellman_group_t diffie_hellman_group_t;
+
+/**
+ * @brief Diffie-Hellman group.
+ *
+ * The modulus (or group) to use for a Diffie-Hellman calculation.
+ *
+ * See IKEv2 RFC 3.3.2 and RFC 3526.
+ *
+ * @ingroup transforms
+ */
+enum diffie_hellman_group_t {
+ MODP_UNDEFINED = 1024,
+ MODP_768_BIT = 1,
+ MODP_1024_BIT = 2,
+ MODP_1536_BIT = 5,
+ MODP_2048_BIT = 14,
+ MODP_3072_BIT = 15,
+ MODP_4096_BIT = 16,
+ MODP_6144_BIT = 17,
+ MODP_8192_BIT = 18
+};
+
+/**
+ * String mappings for diffie_hellman_group_t.
+ */
+extern mapping_t diffie_hellman_group_m[];
+
+
+typedef struct diffie_hellman_t diffie_hellman_t;
+
+/**
+ * @brief Implementation of the widely used Diffie-Hellman algorithm.
+ *
+ * @b Constructors:
+ * - diffie_hellman_create()
+ *
+ * @ingroup transforms
+ */
+struct diffie_hellman_t {
+
+ /**
+ * @brief Returns the shared secret of this diffie hellman exchange.
+ *
+ * @warning Space for returned secret is allocated and must be
+ * freed by the caller.
+ *
+ * @param this calling diffie_hellman_t object
+ * @param[out] secret shared secret will be written into this chunk
+ * @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.
+ *
+ * chunk gets cloned and can be destroyed afterwards.
+ *
+ * @param this calling diffie_hellman_t object
+ * @param public_value public value of partner
+ */
+ void (*set_other_public_value) (diffie_hellman_t *this, chunk_t public_value);
+
+ /**
+ * @brief Gets the public value of partner.
+ *
+ * @warning Space for returned chunk is allocated and must be
+ * freed by the caller.
+ *
+ * @param this calling diffie_hellman_t object
+ * @param[out] public_value public value of partner is stored at this location
+ * @return
+ * - SUCCESS
+ * - FAILED if other public value not set
+ */
+ status_t (*get_other_public_value) (diffie_hellman_t *this, chunk_t *public_value);
+
+ /**
+ * @brief Gets the public value of caller
+ *
+ * @warning Space for returned chunk is allocated and must be
+ * freed by the caller.
+ *
+ * @param this calling diffie_hellman_t object
+ * @param[out] public_value public value of caller is stored at this location
+ */
+ void (*get_my_public_value) (diffie_hellman_t *this, chunk_t *public_value);
+
+ /**
+ * @brief Get the DH group used.
+ *
+ * @param this calling diffie_hellman_t 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
+ */
+ void (*destroy) (diffie_hellman_t *this);
+};
+
+/**
+ * @brief Creates a new diffie_hellman_t object.
+ *
+ * The first diffie hellman public value gets automatically created.
+ *
+ * @param dh_group_number Diffie Hellman group number to use
+ * @return
+ * - diffie_hellman_t object
+ * - NULL if dh group not supported
+ *
+ * @ingroup transforms
+ */
+diffie_hellman_t *diffie_hellman_create(diffie_hellman_group_t dh_group_number);
+
+#endif /*DIFFIE_HELLMAN_H_*/
diff --git a/programs/charon/lib/crypto/hashers/Makefile.hashers b/programs/charon/lib/crypto/hashers/Makefile.hashers
new file mode 100644
index 000000000..e05d41af3
--- /dev/null
+++ b/programs/charon/lib/crypto/hashers/Makefile.hashers
@@ -0,0 +1,27 @@
+# Copyright (C) 2005 Jan Hutter, Martin Willi
+# Hochschule fuer Technik Rapperswil
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+
+HASHERS_DIR= $(CRYPTO_DIR)hashers/
+
+LIB_OBJS+= $(BUILD_DIR)hasher.o
+$(BUILD_DIR)hasher.o : $(HASHERS_DIR)hasher.c $(HASHERS_DIR)hasher.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+LIB_OBJS+= $(BUILD_DIR)sha1_hasher.o
+$(BUILD_DIR)sha1_hasher.o : $(HASHERS_DIR)sha1_hasher.c $(HASHERS_DIR)sha1_hasher.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+LIB_OBJS+= $(BUILD_DIR)md5_hasher.o
+$(BUILD_DIR)md5_hasher.o : $(HASHERS_DIR)md5_hasher.c $(HASHERS_DIR)md5_hasher.h
+ $(CC) $(CFLAGS) -c -o $@ $<
diff --git a/programs/charon/lib/crypto/hashers/hasher.c b/programs/charon/lib/crypto/hashers/hasher.c
new file mode 100644
index 000000000..c15f41804
--- /dev/null
+++ b/programs/charon/lib/crypto/hashers/hasher.c
@@ -0,0 +1,60 @@
+/**
+ * @file hasher.c
+ *
+ * @brief Generic constructor for hasher_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#include "hasher.h"
+
+#include <crypto/hashers/sha1_hasher.h>
+#include <crypto/hashers/md5_hasher.h>
+
+/**
+ * String mappings for hash_algorithm_t.
+ */
+mapping_t hash_algorithm_m[] = {
+ {HASH_MD2,"HASH_MD2"},
+ {HASH_MD5,"HASH_MD5"},
+ {HASH_SHA1,"HASH_SHA1"},
+ {HASH_SHA256,"HASH_SHA256"},
+ {HASH_SHA384,"HASH_SHA384"},
+ {HASH_SHA512,"HASH_SHA512"},
+ {MAPPING_END, NULL}
+};
+
+/*
+ * 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_MD5:
+ {
+ return (hasher_t*)md5_hasher_create();
+ }
+ default:
+ return NULL;
+ }
+}
diff --git a/programs/charon/lib/crypto/hashers/hasher.h b/programs/charon/lib/crypto/hashers/hasher.h
new file mode 100644
index 000000000..24683c01b
--- /dev/null
+++ b/programs/charon/lib/crypto/hashers/hasher.h
@@ -0,0 +1,147 @@
+/**
+ * @file hasher.h
+ *
+ * @brief Interface hasher_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef HASHER_H_
+#define HASHER_H_
+
+
+#include <types.h>
+
+
+typedef enum hash_algorithm_t hash_algorithm_t;
+
+/**
+ * @brief Algorithms to use for hashing.
+ *
+ * Currently only the following algorithms are implemented and therefore supported:
+ * - HASH_MD5
+ * - HASH_SHA1
+ *
+ * @ingroup hashers
+ *
+ */
+enum hash_algorithm_t {
+ HASH_MD2,
+ /**
+ * Implemented in class md5_hasher_t.
+ */
+ HASH_MD5,
+ /**
+ * Implemented in class sha1_hasher_t.
+ */
+ HASH_SHA1,
+ HASH_SHA256,
+ HASH_SHA384,
+ HASH_SHA512,
+};
+
+/**
+ * String mappings for hash_algorithm_t.
+ */
+extern mapping_t hash_algorithm_m[];
+
+
+typedef struct hasher_t hasher_t;
+
+/**
+ * @brief Generic interface for all hash functions.
+ *
+ * @b Constructors:
+ * - hasher_create()
+ * - md5_hasher_create()
+ * - sha1_hasher_create()
+ *
+ * @see
+ * - md5_hasher_t
+ * - sha1_hasher_t
+ *
+ * @todo Implement more hash algorithms
+ *
+ * @ingroup hashers
+ */
+struct hasher_t {
+ /**
+ * @brief Hash data and write it in the buffer.
+ *
+ * If the parameter hash is NULL, no result is written back
+ * an more data can be appended to already hashed data.
+ * If not, the result is written back and the hasher is reseted.
+ *
+ * @warning: 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
+ */
+ void (*get_hash) (hasher_t *this, chunk_t data, u_int8_t *hash);
+
+ /**
+ * @brief Hash data and allocate space for the hash.
+ *
+ * If the parameter hash is NULL, no result is written back
+ * an more data can be appended to already hashed data.
+ * If not, the result is written back and the hasher is reseted.
+ *
+ * @param this calling object
+ * @param data chunk with data to hash
+ * @param[out] 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.
+ *
+ * @param this calling object
+ * @return hash size in bytes
+ */
+ size_t (*get_hash_size) (hasher_t *this);
+
+ /**
+ * @brief Resets the hashers state, which allows
+ * computation of a completely new hash.
+ *
+ * @param this calling object
+ */
+ void (*reset) (hasher_t *this);
+
+ /**
+ * @brief Destroys a hasher object.
+ *
+ * @param this calling object
+ */
+ void (*destroy) (hasher_t *this);
+};
+
+/**
+ * @brief Generic interface to create a hasher_t.
+ *
+ * @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);
+
+#endif /*HASHER_H_*/
diff --git a/programs/charon/lib/crypto/hashers/md5_hasher.c b/programs/charon/lib/crypto/hashers/md5_hasher.c
new file mode 100644
index 000000000..bd3ab0c62
--- /dev/null
+++ b/programs/charon/lib/crypto/hashers/md5_hasher.c
@@ -0,0 +1,394 @@
+/**
+ * @file md5_hasher.c
+ *
+ * @brief Implementation of md5_hasher_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * 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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+
+#include "md5_hasher.h"
+
+#include <definitions.h>
+
+#define BLOCK_SIZE_MD5 16
+
+
+/* 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(BLOCK_SIZE_MD5);
+ allocated_hash.len = BLOCK_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 BLOCK_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()
+{
+ 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.destroy = (void (*) (hasher_t*))destroy;
+
+ /* initialize */
+ this->public.hasher_interface.reset(&(this->public.hasher_interface));
+
+ return &(this->public);
+}
diff --git a/programs/charon/lib/crypto/hashers/md5_hasher.h b/programs/charon/lib/crypto/hashers/md5_hasher.h
new file mode 100644
index 000000000..1e6d95d19
--- /dev/null
+++ b/programs/charon/lib/crypto/hashers/md5_hasher.h
@@ -0,0 +1,60 @@
+/**
+ * @file md5_hasher.h
+ *
+ * @brief Interface for md5_hasher_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef MD5_HASHER_H_
+#define MD5_HASHER_H_
+
+#include <crypto/hashers/hasher.h>
+
+
+typedef struct md5_hasher_t md5_hasher_t;
+
+/**
+ * @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();
+
+#endif /*MD5_HASHER_H_*/
diff --git a/programs/charon/lib/crypto/hashers/sha1_hasher.c b/programs/charon/lib/crypto/hashers/sha1_hasher.c
new file mode 100644
index 000000000..2b82ef4ba
--- /dev/null
+++ b/programs/charon/lib/crypto/hashers/sha1_hasher.c
@@ -0,0 +1,269 @@
+/**
+ * @file sha1_hasher.c
+ *
+ * @brief Implementation of hasher_sha_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * Ported from Steve Reid's <steve@edmweb.com> 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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+
+#include "sha1_hasher.h"
+
+#include <definitions.h>
+
+#define BLOCK_SIZE_SHA1 20
+
+/*
+ * 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(BLOCK_SIZE_SHA1);
+ allocated_hash.len = BLOCK_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 BLOCK_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.destroy.
+ */
+static void destroy(private_sha1_hasher_t *this)
+{
+ free(this);
+}
+
+
+/*
+ * Described in header.
+ */
+sha1_hasher_t *sha1_hasher_create()
+{
+ 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.destroy = (void (*) (hasher_t*))destroy;
+
+ /* initialize */
+ this->public.hasher_interface.reset(&(this->public.hasher_interface));
+
+ return &(this->public);
+}
diff --git a/programs/charon/lib/crypto/hashers/sha1_hasher.h b/programs/charon/lib/crypto/hashers/sha1_hasher.h
new file mode 100644
index 000000000..5124ea1a8
--- /dev/null
+++ b/programs/charon/lib/crypto/hashers/sha1_hasher.h
@@ -0,0 +1,60 @@
+/**
+ * @file sha1_hasher.h
+ *
+ * @brief Interface of sha1_hasher_t
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef SHA1_HASHER_H_
+#define SHA1_HASHER_H_
+
+#include <crypto/hashers/hasher.h>
+
+
+typedef struct sha1_hasher_t sha1_hasher_t;
+
+/**
+ * @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();
+
+#endif /*SHA1_HASHER_H_*/
diff --git a/programs/charon/lib/crypto/hmac.c b/programs/charon/lib/crypto/hmac.c
new file mode 100644
index 000000000..bb8880770
--- /dev/null
+++ b/programs/charon/lib/crypto/hmac.c
@@ -0,0 +1,209 @@
+/**
+ * @file hmac.c
+ *
+ * @brief Implementation of hmac_t.
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, 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 hmac License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General hmac License
+ * for more details.
+ */
+
+#include <string.h>
+
+#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:
+ this->b = 64;
+ 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/programs/charon/lib/crypto/hmac.h b/programs/charon/lib/crypto/hmac.h
new file mode 100644
index 000000000..8945fc1fc
--- /dev/null
+++ b/programs/charon/lib/crypto/hmac.h
@@ -0,0 +1,118 @@
+/**
+ * @file hmac.h
+ *
+ * @brief Interface of hmac_t.
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef HMAC_H_
+#define HMAC_H_
+
+#include <crypto/hashers/hasher.h>
+#include <definitions.h>
+
+
+typedef struct hmac_t hmac_t;
+
+/**
+ * @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 transforms
+ */
+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/programs/charon/lib/crypto/prf_plus.c b/programs/charon/lib/crypto/prf_plus.c
new file mode 100644
index 000000000..d408d0517
--- /dev/null
+++ b/programs/charon/lib/crypto/prf_plus.c
@@ -0,0 +1,157 @@
+/**
+ * @file prf_plus.c
+ *
+ * @brief Implementation of prf_plus_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+
+#include "prf_plus.h"
+
+#include <definitions.h>
+
+typedef struct private_prf_plus_t private_prf_plus_t;
+
+/**
+ * Private data of an prf_plus_t object.
+ *
+ */
+struct private_prf_plus_t {
+ /**
+ * Public interface of prf_plus_t.
+ */
+ prf_plus_t public;
+
+ /**
+ * PRF to use.
+ */
+ prf_t *prf;
+
+ /**
+ * Initial seed.
+ */
+ chunk_t seed;
+
+ /**
+ * Buffer to store current PRF result.
+ */
+ chunk_t buffer;
+
+ /**
+ * Already given out bytes in current buffer.
+ */
+ size_t given_out;
+
+ /**
+ * Octet which will be appended to the seed.
+ */
+ u_int8_t appending_octet;
+};
+
+/**
+ * Implementation of prf_plus_t.get_bytes.
+ */
+static void get_bytes(private_prf_plus_t *this, size_t length, u_int8_t *buffer)
+{
+ chunk_t appending_chunk;
+ size_t bytes_in_round;
+ size_t total_bytes_written = 0;
+
+ appending_chunk.ptr = &(this->appending_octet);
+ appending_chunk.len = 1;
+
+ while (length > 0)
+ { /* still more to do... */
+ if (this->buffer.len == this->given_out)
+ { /* no bytes left in buffer, get next*/
+ this->prf->get_bytes(this->prf, this->buffer, NULL);
+ this->prf->get_bytes(this->prf, this->seed, NULL);
+ this->prf->get_bytes(this->prf, appending_chunk, this->buffer.ptr);
+ this->given_out = 0;
+ this->appending_octet++;
+ }
+ /* how many bytes can we write in this round ? */
+ bytes_in_round = min(length, this->buffer.len - this->given_out);
+ /* copy bytes from buffer with offset */
+ memcpy(buffer + total_bytes_written, this->buffer.ptr + this->given_out, bytes_in_round);
+
+ length -= bytes_in_round;
+ this->given_out += bytes_in_round;
+ total_bytes_written += bytes_in_round;
+ }
+}
+
+/**
+ * Implementation of prf_plus_t.allocate_bytes.
+ */
+static void allocate_bytes(private_prf_plus_t *this, size_t length, chunk_t *chunk)
+{
+ chunk->ptr = malloc(length);
+ chunk->len = length;
+ this->public.get_bytes(&(this->public), length, chunk->ptr);
+}
+
+/**
+ * Implementation of prf_plus_t.destroy.
+ */
+static void destroy(private_prf_plus_t *this)
+{
+ free(this->buffer.ptr);
+ free(this->seed.ptr);
+ free(this);
+}
+
+/*
+ * Description in header.
+ */
+prf_plus_t *prf_plus_create(prf_t *prf, chunk_t seed)
+{
+ private_prf_plus_t *this;
+ chunk_t appending_chunk;
+
+ this = malloc_thing(private_prf_plus_t);
+
+ /* set public methods */
+ this->public.get_bytes = (void (*)(prf_plus_t *,size_t,u_int8_t*))get_bytes;
+ this->public.allocate_bytes = (void (*)(prf_plus_t *,size_t,chunk_t*))allocate_bytes;
+ this->public.destroy = (void (*)(prf_plus_t *))destroy;
+
+ /* take over prf */
+ this->prf = prf;
+
+ /* allocate buffer for prf output */
+ this->buffer.len = prf->get_block_size(prf);
+ this->buffer.ptr = malloc(this->buffer.len);
+
+ this->appending_octet = 0x01;
+
+ /* clone seed */
+ this->seed.ptr = clalloc(seed.ptr, seed.len);
+ this->seed.len = seed.len;
+
+ /* do the first run */
+ appending_chunk.ptr = &(this->appending_octet);
+ appending_chunk.len = 1;
+ this->prf->get_bytes(this->prf, this->seed, NULL);
+ this->prf->get_bytes(this->prf, appending_chunk, this->buffer.ptr);
+ this->given_out = 0;
+ this->appending_octet++;
+
+ return &(this->public);
+}
diff --git a/programs/charon/lib/crypto/prf_plus.h b/programs/charon/lib/crypto/prf_plus.h
new file mode 100644
index 000000000..bdcd01966
--- /dev/null
+++ b/programs/charon/lib/crypto/prf_plus.h
@@ -0,0 +1,93 @@
+/**
+ * @file prf_plus.h
+ *
+ * @brief Interface for prf_plus.h.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef PRF_PLUS_H_
+#define PRF_PLUS_H_
+
+
+#include <crypto/prfs/prf.h>
+
+
+typedef struct prf_plus_t prf_plus_t;
+
+/**
+ * @brief 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 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
+ */
+ void (*get_bytes) (prf_plus_t *this, size_t length, u_int8_t *buffer);
+
+ /**
+ * @brief 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
+ */
+ void (*allocate_bytes) (prf_plus_t *this, size_t length, chunk_t *chunk);
+
+ /**
+ * @brief Destroys a prf_plus_t object.
+ *
+ * @param this calling object
+ */
+ void (*destroy) (prf_plus_t *this);
+};
+
+/**
+ * @brief Creates a new prf_plus_t object.
+ *
+ * Seed will be cloned. prf will
+ * not be cloned, must be destroyed outside after
+ * prf_plus_t usage.
+ *
+ * @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_*/
diff --git a/programs/charon/lib/crypto/prfs/Makefile.prfs b/programs/charon/lib/crypto/prfs/Makefile.prfs
new file mode 100644
index 000000000..a98894346
--- /dev/null
+++ b/programs/charon/lib/crypto/prfs/Makefile.prfs
@@ -0,0 +1,23 @@
+# Copyright (C) 2005 Jan Hutter, Martin Willi
+# Hochschule fuer Technik Rapperswil
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+
+PRFS_DIR= $(CRYPTO_DIR)prfs/
+
+LIB_OBJS+= $(BUILD_DIR)prf.o
+$(BUILD_DIR)prf.o : $(PRFS_DIR)prf.c $(PRFS_DIR)prf.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+LIB_OBJS+= $(BUILD_DIR)hmac_prf.o
+$(BUILD_DIR)hmac_prf.o : $(PRFS_DIR)hmac_prf.c $(PRFS_DIR)hmac_prf.h
+ $(CC) $(CFLAGS) -c -o $@ $<
diff --git a/programs/charon/lib/crypto/prfs/hmac_prf.c b/programs/charon/lib/crypto/prfs/hmac_prf.c
new file mode 100644
index 000000000..2a7d34a3a
--- /dev/null
+++ b/programs/charon/lib/crypto/prfs/hmac_prf.c
@@ -0,0 +1,117 @@
+/**
+ * @file hmac_prf.c
+ *
+ * @brief Implementation for hmac_prf_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "hmac_prf.h"
+
+#include <crypto/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)
+{
+ free(this);
+ this->hmac->destroy(this->hmac);
+}
+
+/*
+ * 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/programs/charon/lib/crypto/prfs/hmac_prf.h b/programs/charon/lib/crypto/prfs/hmac_prf.h
new file mode 100644
index 000000000..3a68960f7
--- /dev/null
+++ b/programs/charon/lib/crypto/prfs/hmac_prf.h
@@ -0,0 +1,64 @@
+/**
+ * @file hmac_prf.h
+ *
+ * @brief Interface of hmac_prf_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef PRF_HMAC_H_
+#define PRF_HMAC_H_
+
+#include <types.h>
+#include <crypto/prfs/prf.h>
+#include <crypto/hashers/hasher.h>
+
+typedef struct hmac_prf_t hmac_prf_t;
+
+/**
+ * @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/programs/charon/lib/crypto/prfs/prf.c b/programs/charon/lib/crypto/prfs/prf.c
new file mode 100644
index 000000000..bb7015e64
--- /dev/null
+++ b/programs/charon/lib/crypto/prfs/prf.c
@@ -0,0 +1,67 @@
+/**
+ * @file prf.c
+ *
+ * @brief Generic constructor for all prf_t
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#include "prf.h"
+
+#include <crypto/hashers/hasher.h>
+#include <crypto/prfs/hmac_prf.h>
+
+
+/**
+ * String mappings for encryption_algorithm_t.
+ */
+mapping_t pseudo_random_function_m[] = {
+{PRF_UNDEFINED, "PRF_UNDEFINED"},
+{PRF_HMAC_MD5, "PRF_HMAC_MD5"},
+{PRF_HMAC_SHA1, "PRF_HMAC_SHA1"},
+{PRF_HMAC_TIGER, "PRF_HMAC_TIGER"},
+{PRF_AES128_CBC, "PRF_AES128_CBC"},
+{MAPPING_END, NULL}
+};
+
+/*
+ * 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_TIGER:
+ case PRF_AES128_CBC:
+ default:
+ return NULL;
+ }
+}
+
+
+
+
+
diff --git a/programs/charon/lib/crypto/prfs/prf.h b/programs/charon/lib/crypto/prfs/prf.h
new file mode 100644
index 000000000..b1c1e6a66
--- /dev/null
+++ b/programs/charon/lib/crypto/prfs/prf.h
@@ -0,0 +1,136 @@
+/**
+ * @file prf.h
+ *
+ * @brief Interface prf_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef PRF_H_
+#define PRF_H_
+
+#include <types.h>
+
+typedef enum pseudo_random_function_t pseudo_random_function_t;
+
+/**
+ * @brief Pseudo random function, as in IKEv2 RFC 3.3.2.
+ *
+ * Currently only the following algorithms are implemented and therefore supported:
+ * - PRF_HMAC_MD5
+ * - PRF_HMAC_SHA1
+ *
+ * @ingroup prfs
+ */
+enum pseudo_random_function_t {
+ PRF_UNDEFINED = 1024,
+ /**
+ * Implemented in class hmac_prf_t.
+ */
+ PRF_HMAC_MD5 = 1,
+ /**
+ * Implemented in class hmac_prf_t.
+ */
+ PRF_HMAC_SHA1 = 2,
+ PRF_HMAC_TIGER = 3,
+ PRF_AES128_CBC = 4
+};
+
+/**
+ * String mappings for encryption_algorithm_t.
+ */
+extern mapping_t pseudo_random_function_m[];
+
+
+typedef struct prf_t prf_t;
+
+/**
+ * @brief Generic interface for pseudo-random-functions.
+ *
+ * @b Constructors:
+ * - prf_create()
+ * - hmac_prf_create()
+ *
+ * @todo Implement more prf algorithms
+ *
+ * @ingroup prfs
+ */
+struct prf_t {
+ /**
+ * @brief 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
+ */
+ void (*get_bytes) (prf_t *this, chunk_t seed, u_int8_t *buffer);
+
+ /**
+ * @brief 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
+ */
+ void (*allocate_bytes) (prf_t *this, chunk_t seed, chunk_t *chunk);
+
+ /**
+ * @brief Get the block size of this prf_t object.
+ *
+ * @param this calling object
+ * @return block size in bytes
+ */
+ size_t (*get_block_size) (prf_t *this);
+
+ /**
+ * @brief Get the key size of this prf_t object.
+ *
+ * @param this calling object
+ * @return key size in bytes
+ */
+ size_t (*get_key_size) (prf_t *this);
+
+ /**
+ * @brief Set the key for this prf_t object.
+ *
+ * @param this calling object
+ * @param key key to set
+ */
+ void (*set_key) (prf_t *this, chunk_t key);
+
+ /**
+ * @brief Destroys a prf object.
+ *
+ * @param this calling 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_*/
diff --git a/programs/charon/lib/crypto/rsa/Makefile.rsa b/programs/charon/lib/crypto/rsa/Makefile.rsa
new file mode 100644
index 000000000..1a0204c83
--- /dev/null
+++ b/programs/charon/lib/crypto/rsa/Makefile.rsa
@@ -0,0 +1,23 @@
+# Copyright (C) 2005 Jan Hutter, Martin Willi
+# Hochschule fuer Technik Rapperswil
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+
+RSA_DIR= $(CRYPTO_DIR)rsa/
+
+LIB_OBJS+= $(BUILD_DIR)rsa_private_key.o
+$(BUILD_DIR)rsa_private_key.o : $(RSA_DIR)rsa_private_key.c $(RSA_DIR)rsa_private_key.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+LIB_OBJS+= $(BUILD_DIR)rsa_public_key.o
+$(BUILD_DIR)rsa_public_key.o : $(RSA_DIR)rsa_public_key.c $(RSA_DIR)rsa_public_key.h
+ $(CC) $(CFLAGS) -c -o $@ $< \ No newline at end of file
diff --git a/programs/charon/lib/crypto/rsa/rsa_private_key.c b/programs/charon/lib/crypto/rsa/rsa_private_key.c
new file mode 100644
index 000000000..358653f0e
--- /dev/null
+++ b/programs/charon/lib/crypto/rsa/rsa_private_key.c
@@ -0,0 +1,772 @@
+/**
+ * @file rsa_private_key.c
+ *
+ * @brief Implementation of rsa_private_key_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <gmp.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "rsa_private_key.h"
+
+#include <daemon.h>
+#include <asn1/asn1.h>
+
+/*
+ * Oids for hash algorithms are defined in
+ * rsa_public_key.c.
+ */
+extern u_int8_t md2_oid[18];
+extern u_int8_t md5_oid[18];
+extern u_int8_t sha1_oid[15];
+extern u_int8_t sha256_oid[19];
+extern u_int8_t sha384_oid[19];
+extern u_int8_t sha512_oid[19];
+
+
+/**
+ * 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;
+
+ /**
+ * @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);
+
+ /**
+ * @brief Generate a prime value.
+ *
+ * @param this calling object
+ * @param prime_size size of the prime, in bytes
+ * @param[out] prime uninitialized mpz
+ */
+ status_t (*compute_prime) (private_rsa_private_key_t *this, size_t prime_size, mpz_t *prime);
+
+};
+
+/* 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
+
+static private_rsa_private_key_t *rsa_private_key_create_empty();
+
+/**
+ * Implementation of private_rsa_private_key_t.compute_prime.
+ */
+static status_t compute_prime(private_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;
+
+ /* 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(random_bytes.ptr);
+ }
+ /* check if it isnt too large */
+ while (((mpz_sizeinbase(*prime, 2) + 7) / 8) > prime_size);
+
+ 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(t1);
+ mpz_clear(t2);
+
+ return decrypted;
+}
+
+/**
+ * Implementation of rsa_private_key.build_emsa_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 hash;
+ chunk_t oid;
+ chunk_t em;
+
+ /* get oid string prepended to hash */
+ switch (hash_algorithm)
+ {
+ case HASH_MD2:
+ {
+ oid.ptr = md2_oid;
+ oid.len = sizeof(md2_oid);
+ break;
+ }
+ case HASH_MD5:
+ {
+ oid.ptr = md5_oid;
+ oid.len = sizeof(md5_oid);
+ break;
+ }
+ case HASH_SHA1:
+ {
+ oid.ptr = sha1_oid;
+ oid.len = sizeof(sha1_oid);
+ break;
+ }
+ case HASH_SHA256:
+ {
+ oid.ptr = sha256_oid;
+ oid.len = sizeof(sha256_oid);
+ break;
+ }
+ case HASH_SHA384:
+ {
+ oid.ptr = sha384_oid;
+ oid.len = sizeof(sha384_oid);
+ break;
+ }
+ case HASH_SHA512:
+ {
+ oid.ptr = sha512_oid;
+ oid.len = sizeof(sha512_oid);
+ break;
+ }
+ default:
+ {
+ 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 chunk to rsa-decrypt:
+ * EM = 0x00 || 0x01 || PS || 0x00 || T.
+ * PS = 0xFF padding, with length to fill em
+ * T = oid || 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 - hash.len - oid.len - 1) = 0x00;
+ /* set hash */
+ memcpy(em.ptr + em.len - hash.len, hash.ptr, hash.len);
+ /* set oid */
+ memcpy(em.ptr + em.len - hash.len - oid.len, oid.ptr, oid.len);
+
+ /* build signature */
+ *signature = this->rsasp1(this, em);
+
+ free(hash.ptr);
+ free(em.ptr);
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of rsa_private_key.get_key.
+ */
+static status_t get_key(private_rsa_private_key_t *this, chunk_t *key)
+{
+ chunk_t n, e, p, q, d, exp1, exp2, coeff;
+
+ n.len = this->k;
+ n.ptr = mpz_export(NULL, NULL, 1, n.len, 1, 0, this->n);
+ e.len = this->k;
+ e.ptr = mpz_export(NULL, NULL, 1, e.len, 1, 0, this->e);
+ p.len = this->k;
+ p.ptr = mpz_export(NULL, NULL, 1, p.len, 1, 0, this->p);
+ q.len = this->k;
+ q.ptr = mpz_export(NULL, NULL, 1, q.len, 1, 0, this->q);
+ d.len = this->k;
+ d.ptr = mpz_export(NULL, NULL, 1, d.len, 1, 0, this->d);
+ exp1.len = this->k;
+ exp1.ptr = mpz_export(NULL, NULL, 1, exp1.len, 1, 0, this->exp1);
+ exp2.len = this->k;
+ exp2.ptr = mpz_export(NULL, NULL, 1, exp2.len, 1, 0, this->exp2);
+ coeff.len = this->k;
+ coeff.ptr = mpz_export(NULL, NULL, 1, coeff.len, 1, 0, this->coeff);
+
+ key->len = this->k * 8;
+ key->ptr = malloc(key->len);
+ memcpy(key->ptr + this->k * 0, n.ptr , n.len);
+ memcpy(key->ptr + this->k * 1, e.ptr, e.len);
+ memcpy(key->ptr + this->k * 2, p.ptr, p.len);
+ memcpy(key->ptr + this->k * 3, q.ptr, q.len);
+ memcpy(key->ptr + this->k * 4, d.ptr, d.len);
+ memcpy(key->ptr + this->k * 5, exp1.ptr, exp1.len);
+ memcpy(key->ptr + this->k * 6, exp2.ptr, exp2.len);
+ memcpy(key->ptr + this->k * 7, coeff.ptr, coeff.len);
+
+ free(n.ptr);
+ free(e.ptr);
+ free(p.ptr);
+ free(q.ptr);
+ free(d.ptr);
+ free(exp1.ptr);
+ free(exp2.ptr);
+ free(coeff.ptr);
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of rsa_private_key.save_key.
+ */
+static status_t save_key(private_rsa_private_key_t *this, char *file)
+{
+ return NOT_SUPPORTED;
+}
+
+/**
+ * Implementation of rsa_private_key.get_public_key.
+ */
+rsa_public_key_t *get_public_key(private_rsa_private_key_t *this)
+{
+ return NULL;
+}
+
+/**
+ * Implementation of rsa_private_key.belongs_to.
+ */
+static bool belongs_to(private_rsa_private_key_t *this, rsa_public_key_t *public)
+{
+ if (mpz_cmp(this->n, *public->get_modulus(public)) == 0)
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * 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/8)
+ {
+ return FAILED;
+ }
+
+ /* we picked a max modulus size to simplify buffer allocation */
+ if (this->k > 8192/8)
+ {
+ 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(t);
+ mpz_clear(u);
+ mpz_clear(q1);
+ return status;
+}
+
+/**
+ * Implementation of rsa_private_key.clone.
+ */
+static rsa_private_key_t* _clone(private_rsa_private_key_t *this)
+{
+ private_rsa_private_key_t *clone = rsa_private_key_create_empty();
+
+ mpz_init_set(clone->n, this->n);
+ mpz_init_set(clone->e, this->e);
+ mpz_init_set(clone->p, this->p);
+ mpz_init_set(clone->q, this->q);
+ mpz_init_set(clone->d, this->d);
+ mpz_init_set(clone->exp1, this->exp1);
+ mpz_init_set(clone->exp2, this->exp2);
+ mpz_init_set(clone->coeff, this->coeff);
+ clone->k = this->k;
+
+ return &clone->public;
+}
+
+/**
+ * Implementation of rsa_private_key.destroy.
+ */
+static void destroy(private_rsa_private_key_t *this)
+{
+ mpz_clear(this->n);
+ mpz_clear(this->e);
+ mpz_clear(this->p);
+ mpz_clear(this->q);
+ mpz_clear(this->d);
+ mpz_clear(this->exp1);
+ mpz_clear(this->exp2);
+ mpz_clear(this->coeff);
+ free(this);
+}
+
+/**
+ * Internal generic constructor
+ */
+static private_rsa_private_key_t *rsa_private_key_create_empty()
+{
+ private_rsa_private_key_t *this = malloc_thing(private_rsa_private_key_t);
+
+ /* public functions */
+ 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.get_key = (status_t (*) (rsa_private_key_t*,chunk_t*))get_key;
+ this->public.save_key = (status_t (*) (rsa_private_key_t*,char*))save_key;
+ 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.clone = (rsa_private_key_t*(*)(rsa_private_key_t*))_clone;
+ this->public.destroy = (void (*) (rsa_private_key_t*))destroy;
+
+ /* private functions */
+ this->rsadp = rsadp;
+ this->rsasp1 = rsadp; /* same algorithm */
+ this->compute_prime = compute_prime;
+
+ 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;
+
+ this = rsa_private_key_create_empty();
+ key_size = key_size / 8;
+
+ /* Get values of primes p and q */
+ if (this->compute_prime(this, key_size/2, &p) != SUCCESS)
+ {
+ free(this);
+ return NULL;
+ }
+ if (this->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_set(t, p);
+ mpz_set(p, q);
+ mpz_set(q, t);
+ }
+
+ 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(q1);
+ mpz_clear(m);
+ mpz_clear(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;
+}
+
+/*
+ * 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);
+
+ 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) / 8;
+
+ if (check(this) != SUCCESS)
+ {
+ destroy(this);
+ return NULL;
+ }
+ else
+ {
+ return &this->public;
+ }
+}
+
+/*
+ * see header
+ * TODO: PEM files
+ */
+rsa_private_key_t *rsa_private_key_create_from_file(char *filename, char *passphrase)
+{
+ chunk_t chunk;
+ struct stat stb;
+ FILE *file;
+ char *buffer;
+
+ if (stat(filename, &stb) == -1)
+ {
+ return NULL;
+ }
+
+ buffer = alloca(stb.st_size);
+
+ file = fopen(filename, "r");
+ if (file == NULL)
+ {
+ return NULL;
+ }
+
+ if (fread(buffer, stb.st_size, 1, file) != 1)
+ {
+ fclose(file);
+ return NULL;
+ }
+ fclose(file);
+
+ chunk.ptr = buffer;
+ chunk.len = stb.st_size;
+
+ return rsa_private_key_create_from_chunk(chunk);
+}
diff --git a/programs/charon/lib/crypto/rsa/rsa_private_key.h b/programs/charon/lib/crypto/rsa/rsa_private_key.h
new file mode 100644
index 000000000..b3b8ae87f
--- /dev/null
+++ b/programs/charon/lib/crypto/rsa/rsa_private_key.h
@@ -0,0 +1,185 @@
+/**
+ * @file rsa_private_key.h
+ *
+ * @brief Interface of rsa_private_key_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef RSA_PRIVATE_KEY_H_
+#define RSA_PRIVATE_KEY_H_
+
+#include <types.h>
+#include <definitions.h>
+#include <crypto/rsa/rsa_public_key.h>
+#include <crypto/hashers/hasher.h>
+
+
+typedef struct rsa_private_key_t rsa_private_key_t;
+
+/**
+ * @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
+ *
+ * @todo Implement get_key(), save_key(), get_public_key()
+ *
+ * @ingroup rsa
+ */
+struct rsa_private_key_t {
+
+ /**
+ * @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 Gets the key.
+ *
+ * UNIMPLEMENTED!
+ *
+ * @param this calling object
+ * @param key key (in a propriarity format)
+ * @return
+ * - SUCCESS
+ * - INVALID_STATE, if key not set
+ */
+ status_t (*get_key) (rsa_private_key_t *this, chunk_t *key);
+
+ /**
+ * @brief Saves a key to a file.
+ *
+ * Not implemented!
+ *
+ * @param this calling object
+ * @param file file to which the key should be written.
+ * @return NOT_SUPPORTED
+ */
+ status_t (*save_key) (rsa_private_key_t *this, char *file);
+
+ /**
+ * @brief Generate a new key.
+ *
+ * Generates a new private_key with specified key size
+ *
+ * @param this calling object
+ * @param key_size size of the key in bits
+ * @return
+ * - SUCCESS
+ * - INVALID_ARG if key_size invalid
+ */
+ status_t (*generate_key) (rsa_private_key_t *this, size_t key_size);
+
+ /**
+ * @brief Create a rsa_public_key_t with the public
+ * parts 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 Clone the private key.
+ *
+ * @param this private key to clone
+ * @return clone of this
+ */
+ rsa_private_key_t *(*clone) (rsa_private_key_t *this);
+
+ /**
+ * @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 lenght.
+ *
+ * @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
+ * @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, char *passphrase);
+
+#endif /*RSA_PRIVATE_KEY_H_*/
diff --git a/programs/charon/lib/crypto/rsa/rsa_public_key.c b/programs/charon/lib/crypto/rsa/rsa_public_key.c
new file mode 100644
index 000000000..6601b6cda
--- /dev/null
+++ b/programs/charon/lib/crypto/rsa/rsa_public_key.c
@@ -0,0 +1,458 @@
+/**
+ * @file rsa_public_key.c
+ *
+ * @brief Implementation of rsa_public_key_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <gmp.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "rsa_public_key.h"
+
+#include <daemon.h>
+#include <crypto/hashers/hasher.h>
+#include <asn1/asn1.h>
+
+/*
+ * For simplicity,
+ * we use these predefined values for
+ * hash algorithm OIDs. These also contain
+ * the length of the following hash.
+ * These values are also used in rsa_private_key.c.
+ * TODO: We may move them in asn1 sometime...
+ */
+
+u_int8_t md2_oid[] = {
+ 0x30,0x20,0x30,0x0c,0x06,0x08,0x2a,0x86,
+ 0x48,0x86,0xf7,0x0d,0x02,0x02,0x05,0x00,
+ 0x04,0x10
+};
+
+u_int8_t md5_oid[] = {
+ 0x30,0x20,0x30,0x0c,0x06,0x08,0x2a,0x86,
+ 0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,
+ 0x04,0x10
+};
+
+u_int8_t sha1_oid[] = {
+ 0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,
+ 0x03,0x02,0x1a,0x05,0x00,0x04,0x14
+};
+
+u_int8_t sha256_oid[] = {
+ 0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,
+ 0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,
+ 0x00,0x04,0x20
+};
+
+u_int8_t sha384_oid[] = {
+ 0x30,0x41,0x30,0x0d,0x06,0x09,0x60,0x86,
+ 0x48,0x01,0x65,0x03,0x04,0x02,0x02,0x05,
+ 0x00,0x04,0x30
+};
+
+u_int8_t sha512_oid[] = {
+ 0x30,0x51,0x30,0x0d,0x06,0x09,0x60,0x86,
+ 0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,
+ 0x00,0x04,0x40
+};
+
+/* ASN.1 definition public key */
+static const asn1Object_t pubkey_objects[] = {
+ { 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
+
+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;
+
+ /**
+ * @brief Implements the RSAEP algorithm specified in PKCS#1.
+ *
+ * @param this calling object
+ * @param data data to process
+ * @return processed data
+ */
+ chunk_t (*rsaep) (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) (private_rsa_public_key_t *this, chunk_t data);
+};
+
+
+typedef struct rsa_public_key_info_t rsa_public_key_info_t;
+
+/**
+ * KeyInfo, as it appears in a public key file
+ */
+struct rsa_public_key_info_t {
+ /**
+ * Algorithm for this key
+ */
+ chunk_t algorithm_oid;
+
+ /**
+ * Public key, parseable with rsa_public_key_rules
+ */
+ chunk_t public_key;
+};
+
+private_rsa_public_key_t *rsa_public_key_create_empty();
+
+/**
+ * Implementation of private_rsa_public_key_t.rsaep and private_rsa_public_key_t.rsavp1
+ */
+static chunk_t rsaep(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.verify_emsa_pkcs1_signature.
+ */
+static status_t verify_emsa_pkcs1_signature(private_rsa_public_key_t *this, chunk_t data, chunk_t signature)
+{
+ hasher_t *hasher = NULL;
+ chunk_t hash;
+ chunk_t em;
+ u_int8_t *pos;
+
+ if (signature.len > this->k)
+ {
+ return INVALID_ARG;
+ }
+
+ /* unpack signature */
+ 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))
+ {
+ free(em.ptr);
+ return FAILED;
+ }
+
+ /* find magic 0x00 */
+ pos = em.ptr + 2;
+ while (pos <= em.ptr + em.len)
+ {
+ if (*pos == 0x00)
+ {
+ /* found magic byte, stop */
+ pos++;
+ break;
+ }
+ else if (*pos != 0xFF)
+ {
+ /* bad padding, decryption failed ?!*/
+ free(em.ptr);
+ return FAILED;
+ }
+ pos++;
+ }
+
+ if (pos + 20 > em.ptr + em.len)
+ {
+ /* not enought room for oid compare */
+ free(em.ptr);
+ return FAILED;
+ }
+
+ if (memcmp(md2_oid, pos, sizeof(md2_oid)) == 0)
+ {
+ hasher = hasher_create(HASH_MD2);
+ pos += sizeof(md2_oid);
+ }
+ else if (memcmp(md5_oid, pos, sizeof(md5_oid)) == 0)
+ {
+ hasher = hasher_create(HASH_MD5);
+ pos += sizeof(md5_oid);
+ }
+ else if (memcmp(sha1_oid, pos, sizeof(sha1_oid)) == 0)
+ {
+ hasher = hasher_create(HASH_SHA1);
+ pos += sizeof(sha1_oid);
+ }
+ else if (memcmp(sha256_oid, pos, sizeof(sha256_oid)) == 0)
+ {
+ hasher = hasher_create(HASH_SHA256);
+ pos += sizeof(sha256_oid);
+ }
+ else if (memcmp(sha384_oid, pos, sizeof(sha384_oid)) == 0)
+ {
+ hasher = hasher_create(HASH_SHA384);
+ pos += sizeof(sha384_oid);
+ }
+ else if (memcmp(sha512_oid, pos, sizeof(sha512_oid)) == 0)
+ {
+ hasher = hasher_create(HASH_SHA512);
+ pos += sizeof(sha512_oid);
+ }
+
+ if (hasher == NULL)
+ {
+ /* not supported hash algorithm */
+ free(em.ptr);
+ return NOT_SUPPORTED;
+ }
+
+ if (pos + hasher->get_hash_size(hasher) != em.ptr + em.len)
+ {
+ /* bad length */
+ free(em.ptr);
+ hasher->destroy(hasher);
+ return FAILED;
+ }
+
+ /* build own hash for a compare */
+ hasher->allocate_hash(hasher, data, &hash);
+ hasher->destroy(hasher);
+
+ if (memcmp(hash.ptr, pos, hash.len) != 0)
+ {
+ /* hash does not equal */
+ free(hash.ptr);
+ free(em.ptr);
+ return FAILED;
+
+ }
+
+ /* seems good */
+ free(hash.ptr);
+ free(em.ptr);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of rsa_public_key.get_key.
+ */
+static status_t get_key(private_rsa_public_key_t *this, chunk_t *key)
+{
+ chunk_t n, e;
+
+ n.len = this->k;
+ n.ptr = mpz_export(NULL, NULL, 1, n.len, 1, 0, this->n);
+ e.len = this->k;
+ e.ptr = mpz_export(NULL, NULL, 1, e.len, 1, 0, this->e);
+
+ key->len = this->k * 2;
+ key->ptr = malloc(key->len);
+ memcpy(key->ptr, n.ptr, n.len);
+ memcpy(key->ptr + n.len, e.ptr, e.len);
+ free(n.ptr);
+ free(e.ptr);
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of rsa_public_key.save_key.
+ */
+static status_t save_key(private_rsa_public_key_t *this, char *file)
+{
+ return NOT_SUPPORTED;
+}
+
+/**
+ * Implementation of rsa_public_key.get_modulus.
+ */
+static mpz_t *get_modulus(private_rsa_public_key_t *this)
+{
+ return &this->n;
+}
+
+/**
+ * Implementation of rsa_public_key.clone.
+ */
+static rsa_public_key_t* _clone(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->k = this->k;
+
+ return &clone->public;
+}
+
+/**
+ * Implementation of rsa_public_key.destroy.
+ */
+static void destroy(private_rsa_public_key_t *this)
+{
+ mpz_clear(this->n);
+ mpz_clear(this->e);
+ free(this);
+}
+
+/**
+ * Generic private constructor
+ */
+private_rsa_public_key_t *rsa_public_key_create_empty()
+{
+ private_rsa_public_key_t *this = malloc_thing(private_rsa_public_key_t);
+
+ /* public functions */
+ this->public.verify_emsa_pkcs1_signature = (status_t (*) (rsa_public_key_t*,chunk_t,chunk_t))verify_emsa_pkcs1_signature;
+ this->public.get_key = (status_t (*) (rsa_public_key_t*,chunk_t*))get_key;
+ this->public.save_key = (status_t (*) (rsa_public_key_t*,char*))save_key;
+ this->public.get_modulus = (mpz_t *(*) (rsa_public_key_t*))get_modulus;
+ this->public.clone = (rsa_public_key_t* (*) (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_from_chunk(chunk_t blob)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+ private_rsa_public_key_t *this;
+
+ this = rsa_public_key_create_empty();
+ mpz_init(this->n);
+ mpz_init(this->e);
+
+ asn1_init(&ctx, blob, 0, FALSE);
+
+ while (objectID < PUB_KEY_ROOF)
+ {
+ if (!extract_object(pubkey_objects, &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) / 8;
+ return &this->public;
+}
+
+/*
+ * See header
+ */
+rsa_public_key_t *rsa_public_key_create_from_file(char *filename)
+{
+ struct stat stb;
+ FILE *file;
+ char *buffer;
+ chunk_t chunk;
+
+ if (stat(filename, &stb) == -1)
+ {
+ return NULL;
+ }
+
+ buffer = alloca(stb.st_size);
+
+ file = fopen(filename, "r");
+ if (file == NULL)
+ {
+ return NULL;
+ }
+
+ if (fread(buffer, stb.st_size, 1, file) != 1)
+ {
+ return NULL;
+ }
+
+ chunk.ptr = buffer;
+ chunk.len = stb.st_size;
+
+ return rsa_public_key_create_from_chunk(chunk);
+}
diff --git a/programs/charon/lib/crypto/rsa/rsa_public_key.h b/programs/charon/lib/crypto/rsa/rsa_public_key.h
new file mode 100644
index 000000000..ef79153d6
--- /dev/null
+++ b/programs/charon/lib/crypto/rsa/rsa_public_key.h
@@ -0,0 +1,153 @@
+/**
+ * @file rsa_public_key.h
+ *
+ * @brief Interface of rsa_public_key_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef RSA_PUBLIC_KEY_H_
+#define RSA_PUBLIC_KEY_H_
+
+#include <gmp.h>
+
+#include <types.h>
+#include <definitions.h>
+
+
+typedef struct rsa_public_key_t rsa_public_key_t;
+
+/**
+ * @brief RSA public key with associated functions.
+ *
+ * Currently only supports signature verification using
+ * the EMSA encoding (see PKCS1)
+ *
+ * @b Constructors:
+ * - rsa_public_key_create_from_chunk()
+ * - rsa_public_key_create_from_file()
+ * - rsa_private_key_t.get_public_key()
+ *
+ * @see rsa_private_key_t
+ *
+ * @todo Implement getkey() and savekey()
+ *
+ * @ingroup rsa
+ */
+struct rsa_public_key_t {
+
+ /**
+ * @brief Verify a EMSA-PKCS1 encodined 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 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) (rsa_public_key_t *this, chunk_t data, chunk_t signature);
+
+ /**
+ * @brief Gets the key.
+ *
+ * Currently uses a proprietary format which is only inteded
+ * for testing. This should be replaced with a proper
+ * ASN1 encoded key format, when charon gets the ASN1
+ * capabilities.
+ *
+ * @param this calling object
+ * @param key key (in a propriarity format)
+ * @return
+ * - SUCCESS
+ * - INVALID_STATE, if key not set
+ */
+ status_t (*get_key) (rsa_public_key_t *this, chunk_t *key);
+
+ /**
+ * @brief Saves a key to a file.
+ *
+ * Not implemented!
+ *
+ * @param this calling object
+ * @param file file to which the key should be written.
+ * @return NOT_SUPPORTED
+ */
+ status_t (*save_key) (rsa_public_key_t *this, char *file);
+
+ /**
+ * @brief Get the modulus of the key.
+ *
+ * @param this calling object
+ * @return modulus (n) of the key
+ */
+ mpz_t *(*get_modulus) (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) (rsa_public_key_t *this);
+
+ /**
+ * @brief Destroys the public key.
+ *
+ * @param this public key to destroy
+ */
+ void (*destroy) (rsa_public_key_t *this);
+};
+
+/**
+ * @brief Load an RSA public key from a chunk.
+ *
+ * Load a key from a chunk, encoded in the more frequently
+ * used PublicKeyInfo struct (ASN1 DER encoded).
+ *
+ * @param chunk chunk containing the DER encoded key
+ * @return loaded rsa_public_key_t, or NULL
+ *
+ * @todo Check OID in PublicKeyInfo
+ *
+ * @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
+ *
+ * @todo Implement PEM file loading
+ *
+ * @ingroup rsa
+ */
+rsa_public_key_t *rsa_public_key_create_from_file(char *filename);
+
+#endif /*RSA_PUBLIC_KEY_H_*/
diff --git a/programs/charon/lib/crypto/signers/Makefile.signers b/programs/charon/lib/crypto/signers/Makefile.signers
new file mode 100644
index 000000000..8f161a09d
--- /dev/null
+++ b/programs/charon/lib/crypto/signers/Makefile.signers
@@ -0,0 +1,23 @@
+# Copyright (C) 2005 Jan Hutter, Martin Willi
+# Hochschule fuer Technik Rapperswil
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+
+SIGNERS_DIR= $(CRYPTO_DIR)signers/
+
+LIB_OBJS+= $(BUILD_DIR)signer.o
+$(BUILD_DIR)signer.o : $(SIGNERS_DIR)signer.c $(SIGNERS_DIR)signer.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+LIB_OBJS+= $(BUILD_DIR)hmac_signer.o
+$(BUILD_DIR)hmac_signer.o : $(SIGNERS_DIR)hmac_signer.c $(SIGNERS_DIR)hmac_signer.h
+ $(CC) $(CFLAGS) -c -o $@ $<
diff --git a/programs/charon/lib/crypto/signers/hmac_signer.c b/programs/charon/lib/crypto/signers/hmac_signer.c
new file mode 100644
index 000000000..cb7d08244
--- /dev/null
+++ b/programs/charon/lib/crypto/signers/hmac_signer.c
@@ -0,0 +1,169 @@
+/**
+ * @file hmac_signer.c
+ *
+ * @brief Implementation of hmac_signer_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+
+#include "hmac_signer.h"
+
+#include <crypto/prfs/hmac_prf.h>
+
+/**
+ * This class represents a hmac signer with 12 byte (96 bit) output.
+ */
+#define BLOCK_SIZE 12
+
+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;
+};
+
+/**
+ * Implementation of signer_t.get_signature.
+ */
+static void get_signature (private_hmac_signer_t *this, chunk_t data, u_int8_t *buffer)
+{
+ 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);
+
+ /* copy mac aka signature :-) */
+ memcpy(buffer,full_mac,BLOCK_SIZE);
+}
+
+/**
+ * Implementation of signer_t.allocate_signature.
+ */
+static void allocate_signature (private_hmac_signer_t *this, chunk_t data, chunk_t *chunk)
+{
+ 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(BLOCK_SIZE);
+ signature.len = BLOCK_SIZE;
+
+ /* copy signature */
+ memcpy(signature.ptr,full_mac,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 != BLOCK_SIZE)
+ {
+ return FALSE;
+ }
+
+ /* compare mac aka signature :-) */
+ if (memcmp(signature.ptr,full_mac,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 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)
+{
+ 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;
+ }
+
+ /* 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/programs/charon/lib/crypto/signers/hmac_signer.h b/programs/charon/lib/crypto/signers/hmac_signer.h
new file mode 100644
index 000000000..62427167e
--- /dev/null
+++ b/programs/charon/lib/crypto/signers/hmac_signer.h
@@ -0,0 +1,58 @@
+/**
+ * @file hmac_signer.h
+ *
+ * @brief Interface of hmac_signer_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef HMAC_SIGNER_H_
+#define HMAC_SIGNER_H_
+
+#include <crypto/signers/signer.h>
+#include <crypto/hashers/hasher.h>
+
+typedef struct hmac_signer_t hmac_signer_t;
+
+/**
+ * @brief Implementation of signer_t interface using the
+ * HMAC algorithm in combination with either MD5 or SHA1.
+ *
+ * @ingroup signers
+ */
+struct hmac_signer_t {
+
+ /**
+ * generic signer_t interface for this signer
+ */
+ signer_t signer_interface;
+};
+
+/**
+ * @brief Creates a new hmac_signer_t.
+ *
+ * @param hash_algoritm Hash algorithm to use with signer
+ * @return
+ * - hmac_signer_t
+ * - NULL if hash algorithm not supported
+ *
+ * @ingroup signers
+ */
+hmac_signer_t *hmac_signer_create(hash_algorithm_t hash_algoritm);
+
+
+#endif /*HMAC_SIGNER_H_*/
diff --git a/programs/charon/lib/crypto/signers/signer.c b/programs/charon/lib/crypto/signers/signer.c
new file mode 100644
index 000000000..3e6378957
--- /dev/null
+++ b/programs/charon/lib/crypto/signers/signer.c
@@ -0,0 +1,59 @@
+/**
+ * @file signer.c
+ *
+ * @brief Implementation of generic signer_t constructor.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "signer.h"
+
+#include <crypto/signers/hmac_signer.h>
+
+/**
+ * String mappings for integrity_algorithm_t.
+ */
+mapping_t integrity_algorithm_m[] = {
+ {AUTH_UNDEFINED, "AUTH_UNDEFINED"},
+ {AUTH_HMAC_MD5_96, "AUTH_HMAC_MD5_96"},
+ {AUTH_HMAC_SHA1_96, "AUTH_HMAC_SHA1_96"},
+ {AUTH_DES_MAC, "AUTH_DES_MAC"},
+ {AUTH_KPDK_MD5, "AUTH_KPDK_MD5"},
+ {AUTH_AES_XCBC_96, "AUTH_AES_XCBC_96"},
+ {MAPPING_END, NULL}
+};
+
+
+/*
+ * 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));
+ }
+ case AUTH_HMAC_MD5_96:
+ {
+ return ((signer_t *) hmac_signer_create(HASH_MD5));
+ }
+ default:
+ return NULL;
+ }
+}
diff --git a/programs/charon/lib/crypto/signers/signer.h b/programs/charon/lib/crypto/signers/signer.h
new file mode 100644
index 000000000..9625af813
--- /dev/null
+++ b/programs/charon/lib/crypto/signers/signer.h
@@ -0,0 +1,147 @@
+/**
+ * @file signer.h
+ *
+ * @brief Interface for signer_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef SIGNER_H_
+#define SIGNER_H_
+
+#include <types.h>
+#include <definitions.h>
+
+typedef enum integrity_algorithm_t integrity_algorithm_t;
+
+/**
+ * @brief Integrity algorithm, as in IKEv2 RFC 3.3.2.
+ *
+ * Currently only the following algorithms are implemented and therefore supported:
+ * - AUTH_HMAC_MD5_96
+ * - AUTH_HMAC_SHA1_96
+ *
+ * @ingroup signers
+ */
+enum integrity_algorithm_t {
+ AUTH_UNDEFINED = 1024,
+ /**
+ * Implemented in class hmac_signer_t.
+ */
+ AUTH_HMAC_MD5_96 = 1,
+ /**
+ * Implemented in class hmac_signer_t.
+ */
+ AUTH_HMAC_SHA1_96 = 2,
+ AUTH_DES_MAC = 3,
+ AUTH_KPDK_MD5 = 4,
+ AUTH_AES_XCBC_96 = 5
+};
+
+/**
+ * String mappings for integrity_algorithm_t.
+ */
+extern mapping_t integrity_algorithm_m[];
+
+
+typedef struct signer_t signer_t;
+
+/**
+ * @brief Generig interface for a symmetric signature algorithm.
+ *
+ * @b Constructors:
+ * - signer_create()
+ * - hmac_signer_create()
+ *
+ * @todo Implement more integrity algorithms
+ *
+ * @ingroup signers
+ */
+struct signer_t {
+ /**
+ * @brief Generate a signature.
+ *
+ * @param this calling object
+ * @param data a chunk containing the data to sign
+ * @param[out] 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.
+ *
+ * @param this calling object
+ * @param data a chunk containing the data to sign
+ * @param[out] chunk chunk which will hold the allocated signature
+ */
+ void (*allocate_signature) (signer_t *this, chunk_t data, chunk_t *chunk);
+
+ /**
+ * @brief 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
+ */
+ bool (*verify_signature) (signer_t *this, chunk_t data, chunk_t signature);
+
+ /**
+ * @brief Get the block size of this signature algorithm.
+ *
+ * @param this calling object
+ * @return block size in bytes
+ */
+ size_t (*get_block_size) (signer_t *this);
+
+ /**
+ * @brief Get the key size of the signature algorithm.
+ *
+ * @param this calling object
+ * @return key size in bytes
+ */
+ size_t (*get_key_size) (signer_t *this);
+
+ /**
+ * @brief Set the key for this object.
+ *
+ * @param this calling object
+ * @param key key to set
+ */
+ void (*set_key) (signer_t *this, chunk_t key);
+
+ /**
+ * @brief Destroys a signer_t object.
+ *
+ * @param this calling 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_*/
diff --git a/programs/charon/lib/crypto/x509.c b/programs/charon/lib/crypto/x509.c
new file mode 100755
index 000000000..86a595618
--- /dev/null
+++ b/programs/charon/lib/crypto/x509.c
@@ -0,0 +1,937 @@
+/**
+ * @file x509.c
+ *
+ * @brief Implementation of x509_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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <gmp.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "x509.h"
+
+#include <daemon.h>
+#include <asn1/asn1.h>
+#include <asn1/oid.h>
+#include <utils/logger_manager.h>
+
+typedef const char *err_t; /* error message, or NULL for success */
+
+
+#define BUF_LEN 512
+#define RSA_MIN_OCTETS (512 / 8)
+#define RSA_MIN_OCTETS_UGH "RSA modulus too small for security: less than 512 bits"
+#define RSA_MAX_OCTETS (8192 / 8)
+#define RSA_MAX_OCTETS_UGH "RSA modulus too large: more than 8192 bits"
+
+logger_t *logger;
+
+typedef enum generalNames_t generalNames_t;
+
+/**
+ * Different kinds of generalNames
+ */
+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 generalName_t generalName_t;
+
+/**
+ * A generalName, chainable in a list
+ */
+struct generalName_t {
+ generalName_t *next;
+ generalNames_t kind;
+ chunk_t name;
+};
+
+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;
+
+ /**
+ * Version of the X509 certificate
+ */
+ u_int version;
+
+ /**
+ * ID representing the certificates subject
+ */
+ identification_t *subject;
+
+ /**
+ * ID representing the certificate issuer
+ */
+ identification_t *issuer;
+
+ /**
+ * List of identification_t's representing subjectAltNames
+ */
+ linked_list_t *subjectAltNames;
+
+ /**
+ * List of identification_t's representing issuerAltNames
+ */
+ linked_list_t *issuerAltNames;
+
+ /**
+ * List of identification_t's representing crlDistributionPoints
+ */
+ linked_list_t *crlDistributionPoints;
+
+ /**
+ * Type of the subjects Key (currently RSA only)
+ */
+ auth_method_t subjectPublicKeyAlgorithm;
+
+
+ /**
+ * Subjects RSA public key, if subjectPublicKeyAlgorithm == RSA
+ */
+ rsa_public_key_t *public_key;
+
+
+
+
+ time_t installed;
+ u_char authority_flags;
+ chunk_t x509;
+ chunk_t tbsCertificate;
+ chunk_t serialNumber;
+ /* signature */
+ int sigAlg;
+ /* validity */
+ time_t notBefore;
+ time_t notAfter;
+ /* subjectPublicKeyInfo */
+ chunk_t subjectPublicKey;
+ /* issuerUniqueID */
+ /* subjectUniqueID */
+ /* v3 extensions */
+ /* extension */
+ /* extension */
+ /* extnID */
+ /* critical */
+ /* extnValue */
+ bool isCA;
+ bool isOcspSigner; /* ocsp */
+ chunk_t subjectKeyID;
+ chunk_t authKeyID;
+ chunk_t authKeySerialNumber;
+ chunk_t accessLocation; /* ocsp */
+ /* signatureAlgorithm */
+ int algorithm;
+ chunk_t signature;
+};
+
+/**
+ * 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 time
+ */
+static const asn1Object_t timeObjects[] = {
+ { 0, "utcTime", ASN1_UTCTIME, ASN1_OPT|ASN1_BODY }, /* 0 */
+ { 0, "end opt", ASN1_EOC, ASN1_END }, /* 1 */
+ { 0, "generalizeTime",ASN1_GENERALIZEDTIME, ASN1_OPT|ASN1_BODY }, /* 2 */
+ { 0, "end opt", ASN1_EOC, ASN1_END } /* 3 */
+};
+#define TIME_UTC 0
+#define TIME_GENERALIZED 2
+#define TIME_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(private_x509_t *this, private_x509_t *other)
+{
+ return chunk_equals(this->signature, other->signature);
+}
+
+/**
+ * encode a linked list of subjectAltNames
+ */
+chunk_t build_subjectAltNames(generalName_t *subjectAltNames)
+{
+ u_char *pos;
+ chunk_t names;
+ size_t len = 0;
+ generalName_t *gn = subjectAltNames;
+
+ /* compute the total size of the ASN.1 attributes object */
+ while (gn != NULL)
+ {
+ len += gn->name.len;
+ gn = gn->next;
+ }
+
+ pos = build_asn1_object(&names, ASN1_SEQUENCE, len);
+
+ gn = subjectAltNames;
+ while (gn != NULL)
+ {
+ memcpy(pos, gn->name.ptr, gn->name.len);
+ pos += gn->name.len;
+ gn = gn->next;
+ }
+
+ return asn1_wrap(ASN1_SEQUENCE, "cm",
+ ASN1_subjectAltName_oid,
+ asn1_wrap(ASN1_OCTET_STRING, "m", names)
+ );
+}
+
+/**
+ * free the dynamic memory used to store generalNames
+ */
+void free_generalNames(generalName_t* gn, bool free_name)
+{
+ while (gn != NULL)
+ {
+ generalName_t *gn_top = gn;
+ if (free_name)
+ {
+ free(gn->name.ptr);
+ }
+ gn = gn->next;
+ free(gn_top);
+ }
+}
+
+/**
+ * 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);
+
+ while (objectID < BASIC_CONSTRAINTS_ROOF) {
+
+ if (!extract_object(basicConstraintsObjects, &objectID, &object,&level, &ctx))
+ {
+ break;
+ }
+ if (objectID == BASIC_CONSTRAINTS_CA)
+ {
+ isCA = object.len && *object.ptr;
+ logger->log(logger, RAW|LEVEL1, " %s", isCA ? "TRUE" : "FALSE");
+ }
+ objectID++;
+ }
+ return isCA;
+}
+
+/**
+ * extracts one or several GNs and puts them into a chained list
+ */
+static 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);
+
+ while (objectID < GENERAL_NAMES_ROOF)
+ {
+ if (!extract_object(generalNamesObjects, &objectID, &object, &level, &ctx))
+ return;
+
+ if (objectID == GENERAL_NAMES_GN)
+ {
+ list->insert_last(list, identification_create_from_encoding(ID_DER_ASN1_GN, object));
+ }
+ objectID++;
+ }
+ return;
+}
+
+/**
+ * extracts and converts a UTCTIME or GENERALIZEDTIME object
+ */
+time_t parse_time(chunk_t blob, int level0)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+
+ asn1_init(&ctx, blob, level0, FALSE);
+
+ while (objectID < TIME_ROOF)
+ {
+ if (!extract_object(timeObjects, &objectID, &object, &level, &ctx))
+ return 0;
+
+ if (objectID == TIME_UTC || objectID == TIME_GENERALIZED)
+ {
+ return asn1totime(&object, (objectID == TIME_UTC)
+ ? ASN1_UTCTIME : ASN1_GENERALIZEDTIME);
+ }
+ objectID++;
+ }
+ return 0;
+}
+
+/**
+ * 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);
+
+ extract_object(keyIdentifierObjects, &objectID, &object, &level, &ctx);
+ return object;
+}
+
+/**
+ * extracts an authoritykeyIdentifier
+ */
+void 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;
+
+ asn1_init(&ctx, blob, level0, 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, chunk_t *accessLocation)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+
+ u_int accessMethod = OID_UNKNOWN;
+
+ asn1_init(&ctx, blob, level0, 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:
+ if (*object.ptr == ASN1_CONTEXT_S_6)
+ {
+ if (asn1_length(&object) == ASN1_INVALID_LENGTH)
+ {
+ return;
+ }
+ logger->log(logger, RAW|LEVEL1, " '%.*s'",(int)object.len, object.ptr);
+ /* only HTTP(S) URIs accepted */
+ if (strncasecmp(object.ptr, "http", 4) == 0)
+ {
+ *accessLocation = object;
+ return;
+ }
+ }
+ logger->log(logger, ERROR|LEVEL2, "ignoring OCSP InfoAccessLocation with unkown protocol");
+ 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);
+ 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);
+ 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 */
+ parse_generalNames(object, level+1, TRUE, list);
+
+ }
+ objectID++;
+ }
+}
+
+
+/**
+ * Parses an X.509v3 x509
+ */
+bool parse_x509cert(chunk_t blob, u_int level0, private_x509_t *cert)
+{
+ asn1_ctx_t ctx;
+ bool critical;
+ chunk_t object;
+ u_int level;
+ u_int extn_oid = OID_UNKNOWN;
+ int objectID = 0;
+
+ asn1_init(&ctx, blob, level0, 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:
+ cert->x509 = object;
+ break;
+ case X509_OBJ_TBS_CERTIFICATE:
+ cert->tbsCertificate = object;
+ break;
+ case X509_OBJ_VERSION:
+ cert->version = (object.len) ? (1+(u_int)*object.ptr) : 1;
+ logger->log(logger, RAW|LEVEL1, " v%d", cert->version);
+ break;
+ case X509_OBJ_SERIAL_NUMBER:
+ cert->serialNumber = object;
+ break;
+ case X509_OBJ_SIG_ALG:
+ cert->sigAlg = parse_algorithmIdentifier(object, level, NULL);
+ break;
+ case X509_OBJ_ISSUER:
+ cert->issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object);
+ break;
+ case X509_OBJ_NOT_BEFORE:
+ cert->notBefore = parse_time(object, level);
+ break;
+ case X509_OBJ_NOT_AFTER:
+ cert->notAfter = parse_time(object, level);
+ break;
+ case X509_OBJ_SUBJECT:
+ cert->subject = identification_create_from_encoding(ID_DER_ASN1_DN, object);
+ break;
+ case X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM:
+ if (parse_algorithmIdentifier(object, level, NULL) == OID_RSA_ENCRYPTION)
+ {
+ cert->subjectPublicKeyAlgorithm = RSA_DIGITAL_SIGNATURE;
+ }
+ else
+ {
+ logger->log(logger, ERROR|LEVEL1, " 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
+ {
+ logger->log(logger, ERROR|LEVEL1, " invalid RSA public key format");
+ return FALSE;
+ }
+ break;
+ case X509_OBJ_RSA_PUBLIC_KEY:
+ cert->subjectPublicKey = object;
+ break;
+ case X509_OBJ_EXTN_ID:
+ extn_oid = known_oid(object);
+ break;
+ case X509_OBJ_CRITICAL:
+ critical = object.len && *object.ptr;
+ logger->log(logger, ERROR|LEVEL1, " %s", critical ? "TRUE" : "FALSE");
+ break;
+ case X509_OBJ_EXTN_VALUE:
+ {
+ switch (extn_oid) {
+ case OID_SUBJECT_KEY_ID:
+ cert->subjectKeyID = parse_keyIdentifier(object, level, FALSE);
+ break;
+ case OID_SUBJECT_ALT_NAME:
+ parse_generalNames(object, level, FALSE, cert->subjectAltNames);
+ break;
+ case OID_BASIC_CONSTRAINTS:
+ cert->isCA = parse_basicConstraints(object, level);
+ break;
+ case OID_CRL_DISTRIBUTION_POINTS:
+ parse_crlDistributionPoints(object, level, cert->crlDistributionPoints);
+ break;
+ case OID_AUTHORITY_KEY_ID:
+ parse_authorityKeyIdentifier(object, level , &cert->authKeyID, &cert->authKeySerialNumber);
+ break;
+ case OID_AUTHORITY_INFO_ACCESS:
+ parse_authorityInfoAccess(object, level, &cert->accessLocation);
+ break;
+ case OID_EXTENDED_KEY_USAGE:
+ cert->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:
+ cert->algorithm = parse_algorithmIdentifier(object, level, NULL);
+ break;
+ case X509_OBJ_SIGNATURE:
+ cert->signature = object;
+ break;
+ default:
+ break;
+ }
+ objectID++;
+ }
+ time(&cert->installed);
+ return TRUE;
+}
+
+/**
+ * verify the validity of a x509 by
+ * checking the notBefore and notAfter dates
+ */
+err_t check_validity(const private_x509_t *cert, time_t *until)
+{
+ time_t current_time;
+
+ time(&current_time);
+
+ if (cert->notAfter < *until)
+ {
+ *until = cert->notAfter;
+ }
+ if (current_time < cert->notBefore)
+ {
+ return "x509 is not valid yet";
+ }
+ if (current_time > cert->notAfter)
+ {
+ return "x509 has expired";
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+/**
+ * Implements x509_t.get_public_key
+ */
+static rsa_public_key_t *get_public_key(private_x509_t *this)
+{
+ return this->public_key->clone(this->public_key);;
+}
+
+/**
+ * Implements x509_t.get_subject
+ */
+static identification_t *get_subject(private_x509_t *this)
+{
+ return this->subject;
+}
+
+/**
+ * Implements x509_t.get_issuer
+ */
+static identification_t *get_issuer(private_x509_t *this)
+{
+ return this->issuer;
+}
+
+/**
+ * destroy
+ */
+static void destroy(private_x509_t *this)
+{
+ identification_t *id;
+ while (this->subjectAltNames->remove_last(this->subjectAltNames, (void**)&id) == SUCCESS)
+ {
+ id->destroy(id);
+ }
+ this->subjectAltNames->destroy(this->subjectAltNames);
+ while (this->issuerAltNames->remove_last(this->issuerAltNames, (void**)&id) == SUCCESS)
+ {
+ id->destroy(id);
+ }
+ this->issuerAltNames->destroy(this->issuerAltNames);
+ while (this->crlDistributionPoints->remove_last(this->crlDistributionPoints, (void**)&id) == SUCCESS)
+ {
+ id->destroy(id);
+ }
+ this->crlDistributionPoints->destroy(this->crlDistributionPoints);
+ if (this->issuer)
+ {
+ this->issuer->destroy(this->issuer);
+ }
+ if (this->subject)
+ {
+ this->subject->destroy(this->subject);
+ }
+ if (this->public_key)
+ {
+ this->public_key->destroy(this->public_key);
+ }
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+x509_t *x509_create_from_chunk(chunk_t chunk)
+{
+ private_x509_t *this = malloc_thing(private_x509_t);
+
+ /* public functions */
+ this->public.equals = (bool (*) (x509_t*,x509_t*))equals;
+ this->public.destroy = (void (*) (x509_t*))destroy;
+ this->public.get_public_key = (rsa_public_key_t* (*) (x509_t*))get_public_key;
+ this->public.get_subject = (identification_t* (*) (x509_t*))get_subject;
+ this->public.get_issuer = (identification_t* (*) (x509_t*))get_issuer;
+
+ /* initialize */
+ this->subjectPublicKey = CHUNK_INITIALIZER;
+ this->public_key = NULL;
+ this->subject = NULL;
+ this->issuer = NULL;
+ this->subjectAltNames = linked_list_create(this->subjectAltNames);
+ this->issuerAltNames = linked_list_create(this->issuerAltNames);
+ this->crlDistributionPoints = linked_list_create(this->crlDistributionPoints);
+
+ /* we do not use a per-instance logger right now, since its not always accessible */
+ logger = logger_manager->get_logger(logger_manager, ASN1);
+
+ if (!is_asn1(chunk) ||
+ !parse_x509cert(chunk, 0, this))
+ {
+ destroy(this);
+ return NULL;
+ }
+
+ this->public_key = rsa_public_key_create_from_chunk(this->subjectPublicKey);
+ if (this->public_key == NULL)
+ {
+ destroy(this);
+ return NULL;
+ }
+
+ return &this->public;
+}
+
+/*
+ * Described in header.
+ */
+x509_t *x509_create_from_file(char *filename)
+{
+ struct stat stb;
+ FILE *file;
+ char *buffer;
+ chunk_t chunk;
+
+ if (stat(filename, &stb) == -1)
+ {
+ return NULL;
+ }
+
+ buffer = alloca(stb.st_size);
+
+ file = fopen(filename, "r");
+ if (file == NULL)
+ {
+ return NULL;
+ }
+
+ if (fread(buffer, stb.st_size, 1, file) == -1)
+ {
+ fclose(file);
+ return NULL;
+ }
+ fclose(file);
+
+ chunk.ptr = buffer;
+ chunk.len = stb.st_size;
+
+ return x509_create_from_chunk(chunk);
+}
diff --git a/programs/charon/lib/crypto/x509.h b/programs/charon/lib/crypto/x509.h
new file mode 100755
index 000000000..077238eab
--- /dev/null
+++ b/programs/charon/lib/crypto/x509.h
@@ -0,0 +1,136 @@
+/**
+ * @file x509.h
+ *
+ * @brief Interface of x509_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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef X509_H_
+#define X509_H_
+
+#include <types.h>
+#include <definitions.h>
+#include <crypto/rsa/rsa_public_key.h>
+#include <utils/identification.h>
+#include <utils/iterator.h>
+
+
+typedef struct x509_t x509_t;
+
+/**
+ * @brief X509 certificate.
+ *
+ * @b Constructors:
+ * - x509_create_from_chunk()
+ * - x509_create_from_file()
+ *
+ * @todo more code cleanup needed!
+ * @todo fix unimplemented functions...
+ * @todo handle memory management
+ *
+ * @ingroup transforms
+ */
+struct x509_t {
+
+ /**
+ * @brief Get the RSA public key from the certificate.
+ *
+ * @param this calling object
+ * @return public_key
+ */
+ rsa_public_key_t *(*get_public_key) (x509_t *this);
+
+ /**
+ * @brief Get the certificate issuers 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) (x509_t *this);
+
+ /**
+ * @brief Get the subjects ID.
+ *
+ * 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) (x509_t *this);
+
+ /**
+ * @brief Check if a certificate is valid.
+ *
+ * This function uses the issuers public key to verify
+ * the validity of a certificate.
+ *
+ * @todo implement!
+ */
+ bool (*verify) (x509_t *this, rsa_public_key_t *signer);
+
+ /**
+ * @brief Get the key identifier of the public key.
+ *
+ * @todo implement!
+ */
+ chunk_t (*get_subject_key_identifier) (x509_t *this);
+
+ /**
+ * @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) (x509_t *this, x509_t *other);
+
+ /**
+ * @brief Destroys the certificate.
+ *
+ * @param this certificate to destroy
+ */
+ void (*destroy) (x509_t *this);
+};
+
+/**
+ * @brief Read a x509 certificate from a DER encoded blob.
+ *
+ * @param chunk chunk containing DER encoded data
+ * @return created x509_t certificate, or NULL if invalid.
+ *
+ * @ingroup transforms
+ */
+x509_t *x509_create_from_chunk(chunk_t chunk);
+
+/**
+ * @brief Read a x509 certificate from a DER encoded file.
+ *
+ * @param filename file containing DER encoded data
+ * @return created x509_t certificate, or NULL if invalid.
+ *
+ * @ingroup transforms
+ */
+x509_t *x509_create_from_file(char *filename);
+
+#endif /* X509_H_ */
diff --git a/programs/charon/lib/definitions.c b/programs/charon/lib/definitions.c
new file mode 100644
index 000000000..59c97a29b
--- /dev/null
+++ b/programs/charon/lib/definitions.c
@@ -0,0 +1,40 @@
+/**
+ * @file definitions.c
+ *
+ * @brief General purpose definitions and macros.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "definitions.h"
+
+/*
+ * Described in header.
+ */
+char *mapping_find(mapping_t * maps, int value)
+{
+ int i = 0;
+ while (maps[i].value != MAPPING_END)
+ {
+ if (maps[i].value == value)
+ {
+ return maps[i].string;
+ }
+ i++;
+ }
+ return "INVALID MAPPING";
+}
diff --git a/programs/charon/lib/definitions.h b/programs/charon/lib/definitions.h
new file mode 100644
index 000000000..c9ef066c1
--- /dev/null
+++ b/programs/charon/lib/definitions.h
@@ -0,0 +1,120 @@
+/**
+ * @file definitions.h
+ *
+ * @brief General purpose definitions and macros.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ * Copyright (C) 1998, 1999 D. Hugh Redelmeier. (Endian stuff)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef DEFINITIONS_H_
+#define DEFINITIONS_H_
+
+
+
+/* stolen from strongswan */
+#if linux
+# if defined(i386) && !defined(__i386__)
+# define __i386__ 1
+# define MYHACKFORTHIS 1
+# endif
+# include <endian.h>
+# ifdef MYHACKFORTHIS
+# undef __i386__
+# undef MYHACKFORTHIS
+# endif
+#elif !(defined(BIG_ENDIAN) && defined(LITTLE_ENDIAN) && defined(BYTE_ORDER))
+ /* we don't know how to do this, so we require the macros to be defined
+ * with compiler flags:
+ * -DBIG_ENDIAN=4321 -DLITTLE_ENDIAN=1234 -DBYTE_ORDER=BIG_ENDIAN
+ * or -DBIG_ENDIAN=4321 -DLITTLE_ENDIAN=1234 -DBYTE_ORDER=LITTLE_ENDIAN
+ * Thse match the GNU definitions
+ */
+# include <sys/endian.h>
+#endif
+
+#ifndef BIG_ENDIAN
+ #error "BIG_ENDIAN must be defined"
+#endif
+
+#ifndef LITTLE_ENDIAN
+ #error "LITTLE_ENDIAN must be defined"
+#endif
+
+#ifndef BYTE_ORDER
+ #error "BYTE_ORDER must be defined"
+#endif
+
+
+/**
+ * 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)
+
+/**
+ * Debug macro to follow control flow
+ */
+#define POS printf("%s, line %d\n", __FILE__, __LINE__)
+
+/**
+ * Macro to allocate a sized type.
+ *
+ * @param thing object on which a sizeof is performed
+ * @return poiner to allocated memory
+ */
+#define malloc_thing(thing) ((thing*)malloc(sizeof(thing)))
+
+
+/**
+ * Mapping entry which defines the end of a mapping_t array.
+ */
+#define MAPPING_END (-1)
+
+typedef struct mapping_t mapping_t;
+
+/**
+ * @brief Mapping entry, where enum-to-string mappings are stored.
+ */
+struct mapping_t
+{
+ /**
+ * Enumeration value.
+ */
+ int value;
+
+ /**
+ * Mapped string.
+ */
+ char *string;
+};
+
+
+/**
+ * @brief Find a mapping_string in the mapping[].
+ *
+ * @param mappings mappings array
+ * @param value enum-value to get the string from
+ *
+ */
+char *mapping_find(mapping_t *mappings, int value);
+
+#endif /*DEFINITIONS_H_*/
diff --git a/programs/charon/lib/library.c b/programs/charon/lib/library.c
new file mode 100644
index 000000000..fa9c732bf
--- /dev/null
+++ b/programs/charon/lib/library.c
@@ -0,0 +1,42 @@
+/**
+ * @file library.c
+ *
+ * @brief Library (de-)initialization.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <utils/logger_manager.h>
+#include <utils/leak_detective.h>
+
+/**
+ * Called whenever the library is linked from a process
+ */
+void __attribute__ ((constructor)) library_init()
+{
+ logger_manager_init();
+ leak_detective_init();
+}
+
+/**
+ * Called whenever the library is unlinked from a process
+ */
+void __attribute__ ((destructor)) library_cleanup()
+{
+ leak_detective_cleanup();
+ logger_manager_cleanup();
+}
diff --git a/programs/charon/lib/library.h b/programs/charon/lib/library.h
new file mode 100644
index 000000000..da96befe1
--- /dev/null
+++ b/programs/charon/lib/library.h
@@ -0,0 +1,100 @@
+/**
+ * @file library.h
+ *
+ * @brief Global library header.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef LIBRARY_H_
+#define LIBRARY_H_
+
+/**
+ * @defgroup lib lib
+ *
+ * libstrongswan: library with various crypto related things.
+ */
+
+/**
+ * @defgroup asn1 asn1
+ *
+ * ASN1 definitions, parser and generator functions.
+ *
+ * @ingroup lib
+ */
+
+/**
+ * @defgroup crypto crypto
+ *
+ * Crypto algorithms of different kind.
+ *
+ * @ingroup lib
+ */
+
+/**
+ * @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
+ *
+ * Symmetric signing algorithms,
+ * used to ensure message integrity.
+ *
+ * @ingroup crypto
+ */
+
+/**
+ * @defgroup utils utils
+ *
+ * Generic helper classes.
+ *
+ * @ingroup lib
+ */
+
+
+#endif /* LIBRARY_H_ */
diff --git a/programs/charon/lib/types.c b/programs/charon/lib/types.c
new file mode 100644
index 000000000..09ebf7310
--- /dev/null
+++ b/programs/charon/lib/types.c
@@ -0,0 +1,115 @@
+/**
+ * @file types.c
+ *
+ * @brief Generic types.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+
+#include "types.h"
+
+
+/**
+ * String mappings for type status_t.
+ */
+mapping_t status_m[] = {
+ {SUCCESS, "SUCCESS"},
+ {FAILED, "FAILED"},
+ {OUT_OF_RES, "OUT_OF_RES"},
+ {ALREADY_DONE, "ALREADY_DONE"},
+ {NOT_SUPPORTED, "NOT_SUPPORTED"},
+ {INVALID_ARG, "INVALID_ARG"},
+ {NOT_FOUND, "NOT_FOUND"},
+ {PARSE_ERROR, "PARSE_ERROR"},
+ {VERIFY_ERROR, "VERIFY_ERROR"},
+ {INVALID_STATE, "INVALID_STATE"},
+ {DELETE_ME, "DELETE_ME"},
+ {CREATED, "CREATED"},
+ {MAPPING_END, NULL}
+};
+
+/**
+ * Empty chunk.
+ */
+chunk_t CHUNK_INITIALIZER = {NULL,0};
+
+/**
+ * Described in header.
+ */
+chunk_t chunk_clone(chunk_t chunk)
+{
+ chunk_t clone = CHUNK_INITIALIZER;
+
+ if (chunk.ptr && chunk.len > 0)
+ {
+ clone.ptr = malloc(chunk.len);
+ clone.len = chunk.len;
+ memcpy(clone.ptr, chunk.ptr, chunk.len);
+ }
+
+ return clone;
+}
+
+/**
+ * Described in header.
+ */
+void chunk_free(chunk_t *chunk)
+{
+ free(chunk->ptr);
+ chunk->ptr = NULL;
+ chunk->len = 0;
+}
+
+/**
+ * Described in header.
+ */
+chunk_t chunk_alloc(size_t bytes)
+{
+ chunk_t new_chunk;
+ new_chunk.ptr = malloc(bytes);
+ new_chunk.len = bytes;
+ return new_chunk;
+}
+
+/**
+ * Described in header.
+ */
+bool chunk_equals(chunk_t a, chunk_t b)
+{
+ if (a.ptr == NULL || b.ptr == NULL ||
+ a.len != b.len ||
+ memcmp(a.ptr, b.ptr, a.len) != 0)
+ {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * Described in header.
+ */
+void *clalloc(void * pointer, size_t size)
+{
+ void *data;
+ data = malloc(size);
+
+ memcpy(data, pointer,size);
+
+ return (data);
+}
diff --git a/programs/charon/lib/types.h b/programs/charon/lib/types.h
new file mode 100644
index 000000000..0e0782b31
--- /dev/null
+++ b/programs/charon/lib/types.h
@@ -0,0 +1,186 @@
+/**
+ * @file types.h
+ *
+ * @brief Generic types.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#ifndef TYPES_H_
+#define TYPES_H_
+
+#include <gmp.h>
+#include <sys/types.h>
+#include <stdlib.h>
+
+#include <definitions.h>
+
+/**
+ * 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 ressources.
+ */
+
+ OUT_OF_RES,
+ /**
+ * 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,
+
+ /**
+ * Delete object which function belongs to.
+ */
+ DELETE_ME,
+
+ /**
+ * An object got created.
+ */
+ CREATED,
+};
+
+
+/**
+ * String mappings for type status_t.
+ */
+extern mapping_t status_m[];
+
+/**
+ * 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;
+
+/**
+ * Use struct chunk_t as chunk_t.
+ */
+typedef struct chunk_t chunk_t;
+
+/**
+ * General purpose pointer/length abstraction.
+ */
+struct chunk_t {
+ /**
+ * Pointer to start of data
+ */
+ u_char *ptr;
+
+ /**
+ * Length of data in bytes
+ */
+ size_t len;
+};
+
+/**
+ * {NULL, 0}-chunk, handy for initialization
+ * of chunks.
+ */
+extern chunk_t CHUNK_INITIALIZER;
+
+/**
+ * Initialize a chunk to a static buffer
+ */
+#define chunk_from_buf(str) { str, sizeof(str) }
+
+/**
+ * Clone chunk contents in a newly allocated chunk
+ */
+chunk_t chunk_clone(chunk_t chunk);
+
+/**
+ * Free contents of a chunk
+ */
+void chunk_free(chunk_t *chunk);
+
+/**
+ * Allocate a chunk
+ */
+chunk_t chunk_alloc(size_t bytes);
+
+/**
+ * Compare two chunks for equality,
+ * NULL chunks are never equal.
+ */
+bool chunk_equals(chunk_t a, chunk_t b);
+
+/**
+ * Clone a data to a newly allocated buffer
+ */
+void *clalloc(void *pointer, size_t size);
+
+
+#endif /*TYPES_H_*/
diff --git a/programs/charon/lib/utils/Makefile.utils b/programs/charon/lib/utils/Makefile.utils
new file mode 100644
index 000000000..1c82283d7
--- /dev/null
+++ b/programs/charon/lib/utils/Makefile.utils
@@ -0,0 +1,47 @@
+# Copyright (C) 2005 Jan Hutter, Martin Willi
+# Hochschule fuer Technik Rapperswil
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+
+UTILS_DIR= $(LIB_DIR)utils/
+
+LIB_OBJS+= $(BUILD_DIR)leak_detective.o
+$(BUILD_DIR)leak_detective.o : $(UTILS_DIR)leak_detective.c $(UTILS_DIR)leak_detective.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+LIB_OBJS+= $(BUILD_DIR)linked_list.o
+$(BUILD_DIR)linked_list.o : $(UTILS_DIR)linked_list.c $(UTILS_DIR)linked_list.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+LIB_OBJS+= $(BUILD_DIR)logger.o
+$(BUILD_DIR)logger.o : $(UTILS_DIR)logger.c $(UTILS_DIR)logger.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+LIB_OBJS+= $(BUILD_DIR)logger_manager.o
+$(BUILD_DIR)logger_manager.o : $(UTILS_DIR)logger_manager.c $(UTILS_DIR)logger_manager.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+LIB_OBJS+= $(BUILD_DIR)randomizer.o
+$(BUILD_DIR)randomizer.o : $(UTILS_DIR)randomizer.c $(UTILS_DIR)randomizer.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+LIB_OBJS+= $(BUILD_DIR)tester.o
+$(BUILD_DIR)tester.o : $(UTILS_DIR)tester.c $(UTILS_DIR)tester.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+LIB_OBJS+= $(BUILD_DIR)identification.o
+$(BUILD_DIR)identification.o : $(UTILS_DIR)identification.c $(UTILS_DIR)identification.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+LIB_OBJS+= $(BUILD_DIR)host.o
+$(BUILD_DIR)host.o : $(UTILS_DIR)host.c $(UTILS_DIR)host.h
+ $(CC) $(CFLAGS) -c -o $@ $< \ No newline at end of file
diff --git a/programs/charon/lib/utils/host.c b/programs/charon/lib/utils/host.c
new file mode 100644
index 000000000..020ed27f3
--- /dev/null
+++ b/programs/charon/lib/utils/host.c
@@ -0,0 +1,365 @@
+/**
+ * @file host.c
+ *
+ * @brief Implementation of host_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+
+#include "host.h"
+
+
+typedef struct private_host_t private_host_t;
+
+/**
+ * @brief Private Data of a host object.
+ */
+struct private_host_t {
+ /**
+ * Public data
+ */
+ host_t public;
+
+ /**
+ * Address family to use, such as AF_INET or AF_INET6
+ */
+ int family;
+
+ /**
+ * string representation of host
+ */
+ char *string;
+
+ /**
+ * low-lewel structure, wich stores the address
+ */
+ union {
+ struct sockaddr address;
+ struct sockaddr_in address4;
+ };
+ /**
+ * length of address structure
+ */
+ socklen_t socklen;
+};
+
+
+/**
+ * implements host_t.get_sockaddr
+ */
+static sockaddr_t *get_sockaddr(private_host_t *this)
+{
+ return &(this->address);
+}
+
+/**
+ * implements host_t.get_sockaddr_len
+ */
+static socklen_t *get_sockaddr_len(private_host_t *this)
+{
+ return &(this->socklen);
+}
+
+/**
+ * Implementation of host_t.is_default_route.
+ */
+static bool is_default_route (private_host_t *this)
+{
+ switch (this->family)
+ {
+ case AF_INET:
+ {
+ static u_int8_t default_route[4] = {0x00,0x00,0x00,0x00};
+
+ if (memcmp(default_route,&(this->address4.sin_addr.s_addr),4) == 0)
+ {
+ return TRUE;
+ }
+ return FALSE;
+ }
+ default:
+ {
+ /* empty chunk is returned */
+ return FALSE;
+ }
+ }
+}
+
+/**
+ * implements host_t.get_address
+ */
+static char *get_address(private_host_t *this)
+{
+ switch (this->family)
+ {
+ case AF_INET:
+ {
+ char *string;
+ /* we need to clone it, since inet_ntoa overwrites
+ * internal buffer on subsequent calls
+ */
+ free(this->string);
+ string = inet_ntoa(this->address4.sin_addr);
+ this->string = malloc(strlen(string)+1);
+ strcpy(this->string, string);
+ return this->string;
+ }
+ default:
+ {
+ return "(family not supported)";
+ }
+ }
+}
+
+/**
+ * Implementation of host_t.get_address_as_chunk.
+ */
+static chunk_t get_address_as_chunk(private_host_t *this)
+{
+ chunk_t address = CHUNK_INITIALIZER;
+
+ switch (this->family)
+ {
+ case AF_INET:
+ {
+ /* allocate 4 bytes for IPV4 address*/
+ address.ptr = malloc(4);
+ address.len = 4;
+ memcpy(address.ptr,&(this->address4.sin_addr.s_addr),4);
+ }
+ default:
+ {
+ /* empty chunk is returned */
+ return address;
+ }
+ }
+}
+
+static xfrm_address_t get_xfrm_addr(private_host_t *this)
+{
+ switch (this->family)
+ {
+ case AF_INET:
+ {
+ return (xfrm_address_t)(this->address4.sin_addr.s_addr);
+ }
+ default:
+ {
+ /* todo */
+ return (xfrm_address_t)(this->address4.sin_addr.s_addr);
+ }
+ }
+}
+
+static int get_family(private_host_t *this)
+{
+ return this->family;
+}
+
+/**
+ * implements host_t.get_port
+ */
+static u_int16_t get_port(private_host_t *this)
+{
+ switch (this->family)
+ {
+ case AF_INET:
+ {
+ return ntohs(this->address4.sin_port);
+ }
+ default:
+ {
+ return 0;
+ }
+ }
+}
+
+
+/**
+ * Implements host_t.clone.
+ */
+static private_host_t *clone(private_host_t *this)
+{
+ private_host_t *new = malloc_thing(private_host_t);
+
+
+ memcpy(new, this, sizeof(private_host_t));
+ if (this->string)
+ {
+ new->string = malloc(strlen(this->string)+1);
+ strcpy(new->string, this->string);
+ }
+ return new;
+}
+
+/**
+ * Impelements host_t.ip_equals
+ */
+static bool ip_equals(private_host_t *this, private_host_t *other)
+{
+ switch (this->family)
+ {
+ /* IPv4 */
+ case AF_INET:
+ {
+ if ((this->address4.sin_family == other->address4.sin_family) &&
+ (this->address4.sin_addr.s_addr == other->address4.sin_addr.s_addr))
+ {
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+/**
+ * Impelements host_t.equals
+ */
+static bool equals(private_host_t *this, private_host_t *other)
+{
+ switch (this->family)
+ {
+ /* IPv4 */
+ case AF_INET:
+ {
+ if ((this->address4.sin_family == other->address4.sin_family) &&
+ (this->address4.sin_addr.s_addr == other->address4.sin_addr.s_addr) &&
+ (this->address4.sin_port == other->address4.sin_port))
+ {
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+/**
+ * Implements host_t.destroy
+ */
+static void destroy(private_host_t *this)
+{
+ free(this->string);
+ free(this);
+}
+
+/**
+ * Creates an empty host_t object
+ */
+static private_host_t *host_create_empty()
+{
+ private_host_t *this = malloc_thing(private_host_t);
+
+ this->public.get_sockaddr = (sockaddr_t* (*) (host_t*))get_sockaddr;
+ this->public.get_sockaddr_len = (socklen_t*(*) (host_t*))get_sockaddr_len;
+ this->public.clone = (host_t* (*) (host_t*))clone;
+ this->public.get_family = (int (*) (host_t*))get_family;
+ this->public.get_xfrm_addr = (xfrm_address_t (*) (host_t *))get_xfrm_addr;
+ this->public.get_address = (char* (*) (host_t *))get_address;
+ this->public.get_address_as_chunk = (chunk_t (*) (host_t *)) get_address_as_chunk;
+ this->public.get_port = (u_int16_t (*) (host_t *))get_port;
+ this->public.ip_equals = (bool (*) (host_t *,host_t *)) ip_equals;
+ this->public.equals = (bool (*) (host_t *,host_t *)) equals;
+ this->public.is_default_route = (bool (*) (host_t *)) is_default_route;
+ this->public.destroy = (void (*) (host_t*))destroy;
+
+ this->string = NULL;
+
+ return this;
+}
+
+/*
+ * Described in header.
+ */
+host_t *host_create(int family, char *address, u_int16_t port)
+{
+ private_host_t *this = host_create_empty();
+
+ this->family = family;
+
+ switch (family)
+ {
+ /* IPv4 */
+ case AF_INET:
+ {
+ this->address4.sin_family = AF_INET;
+ this->address4.sin_addr.s_addr = inet_addr(address);
+ this->address4.sin_port = htons(port);
+ this->socklen = sizeof(struct sockaddr_in);
+ return &(this->public);
+ }
+ default:
+ {
+ free(this);
+ return NULL;
+
+ }
+ }
+
+}
+
+/*
+ * Described in header.
+ */
+host_t *host_create_from_chunk(int family, chunk_t address, u_int16_t port)
+{
+ private_host_t *this = host_create_empty();
+
+ this->family = family;
+ switch (family)
+ {
+ /* IPv4 */
+ case AF_INET:
+ {
+ if (address.len != 4)
+ {
+ break;
+ }
+ this->address4.sin_family = AF_INET;
+ memcpy(&(this->address4.sin_addr.s_addr),address.ptr,4);
+ this->address4.sin_port = htons(port);
+ this->socklen = sizeof(struct sockaddr_in);
+ return &(this->public);
+ }
+ }
+ free(this);
+ return NULL;
+}
+
+/*
+ * Described in header.
+ */
+host_t *host_create_from_sockaddr(sockaddr_t *sockaddr)
+{
+ chunk_t address;
+
+ switch (sockaddr->sa_family)
+ {
+ /* IPv4 */
+ case AF_INET:
+ {
+ struct sockaddr_in *sin = (struct sockaddr_in *)sockaddr;
+ address.ptr = (void*)&(sin->sin_addr.s_addr);
+ address.len = 4;
+ return host_create_from_chunk(AF_INET, address, ntohs(sin->sin_port));
+ }
+ default:
+ return NULL;
+ }
+}
+
diff --git a/programs/charon/lib/utils/host.h b/programs/charon/lib/utils/host.h
new file mode 100644
index 000000000..d81efffa6
--- /dev/null
+++ b/programs/charon/lib/utils/host.h
@@ -0,0 +1,225 @@
+/**
+ * @file host.h
+ *
+ * @brief Interface of host_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef HOST_H_
+#define HOST_H_
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <linux/xfrm.h>
+
+#include <types.h>
+
+
+typedef struct host_t host_t;
+
+/**
+ * @brief 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 network
+ */
+struct host_t {
+
+ /**
+ * @brief Build a clone of this host object.
+ *
+ * @param this object to clone
+ * @return cloned host
+ */
+ host_t *(*clone) (host_t *this);
+
+ /**
+ * @brief 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
+ */
+ sockaddr_t *(*get_sockaddr) (host_t *this);
+
+ /**
+ * @brief Get the length of the sockaddr struct.
+ *
+ * Sepending on the family, the length of the sockaddr struct
+ * is different. Use this function to get the length of the sockaddr
+ * struct returned by get_sock_addr.
+ *
+ * This is used for sending and receiving via sockets.
+ *
+ * @param this object to clone
+ * @return length of the sockaddr struct
+ */
+ socklen_t *(*get_sockaddr_len) (host_t *this);
+
+ /**
+ * @brief Gets the address as xfrm_address_t.
+ *
+ * This function allows the conversion to an
+ * xfrm_address_t, used for netlink communication
+ * with the kernel.
+ *
+ * @see kernel_interface_t.
+ *
+ * @param this calling object
+ * @return address in xfrm_address_t format
+ */
+ xfrm_address_t (*get_xfrm_addr) (host_t *this);
+
+ /**
+ * @brief Gets the family of the address
+ *
+ * @param this calling object
+ * @return family
+ */
+ int (*get_family) (host_t *this);
+
+ /**
+ * @brief get the address of this host
+ *
+ * Mostly used for debugging purposes.
+ * @warning string must NOT be freed
+ *
+ * @param this object
+ * @return address string,
+ */
+ char* (*get_address) (host_t *this);
+
+ /**
+ * @brief 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
+ */
+ bool (*is_default_route) (host_t *this);
+
+ /**
+ * @brief get the address of this host as chunk_t
+ *
+ * @warning returned chunk has to get destroyed by caller.
+ *
+ * @param this object
+ * @return address string,
+ */
+ chunk_t (*get_address_as_chunk) (host_t *this);
+
+ /**
+ * @brief get the port of this host
+ *
+ * Mostly used for debugging purposes.
+ *
+ * @param this object to clone
+ * @return port number
+ */
+ u_int16_t (*get_port) (host_t *this);
+
+ /**
+ * @brief Compare the ips of two hosts hosts.
+ *
+ * @param this object to compare
+ * @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.
+ *
+ * @param this object to compare
+ * @param other the other to compare
+ * @return TRUE if addresses and ports are equal.
+ */
+ bool (*equals) (host_t *this, host_t *other);
+
+ /**
+ * @brief Destroy this host object
+ *
+ * @param this calling
+ * @return SUCCESS in any case
+ */
+ void (*destroy) (host_t *this);
+};
+
+/**
+ * @brief Constructor to create a host_t object from an address string
+ *
+ * Currently supports only IPv4!
+ *
+ * @param family Address family to use for this object, such as AF_INET or AF_INET6
+ * @param address string of an address, such as "152.96.193.130"
+ * @param port port number
+ * @return
+ * - host_t object
+ * - NULL, if family not supported.
+ *
+ * @ingroup network
+ */
+host_t *host_create(int family, char *address, u_int16_t port);
+
+/**
+ * @brief Constructor to create a host_t object from an address chunk
+ *
+ * Currently supports only IPv4!
+ *
+ * @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 port port number
+ * @return
+ * - host_t object
+ * - NULL, if family not supported or chunk_t length not 4 bytes.
+ *
+ * @ingroup network
+ */
+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
+ *
+ * Currently supports only IPv4!
+ *
+ * @param sockaddr sockaddr struct which contains family, address and port
+ * @return
+ * - host_t object
+ * - NULL, if family not supported.
+ *
+ * @ingroup network
+ */
+host_t *host_create_from_sockaddr(sockaddr_t *sockaddr);
+
+
+#endif /*HOST_H_*/
diff --git a/programs/charon/lib/utils/identification.c b/programs/charon/lib/utils/identification.c
new file mode 100644
index 000000000..33f3d92cd
--- /dev/null
+++ b/programs/charon/lib/utils/identification.c
@@ -0,0 +1,1167 @@
+/**
+ * @file identification.c
+ *
+ * @brief Implementation of identification_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#define _GNU_SOURCE
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "identification.h"
+
+#include <asn1/asn1.h>
+
+/**
+ * String mappings for id_type_t.
+ */
+mapping_t id_type_m[] = {
+ {ID_IPV4_ADDR, "ID_IPV4_ADDR"},
+ {ID_FQDN, "ID_FQDN"},
+ {ID_RFC822_ADDR, "ID_RFC822_ADDR"},
+ {ID_IPV6_ADDR, "ID_IPV6_ADDR"},
+ {ID_DER_ASN1_DN, "ID_DER_ASN1_DN"},
+ {ID_DER_ASN1_GN, "ID_DER_ASN1_GN"},
+ {ID_KEY_ID, "ID_KEY_ID"},
+ {ID_ANY, "ID_ANY"},
+ {MAPPING_END, NULL}
+};
+
+
+/**
+ * X.501 acronyms for well known object identifiers (OIDs)
+ */
+static u_char oid_ND[] = {
+ 0x02, 0x82, 0x06, 0x01,
+ 0x0A, 0x07, 0x14
+};
+static u_char oid_UID[] = {
+ 0x09, 0x92, 0x26, 0x89, 0x93,
+ 0xF2, 0x2C, 0x64, 0x01, 0x01
+};
+static u_char oid_DC[] = {
+ 0x09, 0x92, 0x26, 0x89, 0x93,
+ 0xF2, 0x2C, 0x64, 0x01, 0x19
+};
+static u_char oid_CN[] = {
+ 0x55, 0x04, 0x03
+};
+static u_char oid_S[] = {
+ 0x55, 0x04, 0x04
+};
+static u_char oid_SN[] = {
+ 0x55, 0x04, 0x05
+};
+static u_char oid_C[] = {
+ 0x55, 0x04, 0x06
+};
+static u_char oid_L[] = {
+ 0x55, 0x04, 0x07
+};
+static u_char oid_ST[] = {
+ 0x55, 0x04, 0x08
+};
+static u_char oid_O[] = {
+ 0x55, 0x04, 0x0A
+};
+static u_char oid_OU[] = {
+ 0x55, 0x04, 0x0B
+};
+static u_char oid_T[] = {
+ 0x55, 0x04, 0x0C
+};
+static u_char oid_D[] = {
+ 0x55, 0x04, 0x0D
+};
+static u_char oid_N[] = {
+ 0x55, 0x04, 0x29
+};
+static u_char oid_G[] = {
+ 0x55, 0x04, 0x2A
+};
+static u_char oid_I[] = {
+ 0x55, 0x04, 0x2B
+};
+static u_char oid_ID[] = {
+ 0x55, 0x04, 0x2D
+};
+static u_char oid_EN[] = {
+ 0x60, 0x86, 0x48, 0x01, 0x86,
+ 0xF8, 0x42, 0x03, 0x01, 0x03
+};
+static u_char oid_E[] = {
+ 0x2A, 0x86, 0x48, 0x86, 0xF7,
+ 0x0D, 0x01, 0x09, 0x01
+};
+static u_char oid_UN[] = {
+ 0x2A, 0x86, 0x48, 0x86, 0xF7,
+ 0x0D, 0x01, 0x09, 0x02
+};
+static u_char oid_TCGID[] = {
+ 0x2B, 0x06, 0x01, 0x04, 0x01, 0x89,
+ 0x31, 0x01, 0x01, 0x02, 0x02, 0x4B
+};
+
+/**
+ * coding of X.501 distinguished name
+ */
+typedef struct {
+ const u_char *name;
+ chunk_t oid;
+ u_char type;
+} x501rdn_t;
+
+static const x501rdn_t x501rdns[] = {
+ {"ND", {oid_ND, 7}, ASN1_PRINTABLESTRING},
+ {"UID", {oid_UID, 10}, ASN1_PRINTABLESTRING},
+ {"DC", {oid_DC, 10}, ASN1_PRINTABLESTRING},
+ {"CN", {oid_CN, 3}, ASN1_PRINTABLESTRING},
+ {"S", {oid_S, 3}, ASN1_PRINTABLESTRING},
+ {"SN", {oid_SN, 3}, ASN1_PRINTABLESTRING},
+ {"serialNumber", {oid_SN, 3}, ASN1_PRINTABLESTRING},
+ {"C", {oid_C, 3}, ASN1_PRINTABLESTRING},
+ {"L", {oid_L, 3}, ASN1_PRINTABLESTRING},
+ {"ST", {oid_ST, 3}, ASN1_PRINTABLESTRING},
+ {"O", {oid_O, 3}, ASN1_PRINTABLESTRING},
+ {"OU", {oid_OU, 3}, ASN1_PRINTABLESTRING},
+ {"T", {oid_T, 3}, ASN1_PRINTABLESTRING},
+ {"D", {oid_D, 3}, ASN1_PRINTABLESTRING},
+ {"N", {oid_N, 3}, ASN1_PRINTABLESTRING},
+ {"G", {oid_G, 3}, ASN1_PRINTABLESTRING},
+ {"I", {oid_I, 3}, ASN1_PRINTABLESTRING},
+ {"ID", {oid_ID, 3}, ASN1_PRINTABLESTRING},
+ {"EN", {oid_EN, 10}, ASN1_PRINTABLESTRING},
+ {"employeeNumber", {oid_EN, 10}, ASN1_PRINTABLESTRING},
+ {"E", {oid_E, 9}, ASN1_IA5STRING},
+ {"Email", {oid_E, 9}, ASN1_IA5STRING},
+ {"emailAddress", {oid_E, 9}, ASN1_IA5STRING},
+ {"UN", {oid_UN, 9}, ASN1_IA5STRING},
+ {"unstructuredName",{oid_UN, 9}, ASN1_IA5STRING},
+ {"TCGID", {oid_TCGID, 12}, ASN1_PRINTABLESTRING}
+};
+#define X501_RDN_ROOF 26
+
+/**
+ * Different kinds of generalNames
+ */
+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,
+};
+
+/**
+ * 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
+
+typedef struct private_identification_t private_identification_t;
+
+/**
+ * Private data of an identification_t object.
+ */
+struct private_identification_t {
+ /**
+ * Public interface.
+ */
+ identification_t public;
+
+ /**
+ * String representation of this ID.
+ */
+ char *string;
+
+ /**
+ * Encoded representation of this ID.
+ */
+ chunk_t encoded;
+
+ /**
+ * Type of this ID.
+ */
+ id_type_t type;
+};
+
+static private_identification_t *identification_create();
+
+
+/**
+ * updates a chunk (!????)
+ * TODO: We should reconsider this stuff, its not really clear
+ */
+static void update_chunk(chunk_t *ch, int n)
+{
+ n = (n > -1 && n < (int)ch->len)? n : (int)ch->len-1;
+ ch->ptr += n; ch->len -= n;
+}
+
+/**
+ * Prints a binary string in hexadecimal form
+ */
+void hex_str(chunk_t bin, chunk_t *str)
+{
+ u_int i;
+ update_chunk(str, snprintf(str->ptr,str->len,"0x"));
+ for (i=0; i < bin.len; i++)
+ {
+ update_chunk(str, snprintf(str->ptr,str->len,"%02X",*bin.ptr++));
+ }
+}
+
+/**
+ * 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)
+{
+ *rdn = CHUNK_INITIALIZER;
+ *attribute = CHUNK_INITIALIZER;
+
+ /* a DN is a SEQUENCE OF RDNs */
+ if (*dn.ptr != ASN1_SEQUENCE)
+ {
+ /* DN is not a SEQUENCE */
+ return FAILED;
+ }
+
+ rdn->len = asn1_length(&dn);
+
+ if (rdn->len == ASN1_INVALID_LENGTH)
+ {
+ /* Invalid RDN length */
+ return FAILED;
+ }
+
+ rdn->ptr = dn.ptr;
+
+ /* are there any RDNs ? */
+ *next = rdn->len > 0;
+
+ return SUCCESS;
+}
+
+/**
+ * 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)
+{
+ chunk_t body;
+
+ /* initialize return values */
+ *oid = CHUNK_INITIALIZER;
+ *value = CHUNK_INITIALIZER;
+
+ /* if all attributes have been parsed, get next rdn */
+ if (attribute->len <= 0)
+ {
+ /* an RDN is a SET OF attributeTypeAndValue */
+ if (*rdn->ptr != ASN1_SET)
+ {
+ /* RDN is not a SET */
+ return FAILED;
+ }
+ attribute->len = asn1_length(rdn);
+ if (attribute->len == ASN1_INVALID_LENGTH)
+ {
+ /* Invalid attribute length */
+ return FAILED;
+ }
+ attribute->ptr = rdn->ptr;
+ /* advance to start of next RDN */
+ rdn->ptr += attribute->len;
+ rdn->len -= attribute->len;
+ }
+
+ /* an attributeTypeAndValue is a SEQUENCE */
+ if (*attribute->ptr != ASN1_SEQUENCE)
+ {
+ /* attributeTypeAndValue is not a SEQUENCE */
+ return FAILED;
+ }
+
+ /* extract the attribute body */
+ body.len = asn1_length(attribute);
+
+ if (body.len == ASN1_INVALID_LENGTH)
+ {
+ /* Invalid attribute body length */
+ return FAILED;
+ }
+
+ body.ptr = attribute->ptr;
+
+ /* advance to start of next attribute */
+ attribute->ptr += body.len;
+ attribute->len -= body.len;
+
+ /* attribute type is an OID */
+ if (*body.ptr != ASN1_OID)
+ {
+ /* attributeType is not an OID */
+ return FAILED;
+ }
+ /* extract OID */
+ oid->len = asn1_length(&body);
+
+ if (oid->len == ASN1_INVALID_LENGTH)
+ {
+ /* Invalid attribute OID length */
+ return FAILED;
+ }
+ oid->ptr = body.ptr;
+
+ /* advance to the attribute value */
+ body.ptr += oid->len;
+ body.len -= oid->len;
+
+ /* extract string type */
+ *type = *body.ptr;
+
+ /* extract string value */
+ value->len = asn1_length(&body);
+
+ if (value->len == ASN1_INVALID_LENGTH)
+ {
+ /* Invalid attribute string length */
+ return FAILED;
+ }
+ value->ptr = body.ptr;
+
+ /* are there any RDNs left? */
+ *next = rdn->len > 0 || attribute->len > 0;
+ return SUCCESS;
+}
+
+/**
+ * Parses an ASN.1 distinguished name int its OID/value pairs
+ */
+static status_t dntoa(chunk_t dn, chunk_t *str)
+{
+ chunk_t rdn, oid, attribute, value;
+ asn1_t type;
+ int oid_code;
+ bool next;
+ bool first = TRUE;
+
+ status_t status = init_rdn(dn, &rdn, &attribute, &next);
+
+ if (status != SUCCESS)
+ {/* a parsing error has occured */
+ return status;
+ }
+
+ while (next)
+ {
+ status = get_next_rdn(&rdn, &attribute, &oid, &value, &type, &next);
+
+ if (status != SUCCESS)
+ {/* a parsing error has occured */
+ return status;
+ }
+
+ if (first)
+ { /* first OID/value pair */
+ first = FALSE;
+ }
+ else
+ { /* separate OID/value pair by a comma */
+ update_chunk(str, snprintf(str->ptr,str->len,", "));
+ }
+
+ /* print OID */
+ oid_code = known_oid(oid);
+ if (oid_code == OID_UNKNOWN)
+ { /* OID not found in list */
+ hex_str(oid, str);
+ }
+ else
+ {
+ update_chunk(str, snprintf(str->ptr,str->len,"%s", oid_names[oid_code].name));
+ }
+ /* print value */
+ update_chunk(str, snprintf(str->ptr,str->len,"=%.*s", (int)value.len,value.ptr));
+ }
+ return SUCCESS;
+}
+
+/**
+ * compare two distinguished names by
+ * comparing the individual RDNs
+ */
+static bool same_dn(chunk_t a, chunk_t b)
+{
+ chunk_t rdn_a, rdn_b, attribute_a, attribute_b;
+ chunk_t oid_a, oid_b, value_a, value_b;
+ asn1_t type_a, type_b;
+ bool next_a, next_b;
+
+ /* same lengths for the DNs */
+ if (a.len != b.len)
+ {
+ return FALSE;
+ }
+ /* try a binary comparison first */
+ if (memcmp(a.ptr, b.ptr, b.len) == 0)
+ {
+ 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)
+ {
+ return FALSE;
+ }
+
+ /* fetch next RDN pair */
+ 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)
+ {
+ 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;
+ }
+ /* 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 (strncasecmp(value_a.ptr, value_b.ptr, value_b.len) != 0)
+ {
+ return FALSE;
+ }
+ }
+ else
+ {
+ if (strncmp(value_a.ptr, value_b.ptr, value_b.len) != 0)
+ {
+ return FALSE;
+ }
+ }
+ }
+ /* both DNs must have same number of RDNs */
+ if (next_a || next_b)
+ return FALSE;
+
+ /* the two DNs are equal! */
+ return TRUE;
+}
+
+
+/**
+ * compare two distinguished names by comparing the individual RDNs.
+ * A single'*' character designates a wildcard RDN in DN b.
+ * TODO: Add support for different RDN order in DN !!
+ */
+bool match_dn(chunk_t a, chunk_t b, int *wildcards)
+{
+ chunk_t rdn_a, rdn_b, attribute_a, attribute_b;
+ chunk_t oid_a, oid_b, value_a, value_b;
+ asn1_t type_a, type_b;
+ bool next_a, next_b;
+
+ /* initialize wildcard counter */
+ *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)
+ {
+ return FALSE;
+ }
+ /* fetch next RDN pair */
+ 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)
+ {
+ 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 == '*')
+ {
+ (*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 (strncasecmp(value_a.ptr, value_b.ptr, value_b.len) != 0)
+ {
+ return FALSE;
+ }
+ }
+ else
+ {
+ if (strncmp(value_a.ptr, value_b.ptr, value_b.len) != 0)
+ {
+ return FALSE;
+ }
+ }
+ }
+ /* both DNs must have same number of RDNs */
+ if (next_a || next_b)
+ {
+ return FALSE;
+ }
+ /* the two DNs match! */
+ return TRUE;
+}
+
+/**
+ * get string representation of a general name
+ * TODO: Add support for gn types
+ */
+static char *gntoa(chunk_t blob)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ int objectID = 0;
+ u_int level;
+ char buf[128];
+
+ asn1_init(&ctx, blob, 0, FALSE);
+
+ while (objectID < GN_OBJ_ROOF)
+ {
+ if (!extract_object(generalNameObjects, &objectID, &object, &level, &ctx))
+ {
+ return NULL;
+ }
+ switch (objectID)
+ {
+ case GN_OBJ_RFC822_NAME:
+ case GN_OBJ_DNS_NAME:
+ case GN_OBJ_URI:
+ snprintf(buf, sizeof(buf), "%.*s", object.len, object.ptr);
+ return strdup(buf);
+ case GN_OBJ_IP_ADDRESS:
+ if (object.len == 4 &&
+ inet_ntop(AF_INET, object.ptr, buf, sizeof(buf)))
+ {
+ return strdup(buf);
+ }
+ return NULL;
+ break;
+ case GN_OBJ_OTHER_NAME:
+ return strdup("(other name)");
+ case GN_OBJ_X400_ADDRESS:
+ return strdup("(X400 Address)");
+ case GN_OBJ_EDI_PARTY_NAME:
+ return strdup("(EDI party name)");
+ case GN_OBJ_REGISTERED_ID:
+ return strdup("(registered ID)");
+ case GN_OBJ_DIRECTORY_NAME:
+ return strdup("(directory name)");
+ default:
+ break;
+ }
+ objectID++;
+ }
+ return NULL;
+}
+
+/**
+ * Converts an LDAP-style human-readable ASCII-encoded
+ * ASN.1 distinguished name into binary DER-encoded format
+ */
+static status_t atodn(char *src, chunk_t *dn)
+{
+ /* finite state machine for atodn */
+ typedef enum {
+ SEARCH_OID = 0,
+ READ_OID = 1,
+ SEARCH_NAME = 2,
+ READ_NAME = 3,
+ UNKNOWN_OID = 4
+ } state_t;
+
+ char *wrap_mode;
+ chunk_t oid = CHUNK_INITIALIZER;
+ chunk_t name = CHUNK_INITIALIZER;
+ chunk_t names[25]; /* max to 25 rdns */
+ int name_count = 0;
+ int whitespace = 0;
+ int pos = 0;
+ asn1_t rdn_type;
+ state_t state = SEARCH_OID;
+ status_t status = SUCCESS;
+
+ do
+ {
+ switch (state)
+ {
+ case SEARCH_OID:
+ if (*src != ' ' && *src != '/' && *src != ',')
+ {
+ oid.ptr = src;
+ oid.len = 1;
+ state = READ_OID;
+ }
+ break;
+ case READ_OID:
+ if (*src != ' ' && *src != '=')
+ {
+ oid.len++;
+ }
+ else
+ {
+ for (pos = 0; pos < X501_RDN_ROOF; pos++)
+ {
+ if (strlen(x501rdns[pos].name) == oid.len &&
+ strncasecmp(x501rdns[pos].name, oid.ptr, oid.len) == 0)
+ {
+ break; /* found a valid OID */
+ }
+ }
+ if (pos == X501_RDN_ROOF)
+ {
+ status = NOT_SUPPORTED;
+ state = UNKNOWN_OID;
+ break;
+ }
+ /* reset oid and change state */
+ oid = CHUNK_INITIALIZER;
+ state = SEARCH_NAME;
+ }
+ break;
+ case SEARCH_NAME:
+ if (*src != ' ' && *src != '=')
+ {
+ name.ptr = src;
+ name.len = 1;
+ whitespace = 0;
+ state = READ_NAME;
+ }
+ break;
+ case READ_NAME:
+ if (*src != ',' && *src != '/' && *src != '\0')
+ {
+ name.len++;
+ if (*src == ' ')
+ {
+ whitespace++;
+ }
+ else
+ {
+ whitespace = 0;
+ }
+ }
+ else
+ {
+ name.len -= whitespace;
+ rdn_type = (x501rdns[pos].type == ASN1_PRINTABLESTRING
+ && !is_printablestring(name))? ASN1_T61STRING : x501rdns[pos].type;
+
+ if (name_count < 25)
+ {
+ names[name_count++] =
+ asn1_wrap(ASN1_SET, "m",
+ asn1_wrap(ASN1_SEQUENCE, "mm",
+ asn1_wrap(ASN1_OID, "c", x501rdns[pos].oid),
+ asn1_wrap(rdn_type, "c", name)
+ )
+ );
+ }
+ else
+ {
+ status = OUT_OF_RES;
+ }
+ /* reset name and change state */
+ name = CHUNK_INITIALIZER;
+ state = SEARCH_OID;
+ }
+ break;
+ case UNKNOWN_OID:
+ break;
+ }
+ } while (*src++ != '\0');
+
+
+ /* build the distinguished name sequence */
+ wrap_mode = alloca(26);
+ memset(wrap_mode, 0, 26);
+ memset(wrap_mode, 'm', name_count);
+ *dn = asn1_wrap(ASN1_SEQUENCE, wrap_mode,
+ names[0], names[1], names[2], names[3], names[4],
+ names[5], names[6], names[7], names[8], names[9],
+ names[10], names[11], names[12], names[13], names[14],
+ names[15], names[16], names[17], names[18], names[19],
+ names[20], names[21], names[22], names[23], names[24]);
+ if (status != SUCCESS)
+ {
+ free(dn->ptr);
+ *dn = CHUNK_INITIALIZER;
+ }
+ return status;
+}
+
+/**
+ * Implementation of identification_t.get_encoding.
+ */
+static chunk_t get_encoding(private_identification_t *this)
+{
+ return this->encoded;
+}
+
+/**
+ * Implementation of identification_t.get_type.
+ */
+static id_type_t get_type(private_identification_t *this)
+{
+ return this->type;
+}
+
+/**
+ * Implementation of identification_t.get_string.
+ */
+static char *get_string(private_identification_t *this)
+{
+ return this->string;
+}
+
+/**
+ * Implementation of identification_t.contains_wildcards.
+ */
+static bool contains_wildcards(private_identification_t *this)
+{
+ if (this->type == ID_ANY ||
+ memchr(this->encoded.ptr, '*', this->encoded.len) != NULL)
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * Default implementation of identification_t.equals and identification_t.belongs_to.
+ * compares encoded chunk for equality.
+ */
+static bool equals_binary(private_identification_t *this,private_identification_t *other)
+{
+ if (this->type == other->type)
+ {
+ if (this->encoded.len == other->encoded.len &&
+ memcmp(this->encoded.ptr, other->encoded.ptr, this->encoded.len) == 0)
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ * Special implementation of identification_t.equals for ID_DER_ASN1_DN
+ */
+static bool equals_dn(private_identification_t *this, private_identification_t *other)
+{
+ return same_dn(this->encoded, other->encoded);
+}
+
+/**
+ * Special implementation of identification_t.belongs_to for ID_RFC822_ADDR/ID_FQDN.
+ * checks for a wildcard in other-string, and compares it against this-string.
+ */
+static bool belongs_to_wc_string(private_identification_t *this, private_identification_t *other)
+{
+ char *this_str, *other_str, *pos;
+
+ if (other->type == ID_ANY)
+ {
+ return TRUE;
+ }
+
+ if (this->type == other->type)
+ {
+ /* try a binary comparison first */
+ if (equals_binary(this, other))
+ {
+ return TRUE;
+ }
+ }
+ if (other->encoded.len > 0 &&
+ *(other->encoded.ptr) == '*')
+ {
+ if (other->encoded.len == 1)
+ {
+ /* other contains just a wildcard, and therefore matches anything */
+ return TRUE;
+ }
+ /* We strdup chunks, since they are NOT null-terminated */
+ this_str = strndupa(this->encoded.ptr, this->encoded.len);
+ other_str = strndupa(other->encoded.ptr + 1, other->encoded.len - 1);
+ pos = strstr(this_str, other_str);
+ if (pos != NULL)
+ {
+ /* ok, other is contained in this, but there may be more characters, so check it */
+ if (strlen(pos) == strlen(other_str))
+ {
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ * Special implementation of identification_t.belongs_to for ID_ANY.
+ * ANY matches only another ANY, but nothing other
+ */
+static bool belongs_to_any(private_identification_t *this, private_identification_t *other)
+{
+ if (other->type == ID_ANY)
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * Special implementation of identification_t.belongs_to for ID_DER_ASN1_DN.
+ * ANY matches any, even ANY, thats why its there...
+ */
+static bool belongs_to_dn(private_identification_t *this, private_identification_t *other)
+{
+ int wildcards;
+
+ if (other->type == ID_ANY)
+ {
+ return TRUE;
+ }
+
+ if (this->type == other->type)
+ {
+ return match_dn(this->encoded, other->encoded, &wildcards);
+ }
+ return FALSE;
+}
+
+/**
+ * Implementation of identification_t.clone.
+ */
+static identification_t *clone(private_identification_t *this)
+{
+ private_identification_t *clone = identification_create();
+
+ clone->type = this->type;
+ clone->encoded = chunk_clone(this->encoded);
+ clone->string = malloc(strlen(this->string) + 1);
+ strcpy(clone->string, this->string);
+
+ return &clone->public;
+}
+
+/**
+ * Implementation of identification_t.destroy.
+ */
+static void destroy(private_identification_t *this)
+{
+ free(this->string);
+ free(this->encoded.ptr);
+ free(this);
+}
+
+/**
+ * Generic constructor used for the other constructors.
+ */
+static private_identification_t *identification_create()
+{
+ private_identification_t *this = malloc_thing(private_identification_t);
+
+ this->public.get_encoding = (chunk_t (*) (identification_t*))get_encoding;
+ this->public.get_type = (id_type_t (*) (identification_t*))get_type;
+ this->public.get_string = (char* (*) (identification_t*))get_string;
+ this->public.contains_wildcards = (bool (*) (identification_t *this))contains_wildcards;
+ this->public.clone = (identification_t* (*) (identification_t*))clone;
+ 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.belongs_to = (bool (*) (identification_t*,identification_t*))equals_binary;
+
+ this->string = NULL;
+ this->encoded = CHUNK_INITIALIZER;
+
+ return this;
+}
+
+/*
+ * Described in header.
+ */
+identification_t *identification_create_from_string(char *string)
+{
+ private_identification_t *this = identification_create();
+
+ if (strchr(string, '=') != NULL)
+ {
+ /* we interpret this as an ASCII X.501 ID_DER_ASN1_DN.
+ * convert from LDAP style or openssl x509 -subject style to ASN.1 DN
+ * discard optional @ character in front of DN
+ */
+ if (atodn((*string == '@') ? string + 1 : string, &this->encoded) != SUCCESS)
+ {
+ free(this);
+ return NULL;
+ }
+ this->string = strdup(string);
+ this->type = ID_DER_ASN1_DN;
+ this->public.equals = (bool (*) (identification_t*,identification_t*))equals_dn;
+ this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_dn;
+ return &this->public;
+ }
+ else if (strchr(string, '@') == NULL)
+ {
+ if (strcmp(string, "%any") == 0 ||
+ strcmp(string, "0.0.0.0") == 0 ||
+ strcmp(string, "*") == 0 ||
+ strcmp(string, "::") == 0||
+ strcmp(string, "0::0") == 0)
+ {
+ /* any ID will be accepted */
+ this->type = ID_ANY;
+ this->string = strdup("%any");
+ this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_any;
+ return &this->public;
+ }
+ else
+ {
+ /* TODO: Pluto resolve domainnames without '@' to IPv4/6 address. Is this really needed? */
+
+ if (strchr(string, ':') == NULL)
+ {
+ /* try IPv4 */
+ struct in_addr address;
+ chunk_t chunk = {(void*)&address, sizeof(address)};
+
+ if (inet_pton(AF_INET, string, &address) <= 0)
+ {
+ free(this);
+ return NULL;
+ }
+ this->encoded = chunk_clone(chunk);
+ this->string = strdup(string);
+ this->type = ID_IPV4_ADDR;
+ return &(this->public);
+ }
+ else
+ {
+ /* try IPv6 */
+ struct in6_addr address;
+ chunk_t chunk = {(void*)&address, sizeof(address)};
+
+ if (inet_pton(AF_INET6, string, &address) <= 0)
+ {
+ free(this);
+ return NULL;
+ }
+ this->encoded = chunk_clone(chunk);
+ this->string = strdup(string);
+ this->type = ID_IPV6_ADDR;
+ return &(this->public);
+ }
+ }
+ }
+ else
+ {
+ if (*string == '@')
+ {
+ if (*(string + 1) == '#')
+ {
+ /* TODO: Pluto handles '#' as hex encoded ASN1/KEY ID. Do we need this, too? */
+ free(this);
+ return NULL;
+ }
+ else
+ {
+ this->type = ID_FQDN;
+ this->string = strdup(string + 1); /* discard @ */
+ this->encoded.ptr = strdup(string + 1);
+ this->encoded.len = strlen(string + 1);
+ this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_wc_string;
+ return &(this->public);
+ }
+ }
+ else
+ {
+ this->type = ID_RFC822_ADDR;
+ this->string = strdup(string);
+ this->encoded.ptr = strdup(string);
+ this->encoded.len = strlen(string);
+ this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_wc_string;
+ return &(this->public);
+ }
+ }
+}
+
+/*
+ * Described in header.
+ */
+identification_t *identification_create_from_encoding(id_type_t type, chunk_t encoded)
+{
+ private_identification_t *this = identification_create();
+ char buf[256];
+ chunk_t buf_chunk = chunk_from_buf(buf);
+ char *pos;
+
+ this->type = type;
+ switch (type)
+ {
+ case ID_ANY:
+ this->string = strdup("%any");
+ this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_any;
+ break;
+ case ID_IPV4_ADDR:
+ if (encoded.len < sizeof(struct in_addr) ||
+ inet_ntop(AF_INET, encoded.ptr, buf, sizeof(buf)) == NULL)
+ {
+ this->string = strdup("(invalid ID_IPV4_ADDR)");
+ }
+ else
+ {
+ this->string = strdup(buf);
+ }
+ break;
+ case ID_IPV6_ADDR:
+ if (encoded.len < sizeof(struct in6_addr) ||
+ inet_ntop(AF_INET6, encoded.ptr, buf, INET6_ADDRSTRLEN) == NULL)
+ {
+ this->string = strdup("(invalid ID_IPV6_ADDR)");
+ }
+ else
+ {
+ this->string = strdup(buf);
+ }
+ break;
+ case ID_FQDN:
+ snprintf(buf, sizeof(buf), "@%.*s", encoded.len, encoded.ptr);
+ this->string = strdup(buf);
+ this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_wc_string;
+ break;
+ case ID_RFC822_ADDR:
+ snprintf(buf, sizeof(buf), "%.*s", encoded.len, encoded.ptr);
+ this->string = strdup(buf);
+ this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_wc_string;
+ break;
+ case ID_DER_ASN1_DN:
+ snprintf(buf, sizeof(buf), "%.*s", encoded.len, encoded.ptr);
+ /* TODO: whats returned on failure */
+ dntoa(encoded, &buf_chunk);
+ this->string = strdup(buf);
+ this->public.equals = (bool (*) (identification_t*,identification_t*))equals_dn;
+ this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_dn;
+ break;
+ case ID_DER_ASN1_GN:
+ this->string = gntoa(encoded);
+ break;
+ case ID_KEY_ID:
+ this->string = strdup("(unparsed KEY_ID)");
+ break;
+ default:
+ snprintf(buf, sizeof(buf), "(invalid ID type: %d)", type);
+ this->string = strdup(buf);
+ break;
+ }
+
+ /* apply encoded chunk */
+ if (type != ID_ANY)
+ {
+ this->encoded = chunk_clone(encoded);
+ }
+
+ /* remove unprintable chars in string */
+ for (pos = this->string; *pos != '\0'; pos++)
+ {
+ if (!isprint(*pos))
+ {
+ *pos = '?';
+ }
+ }
+ return &(this->public);
+}
diff --git a/programs/charon/lib/utils/identification.h b/programs/charon/lib/utils/identification.h
new file mode 100644
index 000000000..309b6858c
--- /dev/null
+++ b/programs/charon/lib/utils/identification.h
@@ -0,0 +1,245 @@
+/**
+ * @file identification.h
+ *
+ * @brief Interface of identification_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#ifndef IDENTIFICATION_H_
+#define IDENTIFICATION_H_
+
+
+#include "types.h"
+
+typedef enum id_type_t id_type_t;
+
+/**
+ * @brief ID Types in a ID payload.
+ *
+ * @ingroup utils
+ */
+enum id_type_t {
+
+ /**
+ * ID data is a single four (4) octet IPv4 address.
+ */
+ ID_IPV4_ADDR = 1,
+
+ /**
+ * ID data is a fully-qualified domain name string.
+ * An example of a ID_FQDN is, "example.com".
+ * The string MUST not contain any terminators (e.g., NULL, CR, etc.).
+ */
+ ID_FQDN = 2,
+
+ /**
+ * ID data is a fully-qualified RFC822 email address string, An example of
+ * a ID_RFC822_ADDR is, "jsmith@example.com". The string MUST
+ * not contain any terminators.
+ */
+ ID_RFC822_ADDR = 3,
+
+ /**
+ * ID data is a single sixteen (16) octet IPv6 address.
+ */
+ ID_IPV6_ADDR = 5,
+
+ /**
+ * ID data is the binary DER encoding of an ASN.1 X.500 Distinguished Name
+ * [X.501].
+ */
+ ID_DER_ASN1_DN = 9,
+
+ /**
+ * ID data is the binary DER encoding of an ASN.1 X.500 GeneralName
+ * [X.509].
+ */
+ ID_DER_ASN1_GN = 10,
+
+ /**
+ * ID data is an opaque octet stream which may be used to pass vendor-
+ * specific information necessary to do certain proprietary
+ * types of identification.
+ */
+ ID_KEY_ID = 11,
+
+ /**
+ * Special type of PRIVATE USE which matches to any other id.
+ */
+ ID_ANY = 201,
+};
+
+/**
+ * String mappings for id_type_t.
+ */
+extern mapping_t id_type_m[];
+
+typedef struct identification_t identification_t;
+
+/**
+ * @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
+ *
+ * @b Constructors:
+ * - identification_create_from_string()
+ * - identification_create_from_encoding()
+ *
+ * @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
+ * the network.
+ *
+ * @warning 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.
+ *
+ * @param this the identification_t object
+ * @return id_type_t
+ */
+ id_type_t (*get_type) (identification_t *this);
+
+ /**
+ * @brief Get a string representation of this id.
+ *
+ * @warning Result points to internal data, do NOT free!
+ *
+ * @param this the identification_t object
+ * @return string
+ */
+ char *(*get_string) (identification_t *this);
+
+ /**
+ * @brief 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 belongs to 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
+ * - IDs are identical
+ * - other is of type ID_ANY
+ * - other contains a wildcard and matches this
+ *
+ * @param this the ID without wildcard
+ * @param other the ID containing a wildcard
+ * @return TRUE if other belongs to this
+ */
+ bool (*belongs_to) (identification_t *this, identification_t *other);
+
+ /**
+ * @brief 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.
+ *
+ * @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
+ */
+ 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.
+ *
+ * The input string may be e.g. one of the following:
+ * - ID_IPV4_ADDR: 192.168.0.1
+ * - ID_IPV6_ADDR: 2001:0db8:85a3:08d3:1319:8a2e:0370:7345
+ * - ID_FQDN: @www.strongswan.org (@indicates FQDN)
+ * - ID_RFC822_ADDR: alice@wonderland.org
+ * - ID_DER_ASN1_DN: C=CH, O=Linux strongSwan, CN=bob
+ *
+ * In favour of pluto, domainnames are prepended with an @, since
+ * pluto resolves domainnames without an @ to IPv4 addresses. Since
+ * we use a seperate host_t class for addresses, this doesn't
+ * make sense for us.
+ *
+ * A distinguished name may contain one or more of the following RDNs:
+ * 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
+ */
+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
+ *
+ * In contrast to identification_create_from_string(), this constructor never
+ * returns NULL, even when the conversion to a sring representation fails.
+ *
+ * @ingroup utils
+ */
+identification_t * identification_create_from_encoding(id_type_t type, chunk_t encoded);
+
+
+#endif /* IDENTIFICATION_H_ */
diff --git a/programs/charon/lib/utils/iterator.h b/programs/charon/lib/utils/iterator.h
new file mode 100644
index 000000000..de81db8e9
--- /dev/null
+++ b/programs/charon/lib/utils/iterator.h
@@ -0,0 +1,153 @@
+/**
+ * @file iterator.h
+ *
+ * @brief Interface iterator_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef ITERATOR_H_
+#define ITERATOR_H_
+
+typedef struct iterator_t iterator_t;
+
+/**
+ * @brief Iterator interface, allows iteration over collections.
+ *
+ * iterator_t defines an interface for iterating over collections.
+ * It allows searching, deleting, updating and inserting.
+ *
+ * Thanks to JMP for iterator lessons :-)
+ *
+ * @b Constructors:
+ * - via linked_list_t.create_iterator, or
+ * - any other class which supports the iterator_t interface
+ *
+ * @see linked_list_t
+ *
+ * @ingroup utils
+ */
+struct iterator_t {
+
+ /**
+ * @brief Iterate over all items.
+ *
+ * The easy way to iterate over items.
+ *
+ * @param this calling object
+ * @param[out] value item
+ * @return
+ * - TRUE, if more elements are avaiable,
+ * - FALSE otherwise
+ */
+ bool (*iterate) (iterator_t *this, void** value);
+
+ /**
+ * @brief Moves to the next element, if available.
+ *
+ * A newly created iterator_t object doesn't point to any item.
+ * Call iterator_t.has_next first to point it to the first item.
+ *
+ * @param this calling object
+ * @return
+ * - TRUE, if more elements are avaiable,
+ * - FALSE otherwise
+ */
+ bool (*has_next) (iterator_t *this);
+
+ /**
+ * @brief Returns the current value at the iterator position.
+ *
+ * @param this calling object
+ * @param[out] value value is set to the current value at iterator position
+ * @return
+ * - SUCCESS
+ * - FAILED if iterator on an invalid position
+ */
+ status_t (*current) (iterator_t *this, void **value);
+
+ /**
+ * @brief 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
+ */
+ void (*insert_before) (iterator_t *this, void *item);
+
+ /**
+ * @brief 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
+ */
+ void (*insert_after) (iterator_t *this, void *item);
+
+ /**
+ * @brief 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
+ */
+ status_t (*replace) (iterator_t *this, void **old_item, void *new_item);
+
+ /**
+ * @brief Removes an element from list at the given iterator position.
+ *
+ * The position of the iterator is set in the following order:
+ * - to the item before, if available
+ * - otherwise to the item after, if available
+ * - otherwise it gets reseted
+ *
+ * @param linked_list calling object
+ * @return
+ * - SUCCESS
+ * - FAILED if iterator is on an invalid position
+ */
+ status_t (*remove) (iterator_t *iterator);
+
+ /**
+ * @brief 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
+ *
+ */
+ void (*destroy) (iterator_t *this);
+};
+
+#endif /*ITERATOR_H_*/
diff --git a/programs/charon/lib/utils/leak_detective.c b/programs/charon/lib/utils/leak_detective.c
new file mode 100644
index 000000000..780ba4c05
--- /dev/null
+++ b/programs/charon/lib/utils/leak_detective.c
@@ -0,0 +1,540 @@
+/**
+ * @file leak_detective.c
+ *
+ * @brief Allocation hooks to find memory leaks.
+ */
+
+/*
+ * Copyright (C) 2006 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <execinfo.h>
+#include <signal.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <dlfcn.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <pthread.h>
+
+#include "leak_detective.h"
+
+#include <types.h>
+#include <utils/logger_manager.h>
+
+#ifdef LEAK_DETECTIVE
+
+/**
+ * Magic value which helps to detect memory corruption
+ */
+#define MEMORY_HEADER_MAGIC 0xF1367ADF
+
+static void install_hooks(void);
+static void uninstall_hooks(void);
+static void *malloc_hook(size_t, const void *);
+static void *realloc_hook(void *, size_t, const void *);
+static void free_hook(void*, const void *);
+static void load_excluded_functions();
+
+typedef struct memory_header_t memory_header_t;
+
+/**
+ * Header which is prepended to each allocated memory block
+ */
+struct memory_header_t {
+ /**
+ * Magci byte which must(!) hold MEMORY_HEADER_MAGIC
+ */
+ u_int32_t magic;
+
+ /**
+ * Number of bytes following after the header
+ */
+ size_t bytes;
+
+ /**
+ * Stack frames at the time of allocation
+ */
+ void *stack_frames[STACK_FRAMES_COUNT];
+
+ /**
+ * Number of stacks frames obtained in stack_frames
+ */
+ int stack_frame_count;
+
+ /**
+ * Pointer to previous entry in linked list
+ */
+ memory_header_t *previous;
+
+ /**
+ * Pointer to next entry in linked list
+ */
+ memory_header_t *next;
+};
+
+/**
+ * first mem header is just a dummy to chain
+ * the others on it...
+ */
+static memory_header_t first_header = {
+ magic: MEMORY_HEADER_MAGIC,
+ bytes: 0,
+ stack_frame_count: 0,
+ previous: NULL,
+ next: NULL
+};
+
+/**
+ * logger for the leak detective
+ */
+static logger_t *logger;
+
+/**
+ * standard hooks, used to temparily remove hooking
+ */
+static void *old_malloc_hook, *old_realloc_hook, *old_free_hook;
+
+/**
+ * are the hooks currently installed?
+ */
+static bool installed = FALSE;
+
+/**
+ * Mutex to exclusivly uninstall hooks, access heap list
+ */
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+
+/**
+ * log stack frames queried by backtrace()
+ * TODO: Dump symbols of static functions!!!
+ */
+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);
+
+ logger->log(logger, ERROR, " dumping %d stack frame addresses.", stack_frame_count);
+
+ for (i = 0; i < stack_frame_count; i++)
+ {
+ logger->log(logger, ERROR, " %s", strings[i]);
+ }
+ free (strings);
+}
+
+/**
+ * Report leaks at library destruction
+ */
+void report_leaks()
+{
+ memory_header_t *hdr;
+ int leaks = 0;
+
+ /* reaquire a logger is necessary, this will force ((destructor))
+ * order to work correctly */
+ logger = logger_manager->get_logger(logger_manager, LEAK_DETECT);
+ for (hdr = first_header.next; hdr != NULL; hdr = hdr->next)
+ {
+ logger->log(logger, ERROR, "Leak (%d bytes at %p)", hdr->bytes, hdr + 1);
+ log_stack_frames(hdr->stack_frames, hdr->stack_frame_count);
+ leaks++;
+ }
+
+ switch (leaks)
+ {
+ case 0:
+ logger->log(logger, CONTROL, "No leaks detected");
+ break;
+ case 1:
+ logger->log(logger, ERROR, "One leak detected");
+ break;
+ default:
+ logger->log(logger, ERROR, "%d leaks detected", leaks);
+ break;
+ }
+}
+
+/**
+ * Installs the malloc hooks, enables leak detection
+ */
+static void install_hooks()
+{
+ if (!installed)
+ {
+ old_malloc_hook = __malloc_hook;
+ old_realloc_hook = __realloc_hook;
+ old_free_hook = __free_hook;
+ __malloc_hook = malloc_hook;
+ __realloc_hook = realloc_hook;
+ __free_hook = free_hook;
+ installed = TRUE;
+ }
+}
+
+/**
+ * Uninstalls the malloc hooks, disables leak detection
+ */
+static void uninstall_hooks()
+{
+ if (installed)
+ {
+ __malloc_hook = old_malloc_hook;
+ __free_hook = old_free_hook;
+ __realloc_hook = old_realloc_hook;
+ installed = FALSE;
+ }
+}
+
+/**
+ * Hook function for malloc()
+ */
+void *malloc_hook(size_t bytes, const void *caller)
+{
+ memory_header_t *hdr;
+
+ pthread_mutex_lock(&mutex);
+ uninstall_hooks();
+ hdr = malloc(bytes + sizeof(memory_header_t));
+
+ hdr->magic = MEMORY_HEADER_MAGIC;
+ hdr->bytes = bytes;
+ hdr->stack_frame_count = backtrace(hdr->stack_frames, STACK_FRAMES_COUNT);
+
+ /* insert at the beginning of the list */
+ hdr->next = first_header.next;
+ if (hdr->next)
+ {
+ hdr->next->previous = hdr;
+ }
+ hdr->previous = &first_header;
+ first_header.next = hdr;
+ install_hooks();
+ pthread_mutex_unlock(&mutex);
+ return hdr + 1;
+}
+
+/**
+ * Hook function for free()
+ */
+void free_hook(void *ptr, const void *caller)
+{
+ void *stack_frames[STACK_FRAMES_COUNT];
+ int stack_frame_count;
+ memory_header_t *hdr = ptr - sizeof(memory_header_t);
+
+ /* allow freeing of NULL */
+ if (ptr == NULL)
+ {
+ return;
+ }
+
+ pthread_mutex_lock(&mutex);
+ if (hdr->magic != MEMORY_HEADER_MAGIC)
+ {
+ pthread_mutex_unlock(&mutex);
+ /* TODO: since pthread_join cannot be excluded cleanly, we are not whining about bad frees */
+ return;
+ logger->log(logger, ERROR, "freeing of invalid memory (%p)", ptr);
+ stack_frame_count = backtrace(stack_frames, STACK_FRAMES_COUNT);
+ log_stack_frames(stack_frames, stack_frame_count);
+ return;
+ }
+ /* remove magic from hdr */
+ hdr->magic = 0;
+
+ /* remove item from list */
+ if (hdr->next)
+ {
+ hdr->next->previous = hdr->previous;
+ }
+ hdr->previous->next = hdr->next;
+
+ uninstall_hooks();
+ free(hdr);
+ install_hooks();
+ pthread_mutex_unlock(&mutex);
+}
+
+/**
+ * Hook function for realloc()
+ */
+void *realloc_hook(void *old, size_t bytes, const void *caller)
+{
+ void *new;
+ memory_header_t *hdr = old - sizeof(memory_header_t);
+ void *stack_frames[STACK_FRAMES_COUNT];
+ int stack_frame_count;
+
+ /* allow reallocation of NULL */
+ if (old == NULL)
+ {
+ return malloc_hook(bytes, caller);
+ }
+ if (hdr->magic != MEMORY_HEADER_MAGIC)
+ {
+ logger->log(logger, ERROR, "reallocation of invalid memory (%p)", old);
+ stack_frame_count = backtrace(stack_frames, STACK_FRAMES_COUNT);
+ log_stack_frames(stack_frames, stack_frame_count);
+ kill(getpid(), SIGKILL);
+ return NULL;
+ }
+
+ /* malloc and free is done with hooks */
+ new = malloc_hook(bytes, caller);
+ memcpy(new, old, min(bytes, hdr->bytes));
+ free_hook(old, caller);
+
+ return new;
+}
+
+
+/**
+ * Setup leak detective
+ */
+void leak_detective_init()
+{
+ logger = logger_manager->get_logger(logger_manager, LEAK_DETECT);
+ load_excluded_functions();
+ install_hooks();
+}
+
+/**
+ * Clean up leak detective
+ */
+void leak_detective_cleanup()
+{
+ uninstall_hooks();
+ report_leaks();
+}
+
+
+/**
+ * The following glibc functions are excluded from leak detection, since
+ * they use static allocated buffers or other ugly allocation hacks.
+ * For this to work, the linker must link libstrongswan preferred to
+ * the other (overriden) libs.
+ */
+struct excluded_function {
+ char *lib_name;
+ char *function_name;
+ void *handle;
+ void *lib_function;
+} excluded_functions[] = {
+ {"libc.so.6", "inet_ntoa", NULL, NULL},
+ {"libpthread.so.0", "pthread_create", NULL, NULL},
+ {"libpthread.so.0", "pthread_cancel", NULL, NULL},
+ {"libpthread.so.0", "pthread_join", NULL, NULL},
+ {"libpthread.so.0", "_pthread_cleanup_push",NULL, NULL},
+ {"libpthread.so.0", "_pthread_cleanup_pop", NULL, NULL},
+ {"libc.so.6", "mktime", NULL, NULL},
+ {"libc.so.6", "vsyslog", NULL, NULL},
+ {"libc.so.6", "strerror", NULL, NULL},
+};
+#define INET_NTOA 0
+#define PTHREAD_CREATE 1
+#define PTHREAD_CANCEL 2
+#define PTHREAD_JOIN 3
+#define PTHREAD_CLEANUP_PUSH 4
+#define PTHREAD_CLEANUP_POP 5
+#define MKTIME 6
+#define VSYSLOG 7
+#define STRERROR 8
+
+
+/**
+ * Load libraries and function pointers for excluded functions
+ */
+static void load_excluded_functions()
+{
+ int i;
+
+ for (i = 0; i < sizeof(excluded_functions)/sizeof(struct excluded_function); i++)
+ {
+ void *handle, *function;
+ handle = dlopen(excluded_functions[i].lib_name, RTLD_LAZY);
+ if (handle == NULL)
+ {
+ kill(getpid(), SIGSEGV);
+ }
+
+ function = dlsym(handle, excluded_functions[i].function_name);
+
+ if (function == NULL)
+ {
+ dlclose(handle);
+ kill(getpid(), SIGSEGV);
+ }
+ excluded_functions[i].handle = handle;
+ excluded_functions[i].lib_function = function;
+ }
+}
+
+char *inet_ntoa(struct in_addr in)
+{
+ char *(*_inet_ntoa)(struct in_addr) = excluded_functions[INET_NTOA].lib_function;
+ char *result;
+
+ pthread_mutex_lock(&mutex);
+ uninstall_hooks();
+
+ result = _inet_ntoa(in);
+
+ install_hooks();
+ pthread_mutex_unlock(&mutex);
+ return result;
+}
+
+int pthread_create(pthread_t *__restrict __threadp, __const pthread_attr_t *__restrict __attr,
+ void *(*__start_routine) (void *), void *__restrict __arg)
+{
+ int (*_pthread_create) (pthread_t *__restrict __threadp,
+ __const pthread_attr_t *__restrict __attr,
+ void *(*__start_routine) (void *),
+ void *__restrict __arg) = excluded_functions[PTHREAD_CREATE].lib_function;
+ int result;
+
+ pthread_mutex_lock(&mutex);
+ uninstall_hooks();
+
+ result = _pthread_create(__threadp, __attr, __start_routine, __arg);
+
+ install_hooks();
+ pthread_mutex_unlock(&mutex);
+ return result;
+}
+
+
+int pthread_cancel(pthread_t __th)
+{
+ int (*_pthread_cancel) (pthread_t) = excluded_functions[PTHREAD_CANCEL].lib_function;
+ int result;
+
+ pthread_mutex_lock(&mutex);
+ uninstall_hooks();
+
+ result = _pthread_cancel(__th);
+
+ install_hooks();
+ pthread_mutex_unlock(&mutex);
+ return result;
+}
+
+// /* TODO: join has probs, since it dellocates memory
+// * allocated (somewhere) with leak_detective :-(.
+// * We should exclude all pthread_ functions to fix it !? */
+// int pthread_join(pthread_t __th, void **__thread_return)
+// {
+// int (*_pthread_join) (pthread_t, void **) = excluded_functions[PTHREAD_JOIN].lib_function;
+// int result;
+//
+// pthread_mutex_lock(&mutex);
+// uninstall_hooks();
+//
+// result = _pthread_join(__th, __thread_return);
+//
+// install_hooks();
+// pthread_mutex_unlock(&mutex);
+// return result;
+// }
+//
+// void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer,
+// void (*__routine) (void *),
+// void *__arg)
+// {
+// int (*__pthread_cleanup_push) (struct _pthread_cleanup_buffer *__buffer,
+// void (*__routine) (void *),
+// void *__arg) =
+// excluded_functions[PTHREAD_CLEANUP_PUSH].lib_function;
+//
+// pthread_mutex_lock(&mutex);
+// uninstall_hooks();
+//
+// __pthread_cleanup_push(__buffer, __routine, __arg);
+//
+// install_hooks();
+// pthread_mutex_unlock(&mutex);
+// return;
+// }
+//
+// void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer, int __execute)
+// {
+// int (*__pthread_cleanup_pop) (struct _pthread_cleanup_buffer *__buffer, int __execute) =
+// excluded_functions[PTHREAD_CLEANUP_POP].lib_function;
+//
+// pthread_mutex_lock(&mutex);
+// uninstall_hooks();
+//
+// __pthread_cleanup_pop(__buffer, __execute);
+//
+// install_hooks();
+// pthread_mutex_unlock(&mutex);
+// return;
+// }
+
+time_t mktime(struct tm *tm)
+{
+ time_t (*_mktime)(struct tm *tm) = excluded_functions[MKTIME].lib_function;
+ time_t result;
+
+ pthread_mutex_lock(&mutex);
+ uninstall_hooks();
+
+ result = _mktime(tm);
+
+ install_hooks();
+ pthread_mutex_unlock(&mutex);
+ return result;
+}
+
+void vsyslog (int __pri, __const char *__fmt, __gnuc_va_list __ap)
+{
+ void (*_vsyslog) (int __pri, __const char *__fmt, __gnuc_va_list __ap) = excluded_functions[VSYSLOG].lib_function;
+
+ pthread_mutex_lock(&mutex);
+ uninstall_hooks();
+
+ _vsyslog(__pri, __fmt, __ap);
+
+ install_hooks();
+ pthread_mutex_unlock(&mutex);
+ return;
+}
+
+
+
+char *strerror(int errnum)
+{
+ char* (*_strerror) (int) = excluded_functions[STRERROR].lib_function;
+ char *result;
+
+ pthread_mutex_lock(&mutex);
+ uninstall_hooks();
+
+ result = _strerror(errnum);
+
+ install_hooks();
+ pthread_mutex_unlock(&mutex);
+ return result;
+}
+
+#endif /* LEAK_DETECTION */
diff --git a/programs/charon/lib/utils/leak_detective.h b/programs/charon/lib/utils/leak_detective.h
new file mode 100644
index 000000000..13c0d01ab
--- /dev/null
+++ b/programs/charon/lib/utils/leak_detective.h
@@ -0,0 +1,50 @@
+/**
+ * @file leak_detective.h
+ *
+ * @brief malloc/free hooks to detect leaks.
+ */
+
+/*
+ * Copyright (C) 2006 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef LEAK_DETECTIVE_H_
+#define LEAK_DETECTIVE_H_
+
+
+#ifdef LEAK_DETECTIVE
+
+/**
+ * Max number of stack frames to include in a backtrace.
+ */
+#define STACK_FRAMES_COUNT 30
+
+/**
+ * Initialize leak detective, activates it
+ */
+void leak_detective_init();
+
+/**
+ * Cleanup leak detective, deactivates it
+ */
+void leak_detective_cleanup();
+
+#else /* !LEAK_DETECTIVE */
+
+#define leak_detective_init() {}
+#define leak_detective_cleanup() {}
+
+#endif /* LEAK_DETECTIVE */
+
+#endif /* LEAK_DETECTIVE_H_ */
diff --git a/programs/charon/lib/utils/linked_list.c b/programs/charon/lib/utils/linked_list.c
new file mode 100644
index 000000000..64443434b
--- /dev/null
+++ b/programs/charon/lib/utils/linked_list.c
@@ -0,0 +1,727 @@
+/**
+ * @file linked_list.c
+ *
+ * @brief Implementation of linked_list_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stdlib.h>
+
+#include "linked_list.h"
+
+
+
+typedef struct linked_list_element_t linked_list_element_t;
+
+/**
+ * @brief Element in a linked list.
+ *
+ * This element holds a pointer to the value it represents.
+ */
+struct linked_list_element_t {
+
+ /**
+ * Value of a list item.
+ */
+ void *value;
+
+ /**
+ * Previous list element.
+ *
+ * NULL if first element in list.
+ */
+ linked_list_element_t *previous;
+
+ /**
+ * Next list element.
+ *
+ * NULL if last element in list.
+ */
+ linked_list_element_t *next;
+
+ /**
+ * Destroys a linked_list_element object.
+ *
+ * @param linked_list_element_t calling object
+ */
+ void (*destroy) (linked_list_element_t *this);
+};
+
+/**
+ * Implementation of linked_list_element_t.destroy.
+ */
+static void linked_list_element_destroy(linked_list_element_t *this)
+{
+ free(this);
+}
+
+/**
+ * @brief Creates an empty linked list object.
+ *
+ * @warning Only the pointer to the value is stored.
+ *
+ * @param[in] value value of item to be set
+ * @return linked_list_element_t object
+ */
+
+linked_list_element_t *linked_list_element_create(void *value)
+{
+ linked_list_element_t *this = malloc_thing(linked_list_element_t);
+
+ this->destroy = linked_list_element_destroy;
+
+ this->previous=NULL;
+ this->next=NULL;
+ this->value = value;
+
+ return (this);
+}
+
+
+typedef struct private_linked_list_t private_linked_list_t;
+
+/**
+ * Private data of a linked_list_t object.
+ *
+ */
+struct private_linked_list_t {
+ /**
+ * Public part of linked list.
+ */
+ linked_list_t public;
+
+ /**
+ * Number of items in the list.
+ */
+ int count;
+
+ /**
+ * First element in list.
+ * NULL if no elements in list.
+ */
+ linked_list_element_t *first;
+
+ /**
+ * Last element in list.
+ * NULL if no elements in list.
+ */
+ linked_list_element_t *last;
+};
+
+
+typedef struct private_iterator_t private_iterator_t;
+
+/**
+ * Private variables and functions of linked list iterator.
+ */
+struct private_iterator_t {
+ /**
+ * Public part of linked list iterator.
+ */
+ iterator_t public;
+
+ /**
+ * Associated linked list.
+ */
+ private_linked_list_t * list;
+
+ /**
+ * Current element of the iterator.
+ */
+ linked_list_element_t *current;
+
+ /**
+ * Direction of iterator.
+ */
+ bool forward;
+};
+
+/**
+ * Implementation of iterator_t.has_next.
+ */
+static bool iterate(private_iterator_t *this, void** value)
+{
+ if (this->list->count == 0)
+ {
+ return FALSE;
+ }
+ if (this->current == NULL)
+ {
+ this->current = (this->forward) ? this->list->first : this->list->last;
+ *value = this->current->value;
+ return TRUE;
+ }
+ if (this->forward)
+ {
+ if (this->current->next == NULL)
+ {
+ return FALSE;
+ }
+ this->current = this->current->next;
+ *value = this->current->value;
+ return TRUE;
+ }
+ /* backward */
+ if (this->current->previous == NULL)
+ {
+ return FALSE;
+ }
+ this->current = this->current->previous;
+ *value = this->current->value;
+ return TRUE;
+}
+
+/**
+ * Implementation of iterator_t.has_next.
+ */
+static bool iterator_has_next(private_iterator_t *this)
+{
+ if (this->list->count == 0)
+ {
+ return FALSE;
+ }
+ if (this->current == NULL)
+ {
+ this->current = (this->forward) ? this->list->first : this->list->last;
+ return TRUE;
+ }
+ if (this->forward)
+ {
+ if (this->current->next == NULL)
+ {
+ return FALSE;
+ }
+ this->current = this->current->next;
+ return TRUE;
+ }
+ /* backward */
+ if (this->current->previous == NULL)
+ {
+ return FALSE;
+ }
+ this->current = this->current->previous;
+ return TRUE;
+}
+
+/**
+ * Implementation of iterator_t.current.
+ */
+static status_t iterator_current(private_iterator_t *this, void **value)
+{
+ if (this->current == NULL)
+ {
+ return NOT_FOUND;
+ }
+ *value = this->current->value;
+ return SUCCESS;
+}
+
+/**
+ * Implementation of iterator_t.reset.
+ */
+static void iterator_reset(private_iterator_t *this)
+{
+ this->current = NULL;
+}
+
+/**
+ * Implementation of iterator_t.remove.
+ */
+static status_t remove(private_iterator_t *this)
+{
+ linked_list_element_t *new_current;
+
+ if (this->current == NULL)
+ {
+ return NOT_FOUND;
+ }
+
+ if (this->list->count == 0)
+ {
+ return NOT_FOUND;
+ }
+ /* find out the new iterator position */
+ if (this->current->previous != NULL)
+ {
+ new_current = this->current->previous;
+ }
+ else if (this->current->next != NULL)
+ {
+ new_current = this->current->next;
+ }
+ else
+ {
+ new_current = NULL;
+ }
+
+ /* now delete the entry :-) */
+ if (this->current->previous == NULL)
+ {
+ if (this->current->next == NULL)
+ {
+ this->list->first = NULL;
+ this->list->last = NULL;
+ }
+ else
+ {
+ this->current->next->previous = NULL;
+ this->list->first = this->current->next;
+ }
+ }
+ else if (this->current->next == NULL)
+ {
+ this->current->previous->next = NULL;
+ this->list->last = this->current->previous;
+ }
+ else
+ {
+ this->current->previous->next = this->current->next;
+ this->current->next->previous = this->current->previous;
+ }
+
+ this->list->count--;
+ this->current->destroy(this->current);
+ /* set the new iterator position */
+ this->current = new_current;
+ return SUCCESS;
+}
+
+/**
+ * Implementation of iterator_t.insert_before.
+ */
+static void insert_before(private_iterator_t * iterator, void *item)
+{
+ if (iterator->current == NULL)
+ {
+ iterator->list->public.insert_first(&(iterator->list->public), item);
+ }
+
+ linked_list_element_t *element =(linked_list_element_t *) linked_list_element_create(item);
+
+ if (iterator->current->previous == NULL)
+ {
+ iterator->current->previous = element;
+ element->next = iterator->current;
+ iterator->list->first = element;
+ }
+ else
+ {
+ iterator->current->previous->next = element;
+ element->previous = iterator->current->previous;
+ iterator->current->previous = element;
+ element->next = iterator->current;
+ }
+
+ iterator->list->count++;
+}
+
+/**
+ * Implementation of iterator_t.replace.
+ */
+static status_t replace (private_iterator_t *this, void **old_item, void *new_item)
+{
+ if (this->current == NULL)
+ {
+ return NOT_FOUND;
+ }
+ if (old_item != NULL)
+ {
+ *old_item = this->current->value;
+ }
+ this->current->value = new_item;
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of iterator_t.insert_after.
+ */
+static void insert_after(private_iterator_t * iterator, void *item)
+{
+ if (iterator->current == NULL)
+ {
+ iterator->list->public.insert_first(&(iterator->list->public),item);
+ return;
+ }
+
+ linked_list_element_t *element =(linked_list_element_t *) linked_list_element_create(item);
+
+ if (iterator->current->next == NULL)
+ {
+ iterator->current->next = element;
+ element->previous = iterator->current;
+ iterator->list->last = element;
+ }
+ else
+ {
+ iterator->current->next->previous = element;
+ element->next = iterator->current->next;
+ iterator->current->next = element;
+ element->previous = iterator->current;
+ }
+ iterator->list->count++;
+}
+
+/**
+ * Implementation of iterator_t.destroy.
+ */
+static void iterator_destroy(private_iterator_t *this)
+{
+ free(this);
+}
+
+/**
+ * Implementation of linked_list_t.get_count.
+ */
+static int get_count(private_linked_list_t *this)
+{
+ return this->count;
+}
+
+/**
+ * Implementation of linked_list_t.call_on_items.
+ */
+static void call_on_items(private_linked_list_t *this, void(*func)(void*))
+{
+ iterator_t *iterator;
+ void *item;
+
+ iterator = this->public.create_iterator(&(this->public),TRUE);
+
+ while (iterator->has_next(iterator))
+ {
+ iterator->current(iterator, &item);
+ (*func)(item);
+ }
+ iterator->destroy(iterator);
+}
+
+/**
+ * Implementation of linked_list_t.insert_first.
+ */
+static void insert_first(private_linked_list_t *this, void *item)
+{
+ linked_list_element_t *element;
+
+ element =(linked_list_element_t *) linked_list_element_create(item);
+
+ if (this->count == 0)
+ {
+ /* first entry in list */
+ this->first = element;
+ this->last = element;
+ element->previous = NULL;
+ element->next = NULL;
+ }
+ else
+ {
+ linked_list_element_t *old_first_element = this->first;
+ element->next = old_first_element;
+ element->previous = NULL;
+ old_first_element->previous = element;
+ this->first = element;
+ }
+
+ this->count++;
+}
+
+/**
+ * Implementation of linked_list_t.remove_first.
+ */
+static status_t remove_first(private_linked_list_t *this, void **item)
+{
+ if (this->count == 0)
+ {
+ return NOT_FOUND;
+ }
+
+ linked_list_element_t *element = this->first;
+
+ if (element->next != NULL)
+ {
+ element->next->previous = NULL;
+ }
+ this->first = element->next;
+
+ if (item != NULL)
+ {
+ *item = element->value;
+ }
+
+ this->count--;
+
+ element->destroy(element);
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of linked_list_t.get_first.
+ */
+static status_t get_first(private_linked_list_t *this, void **item)
+{
+ if (this->count == 0)
+ {
+ return NOT_FOUND;
+ }
+
+ *item = this->first->value;
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of linked_list_t.insert_last.
+ */
+static void insert_last(private_linked_list_t *this, void *item)
+{
+ linked_list_element_t *element = (linked_list_element_t *) linked_list_element_create(item);
+
+ if (this->count == 0)
+ {
+ /* first entry in list */
+ this->first = element;
+ this->last = element;
+ element->previous = NULL;
+ element->next = NULL;
+ }
+ else
+ {
+
+ linked_list_element_t *old_last_element = this->last;
+ element->previous = old_last_element;
+ element->next = NULL;
+ old_last_element->next = element;
+ this->last = element;
+ }
+
+ this->count++;
+}
+
+/**
+ * Implementation of linked_list_t.remove_last.
+ */
+static status_t remove_last(private_linked_list_t *this, void **item)
+{
+ if (this->count == 0)
+ {
+ return NOT_FOUND;
+ }
+
+ linked_list_element_t *element = this->last;
+
+ if (element->previous != NULL)
+ {
+ element->previous->next = NULL;
+ }
+ this->last = element->previous;
+
+ if (item != NULL)
+ {
+ *item = element->value;
+ }
+
+ this->count--;
+
+ element->destroy(element);
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of linked_list_t.insert_at_position.
+ */
+static status_t insert_at_position (private_linked_list_t *this,size_t position, void *item)
+{
+ linked_list_element_t *current_element;
+ int i;
+
+ if (this->count <= position)
+ {
+ return INVALID_ARG;
+ }
+
+ current_element = this->first;
+
+ for (i = 0; i < position;i++)
+ {
+ current_element = current_element->next;
+ }
+
+ if (current_element == NULL)
+ {
+ this->public.insert_last(&(this->public),item);
+ return SUCCESS;
+ }
+
+ linked_list_element_t *element =(linked_list_element_t *) linked_list_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;
+}
+
+/**
+ * Implementation of linked_list_t.remove_at_position.
+ */
+static status_t remove_at_position (private_linked_list_t *this,size_t position, void **item)
+{
+ iterator_t *iterator;
+ int i;
+
+ if (this->count <= position)
+ {
+ return INVALID_ARG;
+ }
+
+ iterator = this->public.create_iterator(&(this->public),TRUE);
+
+ iterator->has_next(iterator);
+ for (i = 0; i < position;i++)
+ {
+ iterator->has_next(iterator);
+ }
+ iterator->current(iterator,item);
+ 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;
+ status_t status;
+ if (this->count <= position)
+ {
+ return INVALID_ARG;
+ }
+
+ iterator = this->public.create_iterator(&(this->public),TRUE);
+
+ iterator->has_next(iterator);
+ for (i = 0; i < position;i++)
+ {
+ iterator->has_next(iterator);
+ }
+ status = iterator->current(iterator,item);
+ iterator->destroy(iterator);
+ return status;
+}
+
+/**
+ * Implementation of linked_list_t.get_last.
+ */
+static status_t get_last(private_linked_list_t *this, void **item)
+{
+ if (this->count == 0)
+ {
+ return NOT_FOUND;
+ }
+
+ *item = this->last->value;
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of linked_list_t.create_iterator.
+ */
+static iterator_t *create_iterator (private_linked_list_t *linked_list,bool forward)
+{
+ private_iterator_t *this = malloc_thing(private_iterator_t);
+
+ this->public.iterate = (bool (*) (iterator_t *this, void **value)) iterate;
+ this->public.has_next = (bool (*) (iterator_t *this)) iterator_has_next;
+ this->public.current = (status_t (*) (iterator_t *this, void **value)) iterator_current;
+ this->public.insert_before = (void (*) (iterator_t *this, void *item)) insert_before;
+ this->public.insert_after = (void (*) (iterator_t *this, void *item)) insert_after;
+ this->public.replace = (status_t (*) (iterator_t *, void **, void *)) replace;
+ this->public.remove = (status_t (*) (iterator_t *this)) remove;
+ this->public.reset = (void (*) (iterator_t *this)) iterator_reset;
+ this->public.destroy = (void (*) (iterator_t *this)) iterator_destroy;
+
+ this->forward = forward;
+ this->current = NULL;
+ this->list = linked_list;
+
+ return &(this->public);
+}
+
+/**
+ * Implementation of linked_list_t.destroy.
+ */
+static void linked_list_destroy(private_linked_list_t *this)
+{
+ void * value;
+ /* Remove all list items before destroying list */
+ while (this->public.remove_first(&(this->public),&value) != NOT_FOUND)
+ {
+ /* values are not destroyed so memory leaks are possible
+ * if list is not empty when deleting */
+ }
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+linked_list_t *linked_list_create()
+{
+ private_linked_list_t *this = malloc_thing(private_linked_list_t);
+
+ this->public.get_count = (int (*) (linked_list_t *)) get_count;
+ this->public.create_iterator = (iterator_t * (*) (linked_list_t *,bool )) create_iterator;
+ this->public.call_on_items = (void (*) (linked_list_t *, void(*func)(void*)))call_on_items;
+ this->public.get_first = (status_t (*) (linked_list_t *, void **item)) get_first;
+ this->public.get_last = (status_t (*) (linked_list_t *, void **item)) get_last;
+ this->public.insert_first = (void (*) (linked_list_t *, void *item)) insert_first;
+ 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.destroy = (void (*) (linked_list_t *)) linked_list_destroy;
+
+ this->count = 0;
+ this->first = NULL;
+ this->last = NULL;
+
+ return (&(this->public));
+}
diff --git a/programs/charon/lib/utils/linked_list.h b/programs/charon/lib/utils/linked_list.h
new file mode 100644
index 000000000..8647f064d
--- /dev/null
+++ b/programs/charon/lib/utils/linked_list.h
@@ -0,0 +1,203 @@
+/**
+ * @file linked_list.h
+ *
+ * @brief Interface of linked_list_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef LINKED_LIST_H_
+#define LINKED_LIST_H_
+
+#include <types.h>
+#include <utils/iterator.h>
+
+
+typedef struct linked_list_t linked_list_t;
+
+/**
+ * @brief Class implementing a double linked list (named only as linked list).
+ *
+ * @warning Access to an object of this type is not thread-save.
+ *
+ * @b Costructors:
+ * - linked_list_create()
+ *
+ * @see
+ * - job_queue_t
+ * - event_queue_t
+ * - send_queue_t
+ *
+ * @ingroup utils
+ */
+struct linked_list_t {
+
+ /**
+ * @brief Gets the count of items in the list.
+ *
+ * @param linked_list calling object
+ * @return number of items in list
+ */
+ int (*get_count) (linked_list_t *linked_list);
+
+ /**
+ * @brief Creates a iterator for the given list.
+ *
+ * @warning Created iterator_t object has to get destroyed by the caller.
+ *
+ * @param linked_list calling object
+ * @param forward iterator direction (TRUE: front to end)
+ * @return new iterator_t object
+ */
+ iterator_t * (*create_iterator) (linked_list_t *linked_list, bool forward);
+
+ /**
+ * @brief Call a function with list element as argument.
+ *
+ * This method accepts a function, which will be called for
+ * each list element once. The function must accept the list
+ * element as the first argument. Handy for destruction of
+ * list elements.
+ *
+ * @todo Additional vararg which are passed to the
+ * function would be nice...
+ *
+ * @param linked_list calling object
+ * @param func function to call
+ */
+ void (*call_on_items) (linked_list_t *linked_list, void(*func)(void*));
+
+ /**
+ * @brief Inserts a new item at the beginning of the list.
+ *
+ * @param linked_list calling object
+ * @param[in] item item value to insert in list
+ */
+ void (*insert_first) (linked_list_t *linked_list, void *item);
+
+ /**
+ * @brief Removes the first item in the list and returns its value.
+ *
+ * @param linked_list calling object
+ * @param[out] item returned value of first item, or NULL
+ * @return
+ * - SUCCESS
+ * - NOT_FOUND, if list is empty
+ */
+ status_t (*remove_first) (linked_list_t *linked_list, void **item);
+
+ /**
+ * @brief Returns the value of the first list item without removing it.
+ *
+ * @param linked_list calling object
+ * @param[out] item item returned value of first item
+ * @return
+ * - SUCCESS
+ * - NOT_FOUND, if list is empty
+ */
+ status_t (*get_first) (linked_list_t *linked_list, void **item);
+
+ /**
+ * @brief Inserts a new item at the end of the list.
+ *
+ * @param linked_list calling object
+ * @param[in] item item value to insert into list
+ */
+ void (*insert_last) (linked_list_t *linked_list, void *item);
+
+ /**
+ * @brief Inserts a new item at a given position in the list.
+ *
+ * @param linked_list calling object
+ * @param position position starting at 0 to insert new entry
+ * @param[in] item item value to insert into list
+ * @return
+ * - SUCCESS
+ * - INVALID_ARG if position not existing
+ */
+ status_t (*insert_at_position) (linked_list_t *linked_list,size_t position, void *item);
+
+ /**
+ * @brief Removes an item from a given position in the list.
+ *
+ * @param linked_list 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
+ */
+ status_t (*remove_at_position) (linked_list_t *linked_list,size_t position, void **item);
+
+ /**
+ * @brief Get an item from a given position in the list.
+ *
+ * @param linked_list 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
+ */
+ status_t (*get_at_position) (linked_list_t *linked_list,size_t position, void **item);
+
+ /**
+ * @brief Removes the last item in the list and returns its value.
+ *
+ * @param linked_list calling object
+ * @param[out] item returned value of last item, or NULL
+ * @return
+ * - SUCCESS
+ * - NOT_FOUND if list is empty
+ */
+ status_t (*remove_last) (linked_list_t *linked_list, void **item);
+
+ /**
+ * @brief Returns the value of the last list item without removing it.
+ *
+ * @param linked_list calling object
+ * @param[out] item returned value of last item
+ * @return
+ * - SUCCESS
+ * - NOT_FOUND if list is empty
+ */
+ status_t (*get_last) (linked_list_t *linked_list, void **item);
+
+ /**
+ * @brief Destroys a linked_list object.
+ *
+ * @warning All items are removed before deleting the list. The
+ * associated values are NOT destroyed.
+ * Destroying an list which is not empty may cause
+ * memory leaks!
+ *
+ * @param linked_list calling object
+ */
+ void (*destroy) (linked_list_t *linked_list);
+};
+
+/**
+ * @brief Creates an empty linked list object.
+ *
+ * @return linked_list_t object.
+ *
+ * @ingroup utils
+ */
+linked_list_t *linked_list_create();
+
+
+#endif /*LINKED_LIST_H_*/
diff --git a/programs/charon/lib/utils/logger.c b/programs/charon/lib/utils/logger.c
new file mode 100644
index 000000000..fdaeddff0
--- /dev/null
+++ b/programs/charon/lib/utils/logger.c
@@ -0,0 +1,342 @@
+/**
+ * @file logger.c
+ *
+ * @brief Implementation of logger_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <syslog.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+#include <pthread.h>
+
+#include "logger.h"
+
+
+/**
+ * Maximum length of a log entry (only used for logger_s.log).
+ */
+#define MAX_LOG 8192
+
+/**
+ * Maximum number of logged bytes per line
+ */
+#define MAX_BYTES 16
+
+typedef struct private_logger_t private_logger_t;
+
+/**
+ * @brief Private data of a logger_t object.
+ */
+struct private_logger_t {
+ /**
+ * Public data.
+ */
+ logger_t public;
+ /**
+ * Detail-level of logger.
+ */
+ log_level_t level;
+ /**
+ * Name of logger.
+ */
+ char *name;
+ /**
+ * File to write log output to.
+ * NULL for syslog.
+ */
+ FILE *output;
+
+ /**
+ * Should a thread_id be included in the log?
+ */
+ bool log_thread_id;
+};
+
+/**
+ * prepend the logging prefix to string and store it in buffer
+ */
+static void prepend_prefix(private_logger_t *this, log_level_t loglevel, const char *string, char *buffer)
+{
+ char log_type, log_details;
+ char thread_id[10] = "";
+
+ if (loglevel & CONTROL)
+ {
+ log_type = 'C';
+ }
+ else if (loglevel & ERROR)
+ {
+ log_type = 'E';
+ }
+ else if (loglevel & RAW)
+ {
+ log_type = 'R';
+ }
+ else if (loglevel & PRIVATE)
+ {
+ log_type = 'P';
+ }
+ else if (loglevel & AUDIT)
+ {
+ log_type = 'A';
+ }
+ else
+ {
+ log_type = '-';
+ }
+
+ if (loglevel & (LEVEL3 - LEVEL2))
+ {
+ log_details = '3';
+ }
+ else if (loglevel & (LEVEL2 - LEVEL1))
+ {
+ log_details = '2';
+ }
+ else if (loglevel & LEVEL1)
+ {
+ log_details = '1';
+ }
+ else
+ {
+ log_details = '0';
+ }
+
+ if (this->log_thread_id)
+ {
+ snprintf(thread_id, sizeof(thread_id), " @%d", (int)pthread_self());
+ }
+ snprintf(buffer, MAX_LOG, "[%c%c:%s]%s %s", log_type, log_details, this->name, thread_id, string);
+}
+
+/**
+ * Convert a charon-loglevel to a syslog priority
+ */
+static int get_priority(log_level_t loglevel)
+{
+ if (loglevel & AUDIT)
+ {
+ return LOG_AUTHPRIV|LOG_INFO;
+ }
+ return LOG_DAEMON|LOG_DEBUG;
+}
+
+/**
+ * Implementation of logger_t.log.
+ *
+ * Yes, logg is written wrong :-).
+ */
+static void logg(private_logger_t *this, log_level_t loglevel, const char *format, ...)
+{
+ if ((this->level & loglevel) == loglevel)
+ {
+ char buffer[MAX_LOG];
+ va_list args;
+
+
+ if (this->output == NULL)
+ {
+ /* syslog */
+ prepend_prefix(this, loglevel, format, buffer);
+ va_start(args, format);
+ vsyslog(get_priority(loglevel), buffer, args);
+ va_end(args);
+ }
+ else
+ {
+ /* File output */
+ prepend_prefix(this, loglevel, format, buffer);
+ va_start(args, format);
+ vfprintf(this->output, buffer, args);
+ va_end(args);
+ fprintf(this->output, "\n");
+ }
+
+ }
+}
+
+/**
+ * Implementation of logger_t.log_bytes.
+ */
+static void log_bytes(private_logger_t *this, log_level_t loglevel, const char *label, const char *bytes, size_t len)
+{
+ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+ if ((this->level & loglevel) == loglevel)
+ {
+ char thread_id[10] = "";
+ char buffer[MAX_LOG];
+ char ascii_buffer[MAX_BYTES+1];
+
+ char *buffer_pos = buffer;
+ const char format[] = "%s %d bytes @ %p";
+ const char *bytes_pos = bytes;
+ const char *bytes_roof = bytes + len;
+
+ int line_start = 0;
+ int i = 0;
+
+ if (this->log_thread_id)
+ {
+ snprintf(thread_id, sizeof(thread_id), " @%d", (int)pthread_self());
+ }
+
+ /* since me can't do multi-line output to syslog,
+ * we must do multiple syslogs. To avoid
+ * problems in output order, lock this by a mutex.
+ */
+ pthread_mutex_lock(&mutex);
+
+ prepend_prefix(this, loglevel, format, buffer);
+
+ if (this->output == NULL)
+ {
+ syslog(get_priority(loglevel), buffer, label, len, bytes);
+ }
+ else
+ {
+ fprintf(this->output, buffer, label, len, bytes);
+ fprintf(this->output, "\n");
+ }
+
+ while (bytes_pos < bytes_roof)
+ {
+ static char hexdig[] = "0123456789ABCDEF";
+
+ *buffer_pos++ = hexdig[(*bytes_pos >> 4) & 0xF];
+ *buffer_pos++ = hexdig[ *bytes_pos & 0xF];
+
+ ascii_buffer[i++] = (*bytes_pos > 31 && *bytes_pos < 127)
+ ? *bytes_pos : '.';
+
+ if (++bytes_pos == bytes_roof || i == MAX_BYTES)
+ {
+ int padding = 3 * (MAX_BYTES - i);
+
+ while (padding--)
+ {
+ *buffer_pos++ = ' ';
+ }
+ *buffer_pos++ = '\0';
+ ascii_buffer[i] = '\0';
+
+ if (this->output == NULL)
+ {
+ syslog(get_priority(loglevel), "[ :%5d]%s %s %s", line_start, thread_id, buffer, ascii_buffer);
+ }
+ else
+ {
+ fprintf(this->output, "[ :%5d]%s %s %s\n", line_start, thread_id, buffer, ascii_buffer);
+ }
+ buffer_pos = buffer;
+ line_start += MAX_BYTES;
+ i = 0;
+ }
+ else
+ {
+ *buffer_pos++ = ' ';
+ }
+ }
+ pthread_mutex_unlock(&mutex);
+ }
+}
+
+/**
+ * Implementation of logger_t.log_chunk.
+ */
+static void log_chunk(logger_t *this, log_level_t loglevel, const char *label, chunk_t chunk)
+{
+ this->log_bytes(this, loglevel, label, chunk.ptr, chunk.len);
+}
+
+/**
+ * Implementation of logger_t.enable_level.
+ */
+static void enable_level(private_logger_t *this, log_level_t log_level)
+{
+ this->level |= log_level;
+}
+
+/**
+ * Implementation of logger_t.disable_level.
+ */
+static void disable_level(private_logger_t *this, log_level_t log_level)
+{
+ this->level &= ~log_level;
+}
+
+/**
+ * Implementation of logger_t.set_output.
+ */
+static void set_output(private_logger_t *this, FILE * output)
+{
+ this->output = output;
+}
+
+/**
+ * Implementation of logger_t.get_level.
+ */
+static log_level_t get_level(private_logger_t *this)
+{
+ return this->level;
+}
+
+/**
+ * Implementation of logger_t.destroy.
+ */
+static void destroy(private_logger_t *this)
+{
+ free(this->name);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+logger_t *logger_create(char *logger_name, log_level_t log_level, bool log_thread_id, FILE * output)
+{
+ private_logger_t *this = malloc_thing(private_logger_t);
+
+ /* public functions */
+ this->public.log = (void(*)(logger_t*,log_level_t,const char*,...))logg;
+ this->public.log_bytes = (void(*)(logger_t*, log_level_t, const char*, const char*,size_t))log_bytes;
+ this->public.log_chunk = log_chunk;
+ this->public.enable_level = (void(*)(logger_t*,log_level_t))enable_level;
+ this->public.disable_level = (void(*)(logger_t*,log_level_t))disable_level;
+ this->public.get_level = (log_level_t(*)(logger_t*))get_level;
+ this->public.set_output = (void(*)(logger_t*,FILE*))set_output;
+ this->public.destroy = (void(*)(logger_t*))destroy;
+
+ if (logger_name == NULL)
+ {
+ logger_name = "";
+ }
+
+ /* private variables */
+ this->level = log_level;
+ this->log_thread_id = log_thread_id;
+ this->name = malloc(strlen(logger_name) + 1);
+
+ strcpy(this->name,logger_name);
+ this->output = output;
+
+ return (logger_t*)this;
+}
diff --git a/programs/charon/lib/utils/logger.h b/programs/charon/lib/utils/logger.h
new file mode 100644
index 000000000..dec73078e
--- /dev/null
+++ b/programs/charon/lib/utils/logger.h
@@ -0,0 +1,198 @@
+/**
+ * @file logger.h
+ *
+ * @brief Interface of logger_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef LOGGER_H_
+#define LOGGER_H_
+
+#include <stdio.h>
+
+#include <types.h>
+
+typedef enum log_level_t log_level_t;
+
+/**
+ * @brief Log Levels supported by the logger object.
+ *
+ * Logleves are devided in two different kinds:
+ * - levels to specify the type of the log
+ * - levels to specify the detail-level of the log
+ *
+ * Use combinations of these to build detailed loglevels, such
+ * as CONTROL|LEVEL2 fore a detailed cotrol level, or
+ * use RAW to see all raw data dumps (except private).
+ *
+ * @ingroup utils
+ */
+enum log_level_t {
+ /**
+ * Control flow.
+ */
+ CONTROL = 1,
+ /**
+ * Error reporting.
+ */
+ ERROR = 2,
+ /**
+ * Logs important for the sysadmin.
+ */
+ AUDIT = 4,
+ /**
+ * Raw data dumps.
+ */
+ RAW = 8,
+ /**
+ * Private data dumps.
+ */
+ PRIVATE = 16,
+
+ /**
+ * Log most important output, can be omitted.
+ */
+ LEVEL0 = 0,
+ /**
+ * Log more detailed output.
+ */
+ LEVEL1 = 32,
+ /**
+ * Log even more detailed output.
+ */
+ LEVEL2 = LEVEL1 + 64,
+ /**
+ * Use maximum detailed output.
+ */
+ LEVEL3 = LEVEL2 + 128,
+
+ /**
+ * Summary for all types with all detail-levels.
+ */
+ FULL = LEVEL3 + CONTROL + ERROR + RAW + PRIVATE + AUDIT
+};
+
+typedef struct logger_t logger_t;
+
+/**
+ * @brief Class to simplify logging.
+ *
+ * @b Constructors:
+ * - logger_create()
+ *
+ * @ingroup utils
+ */
+struct logger_t {
+
+ /**
+ * @brief Log an entry, using printf()-like params.
+ *
+ * All specified loglevels must be activated that
+ * the log is done.
+ *
+ * @param this logger_t object
+ * @param loglevel or'ed set of log_level_t's
+ * @param format printf like format string
+ * @param ... printf like parameters
+ */
+ void (*log) (logger_t *this, log_level_t log_level, const char *format, ...);
+
+ /**
+ * @brief Log some bytes, useful for debugging.
+ *
+ * All specified loglevels must be activated that
+ * the log is done.
+ *
+ * @param this logger_t object
+ * @param loglevel or'ed set of log_level_t's
+ * @param label a labeling name, logged with the bytes
+ * @param bytes pointer to the bytes to dump
+ * @param len number of bytes to dump
+ */
+ void (*log_bytes) (logger_t *this, log_level_t loglevel, const char *label, const char *bytes, size_t len);
+
+ /**
+ * @brief Log a chunk, useful for debugging.
+ *
+ * All specified loglevels must be activated that
+ * the log is done.
+ *
+ * @param this logger_t object
+ * @param loglevel or'ed set of log_level_t's
+ * @param label a labeling name, logged with the bytes
+ * @param chunk chunk to log
+ */
+ void (*log_chunk) (logger_t *this, log_level_t loglevel, const char *label, chunk_t chunk);
+
+ /**
+ * @brief Enables a loglevel for the current logger_t object.
+ *
+ * @param this logger_t object
+ * @param log_level loglevel to enable
+ */
+ void (*enable_level) (logger_t *this, log_level_t log_level);
+
+ /**
+ * @brief Disables a loglevel for the current logger_t object.
+ *
+ * @param this logger_t object
+ * @param log_level loglevel to enable
+ */
+ void (*disable_level) (logger_t *this, log_level_t log_level);
+
+ /**
+ * @brief Set the output of the logger.
+ *
+ * Use NULL for syslog.
+ *
+ * @param this logger_t object
+ * @param output file, where log output should be written
+ */
+ void (*set_output) (logger_t *this, FILE *output);
+
+ /**
+ * @brief Get the currently used loglevel.
+ *
+ * @param this logger_t object
+ * @return currently used loglevel
+ */
+ log_level_t (*get_level) (logger_t *this);
+
+ /**
+ * @brief Destroys a logger_t object.
+ *
+ * @param this logger_t object
+ */
+ void (*destroy) (logger_t *this);
+};
+
+/**
+ * @brief Constructor to create a logger_t object.
+ *
+ * @param logger_name name for the logger_t object
+ * @param log_level or'ed set of log_levels to assign to the new logger_t object
+ * @param log_thread_id TRUE if thread id should also be logged
+ * @param output FILE * if log has to go on a file output, NULL for syslog
+ * @return logger_t object
+ *
+ * @ingroup utils
+ */
+logger_t *logger_create(char *logger_name, log_level_t log_level, bool log_thread_id, FILE * output);
+
+
+#endif /*LOGGER_H_*/
diff --git a/programs/charon/lib/utils/logger_manager.c b/programs/charon/lib/utils/logger_manager.c
new file mode 100644
index 000000000..ecbe1a6c1
--- /dev/null
+++ b/programs/charon/lib/utils/logger_manager.c
@@ -0,0 +1,220 @@
+/**
+ * @file logger_manager.c
+ *
+ * @brief Implementation of logger_manager_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#include "logger_manager.h"
+
+#include <daemon.h>
+#include <definitions.h>
+#include <utils/linked_list.h>
+
+/**
+ * String mappings for logger_context_t
+ */
+mapping_t logger_context_t_mappings[] = {
+ {PARSER, "PARSER"},
+ {GENERATOR, "GENERATOR"},
+ {IKE_SA, "IKE_SA"},
+ {IKE_SA_MANAGER, "IKE_SA_MANAGER"},
+ {CHILD_SA, "CHILD_SA"},
+ {MESSAGE, "MESSAGE"},
+ {THREAD_POOL, "THREAD_POOL"},
+ {WORKER, "WORKER"},
+ {SCHEDULER, "SCHEDULER"},
+ {SENDER, "SENDER"},
+ {RECEIVER, "RECEIVER"},
+ {SOCKET, "SOCKET"},
+ {TESTER, "TESTER"},
+ {DAEMON, "DAEMON"},
+ {CONFIG, "CONFIG"},
+ {ENCRYPTION_PAYLOAD, "ENCRYPTION_PAYLOAD"},
+ {PAYLOAD, "PAYLOAD"},
+ {DER_DECODER, "DER_DECODER"},
+ {DER_ENCODER, "DER_ENCODER"},
+ {ASN1, "ASN1"},
+ {XFRM, "XFRM"},
+ {LEAK_DETECT, "LEAK_DETECT"},
+ {MAPPING_END, NULL},
+};
+
+struct {
+ char *name;
+ log_level_t level;
+ bool log_thread_ids;
+} logger_defaults[] = {
+ { "PARSR", ERROR|CONTROL|AUDIT|LEVEL0, TRUE }, /* PARSER */
+ { "GNRAT", ERROR|CONTROL|AUDIT|LEVEL0, TRUE }, /* GENERATOR */
+ { "IKESA", ERROR|CONTROL|AUDIT|LEVEL0, TRUE }, /* IKE_SA */
+ { "SAMGR", ERROR|CONTROL|AUDIT|LEVEL0, TRUE }, /* IKE_SA_MANAGER */
+ { "CHDSA", ERROR|CONTROL|AUDIT|LEVEL0, TRUE }, /* CHILD_SA */
+ { "MESSG", ERROR|CONTROL|AUDIT|LEVEL0, TRUE }, /* MESSAGE */
+ { "TPOOL", ERROR|CONTROL|AUDIT|LEVEL0, FALSE}, /* THREAD_POOL */
+ { "WORKR", ERROR|CONTROL|AUDIT|LEVEL0, TRUE }, /* WORKER */
+ { "SCHED", ERROR|CONTROL|AUDIT|LEVEL0, FALSE}, /* SCHEDULER */
+ { "SENDR", ERROR|CONTROL|AUDIT|LEVEL0, FALSE}, /* SENDER */
+ { "RECVR", ERROR|CONTROL|AUDIT|LEVEL0, FALSE}, /* RECEIVER */
+ { "SOCKT", ERROR|CONTROL|AUDIT|LEVEL0, FALSE}, /* SOCKET */
+ { "TESTR", ERROR|CONTROL|AUDIT|LEVEL0, FALSE}, /* TESTER */
+ { "DAEMN", ERROR|CONTROL|AUDIT|LEVEL0, FALSE}, /* DAEMON */
+ { "CONFG", ERROR|CONTROL|AUDIT|LEVEL0, TRUE }, /* CONFIG */
+ { "ENCPL", ERROR|CONTROL|AUDIT|LEVEL0, TRUE }, /* ENCRYPTION_PAYLOAD */
+ { "PAYLD", ERROR|CONTROL|AUDIT|LEVEL0, TRUE }, /* PAYLOAD */
+ { "DERDC", ERROR|CONTROL|AUDIT|LEVEL0, TRUE }, /* DER_DECODER */
+ { "DEREC", ERROR|CONTROL|AUDIT|LEVEL0, TRUE }, /* DER_ENCODER */
+ { "ASN_1", ERROR|CONTROL|AUDIT|LEVEL0, TRUE }, /* ASN1 */
+ { "XFRM ", ERROR|CONTROL|AUDIT|LEVEL0, TRUE }, /* XFRM */
+ { "LEAKD", ERROR|CONTROL|AUDIT|LEVEL0, FALSE}, /* LEAK_DETECT */
+};
+
+
+typedef struct private_logger_manager_t private_logger_manager_t;
+
+/**
+ * Private data of logger_manager_t object.
+ */
+struct private_logger_manager_t {
+ /**
+ * Public data.
+ */
+ logger_manager_t public;
+
+ /**
+ * Array of loggers, one for each context
+ */
+ logger_t *loggers[LOGGER_CONTEXT_ROOF];
+};
+
+/**
+ * The one and only instance of the logger manager
+ */
+static private_logger_manager_t private_logger_manager;
+
+/**
+ * Exported pointer for the logger manager
+ */
+logger_manager_t *logger_manager = (logger_manager_t *)&private_logger_manager;
+
+/**
+ * Implementation of logger_manager_t.get_logger.
+ */
+static logger_t *get_logger(private_logger_manager_t *this, logger_context_t context)
+{
+ return this->loggers[context];
+}
+
+/**
+ * Implementation of logger_manager_t.get_log_level.
+ */
+static log_level_t get_log_level (private_logger_manager_t *this, logger_context_t context)
+{
+ return this->loggers[context]->get_level(this->loggers[context]);
+}
+
+/**
+ * Implementation of private_logger_manager_t.enable_log_level.
+ */
+static void enable_log_level(private_logger_manager_t *this, logger_context_t context, log_level_t level)
+{
+ if (context == ALL_LOGGERS)
+ {
+ for (context = 0; context < LOGGER_CONTEXT_ROOF; context++)
+ {
+ this->loggers[context]->enable_level(this->loggers[context], level);
+ }
+ }
+ else
+ {
+ this->loggers[context]->enable_level(this->loggers[context], level);
+ }
+}
+
+/**
+ * Implementation of private_logger_manager_t.disable_log_level.
+ */
+static void disable_log_level(private_logger_manager_t *this, logger_context_t context, log_level_t level)
+{
+ if (context == ALL_LOGGERS)
+ {
+ for (context = 0; context < LOGGER_CONTEXT_ROOF; context++)
+ {
+ this->loggers[context]->disable_level(this->loggers[context], level);
+ }
+ }
+ else
+ {
+ this->loggers[context]->disable_level(this->loggers[context], level);
+ }
+}
+
+/**
+ * Implementation of private_logger_manager_t.set_output.
+ */
+static void set_output(private_logger_manager_t *this, logger_context_t context, FILE *output)
+{
+ if (context == ALL_LOGGERS)
+ {
+ for (context = 0; context < LOGGER_CONTEXT_ROOF; context++)
+ {
+ this->loggers[context]->set_output(this->loggers[context], output);
+ }
+ }
+ else
+ {
+ this->loggers[context]->set_output(this->loggers[context], output);
+ }
+}
+
+
+/**
+ * Creates the instance of the logger manager at library startup
+ */
+void logger_manager_init()
+{
+ int i;
+
+ logger_manager->get_logger = (logger_t *(*)(logger_manager_t*,logger_context_t context))get_logger;
+ logger_manager->get_log_level = (log_level_t (*)(logger_manager_t *, logger_context_t)) get_log_level;
+ logger_manager->enable_log_level = (void (*)(logger_manager_t *, logger_context_t, log_level_t)) enable_log_level;
+ logger_manager->disable_log_level = (void (*)(logger_manager_t *, logger_context_t, log_level_t)) disable_log_level;
+ logger_manager->set_output = (void (*)(logger_manager_t *, logger_context_t, FILE*)) set_output;
+
+ for (i = 0; i < LOGGER_CONTEXT_ROOF; i++)
+ {
+ private_logger_manager.loggers[i] = logger_create(logger_defaults[i].name,
+ logger_defaults[i].level,
+ logger_defaults[i].log_thread_ids,
+ INITIAL_LOG_OUTPUT);
+ }
+
+}
+
+/**
+ * Destroy the logger manager at library exit
+ */
+void logger_manager_cleanup()
+{
+ int i;
+ for (i = 0; i < LOGGER_CONTEXT_ROOF; i++)
+ {
+ private_logger_manager.loggers[i]->destroy(private_logger_manager.loggers[i]);
+ }
+}
diff --git a/programs/charon/lib/utils/logger_manager.h b/programs/charon/lib/utils/logger_manager.h
new file mode 100644
index 000000000..a3ff5a37e
--- /dev/null
+++ b/programs/charon/lib/utils/logger_manager.h
@@ -0,0 +1,160 @@
+/**
+ * @file logger_manager.h
+ *
+ * @brief Interface of logger_manager_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef LOGGER_MANAGER_H_
+#define LOGGER_MANAGER_H_
+
+#include <pthread.h>
+
+#include <utils/logger.h>
+
+#define INITIAL_LOG_OUTPUT stdout
+
+typedef enum logger_context_t logger_context_t;
+
+/**
+ * @brief Context of a specific logger.
+ *
+ * @ingroup utils
+ */
+enum logger_context_t {
+ ALL_LOGGERS = -1,
+ PARSER = 0,
+ GENERATOR,
+ IKE_SA,
+ IKE_SA_MANAGER,
+ CHILD_SA,
+ MESSAGE,
+ THREAD_POOL,
+ WORKER,
+ SCHEDULER,
+ SENDER,
+ RECEIVER,
+ SOCKET,
+ TESTER,
+ DAEMON,
+ CONFIG,
+ ENCRYPTION_PAYLOAD,
+ PAYLOAD,
+ DER_DECODER,
+ DER_ENCODER,
+ ASN1,
+ XFRM,
+ LEAK_DETECT,
+ LOGGER_CONTEXT_ROOF,
+};
+
+
+typedef struct logger_manager_t logger_manager_t;
+
+/**
+ * @brief Class to manage logger_t objects.
+ *
+ * The logger manager manages all logger_t object in a list and
+ * allows their manipulation. Via a logger_context_t, the loglevel
+ * of a specific logging type can be adjusted at runtime.
+ * This class differs from others, as it has no constructor or destroy
+ * function. The one and only instance "logger_manager" is created at
+ * library start and destroyed at exit.
+ *
+ * @b Constructors:
+ * - none, logger_manager is the single instance
+ * use logger_manager_init/logger_manager_cleanup
+ *
+ * @see logger_t
+ *
+ * @ingroup utils
+ */
+struct logger_manager_t {
+
+ /**
+ * @brief Gets a logger_t object for a specific logger context.
+ *
+ * @param this logger_manager_t object
+ * @param context logger_context to use the logger for
+ * @param name name for the new logger. Context name is already included
+ * and has not to be specified (so NULL is allowed)
+ * @return logger_t object
+ */
+ logger_t *(*get_logger) (logger_manager_t *this, logger_context_t context);
+
+ /**
+ * @brief Returns the set log_level of a specific context.
+ *
+ * @param this calling object
+ * @param context context to check level
+ * @return log_level for the given logger_context
+ */
+ log_level_t (*get_log_level) (logger_manager_t *this, logger_context_t context);
+
+ /**
+ * @brief Enables a logger level of a specific context.
+ *
+ * Use context ALL_LOGGERS to manipulate all loggers.
+ *
+ * @param this calling object
+ * @param context context to set level
+ * @param log_level logger level to eanble
+ */
+ void (*enable_log_level) (logger_manager_t *this, logger_context_t context,log_level_t log_level);
+
+ /**
+ * @brief Disables a logger level of a specific context.
+ *
+ * Use context ALL_LOGGERS to manipulate all loggers.
+ *
+ * @param this calling object
+ * @param context context to set level
+ * @param log_level logger level to disable
+ */
+ void (*disable_log_level) (logger_manager_t *this, logger_context_t context,log_level_t log_level);
+
+ /**
+ * @brief Sets the output of a logger.
+ *
+ * Use context ALL_LOGGERS to redirect all loggers.
+ *
+ * @param this calling object
+ * @param context context to set output
+ * @param log_level logger level to disable
+ */
+ void (*set_output) (logger_manager_t *this, logger_context_t context, FILE *output);
+};
+
+/**
+ * The single and global instance of the logger_manager
+ */
+extern logger_manager_t *logger_manager;
+
+/**
+ * Initialize the logger manager with all its logger.
+ * Has to be called before logger_manager is accessed.
+ */
+void logger_manager_init();
+
+/**
+ * Free any resources hold by the logger manager. Do
+ * not access logger_manager after this call.
+ */
+void logger_manager_cleanup();
+
+#endif /*LOGGER_MANAGER_H_*/
diff --git a/programs/charon/lib/utils/randomizer.c b/programs/charon/lib/utils/randomizer.c
new file mode 100644
index 000000000..09e81894e
--- /dev/null
+++ b/programs/charon/lib/utils/randomizer.c
@@ -0,0 +1,164 @@
+/**
+ * @file randomizer.c
+ *
+ * @brief Implementation of randomizer_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "randomizer.h"
+
+
+typedef struct private_randomizer_t private_randomizer_t;
+
+/**
+ * Private data of an randomizer_t object.
+ */
+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.
+ */
+static status_t get_bytes_from_device(private_randomizer_t *this,bool pseudo_random, size_t bytes, u_int8_t *buffer)
+{
+ size_t ndone;
+ int device;
+ size_t got;
+ char * device_name;
+
+ device_name = pseudo_random ? PSEUDO_RANDOM_DEVICE : RANDOM_DEVICE;
+
+ device = open(device_name, 0);
+ if (device < 0) {
+ return FAILED;
+ }
+ ndone = 0;
+
+ /* read until nbytes are read */
+ while (ndone < bytes)
+ {
+ got = read(device, buffer + ndone, bytes - ndone);
+ if (got <= 0) {
+ close(device);
+ return FAILED;
+ }
+ ndone += got;
+ }
+ close(device);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of randomizer_t.get_random_bytes.
+ */
+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);
+}
+
+/**
+ * Implementation of randomizer_t.allocate_random_bytes.
+ */
+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);
+ if (status != SUCCESS)
+ {
+ free(chunk->ptr);
+ }
+ return status;
+}
+
+/**
+ * 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)
+{
+ return (this->get_bytes_from_device(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)
+{
+ status_t status;
+ chunk->len = bytes;
+ chunk->ptr = malloc(bytes);
+ status = this->get_bytes_from_device(this, TRUE, bytes, chunk->ptr);
+ if (status != SUCCESS)
+ {
+ free(chunk->ptr);
+ }
+ return status;
+}
+
+/**
+ * Implementation of randomizer_t.destroy.
+ */
+static void destroy(private_randomizer_t *this)
+{
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+randomizer_t *randomizer_create(void)
+{
+ private_randomizer_t *this = malloc_thing(private_randomizer_t);
+
+ /* public functions */
+ this->public.get_random_bytes = (status_t (*) (randomizer_t *,size_t, u_int8_t *)) get_random_bytes;
+ this->public.allocate_random_bytes = (status_t (*) (randomizer_t *,size_t, chunk_t *)) allocate_random_bytes;
+ this->public.get_pseudo_random_bytes = (status_t (*) (randomizer_t *,size_t, u_int8_t *)) get_pseudo_random_bytes;
+ 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);
+}
diff --git a/programs/charon/lib/utils/randomizer.h b/programs/charon/lib/utils/randomizer.h
new file mode 100644
index 000000000..55519550e
--- /dev/null
+++ b/programs/charon/lib/utils/randomizer.h
@@ -0,0 +1,110 @@
+/**
+ * @file randomizer.h
+ *
+ * @brief Interface of randomizer_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef RANDOMIZER_H_
+#define RANDOMIZER_H_
+
+#include <types.h>
+
+
+/**
+ * Device to read real random bytes
+ */
+#define RANDOM_DEVICE "/dev/random"
+
+/**
+ * Device to read pseudo random bytes
+ */
+#define PSEUDO_RANDOM_DEVICE "/dev/urandom"
+
+typedef struct randomizer_t randomizer_t;
+
+/**
+ * @brief Class used to get random and pseudo random values.
+ *
+ * @b Constructors:
+ * - randomizer_create()
+ *
+ * @ingroup utils
+ */
+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
+ */
+ status_t (*get_random_bytes) (randomizer_t *this, size_t bytes, u_int8_t *buffer);
+
+ /**
+ * @brief 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
+ */
+ 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.
+ *
+ * @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
+ */
+ 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.
+ *
+ * @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
+ */
+ 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
+ */
+ void (*destroy) (randomizer_t *this);
+};
+
+/**
+ * @brief Creates a randomizer_t object.
+ *
+ * @return created randomizer_t, or
+ *
+ * @ingroup utils
+ */
+randomizer_t *randomizer_create();
+
+#endif /*RANDOMIZER_H_*/
diff --git a/programs/charon/lib/utils/tester.c b/programs/charon/lib/utils/tester.c
new file mode 100644
index 000000000..a7599dd82
--- /dev/null
+++ b/programs/charon/lib/utils/tester.c
@@ -0,0 +1,256 @@
+/**
+ * @file tester.c
+ *
+ * @brief Implementation of tester_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <sys/time.h>
+
+#include "tester.h"
+
+#include <utils/linked_list.h>
+#include <queues/job_queue.h>
+
+
+typedef struct private_tester_t private_tester_t;
+
+/**
+ * @brief Private Data of tester_t class.
+ *
+ */
+struct private_tester_t {
+
+ /**
+ * Protected interface of tester_t.
+ */
+ protected_tester_t protected;
+
+ /**
+ * Runs a specific test.
+ *
+ * @param tester associated tester object
+ * @param test_function test function to perform
+ * @param test_name name for the given test
+ */
+ void (*run_test) (private_tester_t *tester, void (*test_function) (protected_tester_t * tester), char * test_name);
+
+ /**
+ * Returns the difference of to timeval structs in microseconds.
+ *
+ * @warning this function is also defined in the event queue
+ * in later improvements, this function can be added to a general
+ * class type!
+ *
+ * @param end_time end time
+ * @param start_time start time
+ *
+ * @TODO make object function or move to utils!
+ *
+ * @return difference in microseconds
+ */
+ long (*time_difference) (private_tester_t *tester,struct timeval *end_time, struct timeval *start_time);
+
+ /**
+ * Output is written into this file.
+ */
+ FILE* output;
+
+ /**
+ * Number of already performed tests.
+ */
+ int tests_count;
+
+ /**
+ * Number of failed tests.
+ */
+ int failed_tests_count;
+
+ /**
+ * Number of failed asserts in current test.
+ */
+ int failed_asserts_count;
+
+ /**
+ * TRUE if also succeeded asserts should be written to output.
+ */
+ bool display_succeeded_asserts;
+
+ /**
+ * Mutex to make this class thread-save.
+ */
+ pthread_mutex_t mutex;
+};
+
+/**
+ * Implementation of tester_t.perform_tests.
+ */
+static void perform_tests(private_tester_t *this,test_t **tests)
+{
+ int current_test = 0;
+ fprintf(this->output,"\nStart testing...\n\n");
+ fprintf(this->output,"_____________________________________________________________________\n");
+ fprintf(this->output,"Testname | running time\n");
+ fprintf(this->output,"_______________________________________________________|_____________\n");
+
+ while (tests[current_test] != NULL)
+ {
+ this->run_test(this,tests[current_test]->test_function,tests[current_test]->test_name);
+ current_test++;
+ }
+ fprintf(this->output,"=====================================================================\n");
+ fprintf(this->output,"End testing. %d of %d tests succeeded\n",this->tests_count - this->failed_tests_count,this->tests_count);
+ fprintf(this->output,"=====================================================================\n");
+}
+
+/**
+ * Implementation of tester_t.perform_test.
+ */
+static void perform_test(private_tester_t *this, test_t *test)
+{
+ test_t *tests[] = {test, NULL};
+ return (perform_tests(this,tests));
+}
+
+/**
+ * Returns the difference of to timeval structs in microseconds.
+ *
+ * @warning this function is also defined in the event queue
+ * in later improvements, this function can be added to a general
+ * class type!
+ *
+ * @param end_time end time
+ * @param start_time start time
+ *
+ * @TODO make object function or move to utils!
+ *
+ * @return difference in microseconds
+ */
+static long time_difference(private_tester_t *this,struct timeval *end_time, struct timeval *start_time)
+{
+ long seconds, microseconds;
+
+ seconds = (end_time->tv_sec - start_time->tv_sec);
+ microseconds = (end_time->tv_usec - start_time->tv_usec);
+ return ((seconds * 1000000) + microseconds);
+}
+
+
+/**
+ * Implementation of private_tester_t.run_test.
+ */
+static void run_test(private_tester_t *this, void (*test_function) (protected_tester_t * tester), char * test_name)
+{
+ struct timeval start_time, end_time;
+ long timediff;
+ this->tests_count++;
+ this->failed_asserts_count = 0;
+ fprintf(this->output,"%-55s\n", test_name);
+ gettimeofday(&start_time,NULL);
+ test_function(&(this->protected));
+ gettimeofday(&end_time,NULL);
+ timediff = this->time_difference(this,&end_time, &start_time);
+
+ if (this->failed_asserts_count > 0)
+ {
+ fprintf(this->output," => Test failed: %-37s|%10ld us\n",test_name,timediff);
+ }else
+ {
+ fprintf(this->output,"\033[1A\033[55C|%10ld us\033[1B\033[80D",timediff);
+ }
+ if (this->failed_asserts_count > 0)
+ {
+ this->failed_tests_count++;
+ }
+}
+
+
+/**
+ * Implementation of tester_t.assert_true.
+ */
+static void assert_true(private_tester_t *this, bool to_be_true,char * assert_name)
+{
+ if (assert_name == NULL)
+ {
+ assert_name = "unknown";
+ }
+
+ pthread_mutex_lock(&(this->mutex));
+ if (!to_be_true)
+ {
+ this->failed_asserts_count++;
+ fprintf(this->output," check '%s' failed!\n", assert_name);
+ }else
+ {
+ if (this->display_succeeded_asserts)
+ {
+ fprintf(this->output," check '%s' succeeded\n", assert_name);
+ }
+ }
+ pthread_mutex_unlock(&(this->mutex));
+}
+
+/**
+ * Implementation of tester_t.assert_false.
+ */
+static void assert_false(private_tester_t *this, bool to_be_false,char * assert_name)
+{
+ this->protected.assert_true(&(this->protected),(!to_be_false),assert_name);
+}
+
+/**
+ * Implementation of tester_t.destroy.
+ */
+static void destroy(private_tester_t *tester)
+{
+ private_tester_t *this = (private_tester_t*) tester;
+ pthread_mutex_destroy(&(this->mutex));
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+tester_t *tester_create(FILE *output, bool display_succeeded_asserts)
+{
+ private_tester_t *this = malloc_thing(private_tester_t);
+
+ /* public functions */
+ this->protected.public.destroy = (void (*) (tester_t *))destroy;
+ this->protected.public.perform_tests = (void (*) (tester_t *, test_t**)) perform_tests;
+ this->protected.public.perform_test = (void (*) (tester_t *, test_t*))perform_test;
+ this->protected.assert_true = (void (*) (protected_tester_t *, bool, char*)) assert_true;
+ this->protected.assert_false = (void (*) (protected_tester_t *, bool, char*)) assert_false;
+
+ /* private functions */
+ this->run_test = run_test;
+ this->time_difference = time_difference;
+
+ /* private data */
+ this->display_succeeded_asserts = display_succeeded_asserts;
+ this->failed_tests_count = 0;
+ this->tests_count = 0;
+ this->output = output;
+ pthread_mutex_init(&(this->mutex),NULL);
+
+ return &(this->protected.public);
+}
diff --git a/programs/charon/lib/utils/tester.h b/programs/charon/lib/utils/tester.h
new file mode 100644
index 000000000..3decb2039
--- /dev/null
+++ b/programs/charon/lib/utils/tester.h
@@ -0,0 +1,148 @@
+/**
+ * @file tester.h
+ *
+ * @brief Interface of tester_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef TESTER_H_
+#define TESTER_H_
+
+#include <stdio.h>
+
+#include <types.h>
+
+
+/* must be defined here cause it is used in test_t */
+typedef struct protected_tester_t protected_tester_t;
+
+typedef struct test_t test_t;
+
+/**
+ * @brief Representing a specified test.
+ *
+ * @ingroup utils
+ */
+struct test_t {
+ /**
+ * Testfunction called for this test.
+ *
+ * @param tester associated tester_t object
+ */
+ void (*test_function) (protected_tester_t * tester);
+
+ /**
+ * Name of the test.
+ */
+ char * test_name;
+};
+
+
+typedef struct tester_t tester_t;
+
+/**
+ * @brief A class to perform tests.
+ *
+ * @b Constructors:
+ * - tester_create()
+ *
+ * @ingroup utils
+ */
+struct tester_t {
+ /**
+ * @brief Test all testcases in array tests with specific tester_t object.
+ *
+ * @param tester tester_t object
+ * @param tests pointer to an array of test_t-pointers.
+ * The last item has to be NULL to mark end of array.
+ */
+ void (*perform_tests) (tester_t *tester,test_t **tests);
+
+ /**
+ * @brief Run a specific test case.
+ *
+ * @param this tester_t object
+ * @param test pointer to a test_t object which will be performed
+ */
+ void (*perform_test) (tester_t *tester, test_t *test);
+
+ /**
+ * @brief Destroys a tester_t object.
+ *
+ * @param tester tester_t object
+ */
+ void (*destroy) (tester_t *tester);
+};
+
+
+/**
+ * @brief A class used in a specific testcase.
+ *
+ * For each testcase an object of this type is passed to the testfunction. The testfunction uses this
+ * object to check specific asserts with protected_tester_t.assert_true and protected_tester_t.assert_false.
+ *
+ * @b Constructors:
+ * - tester_create()
+ *
+ * @ingroup utils
+ */
+struct protected_tester_t {
+
+ /**
+ * Public functions of a tester_t object
+ */
+ tester_t public;
+
+ /**
+ * @brief Is called in a testcase to check a specific situation for TRUE.
+ *
+ * Log-Values to the tester output are protected from multiple access.
+ *
+ * @param this tester_t object
+ * @param to_be_true assert which has to be TRUE
+ * @param assert_name name of the assertion
+ */
+ void (*assert_true) (protected_tester_t *tester, bool to_be_true, char *assert_name);
+
+ /**
+ * @brief Is called in a testcase to check a specific situation for FALSE.
+ *
+ * Log-Values to the tester output are protected from multiple access.
+ *
+ * @param this tester_t object
+ * @param to_be_false assert which has to be FALSE
+ * @param assert_name name of the assertion
+ */
+ void (*assert_false) (protected_tester_t *tester, bool to_be_false, char *assert_name);
+};
+
+
+/**
+ * @brief Creates a tester_t object used to perform tests with.
+ *
+ * @param output test output is written to this output.
+ * @param display_succeeded_asserts has to be TRUE, if all asserts should be displayed,
+ * FALSE otherwise
+ *
+ * @return tester_t object
+ *
+ * @ingroup utils
+ */
+tester_t *tester_create(FILE *output, bool display_succeeded_asserts);
+
+#endif /*TESTER_H_*/
diff --git a/programs/charon/patches/strongswan-2.7.0.patch b/programs/charon/patches/strongswan-2.7.0.patch
new file mode 100644
index 000000000..b21e1013b
--- /dev/null
+++ b/programs/charon/patches/strongswan-2.7.0.patch
@@ -0,0 +1,874 @@
+diff -Naur strongswan-2.7.0/Makefile.inc strongswan-2.7.0-patched/Makefile.inc
+--- strongswan-2.7.0/Makefile.inc 2006-01-25 18:23:15.000000000 +0100
++++ strongswan-2.7.0-patched/Makefile.inc 2006-04-28 08:56:38.000000000 +0200
+@@ -84,6 +84,8 @@
+ FINALLIBDIR=$(INC_USRLOCAL)/lib/ipsec
+ LIBDIR=$(DESTDIR)$(FINALLIBDIR)
+
++# sharedlibdir is where shared libraries go
++SHAREDLIBDIR=$(DESTDIR)$(INC_USRLOCAL)/lib
+
+ # where the appropriate manpage tree is located
+ # location within INC_USRLOCAL
+@@ -284,6 +286,9 @@
+ # include PKCS11-based smartcard support
+ USE_SMARTCARD?=false
+
++# support IKEv2 via charon
++USE_IKEV2?=true
++
+ # Default PKCS11 library
+ # Uncomment this line if using OpenSC <= 0.9.6
+ PKCS11_DEFAULT_LIB=\"/usr/lib/pkcs11/opensc-pkcs11.so\"
+diff -Naur strongswan-2.7.0/programs/Makefile strongswan-2.7.0-patched/programs/Makefile
+--- strongswan-2.7.0/programs/Makefile 2006-04-17 13:04:45.000000000 +0200
++++ strongswan-2.7.0-patched/programs/Makefile 2006-04-28 08:56:38.000000000 +0200
+@@ -32,6 +32,10 @@
+ SUBDIRS+=showpolicy
+ endif
+
++ifeq ($(USE_IKEV2),true)
++SUBDIRS+=charon
++endif
++
+ def:
+ @echo "Please read doc/intro.html or INSTALL before running make"
+ @false
+diff -Naur strongswan-2.7.0/programs/ipsec/ipsec.in strongswan-2.7.0-patched/programs/ipsec/ipsec.in
+--- strongswan-2.7.0/programs/ipsec/ipsec.in 2006-03-09 21:09:33.000000000 +0100
++++ strongswan-2.7.0-patched/programs/ipsec/ipsec.in 2006-04-28 08:56:38.000000000 +0200
+@@ -26,6 +26,7 @@
+ export IPSEC_DIR IPSEC_CONFS IPSEC_LIBDIR IPSEC_EXECDIR
+
+ IPSEC_STARTER_PID="/var/run/starter.pid"
++IPSEC_CHARON_PID="/var/run/charon.pid"
+
+ # standardize PATH, and export it for everything else's benefit
+ PATH="${IPSEC_SBINDIR}":/sbin:/usr/sbin:/usr/local/bin:/bin:/usr/bin
+@@ -123,6 +124,10 @@
+ down)
+ shift
+ $IPSEC_EXECDIR/whack --name "$1" --terminate
++ if test -e $IPSEC_CHARON_PID
++ then
++ $IPSEC_EXECDIR/stroke down "$1"
++ fi
+ exit 0
+ ;;
+ listalgs|listpubkeys|listcerts|listcacerts|\
+@@ -134,6 +139,10 @@
+ op="$1"
+ shift
+ $IPSEC_EXECDIR/whack "$@" "--$op"
++ if test -e $IPSEC_CHARON_PID
++ then
++ $IPSEC_EXECDIR/stroke "$op"
++ fi
+ exit 0
+ ;;
+ ready)
+@@ -180,8 +189,16 @@
+ if test $# -eq 0
+ then
+ $IPSEC_EXECDIR/whack "--$op"
++ if test -e $IPSEC_CHARON_PID
++ then
++ $IPSEC_EXECDIR/stroke "$op"
++ fi
+ else
+ $IPSEC_EXECDIR/whack --name "$1" "--$op"
++ if test -e $IPSEC_CHARON_PID
++ then
++ $IPSEC_EXECDIR/stroke "$op" "$1"
++ fi
+ fi
+ exit 0
+ ;;
+@@ -198,6 +215,10 @@
+ up)
+ shift
+ $IPSEC_EXECDIR/whack --name "$1" --initiate
++ if test -e $IPSEC_CHARON_PID
++ then
++ $IPSEC_EXECDIR/stroke up "$1"
++ fi
+ exit 0
+ ;;
+ update)
+diff -Naur strongswan-2.7.0/programs/pluto/Makefile strongswan-2.7.0-patched/programs/pluto/Makefile
+--- strongswan-2.7.0/programs/pluto/Makefile 2006-01-25 18:22:19.000000000 +0100
++++ strongswan-2.7.0-patched/programs/pluto/Makefile 2006-04-28 08:56:38.000000000 +0200
+@@ -170,6 +170,11 @@
+ LIBSPLUTO+= -ldl
+ endif
+
++# enable IKEv2 support
++ifeq ($(USE_IKEV2),true)
++ DEFINES+= -DIKEV2
++endif
++
+ # This compile option activates the leak detective
+ ifeq ($(USE_LEAK_DETECTIVE),true)
+ DEFINES+= -DLEAK_DETECTIVE
+diff -Naur strongswan-2.7.0/programs/pluto/demux.c strongswan-2.7.0-patched/programs/pluto/demux.c
+--- strongswan-2.7.0/programs/pluto/demux.c 2005-02-18 22:08:59.000000000 +0100
++++ strongswan-2.7.0-patched/programs/pluto/demux.c 2006-04-28 08:56:13.000000000 +0200
+@@ -1196,6 +1196,21 @@
+ }
+ #endif
+
++#ifdef IKEV2
++#define IKEV2_VERSION_OFFSET 17
++#define IKEV2_VERSION 0x20
++
++ /* ignore IKEv2 packets - they will be handled by charon */
++ if (pbs_room(&md->packet_pbs) > IKEV2_VERSION_OFFSET
++ && md->packet_pbs.start[IKEV2_VERSION_OFFSET] == IKEV2_VERSION)
++ {
++ DBG(DBG_CONTROLMORE,
++ DBG_log(" ignoring IKEv2 packet")
++ )
++ return FALSE;
++ }
++#endif /* IKEV2 */
++
+ return TRUE;
+ }
+
+@@ -1229,6 +1244,7 @@
+ if (md->packet_pbs.roof - md->packet_pbs.cur >= (ptrdiff_t)isakmp_hdr_desc.size)
+ {
+ struct isakmp_hdr *hdr = (struct isakmp_hdr *)md->packet_pbs.cur;
++
+ if ((hdr->isa_version >> ISA_MAJ_SHIFT) != ISAKMP_MAJOR_VERSION)
+ {
+ SEND_NOTIFICATION(INVALID_MAJOR_VERSION);
+diff -Naur strongswan-2.7.0/programs/starter/Makefile strongswan-2.7.0-patched/programs/starter/Makefile
+--- strongswan-2.7.0/programs/starter/Makefile 2006-02-17 20:34:02.000000000 +0100
++++ strongswan-2.7.0-patched/programs/starter/Makefile 2006-04-28 08:56:38.000000000 +0200
+@@ -34,6 +34,11 @@
+ DEFINES+= -DLEAK_DETECTIVE
+ endif
+
++# Enable charon support
++ifeq ($(USE_IKEV2),true)
++ DEFINES+= -DIKEV2
++endif
++
+ INCLUDES=-I${FREESWANDIR}/linux/include
+ CFLAGS=$(DEFINES) $(INCLUDES) -Wall
+ CFLAGS+=-DIPSEC_EXECDIR=\"${FINALLIBEXECDIR}\" -DIPSEC_CONFDDIR=\"${FINALCONFDDIR}\"
+@@ -46,6 +51,11 @@
+ starterwhack.o klips.o netkey.o interfaces.o exec.o cmp.o confread.o \
+ loglite.o ${PLUTO_OBJS}
+
++# Build charon-only objs
++ifeq ($(USE_IKEV2),true)
++ OBJS+= invokecharon.o starterstroke.o
++endif
++
+ DISTSRC=$(OBJS:.o=.c)
+ DISTSRC+=cmp.h confread.h confwrite.h exec.h files.h interfaces.h klips.h netkey.h
+ DISTSRC+=parser.h args.h invokepluto.h starterwhack.h keywords.h keywords.txt
+diff -Naur strongswan-2.7.0/programs/starter/args.c strongswan-2.7.0-patched/programs/starter/args.c
+--- strongswan-2.7.0/programs/starter/args.c 2006-04-17 12:32:36.000000000 +0200
++++ strongswan-2.7.0-patched/programs/starter/args.c 2006-04-28 08:56:38.000000000 +0200
+@@ -86,6 +86,10 @@
+
+ static const char *LST_keyexchange[] = {
+ "ike",
++#ifdef IKEV2
++ "ikev1",
++ "ikev2",
++#endif /* IKEV2 */
+ NULL
+ };
+
+diff -Naur strongswan-2.7.0/programs/starter/files.h strongswan-2.7.0-patched/programs/starter/files.h
+--- strongswan-2.7.0/programs/starter/files.h 2006-02-04 19:52:58.000000000 +0100
++++ strongswan-2.7.0-patched/programs/starter/files.h 2006-04-28 08:56:38.000000000 +0200
+@@ -37,8 +37,15 @@
+ #define SECRETS_FILE IPSEC_CONFDIR"/ipsec.secrets"
+
+ #define PLUTO_CMD IPSEC_EXECDIR"/pluto"
+-#define CTL_FILE DEFAULT_CTLBASE CTL_SUFFIX
+-#define PID_FILE DEFAULT_CTLBASE PID_SUFFIX
++#define PLUTO_CTL_FILE DEFAULT_CTLBASE CTL_SUFFIX
++#define PLUTO_PID_FILE DEFAULT_CTLBASE PID_SUFFIX
++
++#ifdef IKEV2
++#define CHARON_CMD IPSEC_EXECDIR"/charon"
++#define CHARON_BASE "/var/run/charon"
++#define CHARON_CTL_FILE CHARON_BASE CTL_SUFFIX
++#define CHARON_PID_FILE CHARON_BASE PID_SUFFIX
++#endif /* IKEV2 */
+
+ #define DYNIP_DIR "/var/run/dynip"
+ #define INFO_FILE "/var/run/ipsec.info"
+diff -Naur strongswan-2.7.0/programs/starter/invokecharon.c strongswan-2.7.0-patched/programs/starter/invokecharon.c
+--- strongswan-2.7.0/programs/starter/invokecharon.c 1970-01-01 01:00:00.000000000 +0100
++++ strongswan-2.7.0-patched/programs/starter/invokecharon.c 2006-04-28 08:56:38.000000000 +0200
+@@ -0,0 +1,174 @@
++/* strongSwan charon launcher
++ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
++ * Copyright (C) 2006 Martin Willi - Hochschule fuer Technik Rapperswil
++ *
++ * Ported from invokepluto.c to fit charons needs.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ * for more details.
++ *
++ * RCSID $Id: invokecharon.c $
++ */
++
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <unistd.h>
++#include <signal.h>
++#include <string.h>
++#include <stdlib.h>
++#include <errno.h>
++
++#include <freeswan.h>
++
++#include "../pluto/constants.h"
++#include "../pluto/defs.h"
++#include "../pluto/log.h"
++
++#include "confread.h"
++#include "invokecharon.h"
++#include "files.h"
++
++static int _charon_pid = 0;
++static int _stop_requested;
++
++pid_t
++starter_charon_pid(void)
++{
++ return _charon_pid;
++}
++
++void
++starter_charon_sigchild(pid_t pid)
++{
++ if (pid == _charon_pid)
++ {
++ _charon_pid = 0;
++ if (!_stop_requested)
++ {
++ plog("charon has died -- restart scheduled (%dsec)"
++ , CHARON_RESTART_DELAY);
++ alarm(CHARON_RESTART_DELAY); // restart in 5 sec
++ }
++ unlink(CHARON_PID_FILE);
++ }
++}
++
++int
++starter_stop_charon (void)
++{
++ pid_t pid;
++ int i;
++
++ pid = _charon_pid;
++ if (pid)
++ {
++ _stop_requested = 1;
++
++ /* be more and more aggressive */
++ for (i = 0; i < 20 && (pid = _charon_pid) != 0; i++)
++ {
++ if (i == 0)
++ kill(pid, SIGINT);
++ else if (i < 10)
++ kill(pid, SIGTERM);
++ else
++ kill(pid, SIGKILL);
++ usleep(20000);
++ }
++ if (_charon_pid == 0)
++ return 0;
++ plog("starter_stop_charon(): can't stop charon !!!");
++ return -1;
++ }
++ else
++ {
++ plog("stater_stop_charon(): charon is not started...");
++ }
++ return -1;
++}
++
++
++int
++starter_start_charon (starter_config_t *cfg, bool debug)
++{
++ int pid, i;
++ struct stat stb;
++ int argc = 1;
++ char *arg[] = {
++ CHARON_CMD, NULL, NULL,
++ };
++
++ if (!debug)
++ {
++ arg[argc++] = "--use-syslog";
++ }
++
++ if (_charon_pid)
++ {
++ plog("starter_start_charon(): charon already started...");
++ return -1;
++ }
++ else
++ {
++ unlink(CHARON_CTL_FILE);
++ _stop_requested = 0;
++
++ pid = fork();
++ switch (pid)
++ {
++ case -1:
++ plog("can't fork(): %s", strerror(errno));
++ return -1;
++ case 0:
++ /* child */
++ setsid();
++ sigprocmask(SIG_SETMASK, 0, NULL);
++ execv(arg[0], arg);
++ plog("can't execv(%s,...): %s", arg[0], strerror(errno));
++ exit(1);
++ default:
++ /* father */
++ _charon_pid = pid;
++ for (i = 0; i < 50 && _charon_pid; i++)
++ {
++ /* wait for charon */
++ usleep(20000);
++ if (stat(CHARON_PID_FILE, &stb) == 0)
++ {
++ DBG(DBG_CONTROL,
++ DBG_log("charon (%d) started", _charon_pid)
++ )
++ return 0;
++ }
++ }
++ if (_charon_pid)
++ {
++ /* If charon is started but with no ctl file, stop it */
++ plog("charon too long to start... - kill kill");
++ for (i = 0; i < 20 && (pid = _charon_pid) != 0; i++)
++ {
++ if (i == 0)
++ kill(pid, SIGINT);
++ else if (i < 10)
++ kill(pid, SIGTERM);
++ else
++ kill(pid, SIGKILL);
++ usleep(20000);
++ }
++ }
++ else
++ {
++ plog("charon refused to be started");
++ }
++ return -1;
++ }
++ }
++ return -1;
++}
+diff -Naur strongswan-2.7.0/programs/starter/invokecharon.h strongswan-2.7.0-patched/programs/starter/invokecharon.h
+--- strongswan-2.7.0/programs/starter/invokecharon.h 1970-01-01 01:00:00.000000000 +0100
++++ strongswan-2.7.0-patched/programs/starter/invokecharon.h 2006-04-28 08:56:38.000000000 +0200
+@@ -0,0 +1,31 @@
++/* strongSwan charon launcher
++ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
++ * Copyright (C) 2006 Martin Willi - Hochschule fuer Technik Rapperswil
++ *
++ * Ported from invokepluto.h to fit charons needs.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ * for more details.
++ *
++ * RCSID $Id: invokecharon.h $
++ */
++
++#ifndef _STARTER_CHARON_H_
++#define _STARTER_CHARON_H_
++
++#define CHARON_RESTART_DELAY 5
++
++extern void starter_charon_sigchild (pid_t pid);
++extern pid_t starter_charon_pid (void);
++extern int starter_stop_charon (void);
++extern int starter_start_charon(struct starter_config *cfg, bool debug);
++
++#endif /* _STARTER_CHARON_H_ */
++
+diff -Naur strongswan-2.7.0/programs/starter/invokepluto.c strongswan-2.7.0-patched/programs/starter/invokepluto.c
+--- strongswan-2.7.0/programs/starter/invokepluto.c 2006-02-17 22:41:50.000000000 +0100
++++ strongswan-2.7.0-patched/programs/starter/invokepluto.c 2006-04-28 08:56:38.000000000 +0200
+@@ -54,7 +54,7 @@
+ , PLUTO_RESTART_DELAY);
+ alarm(PLUTO_RESTART_DELAY); // restart in 5 sec
+ }
+- unlink(PID_FILE);
++ unlink(PLUTO_PID_FILE);
+ }
+ }
+
+@@ -203,7 +203,7 @@
+ }
+ else
+ {
+- unlink(CTL_FILE);
++ unlink(PLUTO_CTL_FILE);
+ _stop_requested = 0;
+
+ if (cfg->setup.prepluto)
+@@ -252,7 +252,7 @@
+ {
+ /* wait for pluto */
+ usleep(20000);
+- if (stat(CTL_FILE, &stb) == 0)
++ if (stat(PLUTO_CTL_FILE, &stb) == 0)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("pluto (%d) started", _pluto_pid)
+diff -Naur strongswan-2.7.0/programs/starter/starter.c strongswan-2.7.0-patched/programs/starter/starter.c
+--- strongswan-2.7.0/programs/starter/starter.c 2006-02-15 19:37:46.000000000 +0100
++++ strongswan-2.7.0-patched/programs/starter/starter.c 2006-04-28 08:56:38.000000000 +0200
+@@ -37,6 +37,7 @@
+ #include "files.h"
+ #include "starterwhack.h"
+ #include "invokepluto.h"
++#include "invokecharon.h"
+ #include "klips.h"
+ #include "netkey.h"
+ #include "cmp.h"
+@@ -47,6 +48,9 @@
+ #define FLAG_ACTION_RELOAD 0x04
+ #define FLAG_ACTION_QUIT 0x08
+ #define FLAG_ACTION_LISTEN 0x10
++#ifdef IKEV2
++#define FLAG_ACTION_START_CHARON 0x20
++#endif /* IKEV2 */
+
+ static unsigned int _action_ = 0;
+
+@@ -65,6 +69,10 @@
+ {
+ if (pid == starter_pluto_pid())
+ name = " (Pluto)";
++#ifdef IKEV2
++ if (pid == starter_charon_pid())
++ name = " (Charon)";
++#endif /* IKEV2 */
+ if (WIFSIGNALED(status))
+ DBG(DBG_CONTROL,
+ DBG_log("child %d%s has been killed by sig %d\n",
+@@ -87,6 +95,10 @@
+
+ if (pid == starter_pluto_pid())
+ starter_pluto_sigchild(pid);
++#ifdef IKEV2
++ if (pid == starter_charon_pid())
++ starter_charon_sigchild(pid);
++#endif /* IKEV2 */
+ }
+ }
+ break;
+@@ -97,6 +109,9 @@
+
+ case SIGALRM:
+ _action_ |= FLAG_ACTION_START_PLUTO;
++#ifdef IKEV2
++ _action_ |= FLAG_ACTION_START_CHARON;
++#endif /* IKEV2 */
+ break;
+
+ case SIGHUP:
+@@ -193,6 +208,9 @@
+ signal(SIGQUIT, fsig);
+ signal(SIGALRM, fsig);
+ signal(SIGUSR1, fsig);
++
++
++ plog("Starting strongSwan IPsec %s [starter]...", ipsec_version_code());
+
+ /* verify that we can start */
+ if (getuid() != 0)
+@@ -201,12 +219,24 @@
+ exit(1);
+ }
+
+- if (stat(PID_FILE, &stb) == 0)
++ if (stat(PLUTO_PID_FILE, &stb) == 0)
+ {
+- plog("pluto is already running (%s exists) -- aborting", PID_FILE);
+- exit(1);
++ plog("pluto is already running (%s exists) -- skipping pluto start", PLUTO_PID_FILE);
+ }
+-
++ else
++ {
++ _action_ |= FLAG_ACTION_START_PLUTO;
++ }
++#ifdef IKEV2
++ if (stat(CHARON_PID_FILE, &stb) == 0)
++ {
++ plog("charon is already running (%s exists) -- skipping charon start", CHARON_PID_FILE);
++ }
++ else
++ {
++ _action_ |= FLAG_ACTION_START_CHARON;
++ }
++#endif /* IKEV2 */
+ if (stat(DEV_RANDOM, &stb) != 0)
+ {
+ plog("unable to start strongSwan IPsec -- no %s!", DEV_RANDOM);
+@@ -247,7 +277,11 @@
+
+ last_reload = time(NULL);
+
+- plog("Starting strongSwan IPsec %s [starter]...", ipsec_version_code());
++ if (stat(MY_PID_FILE, &stb) == 0)
++ {
++ plog("starter is already running (%s exists) -- no fork done", MY_PID_FILE);
++ exit(0);
++ }
+
+ /* fork if we're not debugging stuff */
+ if (!no_fork)
+@@ -296,17 +330,19 @@
+ , &cfg->defaultroute);
+ }
+
+- _action_ = FLAG_ACTION_START_PLUTO;
+-
+ for (;;)
+ {
+ /*
+- * Stop pluto (if started) and exit
+- */
++ * Stop pluto/charon (if started) and exit
++ */
+ if (_action_ & FLAG_ACTION_QUIT)
+ {
+ if (starter_pluto_pid())
+ starter_stop_pluto();
++#ifdef IKEV2
++ if (starter_charon_pid())
++ starter_stop_charon();
++#endif IKEV2
+ if (has_netkey)
+ starter_netkey_cleanup();
+ else
+@@ -337,6 +373,9 @@
+ if (conn->state == STATE_ADDED)
+ {
+ starter_whack_del_conn(conn);
++#ifdef IKEV2
++ starter_stroke_del_conn(conn);
++#endif /* IKEV2 */
+ conn->state = STATE_TO_ADD;
+ }
+ }
+@@ -427,6 +466,9 @@
+ {
+ if (conn->state == STATE_ADDED)
+ starter_whack_del_conn(conn);
++#ifdef IKEV2
++ starter_stroke_del_conn(conn);
++#endif /* IKEV2 */
+ }
+
+ /* Look for new ca sections that are already loaded */
+@@ -502,6 +544,27 @@
+ conn->state = STATE_TO_ADD;
+ }
+ }
++
++#ifdef IKEV2
++ /*
++ * Start charon
++ */
++ if (_action_ & FLAG_ACTION_START_CHARON)
++ {
++ if (starter_charon_pid() == 0)
++ {
++ DBG(DBG_CONTROL,
++ DBG_log("Attempting to start charon...")
++ )
++ if (starter_start_charon(cfg, no_fork) != 0)
++ {
++ /* schedule next try */
++ alarm(PLUTO_RESTART_DELAY);
++ }
++ }
++ _action_ &= ~FLAG_ACTION_START_CHARON;
++ }
++#endif /* IKEV2 */
+
+ /*
+ * Tell pluto to reread its interfaces
+@@ -536,11 +599,36 @@
+ conn->id = id++;
+ }
+ starter_whack_add_conn(conn);
++#ifdef IKEV2
++ starter_stroke_add_conn(conn);
++#endif /* IKEV2 */
+ conn->state = STATE_ADDED;
+ if (conn->startup == STARTUP_START)
+- starter_whack_initiate_conn(conn);
++ {
++#ifdef IKEV2
++ if (conn->keyexchange == 2)
++ {
++ starter_stroke_initiate_conn(conn);
++ }
++ else
++#endif /* IKEV2 */
++ {
++ starter_whack_initiate_conn(conn);
++ }
++ }
+ else if (conn->startup == STARTUP_ROUTE)
+- starter_whack_route_conn(conn);
++ {
++#ifdef IKEV2
++ if (conn->keyexchange == 2)
++ {
++ starter_stroke_route_conn(conn);
++ }
++ else
++#endif /* IKEV2 */
++ {
++ starter_whack_route_conn(conn);
++ }
++ }
+ }
+ }
+ }
+diff -Naur strongswan-2.7.0/programs/starter/starterstroke.c strongswan-2.7.0-patched/programs/starter/starterstroke.c
+--- strongswan-2.7.0/programs/starter/starterstroke.c 1970-01-01 01:00:00.000000000 +0100
++++ strongswan-2.7.0-patched/programs/starter/starterstroke.c 2006-04-28 08:56:38.000000000 +0200
+@@ -0,0 +1,161 @@
++/* Stroke for charon is the counterpart to whack from pluto
++ * Copyright (C) 2006 Martin Willi - Hochschule fuer Technik Rapperswil
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ * for more details.
++ *
++ * RCSID $Id: starterstroke.c $
++ */
++
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <sys/un.h>
++#include <linux/stddef.h>
++#include <unistd.h>
++#include <stdlib.h>
++#include <errno.h>
++#include <netinet/in.h>
++#include <arpa/inet.h>
++
++#include <freeswan.h>
++
++#include "../pluto/constants.h"
++#include "../pluto/defs.h"
++#include "../pluto/log.h"
++
++#include "../charon/stroke/stroke.h"
++
++#include "starterstroke.h"
++#include "confread.h"
++#include "files.h"
++
++static char* push_string(stroke_msg_t **strm, char *string)
++{
++ stroke_msg_t *stroke_msg;
++ size_t string_length;
++
++ if (string == NULL)
++ {
++ return NULL;
++ }
++ stroke_msg = *strm;
++ string_length = strlen(string) + 1;
++ stroke_msg->length += string_length;
++
++ stroke_msg = realloc(stroke_msg, stroke_msg->length);
++ strcpy((char*)stroke_msg + stroke_msg->length - string_length, string);
++
++ *strm = stroke_msg;
++ return (char*)(u_int)stroke_msg->length - string_length;
++}
++
++static int
++send_stroke_msg (stroke_msg_t *msg)
++{
++ struct sockaddr_un ctl_addr = { AF_UNIX, CHARON_CTL_FILE };
++ int sock;
++
++ sock = socket(AF_UNIX, SOCK_STREAM, 0);
++ if (sock < 0)
++ {
++ plog("socket() failed: %s", strerror(errno));
++ return -1;
++ }
++ if (connect(sock, (struct sockaddr *)&ctl_addr,
++ offsetof(struct sockaddr_un, sun_path) + strlen(ctl_addr.sun_path)) < 0)
++ {
++ plog("connect(charon_ctl) failed: %s", strerror(errno));
++ close(sock);
++ return -1;
++ }
++
++ /* send message */
++ if (write(sock, msg, msg->length) != msg->length)
++ {
++ plog("write(charon_ctl) failed: %s", strerror(errno));
++ close(sock);
++ return -1;
++ }
++
++ close(sock);
++ return 0;
++}
++
++static char *
++connection_name(starter_conn_t *conn)
++{
++ /* if connection name is '%auto', create a new name like conn_xxxxx */
++ static char buf[32];
++
++ if (streq(conn->name, "%auto"))
++ {
++ sprintf(buf, "conn_%ld", conn->id);
++ return buf;
++ }
++ return conn->name;
++}
++
++
++int starter_stroke_add_conn(starter_conn_t *conn)
++{
++ stroke_msg_t *msg = malloc(sizeof(stroke_msg_t));
++ int res;
++
++ msg->length = sizeof(stroke_msg_t);
++ msg->type = STR_ADD_CONN;
++
++ msg->add_conn.name = push_string(&msg, connection_name(conn));
++
++ msg->add_conn.me.id = push_string(&msg, conn->left.id);
++ msg->add_conn.me.cert = push_string(&msg, conn->left.cert);
++ msg->add_conn.me.address = push_string(&msg, inet_ntoa(conn->left.addr.u.v4.sin_addr));
++ msg->add_conn.me.subnet = push_string(&msg, inet_ntoa(conn->left.subnet.addr.u.v4.sin_addr));
++ msg->add_conn.me.subnet_mask = conn->left.subnet.maskbits;
++
++ msg->add_conn.other.id = push_string(&msg, conn->right.id);
++ msg->add_conn.other.cert = push_string(&msg, conn->right.cert);
++ msg->add_conn.other.address = push_string(&msg, inet_ntoa(conn->right.addr.u.v4.sin_addr));
++ msg->add_conn.other.subnet = push_string(&msg, inet_ntoa(conn->right.subnet.addr.u.v4.sin_addr));
++ msg->add_conn.other.subnet_mask = conn->right.subnet.maskbits;
++
++ res = send_stroke_msg(msg);
++ free(msg);
++ return res;
++}
++
++int starter_stroke_del_conn(starter_conn_t *conn)
++{
++ return 0;
++}
++int starter_stroke_route_conn(starter_conn_t *conn)
++{
++ stroke_msg_t *msg = malloc(sizeof(stroke_msg_t));
++ int res;
++
++ msg->length = sizeof(stroke_msg_t);
++ msg->type = STR_INSTALL;
++ msg->install.name = push_string(&msg, connection_name(conn));
++ res = send_stroke_msg(msg);
++ free(msg);
++ return res;
++}
++
++int starter_stroke_initiate_conn(starter_conn_t *conn)
++{
++ stroke_msg_t *msg = malloc(sizeof(stroke_msg_t));
++ int res;
++
++ msg->length = sizeof(stroke_msg_t);
++ msg->type = STR_INITIATE;
++ msg->initiate.name = push_string(&msg, connection_name(conn));
++ res = send_stroke_msg(msg);
++ free(msg);
++ return res;
++}
+diff -Naur strongswan-2.7.0/programs/starter/starterstroke.h strongswan-2.7.0-patched/programs/starter/starterstroke.h
+--- strongswan-2.7.0/programs/starter/starterstroke.h 1970-01-01 01:00:00.000000000 +0100
++++ strongswan-2.7.0-patched/programs/starter/starterstroke.h 2006-04-28 08:56:38.000000000 +0200
+@@ -0,0 +1,27 @@
++/* Stroke for charon is the counterpart to whack from pluto
++ * Copyright (C) 2006 Martin Willi - Hochschule fuer Technik Rapperswil
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ * for more details.
++ *
++ * RCSID $Id: starterstroke.h $
++ */
++
++#ifndef _STARTER_STROKE_H_
++#define _STARTER_STROKE_H_
++
++#include "confread.h"
++
++extern int starter_stroke_add_conn(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);
++
++#endif /* _STARTER_STROKE_H_ */
+diff -Naur strongswan-2.7.0/programs/starter/starterwhack.c strongswan-2.7.0-patched/programs/starter/starterwhack.c
+--- strongswan-2.7.0/programs/starter/starterwhack.c 2006-04-17 12:32:36.000000000 +0200
++++ strongswan-2.7.0-patched/programs/starter/starterwhack.c 2006-04-28 08:56:38.000000000 +0200
+@@ -54,7 +54,7 @@
+ static int
+ send_whack_msg (whack_message_t *msg)
+ {
+- struct sockaddr_un ctl_addr = { AF_UNIX, CTL_FILE };
++ struct sockaddr_un ctl_addr = { AF_UNIX, PLUTO_CTL_FILE };
+ int sock;
+ ssize_t len;
+ char *str_next, *str_roof;
diff --git a/programs/charon/scripts/alice-key.der b/programs/charon/scripts/alice-key.der
new file mode 100644
index 000000000..5a8aef6cb
--- /dev/null
+++ b/programs/charon/scripts/alice-key.der
Binary files differ
diff --git a/programs/charon/scripts/alice.der b/programs/charon/scripts/alice.der
new file mode 100644
index 000000000..8154defd9
--- /dev/null
+++ b/programs/charon/scripts/alice.der
Binary files differ
diff --git a/programs/charon/scripts/bob-key.der b/programs/charon/scripts/bob-key.der
new file mode 100644
index 000000000..f944dec9f
--- /dev/null
+++ b/programs/charon/scripts/bob-key.der
Binary files differ
diff --git a/programs/charon/scripts/bob.der b/programs/charon/scripts/bob.der
new file mode 100644
index 000000000..401611888
--- /dev/null
+++ b/programs/charon/scripts/bob.der
Binary files differ
diff --git a/programs/charon/scripts/complex1.der b/programs/charon/scripts/complex1.der
new file mode 100644
index 000000000..ba460cbee
--- /dev/null
+++ b/programs/charon/scripts/complex1.der
Binary files differ
diff --git a/programs/charon/scripts/complex2.der b/programs/charon/scripts/complex2.der
new file mode 100644
index 000000000..160b21f47
--- /dev/null
+++ b/programs/charon/scripts/complex2.der
Binary files differ
diff --git a/programs/charon/scripts/daemon-loop.sh b/programs/charon/scripts/daemon-loop.sh
new file mode 100755
index 000000000..9a361e012
--- /dev/null
+++ b/programs/charon/scripts/daemon-loop.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+while [ 1 ]
+do
+ ip x p f
+ ip x s f
+ rm /var/run/charon.*
+ make
+ bin/charon
+ echo ""
+ echo "----------------------------"
+ echo ""
+done
diff --git a/programs/charon/scripts/deleteline b/programs/charon/scripts/deleteline
new file mode 100755
index 000000000..9f529dccc
--- /dev/null
+++ b/programs/charon/scripts/deleteline
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+FILES=`find . -name '*.[ch]'`
+for FILE in $FILES
+do
+ TMP=${FILE}_tmp
+ sed "/$1/d" < $FILE > $TMP
+ mv $TMP $FILE
+done
diff --git a/programs/charon/scripts/replace b/programs/charon/scripts/replace
new file mode 100755
index 000000000..adfc8e09a
--- /dev/null
+++ b/programs/charon/scripts/replace
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+FILES=`find . -name '*.[ch]'`
+for FILE in $FILES
+do
+ TMP=${FILE}_tmp
+ sed "s/$1/$2/g" < $FILE > $TMP
+ mv $TMP $FILE
+done
diff --git a/programs/charon/scripts/to-alice.sh b/programs/charon/scripts/to-alice.sh
new file mode 100755
index 000000000..01ba27f5b
--- /dev/null
+++ b/programs/charon/scripts/to-alice.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+# enable ip forwarding for gateway
+echo 1 > /proc/sys/net/ipv4/ip_forward
+
+# add connection to alice
+MY_ADDR=192.168.0.2 # Address of local peer
+OTHER_ADDR=192.168.0.1 # Address of remote peer
+MY_ID="C=CH, O=Linux strongSwan, CN=bob" # ID of local peer
+OTHER_ID="C=CH, O=Linux strongSwan, CN=alice" # ID of remote peer
+MY_NET=10.2.0.0 # protected local subnet
+OTHER_NET=10.1.0.0 # protected remote subnet
+MY_BITS=16 # size of subnet
+OTHER_BITS=16 # size of subnet
+CONN_NAME=to-alice # connection name
+
+bin/stroke add $CONN_NAME "$MY_ID" "$OTHER_ID" $MY_ADDR $OTHER_ADDR $MY_NET $OTHER_NET $MY_BITS $OTHER_BITS
+
+# initiate
+i=0
+LIMIT=1
+
+while [ "$i" -lt "$LIMIT" ]
+do
+ bin/stroke up $CONN_NAME
+ let "i += 1"
+done
diff --git a/programs/charon/scripts/to-bob.sh b/programs/charon/scripts/to-bob.sh
new file mode 100755
index 000000000..df30bd893
--- /dev/null
+++ b/programs/charon/scripts/to-bob.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+# enable ip forwarding for gateway
+echo 1 > /proc/sys/net/ipv4/ip_forward
+
+# add connection to bob
+MY_ADDR=192.168.0.1 # Address of local peer
+OTHER_ADDR=192.168.0.2 # Address of remote peer
+MY_ID="C=CH, O=Linux strongSwan, CN=alice" # ID of local peer
+OTHER_ID="C=CH, O=Linux strongSwan, CN=bob" # ID of remote peer
+MY_NET=10.1.0.0 # protected local subnet
+OTHER_NET=10.2.0.0 # protected remote subnet
+MY_BITS=16 # size of subnet
+OTHER_BITS=16 # size of subnet
+CONN_NAME=to-bob # connection name
+
+bin/stroke add $CONN_NAME "$MY_ID" "$OTHER_ID" $MY_ADDR $OTHER_ADDR $MY_NET $OTHER_NET $MY_BITS $OTHER_BITS
+
+# initiate
+i=0
+LIMIT=0
+
+while [ "$i" -lt "$LIMIT" ]
+do
+ bin/stroke up $CONN_NAME
+ let "i += 1"
+done
diff --git a/programs/charon/stroke/Makefile.stroke b/programs/charon/stroke/Makefile.stroke
new file mode 100644
index 000000000..c87445095
--- /dev/null
+++ b/programs/charon/stroke/Makefile.stroke
@@ -0,0 +1,17 @@
+# Copyright (C) 2006 Martin Willi
+# Hochschule fuer Technik Rapperswil
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+STROKE_DIR= $(MAIN_DIR)stroke/
+
+$(BUILD_DIR)stroke.o : $(STROKE_DIR)stroke.c $(STROKE_DIR)stroke.h
+ $(CC) $(CFLAGS) -c -o $@ $<
diff --git a/programs/charon/stroke/stroke.c b/programs/charon/stroke/stroke.c
new file mode 100644
index 000000000..9ecda0413
--- /dev/null
+++ b/programs/charon/stroke/stroke.c
@@ -0,0 +1,304 @@
+/* Stroke for charon is the counterpart to whack from pluto
+ * Copyright (C) 2006 Martin Willi - Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <linux/stddef.h>
+
+#include "stroke.h"
+
+static char* push_string(stroke_msg_t **strm, char *string)
+{
+ stroke_msg_t *stroke_msg;
+ size_t string_length;
+
+ if (string == NULL)
+ {
+ return NULL;
+ }
+ stroke_msg = *strm;
+ string_length = strlen(string) + 1;
+ stroke_msg->length += string_length;
+
+ stroke_msg = realloc(stroke_msg, stroke_msg->length);
+ strcpy((char*)stroke_msg + stroke_msg->length - string_length, string);
+
+ *strm = stroke_msg;
+ return (char*)(u_int)stroke_msg->length - string_length;
+}
+
+static int send_stroke_msg (stroke_msg_t *msg)
+{
+ struct sockaddr_un ctl_addr = { AF_UNIX, STROKE_SOCKET };
+ int sock;
+ char buffer[64];
+ int byte_count;
+
+ sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sock < 0)
+ {
+ fprintf(stderr, "Opening unix socket %s: %s\n", STROKE_SOCKET, strerror(errno));
+ return -1;
+ }
+ if (connect(sock, (struct sockaddr *)&ctl_addr,
+ offsetof(struct sockaddr_un, sun_path) + strlen(ctl_addr.sun_path)) < 0)
+ {
+ fprintf(stderr, "Connect to socket failed: %s\n", strerror(errno));
+ close(sock);
+ return -1;
+ }
+
+ /* send message */
+ if (write(sock, msg, msg->length) != msg->length)
+ {
+ fprintf(stderr, "writing to socket failed: %s\n", strerror(errno));
+ close(sock);
+ return -1;
+ }
+
+ while ((byte_count = read(sock, buffer, sizeof(buffer)-1)) > 0)
+ {
+ buffer[byte_count] = '\0';
+ printf("%s", buffer);
+ }
+ if (byte_count < 0)
+ {
+ fprintf(stderr, "reading from socket failed: %s\n", strerror(errno));
+ }
+
+ close(sock);
+ return 0;
+}
+
+static int add_connection(char *name,
+ char *my_id, char *other_id,
+ char *my_addr, char *other_addr,
+ char *my_net, char *other_net,
+ u_int my_netmask, u_int other_netmask)
+{
+ stroke_msg_t *msg = malloc(sizeof(stroke_msg_t));
+ int res;
+
+ msg->length = sizeof(stroke_msg_t);
+ msg->type = STR_ADD_CONN;
+
+ msg->add_conn.name = push_string(&msg, name);
+
+ msg->add_conn.me.id = push_string(&msg, my_id);
+ msg->add_conn.me.address = push_string(&msg, my_addr);
+ msg->add_conn.me.subnet = push_string(&msg, my_net);
+ msg->add_conn.me.subnet_mask = my_netmask;
+ msg->add_conn.me.cert = NULL;
+
+ msg->add_conn.other.id = push_string(&msg, other_id);
+ msg->add_conn.other.address = push_string(&msg, other_addr);
+ msg->add_conn.other.subnet = push_string(&msg, other_net);
+ msg->add_conn.other.subnet_mask = other_netmask;
+ msg->add_conn.other.cert = NULL;
+
+ res = send_stroke_msg(msg);
+ free(msg);
+ return res;
+}
+
+static int initiate_connection(char *name)
+{
+ stroke_msg_t *msg = malloc(sizeof(stroke_msg_t));
+ int res;
+
+ msg->length = sizeof(stroke_msg_t);
+ msg->type = STR_INITIATE;
+ msg->initiate.name = push_string(&msg, name);
+ res = send_stroke_msg(msg);
+ free(msg);
+ return res;
+}
+
+static int terminate_connection(char *name)
+{
+ stroke_msg_t *msg = malloc(sizeof(stroke_msg_t));
+ int res;
+
+ msg->length = sizeof(stroke_msg_t);
+ msg->type = STR_TERMINATE;
+ msg->initiate.name = push_string(&msg, name);
+ res = send_stroke_msg(msg);
+ free(msg);
+ return res;
+}
+
+static int show_status(char *mode, char *connection)
+{
+ stroke_msg_t *msg = malloc(sizeof(stroke_msg_t));
+ int res;
+
+ msg->length = sizeof(stroke_msg_t);
+ if (strcmp(mode, "statusall") == 0)
+ {
+ msg->type = STR_STATUS_ALL;
+ }
+ else
+ {
+ msg->type = STR_STATUS;
+ }
+ msg->status.name = push_string(&msg, connection);
+ res = send_stroke_msg(msg);
+ free(msg);
+ return res;
+}
+
+static int set_logtype(char *context, char *type, int enable)
+{
+ stroke_msg_t *msg = malloc(sizeof(stroke_msg_t));
+ int res;
+
+ msg->length = sizeof(stroke_msg_t);
+ msg->type = STR_LOGTYPE;
+ msg->logtype.context = push_string(&msg, context);
+ msg->logtype.type = push_string(&msg, type);
+ msg->logtype.enable = enable;
+ res = send_stroke_msg(msg);
+ free(msg);
+ return res;
+}
+
+static int set_loglevel(char *context, u_int level)
+{
+ stroke_msg_t *msg = malloc(sizeof(stroke_msg_t));
+ int res;
+
+ msg->length = sizeof(stroke_msg_t);
+ msg->type = STR_LOGLEVEL;
+ msg->loglevel.context = push_string(&msg, context);
+ msg->loglevel.level = level;
+ res = send_stroke_msg(msg);
+ free(msg);
+ return res;
+}
+
+static void exit_error(char *error)
+{
+ if (error)
+ {
+ fprintf(stderr, "%s\n", error);
+ }
+ exit(-1);
+}
+
+static void exit_usage(char *error)
+{
+ printf("Usage:\n");
+ printf(" Add a connection:\n");
+ printf(" stroke add NAME MY_ID OTHER_ID MY_ADDR OTHER_ADDR\\\n");
+ printf(" MY_NET OTHER_NET MY_NETBITS OTHER_NETBITS\n");
+ printf(" where: ID is any IKEv2 ID \n");
+ printf(" ADDR is a IPv4 address\n");
+ printf(" NET is a IPv4 address of the subnet to tunnel\n");
+ printf(" NETBITS is the size of the subnet, as the \"24\" in 192.168.0.0/24\n");
+ printf(" Initiate a connection:\n");
+ printf(" stroke up NAME\n");
+ printf(" where: NAME is a connection name added with \"stroke add\"\n");
+ printf(" Terminate a connection:\n");
+ printf(" stroke down NAME\n");
+ printf(" where: NAME is a connection name added with \"stroke add\"\n");
+ printf(" Set logtype for a logging context:\n");
+ printf(" stroke logtype CONTEXT TYPE ENABLE\n");
+ printf(" where: CONTEXT is PARSR|GNRAT|IKESA|SAMGR|CHDSA|MESSG|TPOOL|WORKR|SCHED|\n");
+ printf(" SENDR|RECVR|SOCKT|TESTR|DAEMN|CONFG|ENCPL|PAYLD\n");
+ printf(" TYPE is CONTROL|ERROR|AUDIT|RAW|PRIVATE\n");
+ printf(" ENABLE is 0|1\n");
+ printf(" Set loglevel for a logging context:\n");
+ printf(" stroke loglevel CONTEXT LEVEL\n");
+ printf(" where: CONTEXT is PARSR|GNRAT|IKESA|SAMGR|CHDSA|MESSG|TPOOL|WORKR|SCHED|\n");
+ printf(" SENDR|RECVR|SOCKT|TESTR|DAEMN|CONFG|ENCPL|PAYLD\n");
+ printf(" LEVEL is 0|1|2|3\n");
+ printf(" Show connection status:\n");
+ printf(" stroke status\n");
+ exit_error(error);
+}
+
+int main(int argc, char *argv[])
+{
+ int res;
+
+ if (argc < 2)
+ {
+ exit_usage(NULL);
+ }
+
+ if (strcmp(argv[1], "status") == 0 ||
+ strcmp(argv[1], "statusall") == 0)
+ {
+ res = show_status(argv[1], argc > 2 ? argv[2] : NULL);
+ }
+
+ else if (strcmp(argv[1], "up") == 0)
+ {
+ if (argc < 3)
+ {
+ exit_usage("\"up\" needs a connection name");
+ }
+ res = initiate_connection(argv[2]);
+ }
+ else if (strcmp(argv[1], "down") == 0)
+ {
+ if (argc < 3)
+ {
+ exit_usage("\"down\" needs a connection name");
+ }
+ res = terminate_connection(argv[2]);
+ }
+ else if (strcmp(argv[1], "add") == 0)
+ {
+ if (argc < 11)
+ {
+ exit_usage("\"add\" needs more parameters...");
+ }
+ res = add_connection(argv[2],
+ argv[3], argv[4],
+ argv[5], argv[6],
+ argv[7], argv[8],
+ atoi(argv[9]), atoi(argv[10]));
+ }
+ else if (strcmp(argv[1], "logtype") == 0)
+ {
+ if (argc < 5)
+ {
+ exit_usage("\"logtype\" needs more parameters...");
+ }
+ res = set_logtype(argv[2], argv[3], atoi(argv[4]));
+ }
+ else if (strcmp(argv[1], "loglevel") == 0)
+ {
+ if (argc < 4)
+ {
+ exit_usage("\"logtype\" needs more parameters...");
+ }
+ res = set_loglevel(argv[2], atoi(argv[3]));
+ }
+ else
+ {
+ exit_usage(NULL);
+ }
+
+ return res;
+}
diff --git a/programs/charon/stroke/stroke.h b/programs/charon/stroke/stroke.h
new file mode 100644
index 000000000..cb40cf843
--- /dev/null
+++ b/programs/charon/stroke/stroke.h
@@ -0,0 +1,91 @@
+/**
+ * @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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef STROKE_H_
+#define STROKE_H_
+
+/**
+ * Socket which is used to communicate between charon and stroke
+ */
+#define STROKE_SOCKET "/var/run/charon.ctl"
+
+
+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 connection */
+ STR_INSTALL,
+ /* 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,
+ /* set a log type to log/not log */
+ STR_LOGTYPE,
+ /* set the verbosity of a logging context */
+ STR_LOGLEVEL,
+ /* more to come */
+ } type;
+ union {
+ /* data for STR_INITIATE, STR_INSTALL, STR_UP, STR_DOWN */
+ struct {
+ char *name;
+ } initiate, install, terminate, status;
+ /* data for STR_ADD_CONN */
+ struct {
+ char *name;
+ struct {
+ char *id;
+ char *cert;
+ char *address;
+ char *subnet;
+ u_int8_t subnet_mask;
+ } me, other;
+ } add_conn;
+ struct {
+ char *context;
+ char *type;
+ int enable;
+ } logtype;
+ struct {
+ char *context;
+ u_int level;
+ } loglevel;
+ };
+ u_int8_t buffer[];
+};
+
+#endif /* STROKE_H_ */
diff --git a/programs/charon/testing/Makefile.testcases b/programs/charon/testing/Makefile.testcases
new file mode 100644
index 000000000..5a261a799
--- /dev/null
+++ b/programs/charon/testing/Makefile.testcases
@@ -0,0 +1,139 @@
+# Copyright (C) 2005 Jan Hutter, Martin Willi
+# Hochschule fuer Technik Rapperswil
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+
+TESTCASES_DIR= $(MAIN_DIR)testing/
+
+
+$(BUILD_DIR)testcases.o : $(TESTCASES_DIR)testcases.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+TEST_OBJS+= $(BUILD_DIR)aes_cbc_crypter_test.o
+$(BUILD_DIR)aes_cbc_crypter_test.o : $(TESTCASES_DIR)aes_cbc_crypter_test.c $(TESTCASES_DIR)aes_cbc_crypter_test.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+TEST_OBJS+= $(BUILD_DIR)diffie_hellman_test.o
+$(BUILD_DIR)diffie_hellman_test.o : $(TESTCASES_DIR)diffie_hellman_test.c $(TESTCASES_DIR)diffie_hellman_test.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+TEST_OBJS+= $(BUILD_DIR)event_queue_test.o
+$(BUILD_DIR)event_queue_test.o : $(TESTCASES_DIR)event_queue_test.c $(TESTCASES_DIR)event_queue_test.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+TEST_OBJS+= $(BUILD_DIR)generator_test.o
+$(BUILD_DIR)generator_test.o : $(TESTCASES_DIR)generator_test.c $(TESTCASES_DIR)generator_test.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+TEST_OBJS+= $(BUILD_DIR)ike_sa_id_test.o
+$(BUILD_DIR)ike_sa_id_test.o : $(TESTCASES_DIR)ike_sa_id_test.c $(TESTCASES_DIR)ike_sa_id_test.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+TEST_OBJS+= $(BUILD_DIR)job_queue_test.o
+$(BUILD_DIR)job_queue_test.o : $(TESTCASES_DIR)job_queue_test.c $(TESTCASES_DIR)job_queue_test.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+TEST_OBJS+= $(BUILD_DIR)parser_test.o
+$(BUILD_DIR)parser_test.o : $(TESTCASES_DIR)parser_test.c $(TESTCASES_DIR)parser_test.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+TEST_OBJS+= $(BUILD_DIR)hasher_test.o
+$(BUILD_DIR)hasher_test.o : $(TESTCASES_DIR)hasher_test.c $(TESTCASES_DIR)hasher_test.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+TEST_OBJS+= $(BUILD_DIR)ike_sa_manager_test.o
+$(BUILD_DIR)ike_sa_manager_test.o : $(TESTCASES_DIR)ike_sa_manager_test.c $(TESTCASES_DIR)ike_sa_manager_test.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+TEST_OBJS+= $(BUILD_DIR)linked_list_test.o
+$(BUILD_DIR)linked_list_test.o : $(TESTCASES_DIR)linked_list_test.c $(TESTCASES_DIR)linked_list_test.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+TEST_OBJS+= $(BUILD_DIR)hmac_test.o
+$(BUILD_DIR)hmac_test.o : $(TESTCASES_DIR)hmac_test.c $(TESTCASES_DIR)hmac_test.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+TEST_OBJS+= $(BUILD_DIR)hmac_signer_test.o
+$(BUILD_DIR)hmac_signer_test.o : $(TESTCASES_DIR)hmac_signer_test.c $(TESTCASES_DIR)hmac_signer_test.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+TEST_OBJS+= $(BUILD_DIR)scheduler_test.o
+$(BUILD_DIR)scheduler_test.o : $(TESTCASES_DIR)scheduler_test.c $(TESTCASES_DIR)scheduler_test.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+TEST_OBJS+= $(BUILD_DIR)prf_plus_test.o
+$(BUILD_DIR)prf_plus_test.o : $(TESTCASES_DIR)prf_plus_test.c $(TESTCASES_DIR)prf_plus_test.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+TEST_OBJS+= $(BUILD_DIR)send_queue_test.o
+$(BUILD_DIR)send_queue_test.o : $(TESTCASES_DIR)send_queue_test.c $(TESTCASES_DIR)send_queue_test.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+TEST_OBJS+= $(BUILD_DIR)socket_test.o
+$(BUILD_DIR)socket_test.o : $(TESTCASES_DIR)socket_test.c $(TESTCASES_DIR)socket_test.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+TEST_OBJS+= $(BUILD_DIR)packet_test.o
+$(BUILD_DIR)packet_test.o : $(TESTCASES_DIR)packet_test.c $(TESTCASES_DIR)packet_test.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+TEST_OBJS+= $(BUILD_DIR)ike_sa_test.o
+$(BUILD_DIR)ike_sa_test.o : $(TESTCASES_DIR)ike_sa_test.c $(TESTCASES_DIR)ike_sa_test.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+TEST_OBJS+= $(BUILD_DIR)sender_test.o
+$(BUILD_DIR)sender_test.o : $(TESTCASES_DIR)sender_test.c $(TESTCASES_DIR)sender_test.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+TEST_OBJS+= $(BUILD_DIR)thread_pool_test.o
+$(BUILD_DIR)thread_pool_test.o : $(TESTCASES_DIR)thread_pool_test.c $(TESTCASES_DIR)thread_pool_test.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+TEST_OBJS+= $(BUILD_DIR)encryption_payload_test.o
+$(BUILD_DIR)encryption_payload_test.o : $(TESTCASES_DIR)encryption_payload_test.c $(TESTCASES_DIR)encryption_payload_test.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+TEST_OBJS+= $(BUILD_DIR)connection_test.o
+$(BUILD_DIR)connection_test.o : $(TESTCASES_DIR)connection_test.c $(TESTCASES_DIR)connection_test.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+TEST_OBJS+= $(BUILD_DIR)policy_test.o
+$(BUILD_DIR)policy_test.o : $(TESTCASES_DIR)policy_test.c $(TESTCASES_DIR)policy_test.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+TEST_OBJS+= $(BUILD_DIR)proposal_test.o
+$(BUILD_DIR)proposal_test.o : $(TESTCASES_DIR)proposal_test.c $(TESTCASES_DIR)proposal_test.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+TEST_OBJS+= $(BUILD_DIR)rsa_test.o
+$(BUILD_DIR)rsa_test.o : $(TESTCASES_DIR)rsa_test.c $(TESTCASES_DIR)rsa_test.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+TEST_OBJS+= $(BUILD_DIR)kernel_interface_test.o
+$(BUILD_DIR)kernel_interface_test.o : $(TESTCASES_DIR)kernel_interface_test.c $(TESTCASES_DIR)kernel_interface_test.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+TEST_OBJS+= $(BUILD_DIR)child_sa_test.o
+$(BUILD_DIR)child_sa_test.o : $(TESTCASES_DIR)child_sa_test.c $(TESTCASES_DIR)child_sa_test.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+TEST_OBJS+= $(BUILD_DIR)certificate_test.o
+$(BUILD_DIR)certificate_test.o : $(TESTCASES_DIR)certificate_test.c $(TESTCASES_DIR)certificate_test.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+TEST_OBJS+= $(BUILD_DIR)leak_detective_test.o
+$(BUILD_DIR)leak_detective_test.o : $(TESTCASES_DIR)leak_detective_test.c $(TESTCASES_DIR)leak_detective_test.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+TEST_OBJS+= $(BUILD_DIR)identification_test.o
+$(BUILD_DIR)identification_test.o : $(TESTCASES_DIR)identification_test.c $(TESTCASES_DIR)identification_test.h
+ $(CC) $(CFLAGS) -c -o $@ $< \ No newline at end of file
diff --git a/programs/charon/testing/aes_cbc_crypter_test.c b/programs/charon/testing/aes_cbc_crypter_test.c
new file mode 100644
index 000000000..30dae3926
--- /dev/null
+++ b/programs/charon/testing/aes_cbc_crypter_test.c
@@ -0,0 +1,201 @@
+/**
+ * @file aes_cbc_crypter_test.c
+ *
+ * @brief Tests for the aes_cbc_crypter_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+
+#include "aes_cbc_crypter_test.h"
+
+#include <daemon.h>
+
+void test_aes_cbc_crypter(protected_tester_t *tester)
+{
+ /*
+ * Test 1 of RFC3602
+ * Key : 0x06a9214036b8a15b512e03d534120006
+ * IV : 0x3dafba429d9eb430b422da802c9fac41
+ * Plaintext : "Single block msg"
+ * Ciphertext: 0xe353779c1079aeb82708942dbe77181a
+ */
+ crypter_t *crypter;
+ u_int8_t key1[] = {0x06,0xa9,0x21,0x40,0x36,0xb8,0xa1,0x5b,
+ 0x51,0x2e,0x03,0xd5,0x34,0x12,0x00,0x06};
+ chunk_t key1_chunk = {ptr: key1, len : 16};
+ u_int8_t iv1[] = {0x3d,0xaf,0xba,0x42,0x9d,0x9e,0xb4,0x30,
+ 0xb4,0x22,0xda,0x80,0x2c,0x9f,0xac,0x41};
+ chunk_t iv1_chunk = {ptr: iv1, len : 16};
+ u_int8_t ciphertext1[] = { 0xe3,0x53,0x77,0x9c,0x10,0x79,0xae,0xb8,
+ 0x27,0x08,0x94,0x2d,0xbe,0x77,0x18,0x1a};
+
+ chunk_t expected_encrypted1 = {ptr: ciphertext1, len : 16};
+ char * plaintext1 = "Single block msg";
+ chunk_t data1 = {ptr: plaintext1, len : 16};
+ chunk_t encrypted1;
+ chunk_t decrypted1;
+ logger_t *logger;
+
+ logger = logger_manager->get_logger(logger_manager,TESTER);
+
+ crypter = (crypter_t *) aes_cbc_crypter_create(16);
+ tester->assert_true(tester, (crypter != NULL), "create call test");
+
+ tester->assert_true(tester, (crypter->set_key(crypter,key1_chunk) == SUCCESS), "set_key call test");
+
+ tester->assert_true(tester, (crypter->encrypt(crypter,data1,iv1_chunk,&encrypted1) == SUCCESS), "encrypt call test");
+
+ tester->assert_true(tester, (memcmp(encrypted1.ptr, expected_encrypted1.ptr, 16) == 0), "Encrypted value");
+
+ logger->log_chunk(logger,RAW,"exptected encrypted :", expected_encrypted1);
+ logger->log_chunk(logger,RAW,"encrypted :", encrypted1);
+
+ tester->assert_true(tester, (crypter->decrypt(crypter,encrypted1,iv1_chunk,&decrypted1) == SUCCESS), "decrypt call test");
+ chunk_free(&encrypted1);
+
+ tester->assert_true(tester, (memcmp(decrypted1.ptr, plaintext1, 16) == 0), "decrypted value");
+
+ logger->log_chunk(logger,RAW,"expected decrypted :", data1);
+ logger->log_chunk(logger,RAW,"decrypted :", decrypted1);
+
+ chunk_free(&decrypted1);
+
+ crypter->destroy(crypter);
+
+
+ /*
+ * Test 2 of RFC3602
+ * Key : 0xc286696d887c9aa0611bbb3e2025a45a
+ * IV : 0x562e17996d093d28ddb3ba695a2e6f58
+ * Plaintext : 0x000102030405060708090a0b0c0d0e0f
+ * 101112131415161718191a1b1c1d1e1f
+ * Ciphertext: 0xd296cd94c2cccf8a3a863028b5e1dc0a
+ * 7586602d253cfff91b8266bea6d61ab1
+ */
+ u_int8_t key2[] = {0xc2,0x86,0x69,0x6d,0x88,0x7c,0x9a,0xa0,
+ 0x61,0x1b,0xbb,0x3e,0x20,0x25,0xa4,0x5a};
+ chunk_t key2_chunk = {ptr: key2, len : 16};
+ u_int8_t iv2[] = {0x56,0x2e,0x17,0x99,0x6d,0x09,0x3d,0x28,
+ 0xdd,0xb3,0xba,0x69,0x5a,0x2e,0x6f,0x58};
+ chunk_t iv2_chunk = {ptr: iv2, len : 16};
+ u_int8_t ciphertext2[] = { 0xd2,0x96,0xcd,0x94,0xc2,0xcc,0xcf,0x8a,
+ 0x3a,0x86,0x30,0x28,0xb5,0xe1,0xdc,0x0a,
+ 0x75,0x86,0x60,0x2d,0x25,0x3c,0xff,0xf9,
+ 0x1b,0x82,0x66,0xbe,0xa6,0xd6,0x1a,0xb1};
+
+ chunk_t expected_encrypted2 = {ptr: ciphertext2, len : 32};
+ u_int8_t plaintext2[] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+ 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+ 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f};
+ chunk_t data2 = {ptr: plaintext2, len : 32};
+ chunk_t encrypted2;
+ chunk_t decrypted2;
+
+
+ crypter = (crypter_t *) aes_cbc_crypter_create(16);
+ tester->assert_true(tester, (crypter != NULL), "create call test");
+
+ tester->assert_true(tester, (crypter->set_key(crypter,key2_chunk) == SUCCESS), "set_key call test");
+
+ tester->assert_true(tester, (crypter->encrypt(crypter,data2,iv2_chunk,&encrypted2) == SUCCESS), "encrypt call test");
+
+ tester->assert_true(tester, (memcmp(encrypted2.ptr, expected_encrypted2.ptr, 32) == 0), "Encrypted value");
+
+ logger->log_chunk(logger,RAW,"exptected encrypted :", expected_encrypted2);
+ logger->log_chunk(logger,RAW,"encrypted :", encrypted2);
+
+ tester->assert_true(tester, (crypter->decrypt(crypter,encrypted2,iv2_chunk,&decrypted2) == SUCCESS), "decrypt call test");
+ chunk_free(&encrypted2);
+
+ tester->assert_true(tester, (memcmp(decrypted2.ptr, plaintext2, 32) == 0), "decrypted value");
+
+ logger->log_chunk(logger,RAW,"expected decrypted :", data2);
+ logger->log_chunk(logger,RAW,"decrypted :", decrypted2);
+
+ chunk_free(&decrypted2);
+
+ crypter->destroy(crypter);
+
+ /*
+ * Test 3 of RFC3603
+ * Key : 0x56e47a38c5598974bc46903dba290349
+ * IV : 0x8ce82eefbea0da3c44699ed7db51b7d9
+ * Plaintext : 0xa0a1a2a3a4a5a6a7a8a9aaabacadaeaf
+ * b0b1b2b3b4b5b6b7b8b9babbbcbdbebf
+ * c0c1c2c3c4c5c6c7c8c9cacbcccdcecf
+ * d0d1d2d3d4d5d6d7d8d9dadbdcdddedf
+ * Ciphertext: 0xc30e32ffedc0774e6aff6af0869f71aa
+ * 0f3af07a9a31a9c684db207eb0ef8e4e
+ * 35907aa632c3ffdf868bb7b29d3d46ad
+ * 83ce9f9a102ee99d49a53e87f4c3da55
+ */
+ u_int8_t key3[] = {0x56,0xe4,0x7a,0x38,0xc5,0x59,0x89,0x74,
+ 0xbc,0x46,0x90,0x3d,0xba,0x29,0x03,0x49};
+ chunk_t key3_chunk = {ptr: key3, len : 16};
+ u_int8_t iv3[] = {0x8c,0xe8,0x2e,0xef,0xbe,0xa0,0xda,0x3c,
+ 0x44,0x69,0x9e,0xd7,0xdb,0x51,0xb7,0xd9};
+ chunk_t iv3_chunk = {ptr: iv3, len : 16};
+ u_int8_t ciphertext3[] = { 0xc3,0x0e,0x32,0xff,0xed,0xc0,0x77,0x4e,
+ 0x6a,0xff,0x6a,0xf0,0x86,0x9f,0x71,0xaa,
+ 0x0f,0x3a,0xf0,0x7a,0x9a,0x31,0xa9,0xc6,
+ 0x84,0xdb,0x20,0x7e,0xb0,0xef,0x8e,0x4e,
+ 0x35,0x90,0x7a,0xa6,0x32,0xc3,0xff,0xdf,
+ 0x86,0x8b,0xb7,0xb2,0x9d,0x3d,0x46,0xad,
+ 0x83,0xce,0x9f,0x9a,0x10,0x2e,0xe9,0x9d,
+ 0x49,0xa5,0x3e,0x87,0xf4,0xc3,0xda,0x55};
+
+ chunk_t expected_encrypted3 = {ptr: ciphertext3, len : 64};
+ u_int8_t plaintext3[] = {0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,
+ 0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,
+ 0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,
+ 0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,
+ 0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf};
+ chunk_t data3 = {ptr: plaintext3, len : 64};
+ chunk_t encrypted3;
+ chunk_t decrypted3;
+
+ crypter = (crypter_t *) aes_cbc_crypter_create(16);
+ tester->assert_true(tester, (crypter != NULL), "create call test");
+
+ tester->assert_true(tester, (crypter->set_key(crypter,key3_chunk) == SUCCESS), "set_key call test");
+
+ tester->assert_true(tester, (crypter->encrypt(crypter,data3,iv3_chunk,&encrypted3) == SUCCESS), "encrypt call test");
+
+ tester->assert_true(tester, (memcmp(encrypted3.ptr, expected_encrypted3.ptr, 64) == 0), "Encrypted value");
+
+ logger->log_chunk(logger,RAW,"exptected encrypted :", expected_encrypted3);
+ logger->log_chunk(logger,RAW,"encrypted :", encrypted3);
+
+ tester->assert_true(tester, (crypter->decrypt(crypter,encrypted3,iv3_chunk,&decrypted3) == SUCCESS), "decrypt call test");
+ chunk_free(&encrypted3);
+
+ tester->assert_true(tester, (memcmp(decrypted3.ptr, plaintext3, 64) == 0), "decrypted value");
+
+ logger->log_chunk(logger,RAW,"expected decrypted :", data3);
+ logger->log_chunk(logger,RAW,"decrypted :", decrypted3);
+
+ chunk_free(&decrypted3);
+
+ crypter->destroy(crypter);
+}
+
diff --git a/programs/charon/testing/aes_cbc_crypter_test.h b/programs/charon/testing/aes_cbc_crypter_test.h
new file mode 100644
index 000000000..c3897a4d6
--- /dev/null
+++ b/programs/charon/testing/aes_cbc_crypter_test.h
@@ -0,0 +1,38 @@
+/**
+ * @file aes_cbc_crypter_test.h
+ *
+ * @brief Tests for the aes_cbc_crypter_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef AES_CBC_CRYPTER_TEST_H_
+#define AES_CBC_CRYPTER_TEST_H_
+
+#include <crypto/crypters/aes_cbc_crypter.h>
+#include <utils/tester.h>
+
+/**
+ * @brief Test function used to test the aes_cbc_crypter_t class.
+ *
+ * @param tester associated tester object
+ *
+ * @ingroup testcases
+ */
+void test_aes_cbc_crypter(protected_tester_t *tester);
+
+#endif /* AES_CBC_CRYPTER_TEST_H_ */
diff --git a/programs/charon/testing/certificate_test.c b/programs/charon/testing/certificate_test.c
new file mode 100644
index 000000000..be8a8f7cf
--- /dev/null
+++ b/programs/charon/testing/certificate_test.c
@@ -0,0 +1,112 @@
+/**
+ * @file certificate_test.c
+ *
+ * @brief Tests for the certificate_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+
+#include "certificate_test.h"
+
+#include <daemon.h>
+#include <crypto/x509.h>
+#include <utils/logger.h>
+
+
+static char certificate_buffer[] = {
+ 0x30,0x82,0x02,0xf9,0x30,0x82,0x01,0xe1,0xa0,0x03,0x02,0x01,0x02,0x02,0x11,0x00,
+ 0xfe,0xae,0xe3,0xcf,0x00,0x27,0x8d,0xa0,0xe1,0xfa,0xb2,0x07,0xd4,0x15,0x40,0x93,
+ 0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x30,
+ 0x38,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,0x0e,0x30,0x0c,0x06,0x03,0x55,
+ 0x04,0x03,0x13,0x05,0x6d,0x61,0x65,0x6e,0x6f,0x30,0x1e,0x17,0x0d,0x30,0x36,0x30,
+ 0x33,0x32,0x37,0x30,0x36,0x35,0x32,0x33,0x38,0x5a,0x17,0x0d,0x31,0x31,0x30,0x33,
+ 0x32,0x36,0x30,0x36,0x35,0x32,0x33,0x38,0x5a,0x30,0x38,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,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x6d,0x61,
+ 0x65,0x6e,0x6f,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,0xe3,0x75,0x56,0xb9,0x68,0x46,0xa6,0x3e,0x6c,0x19,0x36,0xfb,
+ 0x9a,0xb4,0xbc,0xc1,0x22,0x47,0xc0,0x00,0x8a,0x44,0x1c,0xa7,0x44,0x2e,0x73,0x50,
+ 0xfc,0xd2,0x91,0x9c,0xaa,0xc3,0xa3,0x88,0x8c,0x4b,0x33,0xef,0x9a,0x52,0x89,0x9c,
+ 0x8e,0x01,0x62,0x21,0x7a,0x75,0x5e,0xa3,0x3b,0xc0,0xb0,0x58,0xc0,0xc0,0xce,0x77,
+ 0xe0,0x84,0x9a,0x9e,0xc1,0x51,0x71,0xc7,0xc4,0xa0,0x1e,0xf0,0x8e,0xb3,0x90,0x3e,
+ 0xcd,0xe3,0x7d,0x8e,0x11,0x7b,0x92,0x5d,0x4a,0x37,0x3b,0x4b,0xb3,0x3d,0x58,0x9a,
+ 0x8b,0x51,0x39,0x15,0xcd,0x27,0xd4,0x5b,0xad,0x5e,0xa5,0x07,0x94,0x29,0x0f,0x02,
+ 0x0c,0x61,0x85,0x97,0x3b,0xc4,0xcf,0x5d,0x17,0x86,0x4d,0x96,0x5e,0x42,0xe9,0xf2,
+ 0x72,0x2f,0xd4,0x58,0x4d,0x02,0xf8,0x0f,0xbd,0xe7,0x37,0xc8,0xa9,0x87,0xfe,0xab,
+ 0x26,0x37,0x13,0x90,0x65,0x2d,0x51,0x41,0x18,0x18,0xdf,0x48,0x21,0x87,0x70,0x61,
+ 0xcb,0x1b,0x62,0xad,0xaf,0x65,0xd2,0x29,0x27,0x93,0x58,0x7b,0xea,0x89,0xdd,0x58,
+ 0x01,0x6d,0xeb,0x60,0xd8,0xc3,0x82,0x07,0x2c,0x67,0x39,0xc3,0x68,0xfc,0xcd,0xeb,
+ 0xe9,0x7c,0x67,0xe3,0x1b,0x7a,0x50,0xf9,0x36,0x68,0xea,0xe2,0x15,0x01,0xee,0x99,
+ 0xf2,0x52,0xe0,0x0a,0x8e,0x5f,0x63,0xb1,0x61,0x7a,0x38,0x88,0x07,0xae,0xb0,0x8d,
+ 0x44,0x26,0xe8,0xce,0x1b,0x6f,0xcd,0x05,0x4b,0x94,0x9d,0xee,0xb5,0xeb,0x28,0xc4,
+ 0x93,0x47,0xfd,0x47,0x40,0x45,0x58,0xc0,0x3e,0x44,0x74,0x7b,0x78,0x8d,0xc8,0x25,
+ 0xc1,0xe1,0x0a,0x43,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,0x77,0xfd,0xd2,
+ 0x68,0x7e,0xb9,0xc2,0x40,0xb4,0xa3,0xea,0xe8,0x15,0x55,0x18,0xfe,0xe3,0x80,0xe0,
+ 0x73,0xf9,0xe1,0xe5,0xe2,0x91,0xf5,0xa7,0xcb,0xdf,0xfb,0xc1,0x36,0xa6,0x55,0x6a,
+ 0xd9,0x27,0xcd,0xef,0x64,0x30,0x70,0xd8,0x4b,0x72,0x7c,0xd1,0x9c,0x32,0xf8,0xb4,
+ 0x15,0x7f,0xd7,0x79,0x0c,0x9f,0x24,0xf8,0x50,0xea,0xc7,0xd9,0xef,0x1f,0xf1,0x76,
+ 0x3c,0x19,0xdb,0x61,0xb7,0x35,0x97,0xf9,0x03,0x87,0x42,0x77,0x23,0xd8,0xfe,0xd1,
+ 0x74,0xf2,0x1e,0x95,0x87,0x5f,0x42,0x80,0x8e,0xee,0x6c,0x19,0x7b,0x2c,0x25,0xe6,
+ 0xf9,0xdb,0x24,0x35,0x94,0x65,0x44,0xa0,0x56,0x6f,0x7f,0x57,0x2e,0x1a,0xcd,0xa6,
+ 0xed,0x7f,0x42,0xf2,0x64,0xd4,0xf9,0x3f,0xc1,0x46,0xf6,0xc8,0xb1,0xb2,0x80,0x75,
+ 0x3e,0xd1,0xa8,0x5e,0x07,0xd0,0x3b,0x35,0x81,0x49,0x93,0x77,0xd2,0xcf,0xf7,0xb6,
+ 0xd0,0xeb,0xe5,0xf3,0x2c,0x03,0x52,0xc7,0x6d,0x02,0x26,0xa6,0xdc,0x39,0xcd,0x4d,
+ 0x9e,0xca,0x99,0x01,0x01,0x73,0xd6,0x55,0x89,0x93,0x12,0xa0,0xc5,0xe6,0xa7,0x9a,
+ 0xdc,0x5f,0x9f,0x5c,0x2c,0x2b,0xdb,0x23,0xa5,0xee,0x69,0x15,0x1f,0x3a,0xf1,0x76,
+ 0x36,0xb5,0x77,0x18,0x57,0xff,0xff,0xf7,0x45,0x59,0xce,0x1b,0x0b,0x56,0xcb,0x09,
+ 0x00,0x12,0x17,0xb8,0xa2,0x81,0x86,0x70,0x29,0x63,0x99,0x76,0xff,0x18,0x80,0x2b,
+ 0x9b,0x5e,0x04,0xb1,0xcc,0xe4,0x15,0x90,0x29,0xa6,0x40,0xdd,0x85,0x38,0xd7,0xfe,
+ 0x10,0xb5,0x97,0x6e,0x62,0x60,0xb9,0x02,0x67,0xef,0xf1,0xab,0xb3,
+};
+
+/**
+ * Described in header.
+ */
+void test_certificate(protected_tester_t *tester)
+{
+ chunk_t certificate = {certificate_buffer, sizeof(certificate_buffer)};
+ identification_t *id;
+ x509_t *cert;
+
+ cert = x509_create_from_chunk(certificate);
+ id = cert->get_subject(cert);
+ tester->assert_true(tester, strcmp(id->get_string(id), "C=CH, O=Linux strongSwan, CN=maeno") == 0, "subject");
+ id = cert->get_issuer(cert);
+ tester->assert_true(tester, strcmp(id->get_string(id), "C=CH, O=Linux strongSwan, CN=maeno") == 0, "issuer");
+ cert->destroy(cert);
+ /*
+ cert = x509_create_from_file("scripts/complex1.der");
+ id = cert->get_subject(cert);
+ printf("Subject: %s\n", id->get_string(id));
+ id = cert->get_issuer(cert);
+ printf("Issuer: %s\n", id->get_string(id));
+ cert->destroy(cert);
+
+ cert = x509_create_from_file("scripts/complex2.der");
+ id = cert->get_subject(cert);
+ printf("Subject: %s\n", id->get_string(id));
+ id = cert->get_issuer(cert);
+ printf("Issuer: %s\n", id->get_string(id));
+ cert->destroy(cert);*/
+}
diff --git a/programs/charon/testing/certificate_test.h b/programs/charon/testing/certificate_test.h
new file mode 100644
index 000000000..8dcbd0f93
--- /dev/null
+++ b/programs/charon/testing/certificate_test.h
@@ -0,0 +1,42 @@
+/**
+ * @file certificate_test.h
+ *
+ * @brief Tests for the certificate_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#ifndef CERTIFICATE_TEST_H_
+#define CERTIFICATE_TEST_H_
+
+#include <utils/tester.h>
+
+/**
+ * @brief Test function used to test the certificate_t functionality.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_certificate(protected_tester_t *tester);
+
+#endif /* CERTIFICATE_TEST_H_ */
+
+
+
+
diff --git a/programs/charon/testing/child_sa_test.c b/programs/charon/testing/child_sa_test.c
new file mode 100644
index 000000000..0cf354c26
--- /dev/null
+++ b/programs/charon/testing/child_sa_test.c
@@ -0,0 +1,101 @@
+/**
+ * @file child_sa_test.c
+ *
+ * @brief Tests for the child_sa_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "child_sa_test.h"
+
+#include <daemon.h>
+#include <sa/child_sa.h>
+#include <utils/logger.h>
+
+
+/**
+ * Described in header.
+ */
+void test_child_sa(protected_tester_t *tester)
+{
+ proposal_t *proposal1, *proposal2;
+ linked_list_t *list;
+ host_t *local_me, *remote_me;
+ host_t *local_other, *remote_other;
+ child_sa_t *local_sa, *remote_sa;
+ prf_plus_t *local_prf_plus, *remote_prf_plus;
+ prf_t *local_prf, *remote_prf;
+ u_int8_t key_buffer[] = {0x01,0x02,0x03,0x04};
+ chunk_t key = {key_buffer, sizeof(key_buffer)};
+ status_t status;
+
+ /* setup test data */
+ local_me = host_create(AF_INET, "192.168.0.1", 0);
+ local_other = host_create(AF_INET, "192.168.0.2", 0);
+ remote_me = host_create(AF_INET, "192.168.0.3", 0);
+ remote_other = host_create(AF_INET, "192.168.0.4", 0);
+
+ local_sa = child_sa_create(local_me, local_other);
+ remote_sa = child_sa_create(remote_me, remote_other);
+
+ proposal1 = proposal_create(1);
+ proposal1->add_algorithm(proposal1, PROTO_ESP, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16);
+
+ proposal2 = proposal_create(2);
+ proposal2->add_algorithm(proposal2, PROTO_AH, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
+
+ list = linked_list_create();
+ list->insert_last(list, proposal1);
+ list->insert_last(list, proposal2);
+
+ local_prf = prf_create(PRF_HMAC_SHA1);
+ remote_prf = prf_create(PRF_HMAC_SHA1);
+ local_prf->set_key(local_prf, key);
+ remote_prf->set_key(remote_prf, key);
+ local_prf_plus = prf_plus_create(local_prf, key);
+ remote_prf_plus = prf_plus_create(remote_prf, key);
+
+ /*
+ * local plays initiator
+ ***********************
+ */
+ status = local_sa->alloc(local_sa, list);
+ tester->assert_true(tester, status == SUCCESS, "spi allocation");
+
+ status = remote_sa->add(remote_sa, proposal1, remote_prf_plus);
+ tester->assert_true(tester, status == SUCCESS, "sa add");
+
+ status = local_sa->update(local_sa, proposal1, local_prf_plus);
+ tester->assert_true(tester, status == SUCCESS, "sa update");
+
+ /* cleanup */
+ proposal1->destroy(proposal1);
+ proposal2->destroy(proposal2);
+ list->destroy(list);
+ local_prf->destroy(local_prf);
+ local_prf_plus->destroy(local_prf_plus);
+ remote_prf->destroy(remote_prf);
+ remote_prf_plus->destroy(remote_prf_plus);
+ local_sa->destroy(local_sa);
+ remote_sa->destroy(remote_sa);
+ local_me->destroy(local_me);
+ local_other->destroy(local_other);
+ remote_me->destroy(remote_me);
+ remote_other->destroy(remote_other);
+
+
+}
diff --git a/programs/charon/testing/child_sa_test.h b/programs/charon/testing/child_sa_test.h
new file mode 100644
index 000000000..ef92499fe
--- /dev/null
+++ b/programs/charon/testing/child_sa_test.h
@@ -0,0 +1,42 @@
+/**
+ * @file child_sa_test.h
+ *
+ * @brief Tests for the child_sa_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#ifndef CHILD_SA_TEST_H_
+#define CHILD_SA_TEST_H_
+
+#include <utils/tester.h>
+
+/**
+ * @brief Test function used to test the child_sa_t functionality.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_child_sa(protected_tester_t *tester);
+
+#endif /* CHILD_SA_TEST_H_ */
+
+
+
+
diff --git a/programs/charon/testing/connection_test.c b/programs/charon/testing/connection_test.c
new file mode 100644
index 000000000..6b12afc1d
--- /dev/null
+++ b/programs/charon/testing/connection_test.c
@@ -0,0 +1,82 @@
+/**
+ * @file connection_test.c
+ *
+ * @brief Tests for the connection_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "connection_test.h"
+
+#include <config/connections/connection.h>
+#include <crypto/prfs/prf.h>
+
+
+/**
+ * Described in header.
+ */
+void test_connection(protected_tester_t *tester)
+{
+ host_t *alice = host_create(AF_INET, "192.168.0.1", 500);
+ host_t *bob = host_create(AF_INET, "192.168.0.2", 500);
+ identification_t *alice_id = identification_create_from_string("192.168.0.1");
+ identification_t *bob_id = identification_create_from_string("192.168.0.2");
+ connection_t *connection = connection_create(alice, bob, alice_id, bob_id, RSA_DIGITAL_SIGNATURE);
+ proposal_t *prop1, *prop2, *prop3, *prop4;
+ linked_list_t *list;
+
+ prop1 = proposal_create(1);
+ prop1->add_algorithm(prop1, PROTO_IKE, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 20);
+ prop1->add_algorithm(prop1, PROTO_IKE, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 20);
+ prop1->add_algorithm(prop1, PROTO_IKE, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA1, 20);
+ prop1->add_algorithm(prop1, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0);
+
+ prop2 = proposal_create(2);
+ prop2->add_algorithm(prop2, PROTO_IKE, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 20);
+ prop2->add_algorithm(prop2, PROTO_IKE, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 20);
+ prop2->add_algorithm(prop2, PROTO_IKE, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_MD5, 20);
+ prop2->add_algorithm(prop2, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0);
+
+ prop3 = proposal_create(3);
+ prop3->add_algorithm(prop3, PROTO_IKE, ENCRYPTION_ALGORITHM, ENCR_DES, 20);
+ prop3->add_algorithm(prop3, PROTO_IKE, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 20);
+ prop3->add_algorithm(prop3, PROTO_IKE, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_MD5, 20);
+ prop3->add_algorithm(prop3, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_768_BIT, 0);
+
+ prop4 = proposal_create(4);
+ prop4->add_algorithm(prop4, PROTO_IKE, ENCRYPTION_ALGORITHM, ENCR_3DES, 20);
+ prop4->add_algorithm(prop4, PROTO_IKE, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 20);
+ prop4->add_algorithm(prop4, PROTO_IKE, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_TIGER, 20);
+ prop4->add_algorithm(prop4, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_768_BIT, 0);
+
+ connection->add_proposal(connection, prop1);
+ connection->add_proposal(connection, prop2);
+ connection->add_proposal(connection, prop3);
+ connection->add_proposal(connection, prop4);
+
+ list = connection->get_proposals(connection);
+
+ tester->assert_true(tester,(list->get_count(list) == 4), "proposal count check ");
+
+
+ /* going to check proposals */
+ /* TODO test?*/
+
+ list->destroy(list);
+
+ connection->destroy(connection);
+}
diff --git a/programs/charon/testing/connection_test.h b/programs/charon/testing/connection_test.h
new file mode 100644
index 000000000..4d2a1d89e
--- /dev/null
+++ b/programs/charon/testing/connection_test.h
@@ -0,0 +1,38 @@
+/**
+ * @file connection_test.h
+ *
+ * @brief Tests for the connection_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#ifndef INIT_CONFIG_TEST_H_
+#define INIT_CONFIG_TEST_H_
+
+#include <utils/tester.h>
+
+/**
+ * @brief Test function used to test the connection_t functionality.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_connection(protected_tester_t *tester);
+
+#endif /* INIT_CONFIG_TEST_H_ */
diff --git a/programs/charon/testing/diffie_hellman_test.c b/programs/charon/testing/diffie_hellman_test.c
new file mode 100644
index 000000000..0a44a022a
--- /dev/null
+++ b/programs/charon/testing/diffie_hellman_test.c
@@ -0,0 +1,76 @@
+/**
+ * @file diffie_hellman_test.c
+ *
+ * @brief Tests for the diffie_hellman_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+
+#include "diffie_hellman_test.h"
+
+#include <daemon.h>
+#include <utils/logger_manager.h>
+#include <encoding/payloads/transform_substructure.h>
+#include <crypto/diffie_hellman.h>
+
+/*
+ * described in Header-File
+ */
+void test_diffie_hellman(protected_tester_t *tester)
+{
+ diffie_hellman_t *my_diffie_hellman, *other_diffie_hellman;
+ logger_t *logger;
+ chunk_t my_public_value, other_public_value;
+ chunk_t my_secret, other_secret;
+
+ logger = logger_manager->get_logger(logger_manager,TESTER);
+
+
+ my_diffie_hellman = diffie_hellman_create(MODP_1024_BIT);
+ tester->assert_true(tester,(my_diffie_hellman != NULL), "create call check");
+
+ other_diffie_hellman = diffie_hellman_create(MODP_1024_BIT);
+ tester->assert_true(tester,(other_diffie_hellman != NULL), "create call check");
+
+ my_diffie_hellman->get_my_public_value(my_diffie_hellman,&my_public_value);
+ logger->log_chunk(logger,RAW,"My public value",my_public_value);
+
+ other_diffie_hellman->get_my_public_value(other_diffie_hellman,&other_public_value);
+ logger->log_chunk(logger,RAW,"Other public value",other_public_value);
+
+ my_diffie_hellman->set_other_public_value(my_diffie_hellman,other_public_value);
+ other_diffie_hellman->set_other_public_value(other_diffie_hellman,my_public_value);
+
+ free(my_public_value.ptr);
+ free(other_public_value.ptr);
+
+ tester->assert_true(tester,(my_diffie_hellman->get_shared_secret(my_diffie_hellman,&my_secret) == SUCCESS), "get_shared_secret call check");
+ logger->log_chunk(logger,RAW,"My shared secret",my_secret);
+
+ tester->assert_true(tester,(other_diffie_hellman->get_shared_secret(other_diffie_hellman,&other_secret) == SUCCESS), "get_shared_secret call check");
+ logger->log_chunk(logger,RAW,"Other shared secret",other_secret);
+
+ tester->assert_true(tester,(memcmp(my_secret.ptr,other_secret.ptr,other_secret.len) == 0), "shared secret same value check");
+
+ free(my_secret.ptr);
+ free(other_secret.ptr);
+
+ my_diffie_hellman->destroy(my_diffie_hellman);
+ other_diffie_hellman->destroy(other_diffie_hellman);
+}
diff --git a/programs/charon/testing/diffie_hellman_test.h b/programs/charon/testing/diffie_hellman_test.h
new file mode 100644
index 000000000..e6e3ff608
--- /dev/null
+++ b/programs/charon/testing/diffie_hellman_test.h
@@ -0,0 +1,37 @@
+/**
+ * @file diffie_hellman_test.h
+ *
+ * @brief Tests for the diffie_hellman_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef DIFFIE_HELLMAN_TEST_H_
+#define DIFFIE_HELLMAN_TEST_H_
+
+#include <utils/tester.h>
+
+/**
+ * @brief Test function used to test the diffie_hellman_t functionality.
+ *
+ * @param tester associated tester object
+ *
+ * @ingroup testcases
+ */
+void test_diffie_hellman(protected_tester_t *tester);
+
+#endif /*DIFFIE_HELLMAN_TEST_H_*/
diff --git a/programs/charon/testing/encryption_payload_test.c b/programs/charon/testing/encryption_payload_test.c
new file mode 100644
index 000000000..9e4108b9e
--- /dev/null
+++ b/programs/charon/testing/encryption_payload_test.c
@@ -0,0 +1,139 @@
+/**
+ * @file encryption_payload_test.c
+ *
+ * @brief Tests for the encryption_payload_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+
+#include "encryption_payload_test.h"
+
+#include <daemon.h>
+#include <utils/logger_manager.h>
+#include <encoding/generator.h>
+#include <encoding/parser.h>
+#include <encoding/payloads/encryption_payload.h>
+#include <encoding/payloads/nonce_payload.h>
+#include <crypto/crypters/crypter.h>
+#include <crypto/signers/signer.h>
+
+/*
+ * described in Header-File
+ */
+void test_encryption_payload(protected_tester_t *tester)
+{
+ encryption_payload_t *encryption_payload;
+ nonce_payload_t *nonce_payload;
+ crypter_t *crypter;
+ signer_t *signer;
+ chunk_t nonce, got_nonce;
+ chunk_t data;
+ chunk_t key;
+ generator_t *generator;
+ parser_t *parser;
+ status_t status;
+ logger_t *logger;
+ iterator_t *iterator;
+
+
+ u_int8_t key_bytes[] = {
+ 0x01,0x01,0x01,0x01,
+ 0x01,0x01,0x01,0x01,
+ 0x01,0x01,0x01,0x01,
+ 0x01,0x01,0x01,0x01
+ };
+ key.ptr = key_bytes;
+ key.len = sizeof(key_bytes);
+
+ logger = logger_manager->get_logger(logger_manager, TESTER);
+
+ nonce.ptr = "test text und so...";
+ nonce.len = strlen(nonce.ptr) + 1;
+
+ logger->log_chunk(logger, RAW, "nonce", nonce);
+
+ encryption_payload = encryption_payload_create();
+ nonce_payload = nonce_payload_create();
+ nonce_payload->set_nonce(nonce_payload, nonce);
+
+ encryption_payload->add_payload(encryption_payload, (payload_t*)nonce_payload);
+ signer = signer_create(AUTH_HMAC_SHA1_96);
+ crypter = crypter_create(ENCR_AES_CBC, 16);
+
+ signer->set_key(signer, key);
+ crypter->set_key(crypter, key);
+
+
+
+ /* generating */
+
+ encryption_payload->set_transforms(encryption_payload, crypter, signer);
+
+ logger->log(logger, RAW, "encrypt");
+ status = encryption_payload->encrypt(encryption_payload);
+ tester->assert_true(tester, (status == SUCCESS), "encryption");
+
+ generator = generator_create();
+ generator->generate_payload(generator, (payload_t*)encryption_payload);
+
+ generator->write_to_chunk(generator, &data);
+ logger->log_chunk(logger, RAW, "generated data", data);
+
+ encryption_payload->build_signature(encryption_payload, data);
+ logger->log_chunk(logger, RAW, "generated data", data);
+
+ encryption_payload->destroy(encryption_payload);
+
+
+ /* parsing */
+
+ parser = parser_create(data);
+ status = parser->parse_payload(parser, ENCRYPTED, (payload_t**)&encryption_payload);
+ tester->assert_true(tester, (status == SUCCESS), "parsing");
+
+ encryption_payload->set_transforms(encryption_payload, crypter, signer);
+ status = encryption_payload->verify_signature(encryption_payload, data);
+ tester->assert_true(tester, (status == SUCCESS), "signature verification");
+
+ status = encryption_payload->decrypt(encryption_payload);
+ tester->assert_true(tester, (status == SUCCESS), "decryption");
+
+
+ iterator = encryption_payload->create_payload_iterator(encryption_payload, TRUE);
+ while (iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void**)&nonce_payload);
+ got_nonce = nonce_payload->get_nonce(nonce_payload);
+ }
+ iterator->destroy(iterator);
+
+
+ tester->assert_true(tester, (got_nonce.len == nonce.len), "decrypted nonce");
+ tester->assert_false(tester, memcmp(nonce.ptr, got_nonce.ptr, nonce.len), "decrypted nonce");
+
+ logger->log_chunk(logger, RAW, "nonce", got_nonce);
+
+ free(data.ptr);
+ free(got_nonce.ptr);
+ encryption_payload->destroy(encryption_payload);
+ crypter->destroy(crypter);
+ signer->destroy(signer);
+ generator->destroy(generator);
+ parser->destroy(parser);
+}
diff --git a/programs/charon/testing/encryption_payload_test.h b/programs/charon/testing/encryption_payload_test.h
new file mode 100644
index 000000000..5e6353bfd
--- /dev/null
+++ b/programs/charon/testing/encryption_payload_test.h
@@ -0,0 +1,37 @@
+/**
+ * @file encryption_payload_test.h
+ *
+ * @brief Tests for the encryption_payload_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef ENCRYPTION_PAYLOAD_TEST_H_
+#define ENCRYPTION_PAYLOAD_TEST_H_
+
+#include <utils/tester.h>
+
+/**
+ * @brief Test function used to test the encryption_payload_t functionality.
+ *
+ * @param tester associated tester object
+ *
+ * @ingroup testcases
+ */
+void test_encryption_payload(protected_tester_t *tester);
+
+#endif /*ENCRYPTION_PAYLOAD_TEST_H_*/
diff --git a/programs/charon/testing/event_queue_test.c b/programs/charon/testing/event_queue_test.c
new file mode 100644
index 000000000..58a214051
--- /dev/null
+++ b/programs/charon/testing/event_queue_test.c
@@ -0,0 +1,143 @@
+/**
+ * @file event_queue_test.h
+ *
+ * @brief Tests for the event_queue_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stdlib.h>
+#include <pthread.h>
+
+#include "event_queue_test.h"
+
+#include <queues/event_queue.h>
+#include <queues/jobs/initiate_ike_sa_job.h>
+
+/**
+ * Number of different times to insert per thread
+ */
+#define EVENT_QUEUE_TIMES 5
+/**
+ * Number of entries per time per thread
+ */
+#define EVENT_QUEUE_ENTRY_PER_TIME 20
+
+/**
+ * Number of test-thread
+ */
+#define EVENT_QUEUE_INSERT_THREADS 1
+
+/**
+ * @brief Informations for the involved test-thread used in this test
+ *
+ */
+typedef struct event_queue_test_s event_queue_test_t;
+
+struct event_queue_test_s{
+ protected_tester_t *tester;
+ event_queue_t *event_queue;
+
+ /**
+ * number of different event times to be inserted in the event-queue by each thread
+ */
+ int insert_times_count;
+
+ /**
+ * number of event to insert at one time
+ */
+ int entries_per_time;
+};
+
+
+static void event_queue_insert_thread(event_queue_test_t * testinfos)
+{
+ timeval_t current_time;
+ timeval_t time;
+ job_t * job;
+ int i,j;
+ connection_t *connection;
+
+ gettimeofday(&current_time,NULL);
+ for (i = 0; i < testinfos->insert_times_count;i++)
+ {
+
+ for (j = 0; j < testinfos->entries_per_time;j++)
+ {
+ job = (job_t *) initiate_ike_sa_job_create(connection);
+ time.tv_usec = 0;
+ time.tv_sec = current_time.tv_sec + i;
+
+ testinfos->event_queue->add_absolute(testinfos->event_queue,job,time);
+ }
+ }
+}
+
+
+void test_event_queue(protected_tester_t *tester)
+{
+ event_queue_t * event_queue = event_queue_create();
+ event_queue_test_t testinfos;
+ pthread_t threads[EVENT_QUEUE_INSERT_THREADS];
+ int i,j, number_of_total_events;
+ timeval_t current_time, start_time;
+
+ testinfos.tester = tester;
+ testinfos.event_queue = event_queue;
+ testinfos.insert_times_count = EVENT_QUEUE_TIMES;
+ testinfos.entries_per_time = EVENT_QUEUE_ENTRY_PER_TIME;
+
+ number_of_total_events = EVENT_QUEUE_ENTRY_PER_TIME * EVENT_QUEUE_TIMES * EVENT_QUEUE_INSERT_THREADS;
+
+ gettimeofday(&start_time,NULL);
+
+ for (i = 0; i < EVENT_QUEUE_INSERT_THREADS; i++)
+ {
+ int retval;
+ retval = pthread_create( &(threads[i]), NULL,(void*(*)(void*)) &event_queue_insert_thread, (void*) &testinfos);
+ tester->assert_true(tester,(retval== 0), "thread creation call check");
+ }
+
+
+ /* wait for all threads */
+ for (i = 0; i < EVENT_QUEUE_INSERT_THREADS; i++)
+ {
+ int retval;
+ retval = pthread_join(threads[i], NULL);
+ tester->assert_true(tester,(retval== 0), "thread creation call check");
+
+ }
+
+ tester->assert_true(tester,(event_queue->get_count(event_queue) == number_of_total_events), "event count check");
+
+ for (i = 0; i < EVENT_QUEUE_TIMES;i++)
+ {
+ for (j = 0; j < (EVENT_QUEUE_ENTRY_PER_TIME * EVENT_QUEUE_INSERT_THREADS);j++)
+ {
+ job_t *job;
+
+ job = event_queue->get(event_queue);
+ gettimeofday(&current_time,NULL);
+ tester->assert_true(tester,((current_time.tv_sec - start_time.tv_sec) == i), "value of entry check");
+ job->destroy(job);
+ }
+ }
+
+
+ event_queue->destroy(event_queue);
+ return;
+}
diff --git a/programs/charon/testing/event_queue_test.h b/programs/charon/testing/event_queue_test.h
new file mode 100644
index 000000000..5f8c47fad
--- /dev/null
+++ b/programs/charon/testing/event_queue_test.h
@@ -0,0 +1,39 @@
+/**
+ * @file event_queue_test.h
+ *
+ * @brief Tests to test the Event-Queue type event_queue_t
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef EVENT_QUEUE_TEST_H_
+#define EVENT_QUEUE_TEST_H_
+
+#include <utils/tester.h>
+
+/**
+ * @brief Test function used to test the event_queue functionality.
+ *
+ * Tests are performed using one thread.
+ *
+ * @param tester associated tester object
+ *
+ * @ingroup testcases
+ */
+void test_event_queue(protected_tester_t *tester);
+
+#endif /*EVENT_QUEUE_TEST_H_*/
diff --git a/programs/charon/testing/generator_test.c b/programs/charon/testing/generator_test.c
new file mode 100644
index 000000000..004c700e6
--- /dev/null
+++ b/programs/charon/testing/generator_test.c
@@ -0,0 +1,1410 @@
+/**
+ * @file generator_test.c
+ *
+ * @brief Tests for the generator_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+
+#include "generator_test.h"
+
+#include <daemon.h>
+#include <encoding/generator.h>
+#include <utils/logger_manager.h>
+#include <utils/logger.h>
+#include <encoding/payloads/encodings.h>
+#include <encoding/payloads/ike_header.h>
+#include <encoding/payloads/transform_attribute.h>
+#include <encoding/payloads/transform_substructure.h>
+#include <encoding/payloads/proposal_substructure.h>
+#include <encoding/payloads/sa_payload.h>
+#include <encoding/payloads/ke_payload.h>
+#include <encoding/payloads/notify_payload.h>
+#include <encoding/payloads/nonce_payload.h>
+#include <encoding/payloads/id_payload.h>
+#include <encoding/payloads/auth_payload.h>
+#include <encoding/payloads/cert_payload.h>
+#include <encoding/payloads/certreq_payload.h>
+#include <encoding/payloads/ts_payload.h>
+#include <encoding/payloads/delete_payload.h>
+#include <encoding/payloads/vendor_id_payload.h>
+#include <encoding/payloads/cp_payload.h>
+#include <encoding/payloads/eap_payload.h>
+
+/*
+ * Described in Header
+ */
+void test_generator_with_header_payload(protected_tester_t *tester)
+{
+ generator_t *generator;
+ ike_header_t *header_data;
+ chunk_t generated_data;
+ logger_t *logger;
+
+ logger = logger_manager->get_logger(logger_manager, TESTER);
+
+ header_data = ike_header_create();
+ header_data->set_initiator_spi(header_data,1);
+ header_data->set_responder_spi(header_data,2);
+ ((payload_t *) header_data)->set_next_type((payload_t *) header_data, 3);
+ header_data->set_exchange_type(header_data, 6);
+ header_data->set_initiator_flag(header_data, TRUE);
+ header_data->set_response_flag(header_data, TRUE);
+ header_data->set_message_id(header_data,7);
+
+ generator = generator_create();
+ tester->assert_true(tester,(generator != NULL), "generator create check");
+
+ generator->generate_payload(generator,(payload_t *) header_data);
+
+ generator->write_to_chunk(generator,&generated_data);
+
+ u_int8_t expected_generation[] = {
+ 0x01,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,
+ 0x02,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,
+ 0x03,0x20,0x06,0x28,
+ 0x00,0x00,0x00,0x07,
+ 0x00,0x00,0x00,0x1C,
+ };
+
+ logger->log_bytes(logger,RAW,"expected header",expected_generation,sizeof(expected_generation));
+ tester->assert_true(tester,(generated_data.len == sizeof(expected_generation)), "compare generated data length");
+ logger->log_chunk(logger,RAW,"generated header",generated_data);
+ tester->assert_true(tester,(memcmp(expected_generation,generated_data.ptr,sizeof(expected_generation)) == 0), "compare generated data 1");
+ chunk_free(&generated_data);
+
+ generator->destroy(generator);
+
+ header_data->set_initiator_spi(header_data,0x22000054231234LL);
+ header_data->set_responder_spi(header_data,0x122398);
+ ((payload_t *) header_data)->set_next_type((payload_t *) header_data,0xF3);
+ header_data->set_exchange_type(header_data, 0x12);
+ header_data->set_initiator_flag(header_data, TRUE);
+ header_data->set_response_flag(header_data, TRUE);
+ header_data->set_message_id(header_data,0x33AFF3);
+
+ generator = generator_create();
+ tester->assert_true(tester,(generator != NULL), "generator create check");
+
+ generator->generate_payload(generator,(payload_t *)header_data);
+
+ generator->write_to_chunk(generator,&generated_data);
+
+ u_int8_t expected_generation2[] = {
+ 0x34,0x12,0x23,0x54,
+ 0x00,0x00,0x22,0x00,
+ 0x98,0x23,0x12,0x00,
+ 0x00,0x00,0x00,0x00,
+ 0xF3,0x20,0x12,0x28,
+ 0x00,0x33,0xAF,0xF3,
+ 0x00,0x00,0x00,0x1C,
+ };
+
+
+ logger->log_bytes(logger,RAW,"expected header",expected_generation2,sizeof(expected_generation2));
+
+ logger->log_chunk(logger,RAW,"generated header",generated_data);
+
+ tester->assert_true(tester,(memcmp(expected_generation2,generated_data.ptr,sizeof(expected_generation2)) == 0), "compare generated data 2");
+ chunk_free(&generated_data);
+
+ header_data->destroy(header_data);
+
+ generator->destroy(generator);
+}
+
+/*
+ * Described in header
+ */
+void test_generator_with_transform_attribute(protected_tester_t *tester)
+{
+ generator_t *generator;
+ transform_attribute_t *attribute;
+ chunk_t generated_data;
+ logger_t *logger;
+
+ logger = logger_manager->get_logger(logger_manager, TESTER);
+
+
+ /* test empty attribute */
+ generator = generator_create();
+ tester->assert_true(tester,(generator != NULL), "generator create check");
+ attribute = transform_attribute_create();
+ generator->generate_payload(generator,(payload_t *)attribute);
+ generator->write_to_chunk(generator,&generated_data);
+ logger->log_chunk(logger,RAW,"generated attribute",generated_data);
+
+ u_int8_t expected_generation[] = {
+ 0x80,0x00,0x00,0x00,
+ };
+ tester->assert_true(tester,(memcmp(expected_generation,generated_data.ptr,sizeof(expected_generation)) == 0), "compare generated data");
+ chunk_free(&generated_data);
+ attribute->destroy(attribute);
+ generator->destroy(generator);
+
+ /* test attribute with 2 byte data */
+ generator = generator_create();
+ tester->assert_true(tester,(generator != NULL), "generator create check");
+
+ attribute = transform_attribute_create();
+ u_int16_t dataval = 5768;
+ chunk_t data;
+ data.ptr = (void *) &dataval;
+ data.len = 2;
+
+ attribute->set_value_chunk(attribute,data);
+
+ generator->generate_payload(generator,(payload_t *)attribute);
+ generator->write_to_chunk(generator,&generated_data);
+ logger->log_chunk(logger,RAW,"generated attribute",generated_data);
+
+ u_int8_t expected_generation2[] = {
+ 0x80,0x00,0x16,0x88,
+ };
+ tester->assert_true(tester,(memcmp(expected_generation2,generated_data.ptr,sizeof(expected_generation2)) == 0), "compare generated data");
+
+ chunk_free(&generated_data);
+ attribute->destroy(attribute);
+ generator->destroy(generator);
+
+
+
+ /* test attribute with 25 byte data */
+ generator = generator_create();
+ tester->assert_true(tester,(generator != NULL), "generator create check");
+
+ attribute = transform_attribute_create();
+ char *stringval = "ddddddddddeeeeeeeeeefffff";
+ data.ptr = (void *) stringval;
+ data.len = 25;
+
+ attribute->set_value_chunk(attribute,data);
+
+ attribute->set_attribute_type(attribute,456);
+
+
+ generator->generate_payload(generator,(payload_t *)attribute);
+ generator->write_to_chunk(generator,&generated_data);
+ logger->log_chunk(logger,RAW,"generated attribute",generated_data);
+
+ u_int8_t expected_generation3[] = {
+ 0x01,0xC8,0x00,0x19,
+ 0x64,0x64,0x64,0x64,
+ 0x64,0x64,0x64,0x64,
+ 0x64,0x64,0x65,0x65,
+ 0x65,0x65,0x65,0x65,
+ 0x65,0x65,0x65,0x65,
+ 0x66,0x66,0x66,0x66,
+ 0x66
+ };
+ tester->assert_true(tester,(memcmp(expected_generation3,generated_data.ptr,sizeof(expected_generation3)) == 0), "compare generated data");
+
+ chunk_free(&generated_data);
+ attribute->destroy(attribute);
+ generator->destroy(generator);
+}
+
+
+
+/*
+ * Described in header
+ */
+void test_generator_with_transform_substructure(protected_tester_t *tester)
+{
+ generator_t *generator;
+ transform_attribute_t *attribute1, *attribute2;
+ transform_substructure_t *transform;
+ chunk_t data;
+ chunk_t generated_data;
+ logger_t *logger;
+
+ logger = logger_manager->get_logger(logger_manager,TESTER);
+
+ /* create generator */
+ generator = generator_create();
+ tester->assert_true(tester,(generator != NULL), "generator create check");
+
+ /* create attribute 1 */
+ attribute1 = transform_attribute_create();
+ char *stringval = "abcd";
+ data.ptr = (void *) stringval;
+ data.len = 4;
+ attribute1->set_value_chunk(attribute1,data);
+ attribute1->set_attribute_type(attribute1,0);
+ logger->log(logger,CONTROL,"attribute1 created");
+
+ /* create attribute 2 */
+ attribute2 = transform_attribute_create();
+ stringval = "efgh";
+ data.ptr = (void *) stringval;
+ data.len = 4;
+ attribute2->set_value_chunk(attribute2,data);
+ attribute2->set_attribute_type(attribute2,0);
+ logger->log(logger,CONTROL,"attribute2 created");
+
+ /* create transform */
+ transform = transform_substructure_create();
+ tester->assert_true(tester,(transform != NULL), "transform create check");
+ transform->add_transform_attribute(transform,attribute1);
+ transform->add_transform_attribute(transform,attribute2);
+ transform->set_transform_type(transform,5); /* hex 5 */
+ transform->set_transform_id(transform,65000); /* hex FDE8 */
+
+
+ logger->log(logger,CONTROL,"transform created");
+
+ generator->generate_payload(generator,(payload_t *)transform);
+ generator->write_to_chunk(generator,&generated_data);
+ logger->log_chunk(logger,RAW,"generated transform",generated_data);
+
+ u_int8_t expected_generation3[] = {
+ 0x00,0x00,0x00,0x18,
+ 0x05,0x00,0xFD,0xE8,
+ 0x00,0x00,0x00,0x04,
+ 0x61,0x62,0x63,0x64,
+ 0x00,0x00,0x00,0x04,
+ 0x65,0x66,0x67,0x68,
+ };
+ tester->assert_true(tester,(memcmp(expected_generation3,generated_data.ptr,sizeof(expected_generation3)) == 0), "compare generated data");
+
+ chunk_free(&generated_data);
+ transform->destroy(transform);
+ generator->destroy(generator);
+}
+
+
+/*
+ * Described in header
+ */
+void test_generator_with_proposal_substructure(protected_tester_t *tester)
+{
+ generator_t *generator;
+ transform_attribute_t *attribute1, *attribute2, *attribute3;
+ transform_substructure_t *transform1, *transform2;
+ proposal_substructure_t *proposal;
+ chunk_t data;
+ chunk_t generated_data;
+ logger_t *logger;
+
+ logger = logger_manager->get_logger(logger_manager,TESTER);
+
+ /* create generator */
+ generator = generator_create();
+ tester->assert_true(tester,(generator != NULL), "generator create check");
+
+ /* create attribute 1 */
+ attribute1 = transform_attribute_create();
+ char *stringval = "abcd";
+ data.ptr = (void *) stringval;
+ data.len = 4;
+ attribute1->set_value_chunk(attribute1,data);
+ attribute1->set_attribute_type(attribute1,0);
+
+ logger->log(logger,CONTROL,"attribute1 created");
+
+ /* create attribute 2 */
+ attribute2 = transform_attribute_create();
+ stringval = "efgh";
+ data.ptr = (void *) stringval;
+ data.len = 4;
+ attribute2->set_value_chunk(attribute2,data);
+ attribute2->set_attribute_type(attribute2,0);
+ logger->log(logger,CONTROL,"attribute2 created");
+
+ /* create attribute 3 */
+ attribute3 = transform_attribute_create();
+ stringval = "ijkl";
+ data.ptr = (void *) stringval;
+ data.len = 4;
+ attribute3->set_value_chunk(attribute3,data);
+ attribute3->set_attribute_type(attribute3,0);
+ logger->log(logger,CONTROL,"attribute3 created");
+
+ /* create transform 1*/
+ transform1 = transform_substructure_create();
+ tester->assert_true(tester,(transform1 != NULL), "transform create check");
+ transform1->add_transform_attribute(transform1,attribute1);
+ transform1->add_transform_attribute(transform1,attribute2);
+ transform1->set_transform_type(transform1,5); /* hex 5 */
+ transform1->set_transform_id(transform1,65000); /* hex FDE8 */
+
+ /* create transform 2*/
+ transform2 = transform_substructure_create();
+ tester->assert_true(tester,(transform2 != NULL), "transform create check");
+ transform2->add_transform_attribute(transform2,attribute3);
+ transform2->set_transform_type(transform2,3); /* hex 3 */
+ transform2->set_transform_id(transform2,4); /* hex 4 */
+
+ logger->log(logger,CONTROL,"transforms created");
+
+ proposal = proposal_substructure_create();
+ tester->assert_true(tester,(proposal != NULL), "proposal create check");
+
+ stringval = "ABCDEFGH";
+ data.ptr = (void *) stringval;
+ data.len = 8;
+
+ proposal->add_transform_substructure(proposal,transform1);
+ proposal->add_transform_substructure(proposal,transform2);
+ proposal->set_spi(proposal,data);
+ proposal->set_proposal_number(proposal,7);
+ proposal->set_protocol_id(proposal,4);
+
+ generator->generate_payload(generator,(payload_t *)proposal);
+ generator->write_to_chunk(generator,&generated_data);
+ logger->log_chunk(logger,RAW,"generated transform",generated_data);
+
+ u_int8_t expected_generation[] = {
+ /* proposal header */
+ 0x00,0x00,0x00,0x38,
+ 0x07,0x04,0x08,0x02,
+ /* SPI */
+ 0x41,0x42,0x43,0x44,
+ 0x45,0x46,0x47,0x48,
+ /* first transform */
+ 0x03,0x00,0x00,0x18,
+ 0x05,0x00,0xFD,0xE8,
+ /* first transform attributes */
+ 0x00,0x00,0x00,0x04,
+ 0x61,0x62,0x63,0x64,
+ 0x00,0x00,0x00,0x04,
+ 0x65,0x66,0x67,0x68,
+ /* second transform */
+ 0x00,0x00,0x00,0x10,
+ 0x03,0x00,0x00,0x04,
+ /* second transform attributes */
+ 0x00,0x00,0x00,0x04,
+ 0x69,0x6A,0x6B,0x6C
+ };
+ logger->log_bytes(logger,RAW,"expected transform",expected_generation,sizeof(expected_generation));
+
+ tester->assert_true(tester,(memcmp(expected_generation,generated_data.ptr,sizeof(expected_generation)) == 0), "compare generated data");
+
+ chunk_free(&generated_data);
+ proposal->destroy(proposal);
+ generator->destroy(generator);
+}
+
+/*
+ * Described in header
+ */
+void test_generator_with_sa_payload(protected_tester_t *tester)
+{
+ generator_t *generator;
+ transform_attribute_t *attribute1, *attribute2, *attribute3;
+ transform_substructure_t *transform1, *transform2;
+ proposal_substructure_t *proposal_str1, *proposal_str2;
+ linked_list_t *list;
+ proposal_t *proposal1, *proposal2;
+ sa_payload_t *sa_payload;
+ ike_header_t *ike_header;
+
+ chunk_t data;
+ chunk_t generated_data;
+ logger_t *logger;
+
+ logger = logger_manager->get_logger(logger_manager,TESTER);
+
+ /* create generator */
+ generator = generator_create();
+ tester->assert_true(tester,(generator != NULL), "generator create check");
+
+ /* --------------------------- */
+ /* test first with self created proposals */
+
+ /* create attribute 1 */
+ attribute1 = transform_attribute_create();
+ char *stringval = "abcd";
+ data.ptr = (void *) stringval;
+ data.len = 4;
+ attribute1->set_value_chunk(attribute1,data);
+ attribute1->set_attribute_type(attribute1,0);
+ logger->log(logger,CONTROL,"attribute1 created");
+
+ /* create attribute 2 */
+ attribute2 = transform_attribute_create();
+ stringval = "efgh";
+ data.ptr = (void *) stringval;
+ data.len = 4;
+ attribute2->set_value_chunk(attribute2,data);
+ attribute2->set_attribute_type(attribute2,0);
+ logger->log(logger,CONTROL,"attribute2 created");
+
+ /* create attribute 3 */
+ attribute3 = transform_attribute_create();
+ stringval = "ijkl";
+ data.ptr = (void *) stringval;
+ data.len = 4;
+ attribute3->set_value_chunk(attribute3,data);
+ attribute3->set_attribute_type(attribute3,0);
+ logger->log(logger,CONTROL,"attribute3 created");
+
+ /* create transform 1*/
+ transform1 = transform_substructure_create();
+ tester->assert_true(tester,(transform1 != NULL), "transform create check");
+ transform1->add_transform_attribute(transform1,attribute1);
+ transform1->add_transform_attribute(transform1,attribute2);
+ transform1->set_transform_type(transform1,5); /* hex 5 */
+ transform1->set_transform_id(transform1,65000); /* hex FDE8 */
+
+ /* create transform 2*/
+ transform2 = transform_substructure_create();
+ tester->assert_true(tester,(transform2 != NULL), "transform create check");
+ transform2->add_transform_attribute(transform2,attribute3);
+ transform2->set_transform_type(transform2,3); /* hex 3 */
+ transform2->set_transform_id(transform2,4); /* hex 4 */
+
+ logger->log(logger,CONTROL,"transforms created");
+
+ /* create proposal 1 */
+ proposal_str1 = proposal_substructure_create();
+ tester->assert_true(tester,(proposal1 != NULL), "proposal create check");
+
+ stringval = "ABCDEFGH";
+ data.ptr = (void *) stringval;
+ data.len = 8;
+
+ proposal_str1->add_transform_substructure(proposal_str1,transform1);
+ proposal_str1->add_transform_substructure(proposal_str1,transform2);
+ proposal_str1->set_spi(proposal_str1,data);
+ proposal_str1->set_proposal_number(proposal_str1,7);
+ proposal_str1->set_protocol_id(proposal_str1,4);
+
+ /* create proposal 2 */
+ proposal_str2 = proposal_substructure_create();
+ tester->assert_true(tester,(proposal_str2 != NULL), "proposal create check");
+ proposal_str2->set_proposal_number(proposal_str2,7);
+ proposal_str2->set_protocol_id(proposal_str2,5);
+
+ /* create sa_payload */
+ sa_payload = sa_payload_create();
+
+ sa_payload->add_proposal_substructure(sa_payload,proposal_str1);
+ sa_payload->add_proposal_substructure(sa_payload,proposal_str2);
+
+ ike_header = ike_header_create();
+ ike_header->set_initiator_spi(ike_header,0x22000054231234LL);
+ ike_header->set_responder_spi(ike_header,0x122398);
+ ((payload_t *) ike_header)->set_next_type((payload_t *) ike_header,SECURITY_ASSOCIATION);
+ ike_header->set_exchange_type(ike_header, 0x12);
+ ike_header->set_initiator_flag(ike_header, TRUE);
+ ike_header->set_response_flag(ike_header, TRUE);
+ ike_header->set_message_id(ike_header,0x33AFF3);
+
+ generator->generate_payload(generator,(payload_t *)ike_header);
+ generator->generate_payload(generator,(payload_t *)sa_payload);
+ generator->write_to_chunk(generator,&generated_data);
+ logger->log_chunk(logger,RAW,"generated transform",generated_data);
+
+ u_int8_t expected_generation[] = {
+ /* sa payload header */
+ 0x34,0x12,0x23,0x54,
+ 0x00,0x00,0x22,0x00,
+ 0x98,0x23,0x12,0x00,
+ 0x00,0x00,0x00,0x00,
+ 0x21,0x20,0x12,0x28,
+ 0x00,0x33,0xAF,0xF3,
+ 0x00,0x00,0x00,0x60,
+
+ /* sa payload header */
+ 0x00,0x00,0x00,0x44,
+ /* proposal header */
+ 0x02,0x00,0x00,0x38,
+ 0x07,0x04,0x08,0x02,
+ /* SPI */
+ 0x41,0x42,0x43,0x44,
+ 0x45,0x46,0x47,0x48,
+ /* first transform */
+ 0x03,0x00,0x00,0x18,
+ 0x05,0x00,0xFD,0xE8,
+ /* first transform attributes */
+ 0x00,0x00,0x00,0x04,
+ 0x61,0x62,0x63,0x64,
+ 0x00,0x00,0x00,0x04,
+ 0x65,0x66,0x67,0x68,
+ /* second transform */
+ 0x00,0x00,0x00,0x10,
+ 0x03,0x00,0x00,0x04,
+ /* second transform attributes */
+ 0x00,0x00,0x00,0x04,
+ 0x69,0x6A,0x6B,0x6C,
+ /* proposal header 2*/
+ 0x00,0x00,0x00,0x08,
+ 0x07,0x05,0x00,0x00,
+
+ };
+
+ logger->log_bytes(logger,RAW,"expected transform",expected_generation,sizeof(expected_generation));
+
+ tester->assert_true(tester,(memcmp(expected_generation,generated_data.ptr,sizeof(expected_generation)) == 0), "compare generated data");
+
+ chunk_free(&generated_data);
+ ike_header->destroy(ike_header);
+ sa_payload->destroy(sa_payload);
+ generator->destroy(generator);
+
+ /* --------------------------- */
+ /* test with automatic created proposals */
+
+ generator = generator_create();
+ tester->assert_true(tester,(generator != NULL), "generator create check");
+
+
+ proposal1 = proposal_create(1);
+ proposal1->add_algorithm(proposal1, PROTO_IKE, ENCRYPTION_ALGORITHM, 1, 20);
+ proposal1->add_algorithm(proposal1, PROTO_IKE, PSEUDO_RANDOM_FUNCTION, 2, 22);
+ proposal1->add_algorithm(proposal1, PROTO_IKE, INTEGRITY_ALGORITHM, 3, 24);
+ proposal1->add_algorithm(proposal1, PROTO_IKE, DIFFIE_HELLMAN_GROUP, 4, 0);
+
+ proposal2 = proposal_create(2);
+ proposal2->add_algorithm(proposal2, PROTO_IKE, ENCRYPTION_ALGORITHM, 5, 26);
+ proposal2->add_algorithm(proposal2, PROTO_IKE, PSEUDO_RANDOM_FUNCTION, 6, 28);
+ proposal2->add_algorithm(proposal2, PROTO_IKE, INTEGRITY_ALGORITHM, 7, 30);
+ proposal2->add_algorithm(proposal2, PROTO_IKE, DIFFIE_HELLMAN_GROUP, 8, 0);
+
+ list = linked_list_create();
+ list->insert_last(list, (void*)proposal1);
+ list->insert_last(list, (void*)proposal2);
+ sa_payload = sa_payload_create_from_proposal_list(list);
+ tester->assert_true(tester,(sa_payload != NULL), "sa_payload create check");
+
+ generator->generate_payload(generator,(payload_t *)sa_payload);
+ generator->write_to_chunk(generator,&generated_data);
+ logger->log_chunk(logger,RAW,"generated",generated_data);
+
+ u_int8_t expected_generation2[] = {
+ 0x00,0x00,0x00,0x6C, /* payload header*/
+ 0x02,0x00,0x00,0x34, /* a proposal */
+ 0x01,0x01,0x00,0x04,
+ 0x03,0x00,0x00,0x0C, /* transform 1 */
+ 0x01,0x00,0x00,0x01,
+ 0x80,0x0E,0x00,0x14, /* keylength attribute with 20 bytes length */
+ 0x03,0x00,0x00,0x0C, /* transform 2 */
+ 0x02,0x00,0x00,0x02,
+ 0x80,0x0E,0x00,0x16, /* keylength attribute with 20 bytes length */
+ 0x03,0x00,0x00,0x0C, /* transform 3 */
+ 0x03,0x00,0x00,0x03,
+ 0x80,0x0E,0x00,0x18, /* keylength attribute with 20 bytes length */
+ 0x00,0x00,0x00,0x08, /* transform 4 */
+ 0x04,0x00,0x00,0x04,
+ 0x00,0x00,0x00,0x34, /* a proposal */
+ 0x02,0x01,0x00,0x04,
+ 0x03,0x00,0x00,0x0C, /* transform 1 */
+ 0x01,0x00,0x00,0x05,
+ 0x80,0x0E,0x00,0x1A, /* keylength attribute with 16 bytes length */
+ 0x03,0x00,0x00,0x0C, /* transform 2 */
+ 0x02,0x00,0x00,0x06,
+ 0x80,0x0E,0x00,0x1C, /* keylength attribute with 16 bytes length */
+ 0x03,0x00,0x00,0x0C, /* transform 3 */
+ 0x03,0x00,0x00,0x07,
+ 0x80,0x0E,0x00,0x1E, /* keylength attribute with 16 bytes length */
+ 0x00,0x00,0x00,0x08, /* transform 4 */
+ 0x04,0x00,0x00,0x08,
+
+ };
+
+ logger->log_bytes(logger,RAW,"expected",expected_generation2,sizeof(expected_generation2));
+
+ tester->assert_true(tester,(memcmp(expected_generation2,generated_data.ptr,sizeof(expected_generation2)) == 0), "compare generated data");
+
+ sa_payload->destroy(sa_payload);
+ list->destroy(list);
+ proposal1->destroy(proposal1);
+ proposal2->destroy(proposal2);
+ chunk_free(&generated_data);
+ generator->destroy(generator);
+
+
+ /* --------------------------- */
+ /* test with automatic created child proposals */
+
+ generator = generator_create();
+ tester->assert_true(tester,(generator != NULL), "generator create check");
+
+
+ proposal1 = proposal_create(1);
+
+ proposal1->add_algorithm(proposal1, PROTO_AH, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 20);
+ proposal1->add_algorithm(proposal1, PROTO_AH, DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0);
+ proposal1->add_algorithm(proposal1, PROTO_AH, EXTENDED_SEQUENCE_NUMBERS, EXT_SEQ_NUMBERS, 0);
+ proposal1->set_spi(proposal1, PROTO_AH, 0x01010101l);
+
+ proposal1->add_algorithm(proposal1, PROTO_ESP, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 20);
+ proposal1->add_algorithm(proposal1, PROTO_ESP, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0);
+ proposal1->set_spi(proposal1, PROTO_ESP, 0x02020202);
+
+
+ proposal2->add_algorithm(proposal2, PROTO_AH, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 20);
+ proposal2->add_algorithm(proposal2, PROTO_AH, DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0);
+ proposal2->add_algorithm(proposal2, PROTO_AH, EXTENDED_SEQUENCE_NUMBERS, EXT_SEQ_NUMBERS, 0);
+ proposal2->set_spi(proposal2, PROTO_AH, 0x01010101);
+
+ proposal2->add_algorithm(proposal2, PROTO_ESP, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 32);
+ proposal2->add_algorithm(proposal2, PROTO_ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 20);
+ proposal2->add_algorithm(proposal2, PROTO_ESP, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0);
+ proposal2->set_spi(proposal2, PROTO_ESP, 0x02020202);
+
+ list->insert_last(list, (void*)proposal1);
+ list->insert_last(list, (void*)proposal2);
+
+ sa_payload = sa_payload_create_from_proposal_list(list);
+ tester->assert_true(tester,(sa_payload != NULL), "sa_payload create check");
+
+ generator->generate_payload(generator,(payload_t *)sa_payload);
+ generator->write_to_chunk(generator,&generated_data);
+ logger->log_chunk(logger,RAW,"generated",generated_data);
+
+ u_int8_t expected_generation3[] = {
+ 0x00,0x00,0x00,0xA0, /* payload header*/
+
+ /* suite 1 */
+ 0x02,0x00,0x00,0x28, /* a proposal */
+ 0x01,0x02,0x04,0x03,
+ 0x01,0x01,0x01,0x01,
+ 0x03,0x00,0x00,0x0C, /* transform 1 */
+ 0x03,0x00,0x00,0x01,
+ 0x80,0x0E,0x00,0x14, /* keylength attribute with 20 bytes length */
+
+ 0x03,0x00,0x00,0x08, /* transform 2 */
+ 0x04,0x00,0x00,0x0E,
+
+ 0x00,0x00,0x00,0x08, /* transform 3 */
+ 0x05,0x00,0x00,0x01,
+
+
+ 0x02,0x00,0x00,0x20, /* a proposal */
+ 0x01,0x03,0x04,0x02,
+ 0x02,0x02,0x02,0x02,
+
+ 0x03,0x00,0x00,0x0C, /* transform 1 */
+ 0x01,0x00,0x00,0x0C,
+ 0x80,0x0E,0x00,0x20, /* keylength attribute with 32 bytes length */
+
+ 0x00,0x00,0x00,0x08, /* transform 2 */
+ 0x04,0x00,0x00,0x02,
+
+ /* suite 2 */
+ 0x02,0x00,0x00,0x28, /* a proposal */
+ 0x02,0x02,0x04,0x03,
+ 0x01,0x01,0x01,0x01,
+ 0x03,0x00,0x00,0x0C, /* transform 1 */
+ 0x03,0x00,0x00,0x01,
+ 0x80,0x0E,0x00,0x14, /* keylength attribute with 20 bytes length */
+
+ 0x03,0x00,0x00,0x08, /* transform 2 */
+ 0x04,0x00,0x00,0x0E,
+
+ 0x00,0x00,0x00,0x08, /* transform 3 */
+ 0x05,0x00,0x00,0x01,
+
+
+ 0x00,0x00,0x00,0x2C, /* a proposal */
+ 0x02,0x03,0x04,0x03,
+ 0x02,0x02,0x02,0x02,
+
+ 0x03,0x00,0x00,0x0C, /* transform 1 */
+ 0x01,0x00,0x00,0x0C,
+ 0x80,0x0E,0x00,0x20, /* keylength attribute with 32 bytes length */
+
+ 0x03,0x00,0x00,0x0C, /* transform 2 */
+ 0x03,0x00,0x00,0x01,
+ 0x80,0x0E,0x00,0x14, /* keylength attribute with 20 bytes length */
+
+ 0x00,0x00,0x00,0x08, /* transform 3 */
+ 0x04,0x00,0x00,0x02,
+
+ };
+
+
+ logger->log_bytes(logger,RAW,"expected",expected_generation3,sizeof(expected_generation3));
+
+ tester->assert_true(tester,(memcmp(expected_generation3,generated_data.ptr,sizeof(expected_generation3)) == 0), "compare generated data");
+
+ sa_payload->destroy(sa_payload);
+ proposal1->destroy(proposal1);
+ proposal2->destroy(proposal2);
+ list->destroy(list);
+ chunk_free(&generated_data);
+ generator->destroy(generator);
+
+}
+
+/*
+ * Described in header
+ */
+void test_generator_with_ke_payload(protected_tester_t *tester)
+{
+ generator_t *generator;
+ ke_payload_t *ke_payload;
+ logger_t *logger;
+ chunk_t generated_data;
+ chunk_t key_exchange_data;
+
+ logger = logger_manager->get_logger(logger_manager,TESTER);
+
+ /* create generator */
+ generator = generator_create();
+ tester->assert_true(tester,(generator != NULL), "generator create check");
+
+ ke_payload = ke_payload_create();
+
+
+ key_exchange_data.ptr = "test-text";
+ key_exchange_data.len = strlen(key_exchange_data.ptr);
+
+ ke_payload->set_key_exchange_data(ke_payload,key_exchange_data);
+
+ ke_payload->set_dh_group_number(ke_payload,7777);
+
+ generator->generate_payload(generator,(payload_t *)ke_payload);
+ generator->write_to_chunk(generator,&generated_data);
+ logger->log_chunk(logger,RAW,"generated payload",generated_data);
+
+ u_int8_t expected_generation[] = {
+ /* payload header */
+ 0x00,0x00,0x00,0x11,
+ 0x1E,0x61,0x00,0x00,
+ /* key exchange data */
+ 0x74,0x65,0x73,0x74,
+ 0x2D,0x74,0x65,0x78,
+ 0x74
+ };
+
+
+ logger->log_bytes(logger,RAW,"expected payload",expected_generation,sizeof(expected_generation));
+
+ tester->assert_true(tester,(memcmp(expected_generation,generated_data.ptr,sizeof(expected_generation)) == 0), "compare generated data");
+
+ chunk_free(&generated_data);
+
+ ke_payload->destroy(ke_payload);
+ generator->destroy(generator);
+
+}
+
+/*
+ * Described in header
+ */
+void test_generator_with_notify_payload(protected_tester_t *tester)
+{
+ generator_t *generator;
+ notify_payload_t *notify_payload;
+ logger_t *logger;
+ chunk_t generated_data;
+ chunk_t spi,notification_data;
+
+ logger = logger_manager->get_logger(logger_manager,TESTER);
+
+ /* create generator */
+ generator = generator_create();
+ tester->assert_true(tester,(generator != NULL), "generator create check");
+
+ notify_payload = notify_payload_create();
+
+
+ spi.ptr = "12345";
+ spi.len = strlen(spi.ptr);
+
+ notification_data.ptr = "67890";
+ notification_data.len = strlen(notification_data.ptr);
+
+ notify_payload->set_protocol_id(notify_payload,255);
+ notify_payload->set_notify_message_type(notify_payload,63333); /* Hex F765 */
+ notify_payload->set_spi(notify_payload,spi);
+ notify_payload->set_notification_data(notify_payload,notification_data);
+
+ generator->generate_payload(generator,(payload_t *)notify_payload);
+ generator->write_to_chunk(generator,&generated_data);
+ logger->log_chunk(logger,RAW,"generated payload",generated_data);
+
+ u_int8_t expected_generation[] = {
+ /* payload header */
+ 0x00,0x00,0x00,0x12,
+ 0xFF,0x05,0xF7,0x65,
+ /* spi */
+ 0x31,0x32,0x33,0x34,
+ 0x35,
+ /* notification data */
+ 0x36,0x37,0x38,0x39,
+ 0x30,
+ };
+
+ logger->log_bytes(logger,RAW,"expected payload",expected_generation,sizeof(expected_generation));
+
+ tester->assert_true(tester,(memcmp(expected_generation,generated_data.ptr,sizeof(expected_generation)) == 0), "compare generated data");
+
+ chunk_free(&generated_data);
+
+ notify_payload->destroy(notify_payload);
+ generator->destroy(generator);
+}
+
+/*
+ * Described in header
+ */
+void test_generator_with_nonce_payload(protected_tester_t *tester)
+{
+ generator_t *generator;
+ nonce_payload_t *nonce_payload;
+ logger_t *logger;
+ chunk_t generated_data;
+ chunk_t nonce;
+
+ logger = logger_manager->get_logger(logger_manager,TESTER);
+
+ /* create generator */
+ generator = generator_create();
+ tester->assert_true(tester,(generator != NULL), "generator create check");
+
+ nonce_payload = nonce_payload_create();
+
+
+ nonce.ptr = "1234567890123456";
+ nonce.len = strlen("1234567890123456");
+
+ nonce_payload->set_nonce(nonce_payload,nonce);
+
+ generator->generate_payload(generator,(payload_t *)nonce_payload);
+ generator->write_to_chunk(generator,&generated_data);
+ logger->log_chunk(logger,RAW,"generated payload",generated_data);
+
+
+ u_int8_t expected_generation[] = {
+ /* payload header */
+ 0x00,0x00,0x00,0x14,
+ /* nonce data */
+ 0x31,0x32,0x33,0x34,
+ 0x35,0x36,0x37,0x38,
+ 0x39,0x30,0x31,0x32,
+ 0x33,0x34,0x35,0x36
+ };
+
+ logger->log_bytes(logger,RAW,"expected payload",expected_generation,sizeof(expected_generation));
+
+ tester->assert_true(tester,(memcmp(expected_generation,generated_data.ptr,sizeof(expected_generation)) == 0), "compare generated data");
+
+ chunk_free(&generated_data);
+
+
+ nonce_payload->destroy(nonce_payload);
+ generator->destroy(generator);
+}
+
+/*
+ * Described in header.
+ */
+void test_generator_with_id_payload(protected_tester_t *tester)
+{
+ generator_t *generator;
+ id_payload_t *id_payload;
+ logger_t *logger;
+ chunk_t generated_data;
+ chunk_t id;
+
+ logger = logger_manager->get_logger(logger_manager,TESTER);
+
+ /* create generator */
+ generator = generator_create();
+ tester->assert_true(tester,(generator != NULL), "generator create check");
+
+ id_payload = id_payload_create(FALSE);
+
+
+ id.ptr = "123456789012";
+ id.len = strlen(id.ptr);
+
+ id_payload->set_id_type(id_payload,ID_IPV4_ADDR);
+ id_payload->set_data(id_payload,id);
+
+ generator->generate_payload(generator,(payload_t *)id_payload);
+ generator->write_to_chunk(generator,&generated_data);
+ logger->log_chunk(logger,RAW,"generated payload",generated_data);
+
+
+ u_int8_t expected_generation[] = {
+ /* payload header */
+ 0x00,0x00,0x00,0x14,
+ 0x01,0x00,0x00,0x00,
+ /* id data */
+ 0x31,0x32,0x33,0x34,
+ 0x35,0x36,0x37,0x38,
+ 0x39,0x30,0x31,0x32,
+ };
+
+ logger->log_bytes(logger,RAW,"expected payload",expected_generation,sizeof(expected_generation));
+
+ tester->assert_true(tester,(memcmp(expected_generation,generated_data.ptr,sizeof(expected_generation)) == 0), "compare generated data");
+
+ chunk_free(&generated_data);
+
+ id_payload->destroy(id_payload);
+ generator->destroy(generator);
+}
+
+/*
+ * Described in header.
+ */
+void test_generator_with_auth_payload(protected_tester_t *tester)
+{
+ generator_t *generator;
+ auth_payload_t *auth_payload;
+ logger_t *logger;
+ chunk_t generated_data;
+ chunk_t auth;
+
+ logger = logger_manager->get_logger(logger_manager,TESTER);
+
+ /* create generator */
+ generator = generator_create();
+ tester->assert_true(tester,(generator != NULL), "generator create check");
+
+ auth_payload = auth_payload_create(FALSE);
+
+
+ auth.ptr = "123456789012";
+ auth.len = strlen(auth.ptr);
+
+ auth_payload->set_auth_method(auth_payload,SHARED_KEY_MESSAGE_INTEGRITY_CODE);
+ auth_payload->set_data(auth_payload,auth);
+
+ generator->generate_payload(generator,(payload_t *)auth_payload);
+ generator->write_to_chunk(generator,&generated_data);
+ logger->log_chunk(logger,RAW,"generated payload",generated_data);
+
+
+ u_int8_t expected_generation[] = {
+ /* payload header */
+ 0x00,0x00,0x00,0x14,
+ 0x02,0x00,0x00,0x00,
+ /* auth data */
+ 0x31,0x32,0x33,0x34,
+ 0x35,0x36,0x37,0x38,
+ 0x39,0x30,0x31,0x32,
+ };
+
+ logger->log_bytes(logger,RAW,"expected payload",expected_generation,sizeof(expected_generation));
+
+ tester->assert_true(tester,(memcmp(expected_generation,generated_data.ptr,sizeof(expected_generation)) == 0), "compare generated data");
+
+ chunk_free(&generated_data);
+
+ auth_payload->destroy(auth_payload);
+ generator->destroy(generator);
+}
+
+/*
+ * Described in header.
+ */
+void test_generator_with_ts_payload(protected_tester_t *tester)
+{
+ generator_t *generator;
+ ts_payload_t *ts_payload;
+ traffic_selector_substructure_t *ts1, *ts2;
+ host_t *start_host1, *start_host2, *end_host1, *end_host2;
+ logger_t *logger;
+ chunk_t generated_data;
+
+ logger = logger_manager->get_logger(logger_manager,TESTER);
+
+ /* create generator */
+ generator = generator_create();
+ tester->assert_true(tester,(generator != NULL), "generator create check");
+
+ ts_payload = ts_payload_create(TRUE);
+
+ /* first traffic selector */
+ ts1 = traffic_selector_substructure_create();
+
+ start_host1 = host_create(AF_INET,"192.168.1.0",500);
+ ts1->set_start_host(ts1,start_host1);
+ start_host1->destroy(start_host1);
+
+ end_host1 = host_create(AF_INET,"192.168.1.255",500);
+ ts1->set_end_host(ts1,end_host1);
+ end_host1->destroy(end_host1);
+
+ ts_payload->add_traffic_selector_substructure(ts_payload,ts1);
+
+ /* second traffic selector */
+
+ ts2 = traffic_selector_substructure_create();
+
+ start_host2 = host_create(AF_INET,"0.0.0.0",0);
+ ts2->set_start_host(ts2,start_host2);
+ ts2->set_protocol_id(ts2,3);
+ start_host2->destroy(start_host2);
+
+ end_host2 = host_create(AF_INET,"255.255.255.255",65535);
+ ts2->set_end_host(ts2,end_host2);
+ end_host2->destroy(end_host2);
+
+ ts_payload->add_traffic_selector_substructure(ts_payload,ts2);
+
+
+ generator->generate_payload(generator,(payload_t *)ts_payload);
+ generator->write_to_chunk(generator,&generated_data);
+ logger->log_chunk(logger,RAW,"generated payload",generated_data);
+
+
+ u_int8_t expected_generation[] = {
+ /* payload header */
+ 0x00,0x00,0x00,0x28,
+ 0x02,0x00,0x00,0x00,
+
+ /* traffic selector 1 */
+ 0x07,0x00,0x00,0x10,
+ 0x01,0xF4,0x01,0xF4,
+ 0xC0,0xA8,0x01,0x00,
+ 0xC0,0xA8,0x01,0xFF,
+
+ /* traffic selector 2 */
+ 0x07,0x03,0x00,0x10,
+ 0x00,0x00,0xFF,0xFF,
+ 0x00,0x00,0x00,0x00,
+ 0xFF,0xFF,0xFF,0xFF,
+ };
+
+ logger->log_bytes(logger,RAW,"expected payload",expected_generation,sizeof(expected_generation));
+
+ tester->assert_true(tester,(memcmp(expected_generation,generated_data.ptr,sizeof(expected_generation)) == 0), "compare generated data");
+
+ chunk_free(&generated_data);
+
+ ts_payload->destroy(ts_payload);
+ generator->destroy(generator);
+}
+
+/*
+ * Described in header.
+ */
+void test_generator_with_cert_payload(protected_tester_t *tester)
+{
+ generator_t *generator;
+ cert_payload_t *cert_payload;
+ logger_t *logger;
+ chunk_t generated_data;
+ chunk_t cert;
+
+ logger = logger_manager->get_logger(logger_manager,TESTER);
+
+ /* create generator */
+ generator = generator_create();
+ tester->assert_true(tester,(generator != NULL), "generator create check");
+
+ cert_payload = cert_payload_create();
+
+
+ cert.ptr = "123456789012";
+ cert.len = strlen(cert.ptr);
+
+ cert_payload->set_cert_encoding(cert_payload,PGP_CERTIFICATE);
+ cert_payload->set_data(cert_payload,cert);
+
+ generator->generate_payload(generator,(payload_t *)cert_payload);
+ generator->write_to_chunk(generator,&generated_data);
+ logger->log_chunk(logger,RAW,"generated payload",generated_data);
+
+ u_int8_t expected_generation[] = {
+ /* payload header */
+ 0x00,0x00,0x00,0x11,
+ 0x02,
+ /* cert data */
+ 0x31,0x32,0x33,0x34,
+ 0x35,0x36,0x37,0x38,
+ 0x39,0x30,0x31,0x32,
+ };
+
+ logger->log_bytes(logger,RAW,"expected payload",expected_generation,sizeof(expected_generation));
+
+ tester->assert_true(tester,(memcmp(expected_generation,generated_data.ptr,sizeof(expected_generation)) == 0), "compare generated data");
+
+ chunk_free(&generated_data);
+
+ cert_payload->destroy(cert_payload);
+ generator->destroy(generator);
+}
+
+/*
+ * Described in header.
+ */
+void test_generator_with_certreq_payload(protected_tester_t *tester)
+{
+ generator_t *generator;
+ certreq_payload_t *certreq_payload;
+ logger_t *logger;
+ chunk_t generated_data;
+ chunk_t certreq;
+
+ logger = logger_manager->get_logger(logger_manager,TESTER);
+
+ /* create generator */
+ generator = generator_create();
+ tester->assert_true(tester,(generator != NULL), "generator create check");
+
+ certreq_payload = certreq_payload_create();
+
+
+ certreq.ptr = "123456789012";
+ certreq.len = strlen(certreq.ptr);
+
+ certreq_payload->set_cert_encoding(certreq_payload,PGP_CERTIFICATE);
+ certreq_payload->set_data(certreq_payload,certreq);
+
+ generator->generate_payload(generator,(payload_t *)certreq_payload);
+ generator->write_to_chunk(generator,&generated_data);
+ logger->log_chunk(logger,RAW,"generated payload",generated_data);
+
+ u_int8_t expected_generation[] = {
+ /* payload header */
+ 0x00,0x00,0x00,0x11,
+ 0x02,
+ /* certreq data */
+ 0x31,0x32,0x33,0x34,
+ 0x35,0x36,0x37,0x38,
+ 0x39,0x30,0x31,0x32,
+ };
+
+ logger->log_bytes(logger,RAW,"expected payload",expected_generation,sizeof(expected_generation));
+
+ tester->assert_true(tester,(memcmp(expected_generation,generated_data.ptr,sizeof(expected_generation)) == 0), "compare generated data");
+
+ chunk_free(&generated_data);
+
+ certreq_payload->destroy(certreq_payload);
+ generator->destroy(generator);
+}
+
+/*
+ * Described in header.
+ */
+void test_generator_with_delete_payload(protected_tester_t *tester)
+{
+ generator_t *generator;
+ delete_payload_t *delete_payload;
+ logger_t *logger;
+ chunk_t generated_data;
+ chunk_t spis;
+
+ logger = logger_manager->get_logger(logger_manager,TESTER);
+
+ /* create generator */
+ generator = generator_create();
+ tester->assert_true(tester,(generator != NULL), "generator create check");
+
+ delete_payload = delete_payload_create();
+
+
+ spis.ptr = "123456789012";
+ spis.len = strlen(spis.ptr);
+
+ delete_payload->set_protocol_id(delete_payload, PROTO_AH);
+ delete_payload->set_spi_count(delete_payload,3);
+ delete_payload->set_spi_size(delete_payload,4);
+ delete_payload->set_spis(delete_payload,spis);
+
+ generator->generate_payload(generator,(payload_t *)delete_payload);
+ generator->write_to_chunk(generator,&generated_data);
+ logger->log_chunk(logger,RAW,"generated payload",generated_data);
+
+ u_int8_t expected_generation[] = {
+ /* payload header */
+ 0x00,0x00,0x00,0x14,
+ 0x02,0x04,0x00,0x03,
+ /* delete data */
+ 0x31,0x32,0x33,0x34,
+ 0x35,0x36,0x37,0x38,
+ 0x39,0x30,0x31,0x32,
+ };
+
+ logger->log_bytes(logger,RAW,"expected payload",expected_generation,sizeof(expected_generation));
+
+ tester->assert_true(tester,(memcmp(expected_generation,generated_data.ptr,sizeof(expected_generation)) == 0), "compare generated data");
+
+ chunk_free(&generated_data);
+
+ delete_payload->destroy(delete_payload);
+ generator->destroy(generator);
+}
+
+/*
+ * Described in header.
+ */
+void test_generator_with_vendor_id_payload(protected_tester_t *tester)
+{
+ generator_t *generator;
+ vendor_id_payload_t *vendor_id_payload;
+ logger_t *logger;
+ chunk_t generated_data;
+ chunk_t data;
+
+ logger = logger_manager->get_logger(logger_manager,TESTER);
+
+ /* create generator */
+ generator = generator_create();
+ tester->assert_true(tester,(generator != NULL), "generator create check");
+
+ vendor_id_payload = vendor_id_payload_create();
+
+
+ data.ptr = "123456789012";
+ data.len = strlen(data.ptr);
+;
+ vendor_id_payload->set_data(vendor_id_payload,data);
+ generator->generate_payload(generator,(payload_t *)vendor_id_payload);
+ generator->write_to_chunk(generator,&generated_data);
+ logger->log_chunk(logger,RAW,"generated payload",generated_data);
+
+ u_int8_t expected_generation[] = {
+ /* payload header */
+ 0x00,0x00,0x00,0x10,
+ /* vendor_id data */
+ 0x31,0x32,0x33,0x34,
+ 0x35,0x36,0x37,0x38,
+ 0x39,0x30,0x31,0x32,
+ };
+
+ logger->log_bytes(logger,RAW,"expected payload",expected_generation,sizeof(expected_generation));
+
+ tester->assert_true(tester,(memcmp(expected_generation,generated_data.ptr,sizeof(expected_generation)) == 0), "compare generated data");
+
+ chunk_free(&generated_data);
+
+ vendor_id_payload->destroy(vendor_id_payload);
+ generator->destroy(generator);
+}
+
+/*
+ * Described in header
+ */
+void test_generator_with_cp_payload(protected_tester_t *tester)
+{
+ generator_t *generator;
+ configuration_attribute_t *attribute1, *attribute2;
+ cp_payload_t *configuration;
+ chunk_t data;
+ chunk_t generated_data;
+ logger_t *logger;
+
+ logger = logger_manager->get_logger(logger_manager,TESTER);
+
+ /* create generator */
+ generator = generator_create();
+ tester->assert_true(tester,(generator != NULL), "generator create check");
+
+ /* create attribute 1 */
+ attribute1 = configuration_attribute_create();
+ char *stringval = "abcd";
+ data.ptr = (void *) stringval;
+ data.len = 4;
+ attribute1->set_value(attribute1,data);
+ attribute1->set_attribute_type(attribute1,3);
+ logger->log(logger,CONTROL,"attribute1 created");
+
+ /* create attribute 2 */
+ attribute2 = configuration_attribute_create();
+ stringval = "efgh";
+ data.ptr = (void *) stringval;
+ data.len = 4;
+ attribute2->set_value(attribute2,data);
+ attribute2->set_attribute_type(attribute2,4);
+ logger->log(logger,CONTROL,"attribute2 created");
+
+ /* create configuration */
+ configuration = cp_payload_create();
+ tester->assert_true(tester,(configuration != NULL), "configuration create check");
+ configuration->add_configuration_attribute(configuration,attribute1);
+ configuration->add_configuration_attribute(configuration,attribute2);
+ configuration->set_config_type(configuration,5); /* hex 5 */
+
+
+ logger->log(logger,CONTROL,"cp payload created");
+
+ generator->generate_payload(generator,(payload_t *)configuration);
+ generator->write_to_chunk(generator,&generated_data);
+ logger->log_chunk(logger,RAW,"generated configuration",generated_data);
+
+ u_int8_t expected_generation3[] = {
+ /* cp payload header */
+ 0x00,0x00,0x00,0x18,
+ 0x05,0x00,0x00,0x00,
+ /* configuration attribute 1*/
+ 0x00,0x03,0x00,0x04,
+ 0x61,0x62,0x63,0x64,
+ /* configuration attribute 2*/
+ 0x00,0x04,0x00,0x04,
+ 0x65,0x66,0x67,0x68,
+ };
+
+ logger->log_bytes(logger,RAW,"expected configuration",expected_generation3,sizeof(expected_generation3));
+
+ tester->assert_true(tester,(memcmp(expected_generation3,generated_data.ptr,sizeof(expected_generation3)) == 0), "compare generated data");
+
+ chunk_free(&generated_data);
+ configuration->destroy(configuration);
+ generator->destroy(generator);
+}
+
+/*
+ * Described in header.
+ */
+void test_generator_with_eap_payload(protected_tester_t *tester)
+{
+ generator_t *generator;
+ eap_payload_t *eap_payload;
+ logger_t *logger;
+ chunk_t generated_data;
+ chunk_t message;
+
+ logger = logger_manager->get_logger(logger_manager,TESTER);
+
+ /* create generator */
+ generator = generator_create();
+ tester->assert_true(tester,(generator != NULL), "generator create check");
+
+ eap_payload = eap_payload_create();
+
+
+ message.ptr = "123456789012";
+ message.len = strlen(message.ptr);
+;
+ eap_payload->set_message(eap_payload,message);
+ generator->generate_payload(generator,(payload_t *)eap_payload);
+ generator->write_to_chunk(generator,&generated_data);
+ logger->log_chunk(logger,RAW,"generated payload",generated_data);
+
+ u_int8_t expected_generation[] = {
+ /* payload header */
+ 0x00,0x00,0x00,0x10,
+ /* eap data */
+ 0x31,0x32,0x33,0x34,
+ 0x35,0x36,0x37,0x38,
+ 0x39,0x30,0x31,0x32,
+ };
+
+ logger->log_bytes(logger,RAW,"expected payload",expected_generation,sizeof(expected_generation));
+
+ tester->assert_true(tester,(memcmp(expected_generation,generated_data.ptr,sizeof(expected_generation)) == 0), "compare generated data");
+
+ chunk_free(&generated_data);
+
+ eap_payload->destroy(eap_payload);
+ generator->destroy(generator);
+}
diff --git a/programs/charon/testing/generator_test.h b/programs/charon/testing/generator_test.h
new file mode 100644
index 000000000..204255fb7
--- /dev/null
+++ b/programs/charon/testing/generator_test.h
@@ -0,0 +1,183 @@
+/**
+ * @file generator_test.h
+ *
+ * @brief Tests for the generator_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef GENERATOR_TEST_H_
+#define GENERATOR_TEST_H_
+
+#include <utils/tester.h>
+
+/**
+ * @brief Test function used to test the generator with header payload.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_generator_with_header_payload(protected_tester_t *tester);
+
+/**
+ * @brief Test function used to test the generator with transform attribute payload.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_generator_with_transform_attribute(protected_tester_t *tester);
+
+
+/**
+ * @brief Test function used to test the generator with transform substructure payload.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_generator_with_transform_substructure(protected_tester_t *tester);
+
+/**
+ * @brief Test function used to test the generator with proposal substructure payload.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_generator_with_proposal_substructure(protected_tester_t *tester);
+
+/**
+ * @brief Test function used to test the generator with SA payload.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_generator_with_sa_payload(protected_tester_t *tester);
+
+/**
+ * @brief Test function used to test the generator with KE payload.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_generator_with_ke_payload(protected_tester_t *tester);
+
+/**
+ * @brief Test function used to test the generator with Notify payload.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_generator_with_notify_payload(protected_tester_t *tester);
+
+/**
+ * @brief Test function used to test the generator with Nonce payload.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_generator_with_nonce_payload(protected_tester_t *tester);
+
+/**
+ * @brief Test function used to test the generator with ID payload.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_generator_with_id_payload(protected_tester_t *tester);
+
+/**
+ * @brief Test function used to test the generator with AUTH payload.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_generator_with_auth_payload(protected_tester_t *tester);
+
+/**
+ * @brief Test function used to test the generator with TS payload.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_generator_with_ts_payload(protected_tester_t *tester);
+
+/**
+ * @brief Test function used to test the generator with CERT payload.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_generator_with_cert_payload(protected_tester_t *tester);
+
+/**
+ * @brief Test function used to test the generator with CERTREQ payload.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_generator_with_certreq_payload(protected_tester_t *tester);
+
+/**
+ * @brief Test function used to test the generator with DELETE payload.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_generator_with_delete_payload(protected_tester_t *tester);
+
+/**
+ * @brief Test function used to test the generator with VENDOR ID payload.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_generator_with_vendor_id_payload(protected_tester_t *tester);
+
+/**
+ * @brief Test function used to test the generator with CP payload.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_generator_with_cp_payload(protected_tester_t *tester);
+
+/**
+ * @brief Test function used to test the generator with EAP payload.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_generator_with_eap_payload(protected_tester_t *tester);
+
+
+#endif /*GENERATOR_TEST_H_*/
diff --git a/programs/charon/testing/hasher_test.c b/programs/charon/testing/hasher_test.c
new file mode 100644
index 000000000..9130a2092
--- /dev/null
+++ b/programs/charon/testing/hasher_test.c
@@ -0,0 +1,170 @@
+/**
+ * @file hasher_test.h
+ *
+ * @brief Tests for the hasher_t classes.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+
+#include "hasher_test.h"
+
+
+/*
+ * described in Header-File
+ */
+void test_md5_hasher(protected_tester_t *tester)
+{
+ /*
+ * Test vectors from RFC1321:
+ * MD5 ("") = d41d8cd98f00b204e9800998ecf8427e
+ * MD5 ("a") = 0cc175b9c0f1b6a831c399e269772661
+ * MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72
+ * MD5 ("message digest") = f96b697d7cb7938d525a2f31aaf161d0
+ * MD5 ("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b
+ *
+ * currently testing "", "abc", "abcdefghijklmnopqrstuvwxyz"
+ */
+ hasher_t *hasher = hasher_create(HASH_MD5);
+ u_int8_t hash_buffer[16];
+ chunk_t empty, abc, abcd, hash_chunk;
+
+ u_int8_t hash_empty[] = {
+ 0xd4,0x1d,0x8c,0xd9,
+ 0x8f,0x00,0xb2,0x04,
+ 0xe9,0x80,0x09,0x98,
+ 0xec,0xf8,0x42,0x7e
+ };
+
+ u_int8_t hash_abc[] = {
+ 0x90,0x01,0x50,0x98,
+ 0x3c,0xd2,0x4f,0xb0,
+ 0xd6,0x96,0x3f,0x7d,
+ 0x28,0xe1,0x7f,0x72
+ };
+
+ u_int8_t hash_abcd[] = {
+ 0xc3,0xfc,0xd3,0xd7,
+ 0x61,0x92,0xe4,0x00,
+ 0x7d,0xfb,0x49,0x6c,
+ 0xca,0x67,0xe1,0x3b
+ };
+
+ empty.ptr = "";
+ empty.len = 0;
+ abc.ptr = "abc";
+ abc.len = 3;
+ abcd.ptr = "abcdefghijklmnopqrstuvwxyz";
+ abcd.len = strlen(abcd.ptr);
+
+ tester->assert_true(tester, hasher->get_hash_size(hasher) == 16, "block size");
+
+ /* simple hashing, using empty */
+ hasher->get_hash(hasher, empty, hash_buffer);
+ tester->assert_false(tester, memcmp(hash_buffer, hash_empty, 16), "hash for empty");
+
+ /* simple hashing, using "abc" */
+ hasher->get_hash(hasher, abc, hash_buffer);
+ tester->assert_false(tester, memcmp(hash_buffer, hash_abc, 16), "hash for abc");
+
+ /* with allocation, using "abcdb..." */
+ hasher->reset(hasher);
+ hasher->allocate_hash(hasher, abcd, &hash_chunk);
+ tester->assert_true(tester, hash_chunk.len == 16, "hash len");
+ tester->assert_false(tester, memcmp(hash_chunk.ptr, hash_abcd, hash_chunk.len), "hash for abcd...");
+ free(hash_chunk.ptr);
+ hasher->destroy(hasher);
+}
+
+/*
+ * described in Header-File
+ */
+void test_sha1_hasher(protected_tester_t *tester)
+{
+ /*
+ * Test Vectors (from FIPS PUB 180-1)
+ * "abc"
+ * A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+ * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+ * 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+ * A million repetitions of "a"
+ * 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+ */
+ hasher_t *hasher = hasher_create(HASH_SHA1);
+ u_int8_t hash_buffer[20];
+ chunk_t abc, abcdb, aaa, hash_chunk;
+ u_int32_t i;
+ u_int8_t hash_abc[] = {
+ 0xA9,0x99,0x3E,0x36,
+ 0x47,0x06,0x81,0x6A,
+ 0xBA,0x3E,0x25,0x71,
+ 0x78,0x50,0xC2,0x6C,
+ 0x9C,0xD0,0xD8,0x9D
+ };
+ u_int8_t hash_abcdb[] = {
+ 0x84,0x98,0x3E,0x44,
+ 0x1C,0x3B,0xD2,0x6E,
+ 0xBA,0xAE,0x4A,0xA1,
+ 0xF9,0x51,0x29,0xE5,
+ 0xE5,0x46,0x70,0xF1
+ };
+ u_int8_t hash_aaa[] = {
+ 0x34,0xAA,0x97,0x3C,
+ 0xD4,0xC4,0xDA,0xA4,
+ 0xF6,0x1E,0xEB,0x2B,
+ 0xDB,0xAD,0x27,0x31,
+ 0x65,0x34,0x01,0x6F
+ };
+ abc.ptr = "abc";
+ abc.len = 3;
+ abcdb.ptr = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
+ abcdb.len = strlen(abcdb.ptr);
+ aaa.ptr = "aaaaaaaaaa"; /* 10 a's */
+ aaa.len = 10;
+
+ tester->assert_true(tester, hasher->get_hash_size(hasher) == 20, "block size");
+
+ /* simple hashing, using "abc" */
+ hasher->get_hash(hasher, abc, hash_buffer);
+ tester->assert_false(tester, memcmp(hash_buffer, hash_abc, 20), "hash for abc");
+
+ /* with allocation, using "abcdb..." */
+ hasher->reset(hasher);
+ hasher->allocate_hash(hasher, abcdb, &hash_chunk);
+ tester->assert_true(tester, hash_chunk.len == 20, "chunk len");
+ tester->assert_false(tester, memcmp(hash_chunk.ptr, hash_abcdb, hash_chunk.len), "hash for abcdb...");
+ free(hash_chunk.ptr);
+
+ /* updating, using "aaaaaaa..." */
+ hasher->reset(hasher);
+ for(i=0; i<100000; i++)
+ {
+ if (i != 99999)
+ {
+ hasher->get_hash(hasher, aaa, NULL);
+ }
+ else
+ {
+ hasher->get_hash(hasher, aaa, hash_buffer);
+ }
+ }
+ tester->assert_false(tester, memcmp(hash_buffer, hash_aaa, 20), "hash for aaa...");
+
+
+ hasher->destroy(hasher);
+}
diff --git a/programs/charon/testing/hasher_test.h b/programs/charon/testing/hasher_test.h
new file mode 100644
index 000000000..cc6fe52c8
--- /dev/null
+++ b/programs/charon/testing/hasher_test.h
@@ -0,0 +1,49 @@
+/**
+ * @file hasher_test.h
+ *
+ * @brief Tests for the hasher_t classes.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef HASHER_TEST_H_
+#define HASHER_TEST_H_
+
+#include <crypto/hashers/hasher.h>
+#include <crypto/hashers/md5_hasher.h>
+#include <crypto/hashers/sha1_hasher.h>
+#include <utils/tester.h>
+
+/**
+ * @brief Test function used to test the SHA1-hasher functionality.
+ *
+ * @param tester associated tester object
+ *
+ * @ingroup testcases
+ */
+void test_sha1_hasher(protected_tester_t *tester);
+
+/**
+ * @brief Test function used to test the Md5-hasher functionality.
+ *
+ * @param tester associated tester object
+ *
+ * @ingroup testcases
+ */
+void test_md5_hasher(protected_tester_t *tester);
+
+#endif /*HASHER_TEST_H_*/
diff --git a/programs/charon/testing/hmac_signer_test.c b/programs/charon/testing/hmac_signer_test.c
new file mode 100644
index 000000000..a1ac8ea43
--- /dev/null
+++ b/programs/charon/testing/hmac_signer_test.c
@@ -0,0 +1,203 @@
+/**
+ * @file hmac_signer_test.c
+ *
+ * @brief Tests for the hmac_signer_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#include <string.h>
+
+#include "hmac_signer_test.h"
+
+#include <crypto/signers/signer.h>
+#include <daemon.h>
+
+
+/*
+ * Described in header.
+ */
+void test_hmac_md5_signer(protected_tester_t *tester)
+{
+ /* Test cases from RFC2202
+ *
+ * test_case = 5
+ * key = 0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c
+ * key_len = 16
+ * data = "Test With Truncation"
+ * data_len = 20
+ * digest = 0x56461ef2342edc00f9bab995690efd4c
+ * digest-96 0x56461ef2342edc00f9bab995
+ *
+ * currently only this test 5 gets performed!
+ */
+ chunk_t keys[4];
+ chunk_t data[4];
+ chunk_t signature[4];
+ chunk_t reference[4];
+ chunk_t wrong_reference[4];
+ int i;
+ logger_t *logger;
+ bool valid;
+
+ logger = logger_manager->get_logger(logger_manager, TESTER);
+
+ signer_t *signer = (signer_t *) signer_create(AUTH_HMAC_MD5_96);
+ tester->assert_true(tester, (signer != NULL), "signer create call check");
+
+
+ /*
+ * values for test 5
+ */
+ u_int8_t key1[] = {
+ 0x0c,0x0c,0x0c,0x0c,
+ 0x0c,0x0c,0x0c,0x0c,
+ 0x0c,0x0c,0x0c,0x0c,
+ 0x0c,0x0c,0x0c,0x0c,
+ };
+ keys[0].ptr = key1;
+ keys[0].len = sizeof(key1);
+ data[0].ptr = "Test With Truncation";
+ data[0].len = 20;
+ u_int8_t reference1[] = {
+ 0x56,0x46,0x1e,0xf2,0x34,0x2e,
+ 0xdc,0x00,0xf9,0xba,0xb9,0x95
+ };
+ reference[0].ptr = reference1;
+ reference[0].len = sizeof(reference1);
+
+ u_int8_t wrong_reference1[] = {
+ 0x56,0x46,0x1e,0xa2,0x34,0x2e,
+ 0xdc,0x00,0xf9,0xba,0xb9,0x95
+ };
+
+ wrong_reference[0].ptr = wrong_reference1;
+ wrong_reference[0].len = sizeof(wrong_reference1);
+
+ for (i=0; i<1; i++)
+ {
+ signer->set_key(signer, keys[i]);
+ signer->allocate_signature(signer, data[i], &signature[i]);
+ tester->assert_true(tester, signature[i].len == 12, "chunk len");
+ tester->assert_true(tester, (memcmp(signature[i].ptr, reference[i].ptr, 12) == 0), "hmac value");
+ logger->log_chunk(logger,RAW,"expected signature:",reference[i]);
+ logger->log_chunk(logger,RAW,"signature:",signature[i]);
+ free(signature[i].ptr);
+ valid = signer->verify_signature(signer, data[i],reference[i]);
+ tester->assert_true(tester, (valid == TRUE), "Signature valid check");
+
+ valid = signer->verify_signature(signer, data[i],wrong_reference[i]);
+ tester->assert_true(tester, (valid == FALSE), "Signature not valid check");
+ }
+ signer->destroy(signer);
+}
+
+
+/*
+ * Described in header.
+ */
+void test_hmac_sha1_signer(protected_tester_t *tester)
+{
+ /*
+ * test_case = 7
+ * key = 0xaa repeated 80 times
+ * key_len = 80
+ * data = "Test Using Larger Than Block-Size Key and Larger
+ * Than One Block-Size Data"
+ * data_len = 73
+ * digest = 0x4c1a03424b55e07fe7f27be1d58bb9324a9a5a04
+ * digest-96 = 0x4c1a03424b55e07fe7f27be1
+ */
+
+ chunk_t keys[4];
+ chunk_t data[4];
+ chunk_t signature[4];
+ chunk_t reference[4];
+ chunk_t wrong_reference[4];
+ int i;
+ logger_t *logger;
+ bool valid;
+
+ logger = logger_manager->get_logger(logger_manager, TESTER);
+
+ signer_t *signer = (signer_t *) signer_create(AUTH_HMAC_SHA1_96);
+ tester->assert_true(tester, (signer != NULL), "signer create call check");
+
+
+ /*
+ * values for test 5
+ */
+ u_int8_t key1[] = {
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ };
+ keys[0].ptr = key1;
+ keys[0].len = sizeof(key1);
+ data[0].ptr = "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data";
+ data[0].len = 73;
+ u_int8_t reference1[] = {
+ 0xe8,0xe9,0x9d,0x0f,0x45,0x23,
+ 0x7d,0x78,0x6d,0x6b,0xba,0xa7
+ };
+ reference[0].ptr = reference1;
+ reference[0].len = sizeof(reference1);
+
+ u_int8_t wrong_reference1[] = {
+ 0xe8,0xe9,0x9d,0x0f,0x46,0x23,
+ 0x7d,0x71,0x6d,0x6b,0xba,0xa7
+ };
+
+ wrong_reference[0].ptr = wrong_reference1;
+ wrong_reference[0].len = sizeof(wrong_reference1);
+
+ for (i=0; i<1; i++)
+ {
+ signer->set_key(signer, keys[i]);
+ signer->allocate_signature(signer, data[i], &signature[i]);
+ tester->assert_true(tester, signature[i].len == 12, "chunk len");
+ tester->assert_true(tester, (memcmp(signature[i].ptr, reference[i].ptr, 12) == 0), "hmac value");
+ logger->log_chunk(logger,RAW,"expected signature:",reference[i]);
+ logger->log_chunk(logger,RAW,"signature:",signature[i]);
+ free(signature[i].ptr);
+ valid = signer->verify_signature(signer, data[i],reference[i]);
+ tester->assert_true(tester, (valid == TRUE), "Signature valid check");
+
+ valid = signer->verify_signature(signer, data[i],wrong_reference[i]);
+ tester->assert_true(tester, (valid == FALSE), "Signature not valid check");
+ }
+
+ signer->destroy(signer);
+}
diff --git a/programs/charon/testing/hmac_signer_test.h b/programs/charon/testing/hmac_signer_test.h
new file mode 100644
index 000000000..4a2459a8e
--- /dev/null
+++ b/programs/charon/testing/hmac_signer_test.h
@@ -0,0 +1,46 @@
+/**
+ * @file hmac_signer_test.h
+ *
+ * @brief Tests for the hmac_signer_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef HMAC_SIGNER_TEST_H_
+#define HMAC_SIGNER_TEST_H_
+
+#include <utils/tester.h>
+
+/**
+ * @brief Test function used to test the hmac sign functionality using MD5.
+ *
+ * @param tester associated tester object
+ *
+ * @ingroup testcases
+ */
+void test_hmac_md5_signer(protected_tester_t *tester);
+
+/**
+ * @brief Test function used to test the hmac sign functionality using SHA1.
+ *
+ * @param tester associated tester object
+ *
+ * @ingroup testcases
+ */
+void test_hmac_sha1_signer(protected_tester_t *tester);
+
+#endif /* HMAC_SIGNER_TEST_H_ */
diff --git a/programs/charon/testing/hmac_test.c b/programs/charon/testing/hmac_test.c
new file mode 100644
index 000000000..c1341257c
--- /dev/null
+++ b/programs/charon/testing/hmac_test.c
@@ -0,0 +1,408 @@
+/**
+ * @file hmac_test.h
+ *
+ * @brief Tests for the hmac_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+
+#include "hmac_test.h"
+
+#include <crypto/hmac.h>
+
+
+/*
+ * described in Header-File
+ */
+void test_hmac_sha1(protected_tester_t *tester)
+{
+ /*
+ * Test cases from RFC2202
+ *
+ * test_case = 1
+ * key = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
+ * key_len = 20
+ * data = "Hi There"
+ * data_len = 8
+ * digest = 0xb617318655057264e28bc0b6fb378c8ef146be00
+ *
+ * test_case = 2
+ * key = "Jefe"
+ * key_len = 4
+ * data = "what do ya want for nothing?"
+ * data_len = 28
+ * digest = 0xeffcdf6ae5eb2fa2d27416d5f184df9c259a7c79
+ *
+ * test_case = 3
+ * key = 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ * key_len = 20
+ * data = 0xdd repeated 50 times
+ * data_len = 50
+ * digest = 0x125d7342b9ac11cd91a39af48aa17b4f63f175d3
+ *
+ * test_case = 4
+ * key = 0x0102030405060708090a0b0c0d0e0f10111213141516171819
+ * key_len = 25
+ * data = 0xcd repeated 50 times
+ * data_len = 50
+ * digest = 0x4c9007f4026250c6bc8414f9bf50c86c2d7235da
+ *
+ * test_case = 5
+ * key = 0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c
+ * key_len = 20
+ * data = "Test With Truncation"
+ * data_len = 20
+ * digest = 0x4c1a03424b55e07fe7f27be1d58bb9324a9a5a04
+ * digest-96 = 0x4c1a03424b55e07fe7f27be1
+ *
+ * test_case = 6
+ * key = 0xaa repeated 80 times
+ * key_len = 80
+ * data = "Test Using Larger Than Block-Size Key - Hash Key First"
+ * data_len = 54
+ * digest = 0xaa4ae5e15272d00e95705637ce8a3b55ed402112
+ *
+ * test_case = 7
+ * key = 0xaa repeated 80 times
+ * key_len = 80
+ * data = "Test Using Larger Than Block-Size Key and Larger
+ * Than One Block-Size Data"
+ * data_len = 73
+ * digest = 0xe8e99d0f45237d786d6bbaa7965c7808bbff1a91
+ *
+ * currently performing test 1, 2, 4 and 7
+ */
+
+ chunk_t keys[4];
+ chunk_t data[4];
+ chunk_t digest[4];
+ chunk_t reference[4];
+ int i;
+
+ /*
+ * values for test 1
+ */
+ u_int8_t key1[] = {
+ 0x0b,0x0b,0x0b,0x0b,
+ 0x0b,0x0b,0x0b,0x0b,
+ 0x0b,0x0b,0x0b,0x0b,
+ 0x0b,0x0b,0x0b,0x0b,
+ 0x0b,0x0b,0x0b,0x0b
+ };
+ keys[0].ptr = key1;
+ keys[0].len = sizeof(key1);
+ data[0].ptr = "Hi There";
+ data[0].len = 8;
+ u_int8_t reference1[] = {
+ 0xb6,0x17,0x31,0x86,
+ 0x55,0x05,0x72,0x64,
+ 0xe2,0x8b,0xc0,0xb6,
+ 0xfb,0x37,0x8c,0x8e,
+ 0xf1,0x46,0xbe,0x00
+ };
+ reference[0].ptr = reference1;
+ reference[0].len = sizeof(reference1);
+
+ /*
+ * values for test 2
+ */
+ u_int8_t reference2[] = {
+ 0xef,0xfc,0xdf,0x6a,
+ 0xe5,0xeb,0x2f,0xa2,
+ 0xd2,0x74,0x16,0xd5,
+ 0xf1,0x84,0xdf,0x9c,
+ 0x25,0x9a,0x7c,0x79
+ };
+ keys[1].ptr = "Jefe";
+ keys[1].len = 4;
+ data[1].ptr = "what do ya want for nothing?";
+ data[1].len = 28;
+ reference[1].ptr = reference2;
+ reference[1].len = sizeof(reference2);
+
+ /*
+ * values for test 7
+ */
+ u_int8_t key7[] = {
+ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
+ };
+ u_int8_t reference7[] = {
+ 0xe8,0xe9,0x9d,0x0f,
+ 0x45,0x23,0x7d,0x78,
+ 0x6d,0x6b,0xba,0xa7,
+ 0x96,0x5c,0x78,0x08,
+ 0xbb,0xff,0x1a,0x91
+ };
+ keys[2].ptr = key7;
+ keys[2].len = sizeof(key7);
+ data[2].ptr = "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data";
+ data[2].len = 73;
+ reference[2].ptr = reference7;
+ reference[2].len = sizeof(reference7);
+
+
+ for (i=0; i<3; i++)
+ {
+ hmac_t *hmac = hmac_create(HASH_SHA1);
+ hmac->set_key(hmac, keys[i]);
+ hmac->allocate_mac(hmac, data[i], &digest[i]);
+ hmac->destroy(hmac);
+
+ tester->assert_true(tester, digest[i].len == 20, "chunk len");
+ tester->assert_false(tester, memcmp(digest[i].ptr, reference[i].ptr, 20), "hmac value");
+ free(digest[i].ptr);
+ }
+
+ /*
+ * test 4 is donne in append mode
+ */
+ u_int8_t val = 0xcd;
+
+ u_int8_t key4[] = {
+ 0x01,0x02,0x03,0x04,
+ 0x05,0x06,0x07,0x08,
+ 0x09,0x0a,0x0b,0x0c,
+ 0x0d,0x0e,0x0f,0x10,
+ 0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19
+ };
+ keys[3].ptr = key4;
+ keys[3].len = sizeof(key4);
+ u_int8_t reference4[] = {
+ 0x4c,0x90,0x07,0xf4,
+ 0x02,0x62,0x50,0xc6,
+ 0xbc,0x84,0x14,0xf9,
+ 0xbf,0x50,0xc8,0x6c,
+ 0x2d,0x72,0x35,0xda
+ };
+ reference[3].ptr = reference4;
+ reference[3].len = sizeof(reference4);
+
+ hmac_t *hmac = hmac_create(HASH_SHA1);
+ hmac->set_key(hmac, keys[3]);
+ data[3].ptr = &val;
+ data[3].len = 1;
+ for (i=0; i<49; i++)
+ {
+ hmac->get_mac(hmac, data[3], NULL);
+ }
+ hmac->allocate_mac(hmac, data[3], &digest[3]);
+ hmac->destroy(hmac);
+
+ tester->assert_true(tester, digest[3].len == 20, "chunk len append mode");
+ tester->assert_false(tester, memcmp(digest[3].ptr, reference[3].ptr, 20), "hmac value append mode");
+ free(digest[3].ptr);
+}
+
+/*
+ * described in Header-File
+ */
+void test_hmac_md5(protected_tester_t *tester)
+{
+ /*
+ * Test cases from RFC2202
+ *
+ * test_case = 1
+ * key = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
+ * key_len = 16
+ * data = "Hi There"
+ * data_len = 8
+ * digest = 0x9294727a3638bb1c13f48ef8158bfc9d
+ *
+ * test_case = 2
+ * key = "Jefe"
+ * key_len = 4
+ * data = "what do ya want for nothing?"
+ * data_len = 28
+ * digest = 0x750c783e6ab0b503eaa86e310a5db738
+ *
+ * test_case = 3
+ * key = 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ * key_len 16
+ * data = 0xdd repeated 50 times
+ * data_len = 50
+ * digest = 0x56be34521d144c88dbb8c733f0e8b3f6
+ *
+ * test_case = 4
+ * key = 0x0102030405060708090a0b0c0d0e0f10111213141516171819
+ * key_len 25
+ * data = 0xcd repeated 50 times
+ * data_len = 50
+ * digest = 0x697eaf0aca3a3aea3a75164746ffaa79
+ *
+ * test_case = 5
+ * key = 0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c
+ * key_len = 16
+ * data = "Test With Truncation"
+ * data_len = 20
+ * digest = 0x56461ef2342edc00f9bab995690efd4c
+ * digest-96 0x56461ef2342edc00f9bab995
+ *
+ * test_case = 6
+ * key = 0xaa repeated 80 times
+ * key_len = 80
+ * data = "Test Using Larger Than Block-Size Key - Hash Key First"
+ * data_len = 54
+ * digest = 0x6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd
+ *
+ * test_case = 7
+ * key = 0xaa repeated 80 times
+ * key_len = 80
+ * data = "Test Using Larger Than Block-Size Key and Larger
+ * Than One Block-Size Data"
+ * data_len = 73
+ * digest = 0x6f630fad67cda0ee1fb1f562db3aa53e
+ *
+ *
+ *
+ * currently performing test 1, 2, 4 and 7
+ *
+ */
+ chunk_t keys[4];
+ chunk_t data[4];
+ chunk_t digest[4];
+ chunk_t reference[4];
+ int i;
+
+ /*
+ * values for test 1
+ */
+ u_int8_t key1[] = {
+ 0x0b,0x0b,0x0b,0x0b,
+ 0x0b,0x0b,0x0b,0x0b,
+ 0x0b,0x0b,0x0b,0x0b,
+ 0x0b,0x0b,0x0b,0x0b,
+ };
+ keys[0].ptr = key1;
+ keys[0].len = sizeof(key1);
+ data[0].ptr = "Hi There";
+ data[0].len = 8;
+ u_int8_t reference1[] = {
+ 0x92,0x94,0x72,0x7a,
+ 0x36,0x38,0xbb,0x1c,
+ 0x13,0xf4,0x8e,0xf8,
+ 0x15,0x8b,0xfc,0x9d
+ };
+ reference[0].ptr = reference1;
+ reference[0].len = sizeof(reference1);
+
+ /*
+ * values for test 2
+ */
+ u_int8_t reference2[] = {
+ 0x75,0x0c,0x78,0x3e,
+ 0x6a,0xb0,0xb5,0x03,
+ 0xea,0xa8,0x6e,0x31,
+ 0x0a,0x5d,0xb7,0x38
+ };
+ keys[1].ptr = "Jefe";
+ keys[1].len = 4;
+ data[1].ptr = "what do ya want for nothing?";
+ data[1].len = 28;
+ reference[1].ptr = reference2;
+ reference[1].len = sizeof(reference2);
+
+ /*
+ * values for test 7
+ */
+ u_int8_t key7[] = {
+ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
+ };
+ u_int8_t reference7[] = {
+ 0x6f,0x63,0x0f,0xad,
+ 0x67,0xcd,0xa0,0xee,
+ 0x1f,0xb1,0xf5,0x62,
+ 0xdb,0x3a,0xa5,0x3e
+ };
+ keys[2].ptr = key7;
+ keys[2].len = sizeof(key7);
+ data[2].ptr = "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data";
+ data[2].len = 73;
+ reference[2].ptr = reference7;
+ reference[2].len = sizeof(reference7);
+
+
+ for (i=0; i<3; i++)
+ {
+ hmac_t *hmac = hmac_create(HASH_MD5);
+ hmac->set_key(hmac, keys[i]);
+ hmac->allocate_mac(hmac, data[i], &digest[i]);
+ hmac->destroy(hmac);
+ tester->assert_true(tester, digest[i].len == 16, "chunk len");
+ tester->assert_false(tester, memcmp(digest[i].ptr, reference[i].ptr, 16), "hmac value");
+ free(digest[i].ptr);
+ }
+
+ /*
+ * test 4 is donne in append mode
+ */
+ u_int8_t val = 0xcd;
+
+ u_int8_t key4[] = {
+ 0x01,0x02,0x03,0x04,
+ 0x05,0x06,0x07,0x08,
+ 0x09,0x0a,0x0b,0x0c,
+ 0x0d,0x0e,0x0f,0x10,
+ 0x11,0x12,0x13,0x14,
+ 0x15,0x16,0x17,0x18,
+ 0x19
+ };
+ keys[3].ptr = key4;
+ keys[3].len = sizeof(key4);
+ u_int8_t reference4[] = {
+ 0x69,0x7e,0xaf,0x0a,
+ 0xca,0x3a,0x3a,0xea,
+ 0x3a,0x75,0x16,0x47,
+ 0x46,0xff,0xaa,0x79
+ };
+ reference[3].ptr = reference4;
+ reference[3].len = sizeof(reference4);
+
+ hmac_t *hmac = hmac_create(HASH_MD5);
+ hmac->set_key(hmac, keys[3]);
+ data[3].ptr = &val;
+ data[3].len = 1;
+ for (i=0; i<49; i++)
+ {
+ hmac->get_mac(hmac, data[3], NULL);
+ }
+ hmac->allocate_mac(hmac, data[3], &digest[3]);
+ hmac->destroy(hmac);
+
+ tester->assert_true(tester, digest[3].len == 16, "chunk len append mode");
+ tester->assert_false(tester, memcmp(digest[3].ptr, reference[3].ptr, 16), "hmac value append mode");
+ free(digest[3].ptr);
+}
diff --git a/programs/charon/testing/hmac_test.h b/programs/charon/testing/hmac_test.h
new file mode 100644
index 000000000..1eef93cd3
--- /dev/null
+++ b/programs/charon/testing/hmac_test.h
@@ -0,0 +1,49 @@
+/**
+ * @file hmac_test.h
+ *
+ * @brief Tests for the hmac_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef HMAC_TEST_H_
+#define HMAC_TEST_H_
+
+#include <crypto/hmac.h>
+#include <utils/tester.h>
+
+/**
+ * @brief Test function used to test the hmac functionality
+ * using SHA1.
+ *
+ * @param tester associated tester object
+ *
+ * @ingroup testcases
+ */
+void test_hmac_sha1(protected_tester_t *tester);
+
+/**
+ * @brief Test function used to test the hmac functionality
+ * using MD5.
+ *
+ * @param tester associated tester object
+ *
+ * @ingroup testcases
+ */
+void test_hmac_md5(protected_tester_t *tester);
+
+#endif /*HMAC_TEST_H_*/
diff --git a/programs/charon/testing/identification_test.c b/programs/charon/testing/identification_test.c
new file mode 100644
index 000000000..b148b53e0
--- /dev/null
+++ b/programs/charon/testing/identification_test.c
@@ -0,0 +1,166 @@
+/**
+ * @file identification_test.c
+ *
+ * @brief Tests for the identification_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+
+#include "identification_test.h"
+
+#include <utils/identification.h>
+#include <utils/logger.h>
+
+/*
+ * described in Header-File
+ */
+void test_identification(protected_tester_t *tester)
+{
+ identification_t *a, *b, *c, *d;
+ bool result;
+
+ { /* test RFC822_ADDR */
+ char *bob_string = "bob@wonderland.net";
+ chunk_t bob_chunk = {bob_string, strlen(bob_string)};
+
+ a = identification_create_from_string("alice@wonderland.net");
+ b = identification_create_from_encoding(ID_RFC822_ADDR, bob_chunk);
+ c = identification_create_from_string("*@wonderland.net");
+ d = identification_create_from_string("*@badlands.com");
+
+ result = a->belongs_to(a, c);
+ tester->assert_true(tester, result, "alice belongs to wonderland");
+ result = b->belongs_to(b, c);
+ tester->assert_true(tester, result, "bob belongs to wonderland");
+ result = a->belongs_to(a, d);
+ tester->assert_false(tester, result, "alice does not belong to badlands");
+ result = b->belongs_to(b, d);
+ tester->assert_false(tester, result, "bob does not belong to badlands");
+ result = c->belongs_to(c, d);
+ tester->assert_false(tester, result, "wonderland is not in badlands");
+ result = a->belongs_to(a, a);
+ tester->assert_true(tester, result, "alice belongs to alice alice");
+ result = a->equals(a, a);
+ tester->assert_true(tester, result, "alice is alice");
+ result = a->equals(a, b);
+ tester->assert_false(tester, result, "alice is not bob");
+
+ a->destroy(a);
+ b->destroy(b);
+ c->destroy(c);
+ d->destroy(d);
+ }
+
+ { /* test FQDN */
+ char *bob_string = "@dave.nirvana.org";
+ chunk_t bob_chunk = {bob_string, strlen(bob_string)};
+
+ a = identification_create_from_string("@carol.nirvana.org");
+ b = identification_create_from_encoding(ID_FQDN, bob_chunk);
+ c = identification_create_from_string("@*.nirvana.org");
+ d = identification_create_from_string("@*.samsara.com");
+
+ result = a->belongs_to(a, c);
+ tester->assert_true(tester, result, "carol belongs to nirvana");
+ result = b->belongs_to(b, c);
+ tester->assert_true(tester, result, "dave belongs to nirvana");
+ result = a->belongs_to(a, d);
+ tester->assert_false(tester, result, "carol does not belong to samsara");
+ result = b->belongs_to(b, d);
+ tester->assert_false(tester, result, "dave does not belong to samsara");
+ result = c->belongs_to(c, d);
+ tester->assert_false(tester, result, "nirvana is not in samsara");
+ result = a->belongs_to(a, a);
+ tester->assert_true(tester, result, "carol belongs to carol carol");
+ result = a->equals(a, a);
+ tester->assert_true(tester, result, "carol is carol");
+ result = a->equals(a, b);
+ tester->assert_false(tester, result, "carol is not dave");
+
+ a->destroy(a);
+ b->destroy(b);
+ c->destroy(c);
+ d->destroy(d);
+ }
+
+
+ { /* test ID IPV4 ADDR, no wildcards yet */
+ char bob_addr[] = {192,168,0,2};
+ chunk_t bob_chunk = chunk_from_buf(bob_addr);
+
+ a = identification_create_from_string("192.168.0.1");
+ b = identification_create_from_encoding(ID_IPV4_ADDR, bob_chunk);
+ c = identification_create_from_string("192.168.0.2"); /* as bob */
+
+ result = a->equals(a, a);
+ tester->assert_true(tester, result, "IPV4_ADDR of alice equals IPV4_ADDR of alice");
+ result = b->equals(b, c);
+ tester->assert_true(tester, result, "IPV4_ADDR of bob equals IPV4_ADDR of carol");
+ result = a->equals(a, b);
+ tester->assert_false(tester, result, "IPV4_ADDR of alice doesn't equal IPV4_ADDR of bob");
+
+ a->destroy(a);
+ b->destroy(b);
+ c->destroy(c);
+ }
+
+ { /* test ID IPV6 ADDR, no wildcards yet */
+ char bob_addr[] = {0x20,0x01,0x0d,0xb8,0x85,0xa3,0x08,0xd3,0x13,0x19,0x8a,0x2e,0x03,0x70,0x73,0x44};
+ chunk_t bob_chunk = chunk_from_buf(bob_addr);
+
+ a = identification_create_from_string("2001:0db8:85a3:08d3:1319:8a2e:0370:7345");
+ b = identification_create_from_encoding(ID_IPV6_ADDR, bob_chunk);
+ c = identification_create_from_string("2001:0db8:85a3:08d3:1319:8a2e:0370:7344"); /* as bob */
+
+ result = a->equals(a, a);
+ tester->assert_true(tester, result, "IPV6_ADDR of alice equals IPV6_ADDR of alice");
+ result = b->equals(b, c);
+ tester->assert_true(tester, result, "IPV6_ADDR of bob equals IPV6_ADDR of carol");
+ result = a->equals(a, b);
+ tester->assert_false(tester, result, "IPV6_ADDR of alice doesn't equal IPV6_ADDR of bob");
+
+ a->destroy(a);
+ b->destroy(b);
+ c->destroy(c);
+ }
+
+ { /* test ID DER_ASN1_DN */
+ a = identification_create_from_string("C=CH, O=Linux strongSwan, CN=alice");
+ b = identification_create_from_string("O=Linux strongSwan, C=CH, CN=bob");
+ c = identification_create_from_string("C=CH, O=Linux strongSwan, CN=*");
+ d = identification_create_from_string("C=CH, O=Linux openswan, CN=*");
+
+ result = a->equals(a, a);
+ tester->assert_true(tester, result, "DN of alice equals DN of alice");
+ result = a->equals(a, b);
+ tester->assert_false(tester, result, "DN of alice doesn't equal DN of bob");
+ result = a->belongs_to(a, c);
+ tester->assert_true(tester, result, "DN of alice belongs to DN of carol");
+ /* TODO: This does NOT work, wildcard check should work with unordered RDNs */
+ result = b->belongs_to(b, c);
+ tester->assert_true(tester, result, "DN of bob belongs to DN of carol");
+ result = b->belongs_to(b, d);
+ tester->assert_false(tester, result, "DN of bob doesn't belong to DN of dave");
+
+ a->destroy(a);
+ b->destroy(b);
+ c->destroy(c);
+ d->destroy(d);
+ }
+}
diff --git a/programs/charon/testing/identification_test.h b/programs/charon/testing/identification_test.h
new file mode 100644
index 000000000..b1078c52f
--- /dev/null
+++ b/programs/charon/testing/identification_test.h
@@ -0,0 +1,37 @@
+/**
+ * @file identification_test.h
+ *
+ * @brief Tests for the identification_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef IDENTIFICATION_TEST_H_
+#define IDENTIFICATION_TEST_H_
+
+#include <utils/tester.h>
+
+/**
+ * @brief Test function used to test the identification functionality.
+ *
+ * @param tester associated tester object
+ *
+ * @ingroup testcases
+ */
+void test_identification(protected_tester_t *tester);
+
+#endif /* IDENTIFICATION_TEST_H_ */
diff --git a/programs/charon/testing/ike_sa_id_test.c b/programs/charon/testing/ike_sa_id_test.c
new file mode 100644
index 000000000..ba44363fb
--- /dev/null
+++ b/programs/charon/testing/ike_sa_id_test.c
@@ -0,0 +1,84 @@
+/**
+ * @file ike_sa_id_test.c
+ *
+ * @brief Tests for the ike_sa_id_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "ike_sa_id_test.h"
+
+#include <sa/ike_sa_id.h>
+
+/*
+ * described in Header-File
+ */
+void test_ike_sa_id(protected_tester_t *tester)
+{
+ ike_sa_id_t *ike_sa_id, *clone, *equal, *other1, *other2, *other3, *other4;
+ u_int64_t initiator, initiator2, responder, responder2;
+ bool is_initiator;
+
+ initiator = 0;
+
+ initiator2 = 12345612;
+
+ responder = 34334;
+
+ responder2 = 987863;
+
+ is_initiator = TRUE;
+
+ ike_sa_id = ike_sa_id_create(initiator, responder, is_initiator);
+ equal = ike_sa_id_create(initiator, responder, is_initiator);
+ other1 = ike_sa_id_create(initiator, responder2, is_initiator);
+ other2 = ike_sa_id_create(initiator2, responder2, is_initiator);
+ other3 = ike_sa_id_create(initiator2, responder, is_initiator);
+ is_initiator = FALSE;
+ other4 = ike_sa_id_create(initiator, responder, is_initiator);
+
+ /* check equality */
+ tester->assert_true(tester,(ike_sa_id->equals(ike_sa_id,equal) == TRUE), "equal check");
+ tester->assert_true(tester,(equal->equals(equal,ike_sa_id) == TRUE), "equal check");
+
+ /* check clone functionality and equality*/
+ clone = ike_sa_id->clone(ike_sa_id);
+ tester->assert_false(tester,(clone == ike_sa_id), "clone pointer check");
+ tester->assert_true(tester,(ike_sa_id->equals(ike_sa_id,clone) == TRUE), "equal check");
+
+ /* check for non equality */
+ tester->assert_false(tester,(ike_sa_id->equals(ike_sa_id,other1) == TRUE), "equal check");
+
+ tester->assert_false(tester,(ike_sa_id->equals(ike_sa_id,other2) == TRUE), "equal check");
+
+ tester->assert_false(tester,(ike_sa_id->equals(ike_sa_id,other3) == TRUE), "equal check");
+
+ tester->assert_false(tester,(ike_sa_id->equals(ike_sa_id,other4) == TRUE), "equal check");
+
+ other4->replace_values(other4,ike_sa_id);
+ tester->assert_true(tester,(ike_sa_id->equals(ike_sa_id,other4) == TRUE), "equal check");
+
+
+ /* check destroy functionality */
+ ike_sa_id->destroy(ike_sa_id);
+ equal->destroy(equal);
+ clone->destroy(clone);
+ other1->destroy(other1);
+ other2->destroy(other2);
+ other3->destroy(other3);
+ other4->destroy(other4);
+}
diff --git a/programs/charon/testing/ike_sa_id_test.h b/programs/charon/testing/ike_sa_id_test.h
new file mode 100644
index 000000000..75429e4fb
--- /dev/null
+++ b/programs/charon/testing/ike_sa_id_test.h
@@ -0,0 +1,40 @@
+/**
+ * @file ike_sa_id_test.h
+ *
+ * @brief Tests for the ike_sa_id_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef IKE_SA_ID_TEST_H_
+#define IKE_SA_ID_TEST_H_
+
+#include <utils/tester.h>
+
+/**
+ * @brief Test function used to test the ike_sa_id functionality.
+ *
+ * Tests are performed using one thread to test the
+ * features of the ike_sa_id_t.
+ *
+ * @param tester associated tester object
+ *
+ * @ingroup testcases
+ */
+void test_ike_sa_id(protected_tester_t *tester);
+
+#endif /*IKE_SA_ID_TEST_H_*/
diff --git a/programs/charon/testing/ike_sa_manager_test.c b/programs/charon/testing/ike_sa_manager_test.c
new file mode 100644
index 000000000..5247be7f0
--- /dev/null
+++ b/programs/charon/testing/ike_sa_manager_test.c
@@ -0,0 +1,185 @@
+/**
+ * @file ike_sa_manager_test.c
+ *
+ * @brief Tests for the ike_sa_manager_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include "ike_sa_manager_test.h"
+
+#include <types.h>
+#include <sa/ike_sa_manager.h>
+
+
+static struct ike_sa_manager_test_struct_s {
+ protected_tester_t *tester;
+ ike_sa_manager_t *isam;
+} td;
+
+static void test1_thread(ike_sa_id_t *ike_sa_id)
+{
+ ike_sa_t *ike_sa;
+ status_t status;
+
+ status = td.isam->checkout(td.isam, ike_sa_id, &ike_sa);
+ td.tester->assert_true(td.tester, (status == SUCCESS), "checkout of a blocked ike_sa");
+ usleep(10000);
+ status = td.isam->checkin(td.isam, ike_sa);
+ td.tester->assert_true(td.tester, (status == SUCCESS), "checkin of a requested ike_sa");
+}
+
+
+static void test3_thread(ike_sa_id_t *ike_sa_id)
+{
+ ike_sa_t *ike_sa;
+ status_t status;
+
+ status = td.isam->checkout(td.isam, ike_sa_id, &ike_sa);
+ td.tester->assert_true(td.tester, (status == NOT_FOUND), "IKE_SA already deleted");
+}
+
+
+
+
+void test_ike_sa_manager(protected_tester_t *tester)
+{
+ status_t status;
+ u_int64_t initiator, responder;
+ ike_sa_id_t *ike_sa_id, *sa_id;
+ ike_sa_t *ike_sa;
+ int thread_count = 200;
+ int sa_count = 100;
+ int i;
+ pthread_t threads[thread_count];
+
+ td.tester = tester;
+ td.isam = ike_sa_manager_create();
+ tester->assert_true(tester, (td.isam != NULL), "ike_sa_manager creation");
+
+
+
+
+ /* First Test:
+ * we play initiator for IKE_SA_INIT first
+ * create an IKE_SA,
+ *
+ */
+
+ td.isam->create_and_checkout(td.isam, &ike_sa);
+ /* for testing purposes, we manipulate the responder spi.
+ * this is usually done be the response from the communication partner,
+ * but we don't have one...
+ */
+ responder = 123;
+
+ sa_id = ike_sa->get_id(ike_sa);
+ sa_id->set_responder_spi(sa_id, responder);
+
+ ike_sa_id = sa_id->clone(sa_id);
+
+ /* check in, so we should have a "completed" sa, specified by ike_sa_id */
+ status = td.isam->checkin(td.isam, ike_sa);
+ tester->assert_true(tester, (status == SUCCESS), "checkin modified IKE_SA");
+
+ /* now we check it out and start some other threads */
+ status = td.isam->checkout(td.isam, ike_sa_id, &ike_sa);
+ tester->assert_true(tester, (status == SUCCESS), "checkout existing IKE_SA 1");
+
+ for (i = 0; i < thread_count; i++)
+ {
+ if (pthread_create(&threads[i], NULL, (void*(*)(void*))test1_thread, (void*)ike_sa_id))
+ {
+ /* failed, decrease list */
+ thread_count--;
+ i--;
+ }
+ }
+ sleep(1);
+
+
+ status = td.isam->checkin(td.isam, ike_sa);
+ tester->assert_true(tester, (status == SUCCESS), "checkin IKE_SA");
+
+
+ sleep(1);
+ /* we now delete the IKE_SA, while it is requested by the threads.
+ * this should block until the have done their work.*/
+ status = td.isam->delete(td.isam, ike_sa_id);
+ tester->assert_true(tester, (status == SUCCESS), "delete IKE_SA by id");
+
+
+ for (i = 0; i < thread_count; i++)
+ {
+ pthread_join(threads[i], NULL);
+ }
+
+ ike_sa_id->destroy(ike_sa_id);
+
+
+ /* Second Test:
+ * now we simulate our partner initiates an IKE_SA_INIT,
+ * so we are the responder.
+ *
+ */
+ memset(&initiator, 0, sizeof(initiator));
+ memset(&responder, 0, sizeof(responder));
+
+ initiator = 123;
+ ike_sa_id = ike_sa_id_create(initiator, responder, TRUE);
+
+ status = td.isam->checkout(td.isam, ike_sa_id, &ike_sa);
+ tester->assert_false(tester, (status == SUCCESS), "checkout unexisting IKE_SA 2");
+
+ /* let them go acquiring */
+ sleep(1);
+
+
+ ike_sa_id->destroy(ike_sa_id);
+
+ /* Third Test:
+ * put in a lot of IKE_SAs, check it out, set a thread waiting
+ * and destroy the manager...
+ */
+ thread_count = sa_count;
+
+ for (i = 0; i < sa_count; i++)
+ {
+ td.isam->create_and_checkout(td.isam, &ike_sa);
+
+ if (pthread_create(&threads[i], NULL, (void*(*)(void*))test3_thread, (void*)ike_sa->get_id(ike_sa)))
+ {
+ /* failed, decrease list */
+ thread_count--;
+ }
+ }
+
+ /* let them go acquiring */
+ sleep(1);
+
+ td.isam->destroy(td.isam);
+
+ for (i = 0; i < thread_count; i++)
+ {
+ pthread_join(threads[i], NULL);
+ }
+}
+
diff --git a/programs/charon/testing/ike_sa_manager_test.h b/programs/charon/testing/ike_sa_manager_test.h
new file mode 100644
index 000000000..c3e9f99f1
--- /dev/null
+++ b/programs/charon/testing/ike_sa_manager_test.h
@@ -0,0 +1,39 @@
+/**
+ * @file ike_sa_manager_test.h
+ *
+ * @brief Tests for the ike_sa_manager_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef IKE_SA_MANAGER_TEST_H_
+#define IKE_SA_MANAGER_TEST_H_
+
+#include <utils/tester.h>
+
+/**
+ * @brief Test function used to test the ike_sa_manager_t functionality.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_ike_sa_manager(protected_tester_t *tester);
+
+
+
+#endif /*IKE_SA_MANAGER_TEST_H_*/
diff --git a/programs/charon/testing/ike_sa_test.c b/programs/charon/testing/ike_sa_test.c
new file mode 100644
index 000000000..798b5edc9
--- /dev/null
+++ b/programs/charon/testing/ike_sa_test.c
@@ -0,0 +1,56 @@
+/**
+ * @file ike_sa_test.c
+ *
+ * @brief Tests for the ike_sa_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "ike_sa_test.h"
+
+#include <types.h>
+#include <encoding/message.h>
+#include <sa/ike_sa.h>
+
+void test_ike_sa(protected_tester_t *tester)
+{
+ ike_sa_t *ike_sa;
+ ike_sa_id_t *ike_sa_id;
+ u_int64_t initiator, responder;
+ bool is_initiator;
+
+
+ initiator = 0;
+ responder = 34334LL;
+ is_initiator = TRUE;
+ /* create a ike_sa_id object for the new IKE_SA */
+ ike_sa_id = ike_sa_id_create(initiator, responder, is_initiator);
+
+ /* empty message and configuration objects are created */
+
+
+ /* test every ike_sa function */
+ ike_sa = ike_sa_create(ike_sa_id);
+
+/* ike_sa->initialize_connection(ike_sa, NULL);
+
+ tester->assert_true(tester,(ike_sa != NULL), "ike_sa pointer check");
+*/
+ ike_sa->destroy(ike_sa);
+
+ ike_sa_id->destroy(ike_sa_id);
+}
diff --git a/programs/charon/testing/ike_sa_test.h b/programs/charon/testing/ike_sa_test.h
new file mode 100644
index 000000000..e93bc34fd
--- /dev/null
+++ b/programs/charon/testing/ike_sa_test.h
@@ -0,0 +1,37 @@
+/**
+ * @file ike_sa_test.h
+ *
+ * @brief Tests for the ike_sa_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef IKE_SA_TEST_H_
+#define IKE_SA_TEST_H_
+
+#include <utils/tester.h>
+
+/**
+ * @brief Test function used to test the ike_sa_t functionality.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_ike_sa(protected_tester_t *tester);
+
+#endif /*IKE_SA_TEST_H_*/
diff --git a/programs/charon/testing/job_queue_test.c b/programs/charon/testing/job_queue_test.c
new file mode 100644
index 000000000..336a9a188
--- /dev/null
+++ b/programs/charon/testing/job_queue_test.c
@@ -0,0 +1,132 @@
+/**
+ * @file job_queue_test.c
+ *
+ * @brief Tests for the job_queue_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#include <stdlib.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include "job_queue_test.h"
+
+#include <queues/job_queue.h>
+#include <queues/jobs/initiate_ike_sa_job.h>
+
+
+typedef struct job_queue_test_s job_queue_test_t;
+
+/**
+ * @brief Informations for the involved test-thread used in this test
+ *
+ */
+struct job_queue_test_s{
+ protected_tester_t *tester;
+ job_queue_t *job_queue;
+ /**
+ * number of items to be inserted in the job-queue
+ */
+ int insert_item_count;
+ /**
+ * number of items to be removed by each
+ * receiver thread from the job-queue
+ */
+ int remove_item_count;
+};
+
+/**
+ * @brief sender thread used in the the job_queue test function
+ *
+ * @param testinfo informations for the specific thread.
+ */
+static void test_job_queue_sender(job_queue_test_t * testinfo)
+{
+ int i;
+ for (i = 0; i < testinfo->insert_item_count; i++)
+ {
+ job_t *job = (job_t *) initiate_ike_sa_job_create(NULL);
+ testinfo->job_queue->add(testinfo->job_queue,job);
+ }
+}
+
+/**
+ * @brief receiver thread used in the the job_queue test function
+ *
+ * @param testinfo informations for the specific thread.
+ */
+static void test_job_queue_receiver(job_queue_test_t * testinfo)
+{
+ int i;
+ for (i = 0; i < testinfo->remove_item_count; i++)
+ {
+ job_t *job;
+ job = testinfo->job_queue->get(testinfo->job_queue);
+ testinfo->tester->assert_true(testinfo->tester,(job->get_type(job) == INITIATE_IKE_SA), "job type check");
+ job->destroy(job);
+ }
+}
+
+/*
+ * description is in header file
+ */
+void test_job_queue(protected_tester_t *tester)
+{
+ int desired_value, i;
+ int sender_count = 10;
+ int receiver_count = 2;
+ pthread_t sender_threads[sender_count];
+ pthread_t receiver_threads[receiver_count];
+ job_queue_t *job_queue = job_queue_create();
+ job_queue_test_t test_infos;
+
+ test_infos.tester = tester;
+ test_infos.job_queue = job_queue;
+ test_infos.insert_item_count = 10000;
+ test_infos.remove_item_count = 50000;
+
+
+ desired_value = test_infos.insert_item_count * sender_count -
+ test_infos.remove_item_count * receiver_count;
+
+ for (i = 0; i < receiver_count;i++)
+ {
+ pthread_create( &receiver_threads[i], NULL,(void*(*)(void*)) &test_job_queue_receiver, (void*) &test_infos);
+ }
+ for (i = 0; i < sender_count;i++)
+ {
+ pthread_create( &sender_threads[i], NULL,(void*(*)(void*)) &test_job_queue_sender, (void*) &test_infos);
+ }
+
+
+ /* Wait for all threads */
+ for (i = 0; i < sender_count;i++)
+ {
+ pthread_join(sender_threads[i], NULL);
+ }
+ for (i = 0; i < receiver_count;i++)
+ {
+ pthread_join(receiver_threads[i], NULL);
+ }
+
+ /* the job-queue has to have disered_value count entries! */
+ tester->assert_true(tester,(job_queue->get_count(job_queue) == desired_value), "get count value check");
+
+ job_queue->destroy(job_queue);
+}
diff --git a/programs/charon/testing/job_queue_test.h b/programs/charon/testing/job_queue_test.h
new file mode 100644
index 000000000..f2d3edc4c
--- /dev/null
+++ b/programs/charon/testing/job_queue_test.h
@@ -0,0 +1,40 @@
+/**
+ * @file job_queue_test.h
+ *
+ * @brief Tests for the job_queue_test_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef JOB_QUEUE_TEST_H_
+#define JOB_QUEUE_TEST_H_
+
+#include <utils/tester.h>
+
+/**
+ * @brief Test function used to test the job_queue functionality.
+ *
+ * Tests are performed using different threads to test the multi-threaded
+ * features of the job_queue_t.
+ *
+ * @param tester associated tester object
+ *
+ * @ingroup testcases
+ */
+void test_job_queue(protected_tester_t *tester);
+
+#endif /*JOB_QUEUE_TEST_H_*/
diff --git a/programs/charon/testing/kernel_interface_test.c b/programs/charon/testing/kernel_interface_test.c
new file mode 100644
index 000000000..86553e15e
--- /dev/null
+++ b/programs/charon/testing/kernel_interface_test.c
@@ -0,0 +1,84 @@
+/**
+ * @file kernel_interface_test.h
+ *
+ * @brief Tests for the kernel_interface_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#include "kernel_interface_test.h"
+
+#include <daemon.h>
+#include <threads/kernel_interface.h>
+#include <utils/logger.h>
+#include <utils/host.h>
+
+
+/*
+ * described in Header-File
+ */
+void test_kernel_interface(protected_tester_t *tester)
+{
+ kernel_interface_t *kernel_interface;
+ u_int32_t spi;
+ host_t *me, *other, *left, *right;
+ status_t status;
+
+ u_int8_t enc_key_bytes[] = {
+ 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,
+ 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08
+ };
+
+ u_int8_t inc_key_bytes[] = {
+ 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,
+ 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08
+ };
+
+ chunk_t enc_key,inc_key;
+ enc_key.ptr = enc_key_bytes;
+ enc_key.len = sizeof(enc_key_bytes);
+ inc_key.ptr = inc_key_bytes;
+ inc_key.len = sizeof(inc_key_bytes);
+
+
+
+ kernel_interface = kernel_interface_create();
+
+ me = host_create(AF_INET, "192.168.0.2", 0);
+ other = host_create(AF_INET, "192.168.0.3", 0);
+
+ status = kernel_interface->get_spi(kernel_interface, me, other, 50, 1234, &spi);
+ tester->assert_true(tester, status == SUCCESS, "spi get");
+
+ status = kernel_interface->add_sa(kernel_interface, me, other, spi, 50, 1234, ENCR_AES_CBC, enc_key,AUTH_UNDEFINED,inc_key,TRUE);
+ tester->assert_true(tester, status == SUCCESS, "add sa");
+
+ left = host_create(AF_INET, "10.1.0.0", 0);
+ right = host_create(AF_INET, "10.2.0.0", 0);
+
+ status = kernel_interface->add_policy(kernel_interface, me, other, left, right, 16, 16, XFRM_POLICY_OUT, 0, TRUE, FALSE, 1234);
+ tester->assert_true(tester, status == SUCCESS, "add policy");
+
+ me->destroy(me);
+ other->destroy(other);
+ left->destroy(left);
+ right->destroy(right);
+
+ kernel_interface->destroy(kernel_interface);
+
+}
diff --git a/programs/charon/testing/kernel_interface_test.h b/programs/charon/testing/kernel_interface_test.h
new file mode 100644
index 000000000..fc8dab4b6
--- /dev/null
+++ b/programs/charon/testing/kernel_interface_test.h
@@ -0,0 +1,38 @@
+/**
+ * @file kernel_interface_test.h
+ *
+ * @brief Tests for the kernel_interface_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef KERNEL_INTERFACE_TEST_H_
+#define KERNEL_INTERFACE_TEST_H_
+
+#include <utils/tester.h>
+
+/**
+ * @brief Test function used to test the kernel_interface functionality.
+ *
+ * @param tester associated tester object
+ *
+ * @ingroup testcases
+ */
+void test_kernel_interface(protected_tester_t *tester);
+
+
+#endif /*KERNEL_INTERFACE_TEST_H_*/
diff --git a/programs/charon/testing/leak_detective_test.c b/programs/charon/testing/leak_detective_test.c
new file mode 100644
index 000000000..8d71d9f0f
--- /dev/null
+++ b/programs/charon/testing/leak_detective_test.c
@@ -0,0 +1,79 @@
+/**
+ * @file leak_detective_test.h
+ *
+ * @brief Tests for the leak_detective_test.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "leak_detective_test.h"
+
+
+void *mem_a, *mem_b, *mem_c;
+
+void a()
+{
+ mem_a = malloc(4);
+}
+
+void b()
+{
+ a();
+ mem_b = malloc(5);
+}
+
+void c()
+{
+ b();
+ mem_c = malloc(6);
+}
+
+void recursive(int depth)
+{
+ void *tiny = malloc(1);
+ if (--depth > 0)
+ {
+ recursive(depth);
+ }
+ free(tiny);
+}
+
+
+/*
+ * described in Header-File
+ */
+void test_leak_detective(protected_tester_t *tester)
+{
+ void *m1, *m2, *m3;
+
+
+ m1 = malloc(1);
+ m2 = calloc(1, 2);
+ m3 = malloc(3);
+
+ m3 = realloc(m3, 4);
+
+ free(m2);
+ free(m3);
+ free(m1);
+
+ c();
+ free(mem_a);
+ free(mem_c);
+ free(mem_b);
+ recursive(10000);
+}
diff --git a/programs/charon/testing/leak_detective_test.h b/programs/charon/testing/leak_detective_test.h
new file mode 100644
index 000000000..e64266bd5
--- /dev/null
+++ b/programs/charon/testing/leak_detective_test.h
@@ -0,0 +1,38 @@
+/**
+ * @file leak_detective_test.h
+ *
+ * @brief Tests for the leak_detective_public_key_t and leak_detective_private_key classes.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef LEAK_DETEICTVE_TEST_H
+#define LEAK_DETEICTVE_TEST_H
+
+#include <utils/tester.h>
+
+/**
+ * @brief Test function used to test the leak_detective functionality.
+ *
+ * @param tester associated tester object
+ *
+ * @ingroup testcases
+ */
+void test_leak_detective(protected_tester_t *tester);
+
+
+#endif /*LEAK_DETEICTVE_TEST_H*/
diff --git a/programs/charon/testing/linked_list_test.c b/programs/charon/testing/linked_list_test.c
new file mode 100644
index 000000000..3d5666f64
--- /dev/null
+++ b/programs/charon/testing/linked_list_test.c
@@ -0,0 +1,241 @@
+/**
+ * @file linked_list_test.c
+ *
+ * @brief Tests for the linked_list_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+
+#include "linked_list_test.h"
+
+#include <utils/linked_list.h>
+
+ /*
+ * Description in header-file
+ */
+void test_linked_list(protected_tester_t *tester)
+{
+ void *test_value = NULL;
+
+ linked_list_t *linked_list = linked_list_create();
+
+ tester->assert_true(tester,(linked_list->get_count(linked_list) == 0), "count check");
+
+ linked_list->insert_first(linked_list,"one");
+ tester->assert_true(tester,(linked_list->get_count(linked_list) == 1), "count check");
+
+ linked_list->insert_first(linked_list,"two");
+ tester->assert_true(tester,(linked_list->get_count(linked_list) == 2), "count check");
+
+ linked_list->insert_first(linked_list,"three");
+ tester->assert_true(tester,(linked_list->get_count(linked_list) == 3), "count check");
+
+ linked_list->insert_first(linked_list,"four");
+ tester->assert_true(tester,(linked_list->get_count(linked_list) == 4), "count check");
+
+ linked_list->insert_first(linked_list,"five");
+ tester->assert_true(tester,(linked_list->get_count(linked_list) == 5), "count check");
+
+ tester->assert_true(tester,(linked_list->get_first(linked_list,&test_value) == SUCCESS), "get_first call check");
+ tester->assert_true(tester,(strcmp((char *) test_value,"five") == 0), "get_first value check");
+ tester->assert_true(tester,(linked_list->get_count(linked_list) == 5), "count check");
+
+ tester->assert_true(tester,(linked_list->get_last(linked_list,&test_value) == SUCCESS), "get_last call check");
+ tester->assert_true(tester,(strcmp((char *) test_value,"one") == 0), "get_last value check");
+ tester->assert_true(tester,( linked_list->get_count(linked_list) == 5), "count check");
+
+ tester->assert_true(tester,(linked_list->remove_first(linked_list,&test_value) == SUCCESS), "remove_first call check");
+ tester->assert_true(tester,(strcmp((char *) test_value,"five") == 0), "remove_first value check");
+ tester->assert_true(tester,(linked_list->get_count(linked_list) == 4), "count check");
+
+ tester->assert_true(tester,(linked_list->get_first(linked_list,&test_value) == SUCCESS), "get_first call check");
+ tester->assert_true(tester,(strcmp((char *) test_value,"four") == 0), "get_first value check");
+ tester->assert_true(tester,(linked_list->get_count(linked_list) == 4), "count check");
+
+ tester->assert_true(tester,(linked_list->get_last(linked_list,&test_value) == SUCCESS), "get_last call check");
+ tester->assert_true(tester,(strcmp((char *) test_value,"one") == 0), "get_last value check");
+ tester->assert_true(tester,(linked_list->get_count(linked_list) == 4), "count check");
+
+ tester->assert_true(tester,(linked_list->get_at_position(linked_list,0,&test_value) == SUCCESS), "get_at_position call check");
+ tester->assert_true(tester,(strcmp((char *) test_value,"four") == 0), "get_at_position value check");
+
+ tester->assert_true(tester,(linked_list->get_at_position(linked_list,1,&test_value) == SUCCESS), "get_at_position call check");
+ tester->assert_true(tester,(strcmp((char *) test_value,"three") == 0), "get_at_position value check");
+
+ tester->assert_true(tester,(linked_list->get_at_position(linked_list,2,&test_value) == SUCCESS), "get_at_position call check");
+ tester->assert_true(tester,(strcmp((char *) test_value,"two") == 0), "get_at_position value check");
+
+ tester->assert_true(tester,(linked_list->get_at_position(linked_list,3,&test_value) == SUCCESS), "get_at_position call check");
+ tester->assert_true(tester,(strcmp((char *) test_value,"one") == 0), "get_at_position value check");
+
+ tester->assert_false(tester,(linked_list->get_at_position(linked_list,4,&test_value) == SUCCESS), "get_at_position call check");
+ tester->assert_false(tester,(linked_list->remove_at_position(linked_list,4,&test_value) == SUCCESS), "remove_at_position call check");
+ tester->assert_false(tester,(linked_list->insert_at_position(linked_list,5,test_value) == SUCCESS), "insert_at_position call 1 check");
+
+ tester->assert_true(tester,(linked_list->insert_at_position(linked_list,3,"six") == SUCCESS), "insert_at_position call 2 check");
+ tester->assert_true(tester,(linked_list->insert_at_position(linked_list,3,"seven") == SUCCESS), "insert_at_position call 3 check");
+
+ tester->assert_true(tester,(linked_list->get_at_position(linked_list,3,&test_value) == SUCCESS), "get_at_position call check");
+ tester->assert_true(tester,(strcmp((char *) test_value,"seven") == 0), "get_at_position value 1 check");
+
+ tester->assert_true(tester,(linked_list->get_at_position(linked_list,4,&test_value) == SUCCESS), "get_at_position call check");
+ tester->assert_true(tester,(strcmp((char *) test_value,"six") == 0), "get_at_position value 2 check");
+
+ tester->assert_true(tester,(linked_list->get_at_position(linked_list,5,&test_value) == SUCCESS), "get_at_position call check");
+ tester->assert_true(tester,(strcmp((char *) test_value,"one") == 0), "get_at_position value 3 check");
+
+ tester->assert_true(tester,(linked_list->remove_at_position(linked_list,3,&test_value) == SUCCESS), "remove_at_position call check");
+ tester->assert_true(tester,(linked_list->remove_at_position(linked_list,3,&test_value) == SUCCESS), "remove_at_position call check");
+
+
+ tester->assert_true(tester,(linked_list->remove_last(linked_list,&test_value) == SUCCESS), "remove_last call check");
+ tester->assert_true(tester,(strcmp((char *) test_value,"one") == 0), "remove_last value check");
+ tester->assert_true(tester,(linked_list->get_count(linked_list) == 3), "count check");
+
+ tester->assert_true(tester,(linked_list->get_last(linked_list,&test_value) == SUCCESS), "get_last call check");
+ tester->assert_true(tester,(strcmp((char *) test_value,"two") == 0), "get_last value check");
+ tester->assert_true(tester,(linked_list->get_count(linked_list) == 3), "count check");
+
+ tester->assert_true(tester,(linked_list->get_first(linked_list,&test_value) == SUCCESS), "get_first call check");
+ tester->assert_true(tester,(strcmp((char *) test_value,"four") == 0), "get_first value check");
+ tester->assert_true(tester,(linked_list->get_count(linked_list) == 3), "count check");
+
+ linked_list->destroy(linked_list);
+}
+
+ /*
+ * Description in header-file
+ */
+void test_linked_list_iterator(protected_tester_t *tester)
+{
+ void * value;
+
+ linked_list_t *linked_list = linked_list_create();
+ linked_list->insert_first(linked_list,"one");
+ linked_list->insert_first(linked_list,"two");
+ linked_list->insert_first(linked_list,"three");
+ linked_list->insert_first(linked_list,"four");
+ linked_list->insert_first(linked_list,"five");
+
+ iterator_t * iterator;
+ iterator_t * iterator2;
+
+
+ iterator = linked_list->create_iterator(linked_list,TRUE);
+
+ tester->assert_true(tester,iterator->has_next(iterator), "it 1 has_next value check");
+ iterator->current(iterator,&value);
+ tester->assert_true(tester,(strcmp((char *) value,"five") == 0), "it 1 current value check");
+
+ tester->assert_true(tester,iterator->has_next(iterator), "it 1 has_next value check");
+ iterator->current(iterator,&value);
+ tester->assert_true(tester,(strcmp((char *) value,"four") == 0), "it 1 current value check");
+
+ iterator2 = linked_list->create_iterator(linked_list,FALSE);
+
+ tester->assert_true(tester,iterator2->has_next(iterator2), "it 2 has_next value check");
+ iterator2->current(iterator2,&value);
+ tester->assert_true(tester,(strcmp((char *) value,"one") == 0), "it 2 current value check");
+
+ tester->assert_true(tester,iterator->has_next(iterator), "it 1 has_next value check");
+ iterator->current(iterator,&value);
+ tester->assert_true(tester,(strcmp((char *) value,"three") == 0), "it 1 current value check");
+
+ tester->assert_true(tester,iterator2->has_next(iterator2), "it 2 has_next value check");
+ iterator2->current(iterator2,&value);
+ tester->assert_true(tester,(strcmp((char *) value,"two") == 0), "it 2 current value check");
+
+ tester->assert_true(tester,iterator->has_next(iterator), "it 1 has_next value check");
+ iterator->current(iterator,&value);
+ tester->assert_true(tester,(strcmp((char *) value,"two") == 0), "it 1 current value check");
+
+ tester->assert_true(tester,iterator2->has_next(iterator2), "it 2 has_next value check");
+ iterator2->current(iterator2,&value);
+ tester->assert_true(tester,(strcmp((char *) value,"three") == 0), "it 2 current value check");
+
+ tester->assert_true(tester,iterator->has_next(iterator), "it 1 has_next value check");
+ iterator->current(iterator,&value);
+ tester->assert_true(tester,(strcmp((char *) value,"one") == 0), "it 1 current value check");
+
+ tester->assert_false(tester,iterator->has_next(iterator), "it 1 has_next value check");
+
+ tester->assert_true(tester,iterator2->has_next(iterator2), "it 2 has_next value check");
+ tester->assert_true(tester,iterator2->has_next(iterator2), "it 2 has_next value check");
+ tester->assert_false(tester,iterator2->has_next(iterator2), "it 2 has_next value check");
+
+ iterator->destroy(iterator);
+ iterator2->destroy(iterator2);
+ linked_list->destroy(linked_list);
+}
+
+ /*
+ * Description in header-file
+ */
+void test_linked_list_insert_and_remove(protected_tester_t *tester)
+{
+ void *value;
+ iterator_t * iterator;
+
+ linked_list_t *linked_list = linked_list_create();
+ linked_list->insert_first(linked_list,"one");
+ linked_list->insert_first(linked_list,"two");
+
+ linked_list->insert_first(linked_list,"three");
+ linked_list->insert_first(linked_list,"four");
+ linked_list->insert_first(linked_list,"five");
+
+
+
+ iterator = linked_list->create_iterator(linked_list,TRUE);
+
+ iterator->has_next(iterator);
+ iterator->has_next(iterator);
+ iterator->has_next(iterator);
+ iterator->current(iterator,&value);
+ tester->assert_true(tester,(strcmp((char *) value,"three") == 0), "current value check");
+
+ iterator->insert_before(iterator,"before_three");
+ iterator->current(iterator,&value);
+ tester->assert_true(tester,(strcmp((char *) value,"three") == 0), "current value check");
+
+
+ iterator->insert_after(iterator,"after_three");
+ iterator->current(iterator,&value);
+ tester->assert_true(tester,(strcmp((char *) value,"three") == 0), "current value check");
+
+
+ tester->assert_true(tester,(iterator->remove(iterator) == SUCCESS), "remove call check");
+ iterator->current(iterator,&value);
+ tester->assert_true(tester,(strcmp((char *) value,"before_three") == 0), "current value check");
+
+ iterator->reset(iterator);
+
+ iterator->has_next(iterator);
+ iterator->has_next(iterator);
+ iterator->has_next(iterator);
+ iterator->current(iterator,&value);
+ tester->assert_true(tester,(strcmp((char *) value,"before_three") == 0), "current value check");
+ iterator->has_next(iterator);
+ iterator->current(iterator,&value);
+ tester->assert_true(tester,(strcmp((char *) value,"after_three") == 0), "current value check");
+
+ iterator->destroy(iterator);
+
+ linked_list->destroy(linked_list);
+}
diff --git a/programs/charon/testing/linked_list_test.h b/programs/charon/testing/linked_list_test.h
new file mode 100644
index 000000000..a9773f8f0
--- /dev/null
+++ b/programs/charon/testing/linked_list_test.h
@@ -0,0 +1,74 @@
+/**
+ * @file linked_list_test.h
+ *
+ * @brief Tests for the linked_list_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef LINKED_LIST_TEST_H_
+#define LINKED_LIST_TEST_H_
+
+#include <utils/tester.h>
+
+/**
+ * @brief Test function for the type linked_list_t.
+ *
+ * Performs different kinds of assertions to check the functionality
+ * of the linked_list_t in a Single-Threaded environment.
+ *
+ * @warning To be usable in multi-threaded software
+ * this list has to get protected with locks.
+ *
+ * @param tester tester object
+ *
+ * @ingroup testcases
+ */
+void test_linked_list(protected_tester_t *tester);
+
+/**
+ * @brief Test function for the type linked_list_t and its iterator.
+ *
+ * Performs different kinds of assertions to check the functionality
+ * of the linked_list_t and its iterator in a Single-Threaded environment.
+ *
+ * @warning To be usable in multi-threaded software
+ * this list has to get protected with locks.
+ *
+ * @param tester tester object
+ *
+ * @ingroup testcases
+ */
+void test_linked_list_iterator(protected_tester_t *tester);
+
+/**
+ * @brief Test function for the type linked_list_t and its insert and remove
+ * functions.
+ *
+ * Performs different kinds of assertions to check the functionality
+ * of the linked_list_t and its insert and remove functions
+ *
+ * @warning To be usable in multi-threaded software
+ * this list has to get protected with locks.
+ *
+ * @param tester tester object
+ *
+ * @ingroup testcases
+ */
+void test_linked_list_insert_and_remove(protected_tester_t *tester);
+
+#endif /*LINKED_LIST_TEST_H_*/
diff --git a/programs/charon/testing/packet_test.c b/programs/charon/testing/packet_test.c
new file mode 100644
index 000000000..fdb195ec1
--- /dev/null
+++ b/programs/charon/testing/packet_test.c
@@ -0,0 +1,55 @@
+/**
+ * @file packet_test.c
+ *
+ * @brief Tests for the packet_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+
+#include "packet_test.h"
+
+#include <daemon.h>
+#include <network/packet.h>
+#include <utils/logger_manager.h>
+
+
+/*
+ * Described in Header
+ */
+void test_packet(protected_tester_t *tester)
+{
+ packet_t *packet = packet_create();
+ packet_t *packet2;
+ chunk_t data;
+ char *string_to_copy = "aha, soso";
+
+ data.len = strlen(string_to_copy) + 1;
+ data.ptr = malloc(data.len);
+ memcpy(data.ptr, string_to_copy, data.len);
+
+ packet->set_data(packet, data);
+ packet2 = packet->clone(packet);
+ data = packet2->get_data(packet2);
+
+ tester->assert_true(tester,(data.len == (strlen(string_to_copy) + 1)),"value length check");
+ tester->assert_true(tester,(memcmp(data.ptr,string_to_copy,data.len) == 0),"cloned value check");
+
+ packet2->destroy(packet2);
+ packet->destroy(packet);
+}
diff --git a/programs/charon/testing/packet_test.h b/programs/charon/testing/packet_test.h
new file mode 100644
index 000000000..8bc297e1b
--- /dev/null
+++ b/programs/charon/testing/packet_test.h
@@ -0,0 +1,37 @@
+/**
+ * @file packet_test.h
+ *
+ * @brief Tests for the packet_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef PACKET_TEST_H_
+#define PACKET_TEST_H_
+
+#include <utils/tester.h>
+
+/**
+ * @brief Test function used to test the packet_t functionality.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_packet(protected_tester_t *tester);
+
+#endif /*PACKET_TEST_H_*/
diff --git a/programs/charon/testing/parser_test.c b/programs/charon/testing/parser_test.c
new file mode 100644
index 000000000..263c6eb70
--- /dev/null
+++ b/programs/charon/testing/parser_test.c
@@ -0,0 +1,963 @@
+/**
+ * @file parser_test.c
+ *
+ * @brief Tests for the parser_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+
+#include "parser_test.h"
+
+#include <utils/logger_manager.h>
+#include <encoding/generator.h>
+#include <encoding/parser.h>
+#include <encoding/payloads/encodings.h>
+#include <encoding/payloads/ike_header.h>
+#include <encoding/payloads/sa_payload.h>
+#include <encoding/payloads/nonce_payload.h>
+#include <encoding/payloads/id_payload.h>
+#include <encoding/payloads/ke_payload.h>
+#include <encoding/payloads/notify_payload.h>
+#include <encoding/payloads/auth_payload.h>
+#include <encoding/payloads/cert_payload.h>
+#include <encoding/payloads/certreq_payload.h>
+#include <encoding/payloads/ts_payload.h>
+#include <encoding/payloads/delete_payload.h>
+#include <encoding/payloads/vendor_id_payload.h>
+#include <encoding/payloads/cp_payload.h>
+#include <encoding/payloads/eap_payload.h>
+
+
+/*
+ * Described in Header
+ */
+void test_parser_with_header_payload(protected_tester_t *tester)
+{
+ parser_t *parser;
+ ike_header_t *ike_header;
+ status_t status;
+ chunk_t header_chunk;
+
+ u_int8_t header_bytes[] = {
+ 0x01,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,
+ 0x02,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,
+ 0x03,0x45,0x06,0x28,
+ 0x00,0x00,0x00,0x07,
+ 0x00,0x00,0x00,0x1C,
+ };
+ header_chunk.ptr = header_bytes;
+ header_chunk.len = sizeof(header_bytes);
+
+
+ parser = parser_create(header_chunk);
+ tester->assert_true(tester,(parser != NULL), "parser create check");
+ status = parser->parse_payload(parser, HEADER, (payload_t**)&ike_header);
+ tester->assert_true(tester,(status == SUCCESS),"parse_payload call check");
+ parser->destroy(parser);
+
+ if (status != SUCCESS)
+ {
+ return;
+ }
+
+ tester->assert_true(tester,(ike_header->get_initiator_spi(ike_header) == 1),"parsed initiator_spi value");
+ tester->assert_true(tester,(ike_header->get_responder_spi(ike_header) == 2),"parsed responder_spi value");
+ tester->assert_true(tester,(ike_header->payload_interface.get_next_type((payload_t*)ike_header) == 3),"parsed next_payload value");
+ tester->assert_true(tester,(ike_header->get_maj_version(ike_header) == 4),"parsed maj_version value");
+ tester->assert_true(tester,(ike_header->get_min_version(ike_header) == 5),"parsed min_version value");
+ tester->assert_true(tester,(ike_header->get_exchange_type(ike_header) == 6),"parsed exchange_type value");
+ tester->assert_true(tester,(ike_header->get_initiator_flag(ike_header) == TRUE),"parsed flags.initiator value");
+ tester->assert_true(tester,(ike_header->get_version_flag(ike_header) == FALSE),"parsed flags.version value");
+ tester->assert_true(tester,(ike_header->get_response_flag(ike_header) == TRUE),"parsed flags.response value");
+ tester->assert_true(tester,(ike_header->get_message_id(ike_header) == 7),"parsed message_id value");
+ tester->assert_true(tester,(ike_header->payload_interface.get_length((payload_t*)ike_header) == 0x1C),"parsed length value");
+
+ ike_header->destroy(ike_header);
+}
+
+/*
+ * Described in Header
+ */
+void test_parser_with_sa_payload(protected_tester_t *tester)
+{
+ parser_t *parser;
+ sa_payload_t *sa_payload;
+ status_t status;
+ chunk_t sa_chunk, sa_chunk2, sa_chunk3;
+ iterator_t *proposals, *transforms, *attributes;
+
+ /* first test generic parsing functionality */
+
+ u_int8_t sa_bytes[] = {
+ 0x00,0x80,0x00,0x24, /* payload header*/
+ 0x00,0x00,0x00,0x20, /* a proposal */
+ 0x01,0x02,0x04,0x05,
+ 0x01,0x02,0x03,0x04, /* spi */
+ 0x00,0x00,0x00,0x14, /* transform */
+ 0x07,0x00,0x00,0x03,
+ 0x80,0x01,0x00,0x05, /* attribute without length */
+ 0x00,0x03,0x00,0x04, /* attribute with length */
+ 0x01,0x02,0x03,0x04
+
+
+ };
+
+ sa_chunk.ptr = sa_bytes;
+ sa_chunk.len = sizeof(sa_bytes);
+
+
+ parser = parser_create(sa_chunk);
+ tester->assert_true(tester,(parser != NULL), "parser create check");
+ status = parser->parse_payload(parser, SECURITY_ASSOCIATION, (payload_t**)&sa_payload);
+ tester->assert_true(tester,(status == SUCCESS),"parse_payload call check");
+ parser->destroy(parser);
+
+ if (status != SUCCESS)
+ {
+ return;
+ }
+
+
+ proposals = sa_payload->create_proposal_substructure_iterator(sa_payload, TRUE);
+ while (proposals->has_next(proposals))
+ {
+ proposal_substructure_t *proposal;
+ proposals->current(proposals, (void**)&proposal);
+ chunk_t spi;
+ u_int8_t spi_should[] = {0x01, 0x02, 0x03, 0x04};
+
+ tester->assert_true(tester,(proposal->get_proposal_number(proposal) == 1),"proposal number");
+ tester->assert_true(tester,(proposal->get_protocol_id(proposal) == 2),"proposal id");
+ spi = proposal->get_spi(proposal);
+ tester->assert_false(tester,(memcmp(&spi_should, spi.ptr, spi.len)),"proposal spi");
+
+ transforms = proposal->create_transform_substructure_iterator(proposal, TRUE);
+ while(transforms->has_next(transforms))
+ {
+ transform_substructure_t *transform;
+ int loopi;
+ transforms->current(transforms, (void**)&transform);
+ tester->assert_true(tester,(transform->get_transform_type(transform) == 7),"transform type");
+ tester->assert_true(tester,(transform->get_transform_id(transform) == 3),"transform id");
+ attributes = transform->create_transform_attribute_iterator(transform, TRUE);
+ loopi = 0;
+ while (attributes->has_next(attributes))
+ {
+ transform_attribute_t *attribute;
+ attributes->current(attributes, (void**)&attribute);
+ if (loopi == 0)
+ {
+ u_int8_t value[] = {0x05, 0x00};
+ chunk_t attribute_value;
+ tester->assert_true(tester,(attribute->get_attribute_type(attribute) == 1),"attribute 1 type");
+ attribute_value = attribute->get_value_chunk(attribute);
+ tester->assert_false(tester,(memcmp(&value, attribute_value.ptr, attribute_value.len)),"attribute 1 value");
+ }
+ if (loopi == 1)
+ {
+ u_int8_t value[] = {0x01, 0x02, 0x03, 0x04};
+ chunk_t attribute_value;
+ tester->assert_true(tester,(attribute->get_attribute_type(attribute) == 3),"attribute 2 type");
+ attribute_value = attribute->get_value_chunk(attribute);
+ tester->assert_false(tester,(memcmp(&value, attribute_value.ptr, attribute_value.len)),"attribute 2 value");
+ }
+ loopi++;
+ }
+ attributes->destroy(attributes);
+ }
+ transforms->destroy(transforms);
+ }
+ proposals->destroy(proposals);
+
+ sa_payload->destroy(sa_payload);
+
+
+
+ /* now test SA functionality after parsing an SA payload*/
+
+ u_int8_t sa_bytes2[] = {
+ 0x00,0x00,0x00,0x6C, /* payload header*/
+ 0x02,0x00,0x00,0x34, /* a proposal */
+ 0x01,0x01,0x00,0x04,
+ 0x03,0x00,0x00,0x0C, /* transform 1 */
+ 0x01,0x00,0x00,0x01,
+ 0x80,0x0E,0x00,0x14, /* keylength attribute with 20 bytes length */
+ 0x03,0x00,0x00,0x0C, /* transform 2 */
+ 0x02,0x00,0x00,0x01,
+ 0x80,0x0E,0x00,0x14, /* keylength attribute with 20 bytes length */
+ 0x03,0x00,0x00,0x0C, /* transform 3 */
+ 0x03,0x00,0x00,0x01,
+ 0x80,0x0E,0x00,0x14, /* keylength attribute with 20 bytes length */
+ 0x00,0x00,0x00,0x08, /* transform 4 */
+ 0x04,0x00,0x00,0x01,
+ 0x00,0x00,0x00,0x34, /* a proposal */
+ 0x01,0x01,0x00,0x04,
+ 0x03,0x00,0x00,0x0C, /* transform 1 */
+ 0x01,0x00,0x00,0x02,
+ 0x80,0x0E,0x00,0x10, /* keylength attribute with 16 bytes length */
+ 0x03,0x00,0x00,0x0C, /* transform 2 */
+ 0x02,0x00,0x00,0x02,
+ 0x80,0x0E,0x00,0x10, /* keylength attribute with 16 bytes length */
+ 0x03,0x00,0x00,0x0C, /* transform 3 */
+ 0x03,0x00,0x00,0x02,
+ 0x80,0x0E,0x00,0x10, /* keylength attribute with 16 bytes length */
+ 0x00,0x00,0x00,0x08, /* transform 4 */
+ 0x04,0x00,0x00,0x02,
+ };
+
+ sa_chunk2.ptr = sa_bytes2;
+ sa_chunk2.len = sizeof(sa_bytes2);
+
+ parser = parser_create(sa_chunk2);
+ tester->assert_true(tester,(parser != NULL), "parser create check");
+ status = parser->parse_payload(parser, SECURITY_ASSOCIATION, (payload_t**)&sa_payload);
+ tester->assert_true(tester,(status == SUCCESS),"parse_payload call check");
+ parser->destroy(parser);
+
+ if (status != SUCCESS)
+ {
+ return;
+ }
+
+ status = sa_payload->payload_interface.verify(&(sa_payload->payload_interface));
+ tester->assert_true(tester,(status == SUCCESS),"verify call check");
+ /*
+ status = sa_payload->get_ike_proposals (sa_payload, &ike_proposals, &ike_proposal_count);
+ tester->assert_true(tester,(status == SUCCESS),"get ike proposals call check");
+
+ tester->assert_true(tester,(ike_proposal_count == 2),"ike proposal count check");
+ tester->assert_true(tester,(ike_proposals[0].encryption_algorithm == 1),"ike proposal content check");
+ tester->assert_true(tester,(ike_proposals[0].encryption_algorithm_key_length == 20),"ike proposal content check");
+ tester->assert_true(tester,(ike_proposals[0].integrity_algorithm == 1),"ike proposal content check");
+ tester->assert_true(tester,(ike_proposals[0].integrity_algorithm_key_length == 20),"ike proposal content check");
+ tester->assert_true(tester,(ike_proposals[0].pseudo_random_function == 1),"ike proposal content check");
+ tester->assert_true(tester,(ike_proposals[0].pseudo_random_function_key_length == 20),"ike proposal content check");
+ tester->assert_true(tester,(ike_proposals[0].diffie_hellman_group == 1),"ike proposal content check");
+
+ tester->assert_true(tester,(ike_proposals[1].encryption_algorithm == 2),"ike proposal content check");
+ tester->assert_true(tester,(ike_proposals[1].encryption_algorithm_key_length == 16),"ike proposal content check");
+ tester->assert_true(tester,(ike_proposals[1].integrity_algorithm == 2),"ike proposal content check");
+ tester->assert_true(tester,(ike_proposals[1].integrity_algorithm_key_length == 16),"ike proposal content check");
+ tester->assert_true(tester,(ike_proposals[1].pseudo_random_function == 2),"ike proposal content check");
+ tester->assert_true(tester,(ike_proposals[1].pseudo_random_function_key_length == 16),"ike proposal content check");
+ tester->assert_true(tester,(ike_proposals[1].diffie_hellman_group == 2),"ike proposal content check");
+
+
+ if (status == SUCCESS)
+ {
+ free(ike_proposals);
+ }
+ */
+ sa_payload->destroy(sa_payload);
+
+ /* now test SA functionality after parsing an SA payload with child sa proposals*/
+ u_int8_t sa_bytes3[] = {
+ 0x00,0x00,0x00,0xA0, /* payload header*/
+
+ /* suite 1 */
+ 0x02,0x00,0x00,0x28, /* a proposal */
+ 0x01,0x02,0x04,0x03,
+ 0x01,0x01,0x01,0x01,
+ 0x03,0x00,0x00,0x0C, /* transform 1 */
+ 0x03,0x00,0x00,0x01,
+ 0x80,0x0E,0x00,0x14, /* keylength attribute with 20 bytes length */
+
+ 0x03,0x00,0x00,0x08, /* transform 2 */
+ 0x04,0x00,0x00,0x0E,
+
+ 0x00,0x00,0x00,0x08, /* transform 3 */
+ 0x05,0x00,0x00,0x01,
+
+
+ 0x02,0x00,0x00,0x20, /* a proposal */
+ 0x01,0x03,0x04,0x02,
+ 0x02,0x02,0x02,0x02,
+
+ 0x03,0x00,0x00,0x0C, /* transform 1 */
+ 0x01,0x00,0x00,0x0C,
+ 0x80,0x0E,0x00,0x20, /* keylength attribute with 32 bytes length */
+
+ 0x00,0x00,0x00,0x08, /* transform 2 */
+ 0x04,0x00,0x00,0x02,
+
+ /* suite 2 */
+ 0x02,0x00,0x00,0x28, /* a proposal */
+ 0x02,0x02,0x04,0x03,
+ 0x01,0x01,0x01,0x01,
+ 0x03,0x00,0x00,0x0C, /* transform 1 */
+ 0x03,0x00,0x00,0x01,
+ 0x80,0x0E,0x00,0x14, /* keylength attribute with 20 bytes length */
+
+ 0x03,0x00,0x00,0x08, /* transform 2 */
+ 0x04,0x00,0x00,0x0E,
+
+ 0x00,0x00,0x00,0x08, /* transform 3 */
+ 0x05,0x00,0x00,0x01,
+
+
+ 0x00,0x00,0x00,0x2C, /* a proposal */
+ 0x02,0x03,0x04,0x03,
+ 0x02,0x02,0x02,0x02,
+
+ 0x03,0x00,0x00,0x0C, /* transform 1 */
+ 0x01,0x00,0x00,0x0C,
+ 0x80,0x0E,0x00,0x20, /* keylength attribute with 32 bytes length */
+
+ 0x03,0x00,0x00,0x0C, /* transform 2 */
+ 0x03,0x00,0x00,0x01,
+ 0x80,0x0E,0x00,0x14, /* keylength attribute with 20 bytes length */
+
+ 0x00,0x00,0x00,0x08, /* transform 3 */
+ 0x04,0x00,0x00,0x02,
+ };
+
+ sa_chunk3.ptr = sa_bytes3;
+ sa_chunk3.len = sizeof(sa_bytes3);
+
+ parser = parser_create(sa_chunk3);
+ tester->assert_true(tester,(parser != NULL), "parser create check");
+ status = parser->parse_payload(parser, SECURITY_ASSOCIATION, (payload_t**)&sa_payload);
+ tester->assert_true(tester,(status == SUCCESS),"parse_payload call check");
+ parser->destroy(parser);
+
+ if (status != SUCCESS)
+ {
+ return;
+ }
+
+ status = sa_payload->payload_interface.verify(&(sa_payload->payload_interface));
+ tester->assert_true(tester,(status == SUCCESS),"verify call check");
+/*
+ status = sa_payload->get_ike_proposals (sa_payload, &ike_proposals, &ike_proposal_count);
+ tester->assert_false(tester,(status == SUCCESS),"get ike proposals call check");
+
+ status = sa_payload->get_proposals (sa_payload, &proposals, &proposal_count);
+ tester->assert_true(tester,(status == SUCCESS),"get child proposals call check");
+
+
+ tester->assert_true(tester,(proposal_count == 2),"child proposal count check");
+ tester->assert_true(tester,(proposals[0].ah.is_set == TRUE),"is ah set check");
+ tester->assert_true(tester,(proposals[0].ah.integrity_algorithm == AUTH_HMAC_MD5_96),"integrity_algorithm check");
+ tester->assert_true(tester,(proposals[0].ah.integrity_algorithm_key_size == 20),"integrity_algorithm_key_size check");
+ tester->assert_true(tester,(proposals[0].ah.diffie_hellman_group == MODP_2048_BIT),"diffie_hellman_group check");
+ tester->assert_true(tester,(proposals[0].ah.extended_sequence_numbers == EXT_SEQ_NUMBERS),"extended_sequence_numbers check");
+ tester->assert_true(tester,(proposals[0].ah.spi[0] == 1),"spi check");
+ tester->assert_true(tester,(proposals[0].ah.spi[1] == 1),"spi check");
+ tester->assert_true(tester,(proposals[0].ah.spi[2] == 1),"spi check");
+ tester->assert_true(tester,(proposals[0].ah.spi[3] == 1),"spi check");
+
+ tester->assert_true(tester,(proposals[0].esp.is_set == TRUE),"is ah set check");
+ tester->assert_true(tester,(proposals[0].esp.encryption_algorithm == ENCR_AES_CBC),"integrity_algorithm check");
+ tester->assert_true(tester,(proposals[0].esp.encryption_algorithm_key_size == 32),"integrity_algorithm_key_size check");
+ tester->assert_true(tester,(proposals[0].esp.diffie_hellman_group == MODP_1024_BIT),"diffie_hellman_group check");
+ tester->assert_true(tester,(proposals[0].esp.integrity_algorithm == AUTH_UNDEFINED),"integrity_algorithm check");
+ tester->assert_true(tester,(proposals[0].esp.spi[0] == 2),"spi check");
+ tester->assert_true(tester,(proposals[0].esp.spi[1] == 2),"spi check");
+ tester->assert_true(tester,(proposals[0].esp.spi[2] == 2),"spi check");
+ tester->assert_true(tester,(proposals[0].esp.spi[3] == 2),"spi check");
+
+ tester->assert_true(tester,(proposals[1].ah.is_set == TRUE),"is ah set check");
+ tester->assert_true(tester,(proposals[1].ah.integrity_algorithm == AUTH_HMAC_MD5_96),"integrity_algorithm check");
+ tester->assert_true(tester,(proposals[1].ah.integrity_algorithm_key_size == 20),"integrity_algorithm_key_size check");
+ tester->assert_true(tester,(proposals[1].ah.diffie_hellman_group == MODP_2048_BIT),"diffie_hellman_group check");
+ tester->assert_true(tester,(proposals[1].ah.extended_sequence_numbers == EXT_SEQ_NUMBERS),"extended_sequence_numbers check");
+ tester->assert_true(tester,(proposals[1].ah.spi[0] == 1),"spi check");
+ tester->assert_true(tester,(proposals[1].ah.spi[1] == 1),"spi check");
+ tester->assert_true(tester,(proposals[1].ah.spi[2] == 1),"spi check");
+ tester->assert_true(tester,(proposals[1].ah.spi[3] == 1),"spi check");
+
+ tester->assert_true(tester,(proposals[1].esp.is_set == TRUE),"is ah set check");
+ tester->assert_true(tester,(proposals[1].esp.encryption_algorithm == ENCR_AES_CBC),"integrity_algorithm check");
+ tester->assert_true(tester,(proposals[1].esp.encryption_algorithm_key_size == 32),"integrity_algorithm_key_size check");
+ tester->assert_true(tester,(proposals[1].esp.diffie_hellman_group == MODP_1024_BIT),"diffie_hellman_group check");
+ tester->assert_true(tester,(proposals[1].esp.integrity_algorithm == AUTH_HMAC_MD5_96),"integrity_algorithm check");
+ tester->assert_true(tester,(proposals[1].esp.integrity_algorithm_key_size == 20),"integrity_algorithm check");
+ tester->assert_true(tester,(proposals[1].esp.spi[0] == 2),"spi check");
+ tester->assert_true(tester,(proposals[1].esp.spi[1] == 2),"spi check");
+ tester->assert_true(tester,(proposals[1].esp.spi[2] == 2),"spi check");
+ tester->assert_true(tester,(proposals[1].esp.spi[3] == 2),"spi check");
+
+ if (status == SUCCESS)
+ {
+ free(proposals);
+ }
+ */
+
+ sa_payload->destroy(sa_payload);
+}
+
+/*
+ * Described in Header
+ */
+void test_parser_with_nonce_payload(protected_tester_t *tester)
+{
+ parser_t *parser;
+ nonce_payload_t *nonce_payload;
+ status_t status;
+ chunk_t nonce_chunk, result;
+
+ u_int8_t nonce_bytes[] = {
+ 0x00,0x00,0x00,0x14, /* payload header */
+ 0x00,0x01,0x02,0x03, /* 16 Byte nonce */
+ 0x04,0x05,0x06,0x07,
+ 0x08,0x09,0x0A,0x2B,
+ 0x0C,0x0D,0x0E,0x0F
+ };
+
+ nonce_chunk.ptr = nonce_bytes;
+ nonce_chunk.len = sizeof(nonce_bytes);
+
+ parser = parser_create(nonce_chunk);
+ tester->assert_true(tester,(parser != NULL), "parser create check");
+ status = parser->parse_payload(parser, NONCE, (payload_t**)&nonce_payload);
+ tester->assert_true(tester,(status == SUCCESS),"parse_payload call check");
+ parser->destroy(parser);
+
+ if (status != SUCCESS)
+ {
+ return;
+ }
+ result = nonce_payload->get_nonce(nonce_payload);
+ tester->assert_true(tester,(result.len == 16), "parsed nonce lenght");
+ tester->assert_false(tester,(memcmp(nonce_bytes + 4, result.ptr, result.len)), "parsed nonce data");
+ nonce_payload->destroy(nonce_payload);
+ chunk_free(&result);
+}
+
+/*
+ * Described in Header
+ */
+void test_parser_with_id_payload(protected_tester_t *tester)
+{
+ parser_t *parser;
+ id_payload_t *id_payload;
+ status_t status;
+ chunk_t id_chunk, result;
+
+ u_int8_t id_bytes[] = {
+ 0x00,0x00,0x00,0x14, /* payload header */
+ 0x05,0x01,0x02,0x03,
+ 0x04,0x05,0x06,0x07,/* 12 Byte nonce */
+ 0x08,0x09,0x0A,0x2B,
+ 0x0C,0x0D,0x0E,0x0F
+ };
+
+ id_chunk.ptr = id_bytes;
+ id_chunk.len = sizeof(id_bytes);
+
+ parser = parser_create(id_chunk);
+ tester->assert_true(tester,(parser != NULL), "parser create check");
+ status = parser->parse_payload(parser, ID_INITIATOR, (payload_t**)&id_payload);
+ tester->assert_true(tester,(status == SUCCESS),"parse_payload call check");
+ parser->destroy(parser);
+
+ if (status != SUCCESS)
+ {
+ return;
+ }
+ result = id_payload->get_data_clone(id_payload);
+ tester->assert_true(tester,(id_payload->get_initiator(id_payload) == TRUE), "is IDi payload");
+ tester->assert_true(tester,(id_payload->get_id_type(id_payload) == ID_IPV6_ADDR), "is ID_IPV6_ADDR ID type");
+ tester->assert_true(tester,(result.len == 12), "parsed data lenght");
+ tester->assert_false(tester,(memcmp(id_bytes + 8, result.ptr, result.len)), "parsed nonce data");
+ id_payload->destroy(id_payload);
+ chunk_free(&result);
+}
+
+
+/*
+ * Described in Header
+ */
+void test_parser_with_ke_payload(protected_tester_t *tester)
+{
+ parser_t *parser;
+ ke_payload_t *ke_payload;
+ status_t status;
+ chunk_t ke_chunk, result;
+
+ u_int8_t ke_bytes[] = {
+ 0x00,0x00,0x00,0x18, /* payload header */
+ 0x00,0x03,0x00,0x00, /* dh group 3 */
+ 0x01,0x02,0x03,0x03, /* 16 Byte dh data */
+ 0x04,0x05,0x06,0x07,
+ 0x08,0x09,0x0A,0x2B,
+ 0x0C,0x0D,0x0E,0x0F
+ };
+
+ ke_chunk.ptr = ke_bytes;
+ ke_chunk.len = sizeof(ke_bytes);
+
+ parser = parser_create(ke_chunk);
+ tester->assert_true(tester,(parser != NULL), "parser create check");
+ status = parser->parse_payload(parser, KEY_EXCHANGE, (payload_t**)&ke_payload);
+ tester->assert_true(tester,(status == SUCCESS),"parse_payload call check");
+ parser->destroy(parser);
+
+ if (status != SUCCESS)
+ {
+ return;
+ }
+ tester->assert_true(tester,(ke_payload->get_dh_group_number(ke_payload) == 3), "DH group");
+ result = ke_payload->get_key_exchange_data(ke_payload);
+ tester->assert_true(tester,(result.len == 16), "parsed key lenght");
+ tester->assert_false(tester,(memcmp(ke_bytes + 8, result.ptr, result.len)), "parsed key data");
+ ke_payload->destroy(ke_payload);
+}
+
+
+/*
+ * Described in Header
+ */
+void test_parser_with_notify_payload(protected_tester_t *tester)
+{
+ parser_t *parser;
+ notify_payload_t *notify_payload;
+ status_t status;
+ chunk_t notify_chunk, result;
+
+ u_int8_t notify_bytes[] = {
+ 0x00,0x00,0x00,0x1C, /* payload header */
+ 0x03,0x04,0x00,0x01,
+ 0x01,0x02,0x03,0x03, /* spi */
+ 0x04,0x05,0x06,0x07, /* noti dati */
+ 0x08,0x09,0x0A,0x2B,
+ 0x0C,0x0D,0x0E,0x0F,
+ 0x0C,0x0D,0x0E,0x0F
+ };
+
+ notify_chunk.ptr = notify_bytes;
+ notify_chunk.len = sizeof(notify_bytes);
+
+ parser = parser_create(notify_chunk);
+ tester->assert_true(tester,(parser != NULL), "parser create check");
+ status = parser->parse_payload(parser, NOTIFY, (payload_t**)&notify_payload);
+ tester->assert_true(tester,(status == SUCCESS),"parse_payload call check");
+ parser->destroy(parser);
+
+ if (status != SUCCESS)
+ {
+ return;
+ }
+ tester->assert_true(tester,(notify_payload->get_protocol_id(notify_payload) == 3), "Protocol id");
+ tester->assert_true(tester,(notify_payload->get_notify_message_type(notify_payload) == 1), "notify message type");
+
+ result = notify_payload->get_spi(notify_payload);
+ tester->assert_false(tester,(memcmp(notify_bytes + 8, result.ptr, result.len)), "parsed spi");
+
+ result = notify_payload->get_notification_data(notify_payload);
+ tester->assert_false(tester,(memcmp(notify_bytes + 12, result.ptr, result.len)), "parsed notification data");
+
+ notify_payload->destroy(notify_payload);
+}
+
+/*
+ * Described in Header
+ */
+void test_parser_with_auth_payload(protected_tester_t *tester)
+{
+ parser_t *parser;
+ auth_payload_t *auth_payload;
+ status_t status;
+ chunk_t auth_chunk, result;
+
+ u_int8_t auth_bytes[] = {
+ 0x00,0x00,0x00,0x14, /* payload header */
+ 0x03,0x01,0x02,0x03,
+ 0x04,0x05,0x06,0x07,/* 12 Byte nonce */
+ 0x08,0x09,0x0A,0x2B,
+ 0x0C,0x0D,0x0E,0x0F
+ };
+
+ auth_chunk.ptr = auth_bytes;
+ auth_chunk.len = sizeof(auth_bytes);
+
+ parser = parser_create(auth_chunk);
+ tester->assert_true(tester,(parser != NULL), "parser create check");
+ status = parser->parse_payload(parser, AUTHENTICATION, (payload_t**)&auth_payload);
+ tester->assert_true(tester,(status == SUCCESS),"parse_payload call check");
+ parser->destroy(parser);
+
+ if (status != SUCCESS)
+ {
+ return;
+ }
+ result = auth_payload->get_data_clone(auth_payload);
+ tester->assert_true(tester,(auth_payload->get_auth_method(auth_payload) == DSS_DIGITAL_SIGNATURE), "is DSS_DIGITAL_SIGNATURE method");
+ tester->assert_true(tester,(result.len == 12), "parsed data lenght");
+ tester->assert_false(tester,(memcmp(auth_bytes + 8, result.ptr, result.len)), "parsed nonce data");
+ auth_payload->destroy(auth_payload);
+ chunk_free(&result);
+}
+
+/*
+ * Described in Header
+ */
+void test_parser_with_ts_payload(protected_tester_t *tester)
+{
+ parser_t *parser;
+ ts_payload_t *ts_payload;
+ status_t status;
+ chunk_t ts_chunk;
+ traffic_selector_substructure_t *ts1, *ts2;
+ host_t *start_host1, *start_host2, *end_host1, *end_host2;
+ iterator_t *iterator;
+
+ u_int8_t ts_bytes[] = {
+ /* payload header */
+ 0x00,0x00,0x00,0x28,
+ 0x02,0x00,0x00,0x00,
+
+ /* traffic selector 1 */
+ 0x07,0x00,0x00,0x10,
+ 0x01,0xF4,0x01,0xF4,
+ 0xC0,0xA8,0x01,0x00,
+ 0xC0,0xA8,0x01,0xFF,
+
+ /* traffic selector 2 */
+ 0x07,0x03,0x00,0x10,
+ 0x00,0x00,0xFF,0xFF,
+ 0x00,0x00,0x00,0x00,
+ 0xFF,0xFF,0xFF,0xFF,
+ };
+
+ ts_chunk.ptr = ts_bytes;
+ ts_chunk.len = sizeof(ts_bytes);
+
+ parser = parser_create(ts_chunk);
+ tester->assert_true(tester,(parser != NULL), "parser create check");
+ status = parser->parse_payload(parser, TRAFFIC_SELECTOR_RESPONDER, (payload_t**)&ts_payload);
+ tester->assert_true(tester,(status == SUCCESS),"parse_payload call check");
+ parser->destroy(parser);
+
+ if (status != SUCCESS)
+ {
+ return;
+ }
+
+ iterator = ts_payload->create_traffic_selector_substructure_iterator(ts_payload,TRUE);
+
+ tester->assert_true(tester,(iterator->has_next(iterator)), "has next check");
+
+ /* check first ts */
+ iterator->current(iterator,(void **)&ts1);
+ tester->assert_true(tester,(ts1->get_protocol_id(ts1) == 0), "ip protocol id check");
+ start_host1 = ts1->get_start_host(ts1);
+ end_host1 = ts1->get_end_host(ts1);
+ tester->assert_true(tester,(start_host1->get_port(start_host1) == 500), "start port check");
+ tester->assert_true(tester,(end_host1->get_port(end_host1) == 500), "start port check");
+ tester->assert_true(tester,(memcmp(start_host1->get_address(start_host1),"192.168.1.0",strlen("192.168.1.0")) == 0), "start address check");
+ tester->assert_true(tester,(memcmp(end_host1->get_address(end_host1),"192.168.1.255",strlen("192.168.1.255")) == 0), "end address check");
+
+ start_host1->destroy(start_host1);
+ end_host1->destroy(end_host1);
+
+ tester->assert_true(tester,(iterator->has_next(iterator)), "has next check");
+
+ /* check second ts */
+
+ iterator->current(iterator,(void **)&ts2);
+
+ tester->assert_true(tester,(ts2->get_protocol_id(ts2) == 3), "ip protocol id check");
+ start_host2 = ts2->get_start_host(ts2);
+ end_host2 = ts2->get_end_host(ts2);
+ tester->assert_true(tester,(start_host2->get_port(start_host2) == 0), "start port check");
+ tester->assert_true(tester,(end_host2->get_port(end_host2) == 65535), "start port check");
+ tester->assert_true(tester,(memcmp(start_host2->get_address(start_host2),"0.0.0.0",strlen("0.0.0.0")) == 0), "start address check");
+ tester->assert_true(tester,(memcmp(end_host2->get_address(end_host2),"255.255.255.255",strlen("255.255.255.255")) == 0), "end address check");
+ start_host2->destroy(start_host2);
+ end_host2->destroy(end_host2);
+
+
+
+ tester->assert_false(tester,(iterator->has_next(iterator)), "has next check");
+
+ iterator->destroy(iterator);
+
+ ts_payload->destroy(ts_payload);
+}
+
+/*
+ * Described in Header
+ */
+void test_parser_with_cert_payload(protected_tester_t *tester)
+{
+ parser_t *parser;
+ cert_payload_t *cert_payload;
+ status_t status;
+ chunk_t cert_chunk, result;
+
+ u_int8_t cert_bytes[] = {
+ 0x00,0x00,0x00,0x11, /* payload header */
+ 0x03,
+ 0x04,0x05,0x06,0x07,/* 12 Byte nonce */
+ 0x08,0x09,0x0A,0x2B,
+ 0x0C,0x0D,0x0E,0x0F
+ };
+
+ cert_chunk.ptr = cert_bytes;
+ cert_chunk.len = sizeof(cert_bytes);
+
+ parser = parser_create(cert_chunk);
+ tester->assert_true(tester,(parser != NULL), "parser create check");
+ status = parser->parse_payload(parser, CERTIFICATE, (payload_t**)&cert_payload);
+ tester->assert_true(tester,(status == SUCCESS),"parse_payload call check");
+ parser->destroy(parser);
+
+ if (status != SUCCESS)
+ {
+ return;
+ }
+ result = cert_payload->get_data_clone(cert_payload);
+ tester->assert_true(tester,(cert_payload->get_cert_encoding(cert_payload) == DNS_SIGNED_KEY), "is DNS_SIGNED_KEY encoding");
+ tester->assert_true(tester,(result.len == 12), "parsed data lenght");
+ tester->assert_false(tester,(memcmp(cert_bytes + 5, result.ptr, result.len)), "parsed data");
+ cert_payload->destroy(cert_payload);
+ chunk_free(&result);
+}
+
+/*
+ * Described in Header
+ */
+void test_parser_with_certreq_payload(protected_tester_t *tester)
+{
+ parser_t *parser;
+ certreq_payload_t *certreq_payload;
+ status_t status;
+ chunk_t certreq_chunk, result;
+
+ u_int8_t certreq_bytes[] = {
+ 0x00,0x00,0x00,0x11, /* payload header */
+ 0x03,
+ 0x04,0x05,0x06,0x07,/* 12 Byte data */
+ 0x08,0x09,0x0A,0x2B,
+ 0x0C,0x0D,0x0E,0x0F
+ };
+
+ certreq_chunk.ptr = certreq_bytes;
+ certreq_chunk.len = sizeof(certreq_bytes);
+
+ parser = parser_create(certreq_chunk);
+ tester->assert_true(tester,(parser != NULL), "parser create check");
+ status = parser->parse_payload(parser, CERTIFICATE_REQUEST, (payload_t**)&certreq_payload);
+ tester->assert_true(tester,(status == SUCCESS),"parse_payload call check");
+ parser->destroy(parser);
+
+ if (status != SUCCESS)
+ {
+ return;
+ }
+ result = certreq_payload->get_data_clone(certreq_payload);
+ tester->assert_true(tester,(certreq_payload->get_cert_encoding(certreq_payload) == DNS_SIGNED_KEY), "is DNS_SIGNED_KEY encoding");
+ tester->assert_true(tester,(result.len == 12), "parsed data lenght");
+ tester->assert_false(tester,(memcmp(certreq_bytes + 5, result.ptr, result.len)), "parsed data");
+ certreq_payload->destroy(certreq_payload);
+ chunk_free(&result);
+}
+
+/*
+ * Described in Header
+ */
+void test_parser_with_delete_payload(protected_tester_t *tester)
+{
+ parser_t *parser;
+ delete_payload_t *delete_payload;
+ status_t status;
+ chunk_t delete_chunk, result;
+
+ u_int8_t delete_bytes[] = {
+ 0x00,0x00,0x00,0x14, /* payload header */
+ 0x03,0x03,0x00,0x04,
+ 0x04,0x05,0x06,0x07,/* 12 Byte data */
+ 0x08,0x09,0x0A,0x2B,
+ 0x0C,0x0D,0x0E,0x0F
+ };
+
+ delete_chunk.ptr = delete_bytes;
+ delete_chunk.len = sizeof(delete_bytes);
+
+ parser = parser_create(delete_chunk);
+ tester->assert_true(tester,(parser != NULL), "parser create check");
+ status = parser->parse_payload(parser, DELETE, (payload_t**)&delete_payload);
+ tester->assert_true(tester,(status == SUCCESS),"parse_payload call check");
+ parser->destroy(parser);
+
+ if (status != SUCCESS)
+ {
+ return;
+ }
+ result = delete_payload->get_spis(delete_payload);
+ tester->assert_true(tester,(delete_payload->get_protocol_id(delete_payload) == PROTO_ESP), "is ESP protocol");
+ tester->assert_true(tester,(delete_payload->get_spi_size(delete_payload) == 3), "SPI size check");
+ tester->assert_true(tester,(delete_payload->get_spi_count(delete_payload) == 4), "SPI count check");
+ tester->assert_true(tester,(result.len == 12), "parsed data lenght");
+ tester->assert_false(tester,(memcmp(delete_bytes + 8, result.ptr, result.len)), "parsed data");
+ tester->assert_true(tester,(((payload_t *)delete_payload)->verify((payload_t *)delete_payload) == SUCCESS), "verify check");
+
+ delete_payload->destroy(delete_payload);
+}
+
+
+/*
+ * Described in Header
+ */
+void test_parser_with_vendor_id_payload(protected_tester_t *tester)
+{
+ parser_t *parser;
+ vendor_id_payload_t *vendor_id_payload;
+ status_t status;
+ chunk_t vendor_id_chunk, result;
+
+ u_int8_t vendor_id_bytes[] = {
+ 0x00,0x00,0x00,0x10, /* payload header */
+ 0x04,0x05,0x06,0x07,/* 12 Byte data */
+ 0x08,0x09,0x0A,0x2B,
+ 0x0C,0x0D,0x0E,0x0F
+ };
+
+ vendor_id_chunk.ptr = vendor_id_bytes;
+ vendor_id_chunk.len = sizeof(vendor_id_bytes);
+
+ parser = parser_create(vendor_id_chunk);
+ tester->assert_true(tester,(parser != NULL), "parser create check");
+ status = parser->parse_payload(parser, VENDOR_ID, (payload_t**)&vendor_id_payload);
+ tester->assert_true(tester,(status == SUCCESS),"parse_payload call check");
+ parser->destroy(parser);
+
+ if (status != SUCCESS)
+ {
+ return;
+ }
+ result = vendor_id_payload->get_data(vendor_id_payload);
+ tester->assert_true(tester,(result.len == 12), "parsed data lenght");
+ tester->assert_false(tester,(memcmp(vendor_id_bytes + 4, result.ptr, result.len)), "parsed data");
+ tester->assert_true(tester,(((payload_t *)vendor_id_payload)->verify((payload_t *)vendor_id_payload) == SUCCESS), "verify check");
+
+ vendor_id_payload->destroy(vendor_id_payload);
+}
+
+/*
+ * Described in Header
+ */
+void test_parser_with_cp_payload(protected_tester_t *tester)
+{
+ parser_t *parser;
+ cp_payload_t *cp_payload;
+ configuration_attribute_t *attribute;
+ status_t status;
+ chunk_t cp_chunk;
+ iterator_t *iterator;
+
+ /* first test generic parsing functionality */
+
+ u_int8_t cp_bytes[] = {
+ /* cp payload header */
+ 0x00,0x00,0x00,0x18,
+ 0x05,0x00,0x00,0x00,
+ /* configuration attribute 1*/
+ 0x00,0x03,0x00,0x04,
+ 0x61,0x62,0x63,0x64,
+ /* configuration attribute 2*/
+ 0x00,0x04,0x00,0x04,
+ 0x65,0x66,0x67,0x68,
+ };
+
+ cp_chunk.ptr = cp_bytes;
+ cp_chunk.len = sizeof(cp_bytes);
+
+
+ parser = parser_create(cp_chunk);
+ tester->assert_true(tester,(parser != NULL), "parser create check");
+ status = parser->parse_payload(parser, CONFIGURATION, (payload_t**)&cp_payload);
+ tester->assert_true(tester,(status == SUCCESS),"parse_payload call check");
+
+ iterator = cp_payload->create_configuration_attribute_iterator(cp_payload,TRUE);
+
+ tester->assert_true(tester,(iterator->has_next(iterator)),"has_next call check");
+
+ iterator->current(iterator,(void **)&attribute);
+
+
+ tester->assert_true(tester,(attribute->get_attribute_type(attribute) == 3),"get type check");
+ tester->assert_true(tester,(attribute->get_attribute_length(attribute) == 4),"get type check");
+
+ tester->assert_true(tester,(iterator->has_next(iterator)),"has_next call check");
+
+ iterator->current(iterator,(void **)&attribute);
+
+
+ tester->assert_true(tester,(attribute->get_attribute_type(attribute) == 4),"get type check");
+ tester->assert_true(tester,(attribute->get_attribute_length(attribute) == 4),"get type check");
+
+ iterator->current(iterator,(void **)&attribute);
+
+ tester->assert_false(tester,(iterator->has_next(iterator)),"has_next call check");
+
+
+ iterator->destroy(iterator);
+
+ if (status != SUCCESS)
+ {
+ return;
+ }
+
+ cp_payload->destroy(cp_payload);
+ parser->destroy(parser);
+
+}
+
+/*
+ * Described in Header
+ */
+void test_parser_with_eap_payload(protected_tester_t *tester)
+{
+ parser_t *parser;
+ eap_payload_t *eap_payload;
+ status_t status;
+ chunk_t eap_chunk, result;
+
+ u_int8_t eap_bytes[] = {
+ 0x00,0x00,0x00,0x10, /* payload header */
+ 0x04,0x05,0x06,0x07,/* 12 Byte data */
+ 0x08,0x09,0x0A,0x2B,
+ 0x0C,0x0D,0x0E,0x0F
+ };
+
+ eap_chunk.ptr = eap_bytes;
+ eap_chunk.len = sizeof(eap_bytes);
+
+ parser = parser_create(eap_chunk);
+ tester->assert_true(tester,(parser != NULL), "parser create check");
+ status = parser->parse_payload(parser, VENDOR_ID, (payload_t**)&eap_payload);
+ tester->assert_true(tester,(status == SUCCESS),"parse_payload call check");
+ parser->destroy(parser);
+
+ if (status != SUCCESS)
+ {
+ return;
+ }
+ result = eap_payload->get_message(eap_payload);
+ tester->assert_true(tester,(result.len == 12), "parsed data lenght");
+ tester->assert_false(tester,(memcmp(eap_bytes + 4, result.ptr, result.len)), "parsed data");
+ tester->assert_true(tester,(((payload_t *)eap_payload)->verify((payload_t *)eap_payload) == SUCCESS), "verify check");
+
+ eap_payload->destroy(eap_payload);
+}
+
diff --git a/programs/charon/testing/parser_test.h b/programs/charon/testing/parser_test.h
new file mode 100644
index 000000000..4956df13e
--- /dev/null
+++ b/programs/charon/testing/parser_test.h
@@ -0,0 +1,170 @@
+/**
+ * @file parser_test.h
+ *
+ * @brief Tests for the parser_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef PARSER_TEST_H_
+#define PARSER_TEST_H_
+
+#include <utils/tester.h>
+
+/**
+ * @brief Test function used to test the parser_t functionality when
+ * parsing a header payload.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_parser_with_header_payload(protected_tester_t *tester);
+
+/**
+ * @brief Test function used to test the parser_t functionality when
+ * parsing a sa payload.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_parser_with_sa_payload(protected_tester_t *tester);
+
+/**
+ * @brief Test function used to test the parser_t functionality when
+ * parsing a nonce payload.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_parser_with_nonce_payload(protected_tester_t *tester);
+
+/**
+ * @brief Test function used to test the parser_t functionality when
+ * parsing a ID payload.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_parser_with_id_payload(protected_tester_t *tester);
+
+/**
+ * @brief Test function used to test the parser_t functionality when
+ * parsing a ke payload.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_parser_with_ke_payload(protected_tester_t *tester);
+
+/**
+ * @brief Test function used to test the parser_t functionality when
+ * parsing a notify payload.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_parser_with_notify_payload(protected_tester_t *tester);
+
+/**
+ * @brief Test function used to test the parser_t functionality when
+ * parsing a AUTH payload.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_parser_with_auth_payload(protected_tester_t *tester);
+
+/**
+ * @brief Test function used to test the parser_t functionality when
+ * parsing a TS payload.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_parser_with_ts_payload(protected_tester_t *tester);
+
+/**
+ * @brief Test function used to test the parser_t functionality when
+ * parsing a CERT payload.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_parser_with_cert_payload(protected_tester_t *tester);
+
+/**
+ * @brief Test function used to test the parser_t functionality when
+ * parsing a CERTREQ payload.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_parser_with_certreq_payload(protected_tester_t *tester);
+
+/**
+ * @brief Test function used to test the parser_t functionality when
+ * parsing a CERTREQ payload.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_parser_with_delete_payload(protected_tester_t *tester);
+
+/**
+ * @brief Test function used to test the parser_t functionality when
+ * parsing a VENDOR ID payload.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_parser_with_vendor_id_payload(protected_tester_t *tester);
+
+/**
+ * @brief Test function used to test the parser_t functionality when
+ * parsing a CP payload.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_parser_with_cp_payload(protected_tester_t *tester);
+
+/**
+ * @brief Test function used to test the parser_t functionality when
+ * parsing a EAP payload.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_parser_with_eap_payload(protected_tester_t *tester);
+
+
+
+#endif /*PARSER_TEST_H_*/
diff --git a/programs/charon/testing/policy_test.c b/programs/charon/testing/policy_test.c
new file mode 100644
index 000000000..9003eeff0
--- /dev/null
+++ b/programs/charon/testing/policy_test.c
@@ -0,0 +1,246 @@
+/**
+ * @file policy_test.c
+ *
+ * @brief Tests for the policy_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "policy_test.h"
+
+#include <daemon.h>
+#include <config/policies/policy.h>
+#include <config/traffic_selector.h>
+#include <utils/logger.h>
+#include <encoding/payloads/ts_payload.h>
+
+
+/**
+ * Described in header.
+ */
+void test_policy(protected_tester_t *tester)
+{
+ policy_t *policy;
+// traffic_selector_t *ts;
+// linked_list_t *ts_stored, *ts_supplied, *ts_selected, *ts_expected;
+ proposal_t *proposal1, *proposal2, *proposal3, *proposal_sel;
+ linked_list_t *proposals_list;
+ iterator_t *iterator;
+ logger_t *logger;
+ identification_t *alice, *bob;
+
+ logger = logger_manager->get_logger(logger_manager, TESTER);
+ logger->disable_level(logger, FULL);
+
+ alice = identification_create_from_string("152.96.193.131");
+ bob = identification_create_from_string("152.96.193.130");
+ policy = policy_create(alice, bob);
+
+ tester->assert_true(tester, (policy != NULL), "policy construction");
+
+
+ /*
+ * test proposal getting and selection
+ *
+ */
+
+ /* esp only prop */
+ proposal1 = proposal_create(1);
+ proposal1->add_algorithm(proposal1, PROTO_ESP, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16);
+
+ /* ah only prop */
+ proposal2 = proposal_create(2);
+ proposal2->add_algorithm(proposal2, PROTO_AH, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 20);
+
+ /* ah and esp prop */
+ proposal3 = proposal_create(3);
+ proposal3->add_algorithm(proposal3, PROTO_ESP, ENCRYPTION_ALGORITHM, ENCR_3DES, 16);
+ proposal3->add_algorithm(proposal3, PROTO_AH, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 20);
+
+
+ policy->add_proposal(policy, proposal1);
+ policy->add_proposal(policy, proposal2);
+ policy->add_proposal(policy, proposal3);
+
+
+ proposals_list = policy->get_proposals(policy);
+ tester->assert_true(tester, (proposals_list->get_count(proposals_list) == 3), "proposal count");
+
+
+ proposals_list = linked_list_create();
+ proposal1 = proposal_create(1);
+ proposal1->add_algorithm(proposal1, PROTO_ESP, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 32);
+ proposal2 = proposal_create(2);
+ proposal2->add_algorithm(proposal2, PROTO_ESP, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16);
+ proposal2->add_algorithm(proposal2, PROTO_ESP, ENCRYPTION_ALGORITHM, ENCR_3DES, 16);
+ proposal2->add_algorithm(proposal2, PROTO_ESP, ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 0);
+ proposal2->add_algorithm(proposal2, PROTO_AH, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 20);
+ proposal2->add_algorithm(proposal2, PROTO_AH, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 20);
+
+ proposals_list->insert_last(proposals_list, proposal1);
+ proposals_list->insert_last(proposals_list, proposal2);
+
+ proposal_sel = policy->select_proposal(policy, proposals_list);
+ tester->assert_false(tester, proposal_sel == NULL, "proposal select");
+ /* check ESP encryption algo */
+ iterator = proposal_sel->create_algorithm_iterator(proposal_sel, PROTO_ESP, ENCRYPTION_ALGORITHM);
+ tester->assert_false(tester, iterator == NULL, "algorithm select ESP");
+ while (iterator->has_next(iterator))
+ {
+ algorithm_t *algo;
+ iterator->current(iterator, (void**)&algo);
+ tester->assert_true(tester, algo->algorithm == ENCR_3DES, "ESP encryption algo");
+ tester->assert_true(tester, algo->key_size == 16, "ESP encryption keysize");
+ }
+ iterator->destroy(iterator);
+ iterator = proposal_sel->create_algorithm_iterator(proposal_sel, PROTO_AH, INTEGRITY_ALGORITHM);
+ /* check AH integrity algo */
+ tester->assert_false(tester, iterator == NULL, "algorithm select AH");
+ while (iterator->has_next(iterator))
+ {
+ algorithm_t *algo;
+ iterator->current(iterator, (void**)&algo);
+ tester->assert_true(tester, algo->algorithm == AUTH_HMAC_MD5_96, "ESP encryption algo");
+ tester->assert_true(tester, algo->key_size == 20, "ESP encryption keysize");
+ }
+ iterator->destroy(iterator);
+
+ proposal_sel->destroy(proposal_sel);
+
+ /* cleanup */
+ proposal1->destroy(proposal1);
+ proposal1->destroy(proposal2);
+ proposals_list->destroy(proposals_list);
+
+// /*
+// * test traffic selection getting and matching
+// *
+// */
+//
+// ts_stored = linked_list_create();
+//
+// /* allow any tcp */
+// ts = traffic_selector_create_from_string(6, TS_IPV4_ADDR_RANGE, "0.0.0.0", 0, "255.255.255.255", 65535);
+// ts_stored->insert_last(ts_stored, (void*)ts);
+// /* allow udp on port 123 to ".122" */
+// ts = traffic_selector_create_from_string(7, TS_IPV4_ADDR_RANGE, "152.96.193.122", 123, "152.96.193.122", 123);
+// ts_stored->insert_last(ts_stored, (void*)ts);
+// /* allow udp on ports > 2000 in subnet ... */
+// ts = traffic_selector_create_from_string(7, TS_IPV4_ADDR_RANGE, "152.96.193.0", 2000, "152.96.193.255", 65535);
+// ts_stored->insert_last(ts_stored, (void*)ts);
+//
+//
+//
+// /* define request and result */
+//
+// /* udp on subnet:123, should be reduced to ".122" */
+// ts = traffic_selector_create_from_string(7, TS_IPV4_ADDR_RANGE, "152.96.193.0", 123, "152.96.193.255", 123);
+// ts_supplied->insert_last(ts_supplied, (void*)ts);
+// ts_reference[0] = traffic_selector_create_from_string(7, TS_IPV4_ADDR_RANGE, "152.96.193.122", 123, "152.96.193.122", 123);
+//
+// /* should be granted. */
+// ts_request[1] = traffic_selector_create_from_string(7, TS_IPV4_ADDR_RANGE, "152.96.193.0", 2000, "152.96.193.255", 2000);
+// ts_reference[1] = traffic_selector_create_from_string(7, TS_IPV4_ADDR_RANGE, "152.96.193.0", 2000, "152.96.193.255", 2000);
+//
+// /* should be reduced to port 2000 - 3000. and range ".193.*" */
+// ts_request[2] = traffic_selector_create_from_string(7, TS_IPV4_ADDR_RANGE, "152.96.191.0", 1000, "152.96.194.255", 3000);
+// ts_reference[2] = traffic_selector_create_from_string(7, TS_IPV4_ADDR_RANGE, "152.96.193.0", 2000, "152.96.193.255", 3000);
+//
+// /* icmp request, should be discarded */
+// ts_request[3] = traffic_selector_create_from_string(1, TS_IPV4_ADDR_RANGE, "0.0.0.0", 0, "255.255.255.255", 65535);
+//
+// policy->add_my_traffic_selector(policy, ts_policy[0]);
+// policy->add_my_traffic_selector(policy, ts_policy[1]);
+// policy->add_my_traffic_selector(policy, ts_policy[2]);
+//
+// count = policy->get_my_traffic_selectors(policy, &ts_result);
+// tester->assert_true(tester, (count == 3), "ts get count");
+// ts_result[0]->destroy(ts_result[0]);
+// ts_result[0]->destroy(ts_result[1]);
+// ts_result[0]->destroy(ts_result[2]);
+// free(ts_result);
+//
+// count = policy->select_my_traffic_selectors(policy, &ts_request[0], 4, &ts_result);
+// tester->assert_true(tester, (count == 3), "ts select count");
+//
+//
+// /* store and restore into ts payload, tricky tricky */
+// ts_payload = ts_payload_create_from_traffic_selectors(TRUE, ts_result, count);
+//
+// /* destroy */
+// ts_result[0]->destroy(ts_result[0]);
+// ts_result[0]->destroy(ts_result[1]);
+// ts_result[0]->destroy(ts_result[2]);
+// free(ts_result);
+//
+// /* get them again out of the payload */
+// count = ts_payload->get_traffic_selectors(ts_payload, &ts_result);
+// ts_payload->destroy(ts_payload);
+//
+//
+//
+// int i;
+// for (i = 0; i<count; i++)
+// {
+// chunk_t fa_res = ts_result[i]->get_from_address(ts_result[i]);
+// chunk_t fa_ref = ts_reference[i]->get_from_address(ts_reference[i]);
+// chunk_t ta_res = ts_result[i]->get_to_address(ts_result[i]);
+// chunk_t ta_ref = ts_reference[i]->get_to_address(ts_reference[i]);
+// u_int16_t fp_res = ts_result[i]->get_from_port(ts_result[i]);
+// u_int16_t fp_ref = ts_reference[i]->get_from_port(ts_reference[i]);
+// u_int16_t tp_res = ts_result[i]->get_to_port(ts_result[i]);
+// u_int16_t tp_ref = ts_reference[i]->get_to_port(ts_reference[i]);
+//
+//
+// logger->log_chunk(logger, RAW, "from address result", fa_res);
+// logger->log_chunk(logger, RAW, "from address reference", fa_ref);
+// logger->log_chunk(logger, RAW, "to address result", ta_res);
+// logger->log_chunk(logger, RAW, "to address reference", ta_ref);
+// tester->assert_true(tester, fa_res.len == fa_ref.len, "from address len");
+// tester->assert_false(tester, memcmp(fa_res.ptr, fa_ref.ptr,fa_res.len), "from address value");
+// tester->assert_true(tester, ta_res.len == ta_ref.len, "to address len");
+// tester->assert_false(tester, memcmp(ta_res.ptr, ta_ref.ptr,ta_res.len), "to address value");
+//
+// tester->assert_true(tester, fp_res == fp_ref, "from port");
+// tester->assert_true(tester, tp_res == tp_ref, "to port");
+//
+// free(fa_res.ptr);
+// free(fa_ref.ptr);
+// free(ta_res.ptr);
+// free(ta_ref.ptr);
+// }
+//
+//
+// /* destroy */
+// ts_result[0]->destroy(ts_result[0]);
+// ts_result[0]->destroy(ts_result[1]);
+// ts_result[0]->destroy(ts_result[2]);
+// free(ts_result);
+//
+// ts_policy[0]->destroy(ts_policy[0]);
+// ts_policy[1]->destroy(ts_policy[1]);
+// ts_policy[2]->destroy(ts_policy[2]);
+// ts_request[0]->destroy(ts_request[0]);
+// ts_reference[0]->destroy(ts_reference[0]);
+// ts_request[1]->destroy(ts_request[1]);
+// ts_reference[1]->destroy(ts_reference[1]);
+// ts_request[2]->destroy(ts_request[2]);
+// ts_reference[2]->destroy(ts_reference[2]);
+// ts_request[3]->destroy(ts_request[3]);
+
+ policy->destroy(policy);
+}
diff --git a/programs/charon/testing/policy_test.h b/programs/charon/testing/policy_test.h
new file mode 100644
index 000000000..6c8072a9c
--- /dev/null
+++ b/programs/charon/testing/policy_test.h
@@ -0,0 +1,42 @@
+/**
+ * @file policy_test.h
+ *
+ * @brief Tests for the policy_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#ifndef SA_CONFIG_TEST_H_
+#define SA_CONFIG_TEST_H_
+
+#include <utils/tester.h>
+
+/**
+ * @brief Test function used to test the policy_t functionality.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_policy(protected_tester_t *tester);
+
+#endif /* SA_CONFIG_TEST_H_ */
+
+
+
+
diff --git a/programs/charon/testing/prf_plus_test.c b/programs/charon/testing/prf_plus_test.c
new file mode 100644
index 000000000..818c5c17e
--- /dev/null
+++ b/programs/charon/testing/prf_plus_test.c
@@ -0,0 +1,145 @@
+/**
+ * @file prf_plus_test.h
+ *
+ * @brief Tests for the prf_plus_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+
+#include "prf_plus_test.h"
+
+#include <crypto/prf_plus.h>
+
+
+/*
+ * described in Header-File
+ */
+void test_prf_plus(protected_tester_t *tester)
+{
+ prf_plus_t *prf_plus;
+ prf_t *prf;
+ chunk_t key, seed;
+ u_int8_t buffer[10000];
+ int i;
+
+ u_int8_t key_bytes[] = {
+ 0x01,0x02,0x03,0x04
+ };
+ u_int8_t seed_bytes[] = {
+ 0x01,0x02,0x03,0x04
+ };
+
+
+
+ key.ptr = key_bytes;
+ key.len = sizeof(key_bytes);
+ seed.ptr = seed_bytes;
+ seed.len = sizeof(seed_bytes);
+
+ prf = prf_create(PRF_HMAC_SHA1);
+ prf->set_key(prf, key);
+
+ prf_plus = prf_plus_create(prf, seed);
+
+
+ for (i=0; i<100; i++)
+ {
+ prf_plus->get_bytes(prf_plus, i*i, buffer);
+
+ }
+
+ //tester->assert_true(tester, digest[3].len == 20, "chunk len append mode");
+ //tester->assert_false(tester, memcmp(digest[3].ptr, reference[3].ptr, 20), "prf_plus value append mode");
+
+ prf_plus->destroy(prf_plus);
+ prf->destroy(prf);
+}
+
+void test_prf_plus_md5(protected_tester_t *tester)
+{
+ /* md5 test data
+ u_int8_t nonce[] = {
+ 0x58,0xCC,0x4C,0xA3,0x81,0x81,0xDA,0x7D,
+ 0x19,0xA6,0x9F,0xB1,0xE8,0xD3,0xE7,0x96,
+ 0xC2,0x2A,0x6E,0xCB,0x09,0x43,0xDC,0x6E,
+ 0x75,0x22,0x34,0xAE,0xF8,0x53,0x7F,0xEC,
+ 0x00,0xC9,0xF6,0x1C,0x4A,0x39,0xB4,0x29,
+ 0x23,0xD8,0x24,0x22,0x95,0x52,0x77,0x29
+ };
+
+ u_int8_t shared_key[] = {
+ 0xC0,0xDB,0x75,0x0A,0x40,0xBE,0xE2,0x8C,0x68,0x3C,0xB4,0xAA,0xE7,0xA7,0x6E,0xCC,
+ 0x2A,0x4B,0x9C,0x8E,0xC6,0x71,0xAD,0xF4,0xB7,0xC4,0xD6,0x53,0x41,0xB3,0x4A,0xE4,
+ 0x0D,0xC2,0x0C,0x60,0x9F,0x93,0x9E,0x87,0x30,0xCC,0xDC,0x51,0x9F,0x94,0x91,0x5D,
+ 0x31,0xE0,0x6E,0x22,0x3A,0x66,0x53,0xA6,0xD4,0x54,0x5E,0x71,0x61,0xA6,0x64,0x3B,
+ 0x19,0x40,0x6E,0x6F,0x3B,0xE3,0x64,0x3F,0x3B,0x68,0xEB,0x8E,0x4B,0x2A,0x53,0xEC,
+ 0xB0,0xB6,0x8E,0x5C,0x42,0xA1,0xC2,0x7F,0x4F,0x0B,0x7D,0xFC,0xF6,0x7E,0xF5,0xC0,
+ 0xBA,0xA8,0xFB,0x13,0xEF,0xA8,0xBD,0x90,0x95,0x08,0x2C,0x81,0xA9,0xDA,0x7D,0x45,
+ 0xDC,0x35,0x33,0x75,0xA8,0x4D,0xE2,0x34,0xA9,0x66,0x7F,0xAD,0x04,0x3A,0xE5,0x21
+ };
+
+ u_int8_t skeyseed[] = {
+ 0xCD,0xC6,0xC0,0x68,
+ 0x60,0xDF,0x0C,0xC2,
+ 0x10,0xDB,0x0E,0xF7,
+ 0x20,0x6E,0x6C,0xB1
+ };
+ u_int8_t sk_d[] = {
+ 0xE1,0x74,0xA8,0x50,
+ 0x14,0xDB,0x79,0x64,
+ 0x92,0x3E,0x82,0x28,
+ 0x48,0x75,0x64,0xE7
+ };
+ u_int8_t sk_ai[] = {
+ 0xCA,0x19,0x73,0x69,
+ 0x38,0x35,0x40,0xA6,
+ 0xB1,0x98,0x4F,0x63,
+ 0xE6,0xF9,0x66,0xFF
+ };
+ u_int8_t sk_ar[] = {
+ 0x14,0x1D,0x0A,0xC2,
+ 0x7B,0x1C,0x87,0xD2,
+ 0x65,0xA5,0xEF,0x0C,
+ 0x47,0xF4,0xCE,0xE2
+ };
+ u_int8_t sk_ei[] = {
+ 0x52,0x50,0x7E,0xDA,
+ 0x02,0x1D,0x8E,0xCF,
+ 0x20,0xA3,0x67,0xA6,
+ 0x4D,0xA0,0xAB,0x61
+ };
+ u_int8_t sk_er[] = {
+ 0xB9,0x65,0x0A,0x3C,
+ 0x30,0xA8,0x26,0x78,
+ 0x60,0x5A,0x74,0xBB,
+ 0x5C,0xC4,0xF8,0x71
+ };
+ u_int8_t sk_pi[] = {
+ 0xDD,0x61,0xAB,0x53,
+ 0xC8,0xDD,0x3A,0x44,
+ 0xDA,0x47,0x09,0x9B,
+ 0x3B,0xD2,0xBB,0xB6
+ };
+ u_int8_t sk_pr[] = {
+ 0x18,0x75,0xE4,0xC6,
+ 0x57,0xC4,0xDE,0x65,
+ 0x10,0xEB,0xA7,0xB6,
+ 0x24,0x0D,0xEC,0xB4
+ };*/
+}
diff --git a/programs/charon/testing/prf_plus_test.h b/programs/charon/testing/prf_plus_test.h
new file mode 100644
index 000000000..2ad8ce0c1
--- /dev/null
+++ b/programs/charon/testing/prf_plus_test.h
@@ -0,0 +1,38 @@
+/**
+ * @file prf_plus_test.h
+ *
+ * @brief Tests for the prf_plus_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef PRF_PLUS_TEST_H_
+#define PRF_PLUS_TEST_H_
+
+#include <crypto/prf_plus.h>
+#include <utils/tester.h>
+
+/**
+ * @brief Test function used to test the prf_plus class.
+ *
+ * @param tester associated tester object
+ *
+ * @ingroup testcases
+ */
+void test_prf_plus(protected_tester_t *tester);
+
+#endif /*PRF_PLUS_TEST_H_*/
diff --git a/programs/charon/testing/proposal_test.c b/programs/charon/testing/proposal_test.c
new file mode 100644
index 000000000..1b16390d3
--- /dev/null
+++ b/programs/charon/testing/proposal_test.c
@@ -0,0 +1,98 @@
+/**
+ * @file proposal_test.c
+ *
+ * @brief Tests for the proposal_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "proposal_test.h"
+
+#include <daemon.h>
+#include <config/proposal.h>
+#include <utils/logger.h>
+
+
+/**
+ * Described in header.
+ */
+void test_proposal(protected_tester_t *tester)
+{
+ proposal_t *proposal1, *proposal2, *proposal3;
+ iterator_t *iterator;
+ algorithm_t *algo;
+ bool result;
+
+ proposal1 = proposal_create(1);
+ proposal1->add_algorithm(proposal1, PROTO_ESP, ENCRYPTION_ALGORITHM, ENCR_3DES, 0);
+ proposal1->add_algorithm(proposal1, PROTO_ESP, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 32);
+ proposal1->add_algorithm(proposal1, PROTO_ESP, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16);
+ proposal1->add_algorithm(proposal1, PROTO_ESP, ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 0);
+ proposal1->add_algorithm(proposal1, PROTO_ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 20);
+ proposal1->add_algorithm(proposal1, PROTO_ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 20);
+ proposal1->add_algorithm(proposal1, PROTO_AH, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0);
+ proposal1->add_algorithm(proposal1, PROTO_AH, DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0);
+
+ proposal2 = proposal_create(2);
+ proposal2->add_algorithm(proposal2, PROTO_ESP, ENCRYPTION_ALGORITHM, ENCR_3IDEA, 0);
+ proposal2->add_algorithm(proposal2, PROTO_ESP, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16);
+ proposal2->add_algorithm(proposal2, PROTO_ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 20);
+ proposal1->add_algorithm(proposal2, PROTO_AH, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0);
+
+ /* ah and esp prop */
+ proposal3 = proposal1->select(proposal1, proposal2);
+ tester->assert_false(tester, proposal3 == NULL, "proposal select");
+ if (proposal3)
+ {
+ result = proposal3->get_algorithm(proposal3, PROTO_ESP, ENCRYPTION_ALGORITHM, &algo);
+ tester->assert_true(tester, result, "encryption algo select");
+ tester->assert_true(tester, algo->algorithm == ENCR_AES_CBC, "encryption algo");
+ tester->assert_true(tester, algo->key_size == 16, "encryption keylen");
+
+
+ result = proposal3->get_algorithm(proposal3, PROTO_ESP, INTEGRITY_ALGORITHM, &algo);
+ tester->assert_true(tester, result, "integrity algo select");
+ tester->assert_true(tester, algo->algorithm == AUTH_HMAC_MD5_96, "integrity algo");
+ tester->assert_true(tester, algo->key_size == 20, "integrity keylen");
+
+ iterator = proposal3->create_algorithm_iterator(proposal3, PROTO_ESP, INTEGRITY_ALGORITHM);
+ tester->assert_false(tester, iterator == NULL, "integrity algo select");
+ while(iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void**)&algo);
+ tester->assert_true(tester, algo->algorithm == AUTH_HMAC_MD5_96, "integrity algo");
+ tester->assert_true(tester, algo->key_size == 20, "integrity keylen");
+ }
+ iterator->destroy(iterator);
+
+ iterator = proposal3->create_algorithm_iterator(proposal3, PROTO_AH, DIFFIE_HELLMAN_GROUP );
+ tester->assert_false(tester, iterator == NULL, "dh group algo select");
+ while(iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void**)&algo);
+ tester->assert_true(tester, algo->algorithm == MODP_1024_BIT, "dh group algo");
+ tester->assert_true(tester, algo->key_size == 0, "dh gorup keylen");
+ }
+ iterator->destroy(iterator);
+
+ proposal3->destroy(proposal3);
+ }
+
+ proposal1->destroy(proposal1);
+ proposal2->destroy(proposal2);
+ return;
+}
diff --git a/programs/charon/testing/proposal_test.h b/programs/charon/testing/proposal_test.h
new file mode 100644
index 000000000..059af11cc
--- /dev/null
+++ b/programs/charon/testing/proposal_test.h
@@ -0,0 +1,42 @@
+/**
+ * @file proposal_test.h
+ *
+ * @brief Tests for the proposal_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#ifndef CHILD_PROPOSAL_TEST_H_
+#define CHILD_PROPOSAL_TEST_H_
+
+#include <utils/tester.h>
+
+/**
+ * @brief Test function used to test the proposal_t functionality.
+ *
+ * @param tester associated protected_tester_t object
+ *
+ * @ingroup testcases
+ */
+void test_proposal(protected_tester_t *tester);
+
+#endif /* CHILD_PROPOSAL_TEST_H_ */
+
+
+
+
diff --git a/programs/charon/testing/rsa_test.c b/programs/charon/testing/rsa_test.c
new file mode 100644
index 000000000..696901531
--- /dev/null
+++ b/programs/charon/testing/rsa_test.c
@@ -0,0 +1,226 @@
+/**
+ * @file rsa_test.h
+ *
+ * @brief Tests for the hasher_t classes.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+
+#include "rsa_test.h"
+
+#include <daemon.h>
+#include <utils/logger.h>
+#include <crypto/x509.h>
+
+char private_key_buffer[] = {
+ 0x30,0x82,0x04,0xa2,0x02,0x00,0x02,0x82,0x01,0x00,0x6f,0x25,0x74,0x63,0x2a,0x2f,
+ 0x5d,0xd4,0x54,0x03,0xbe,0xd5,0x34,0x71,0xe0,0x30,0x37,0xe5,0x2e,0x39,0xda,0xe7,
+ 0x04,0xd4,0xe2,0x5b,0x43,0xc3,0x6a,0x50,0x61,0xe8,0x4b,0x5d,0x58,0x30,0xa4,0xcc,
+ 0x6d,0xab,0xdf,0x8b,0x75,0x8c,0x22,0x43,0xd4,0xd0,0x18,0x5e,0x32,0x24,0xba,0x38,
+ 0x6f,0xab,0x64,0x86,0x8f,0x54,0x40,0x77,0xcb,0x3a,0xb5,0x30,0xde,0xb4,0xcd,0x98,
+ 0xbb,0xb1,0xdb,0x7a,0xd4,0xc7,0x0e,0xc7,0x99,0xc4,0x05,0xd5,0xa4,0x96,0x2a,0x3c,
+ 0x71,0x0f,0x31,0xa4,0xcd,0xc2,0x15,0x28,0xec,0x16,0x02,0x28,0x61,0x5e,0x8e,0xcf,
+ 0xb6,0x0b,0x8c,0x81,0x79,0x58,0xfc,0x9b,0x5b,0x32,0x26,0xcb,0xbc,0xf2,0xc9,0x8a,
+ 0x76,0x26,0x4e,0x87,0xaa,0x1b,0xd4,0xa7,0xb3,0xcf,0x96,0x99,0x86,0xcc,0xcb,0x5e,
+ 0xb2,0x66,0xc9,0xe0,0x10,0xbe,0xf7,0xd9,0x99,0xa3,0x49,0x5c,0x41,0x1f,0xa4,0xd0,
+ 0xd0,0x48,0x77,0xad,0x0f,0xbc,0x2c,0x2a,0x29,0x34,0x3f,0x20,0xb5,0x15,0xa1,0xa7,
+ 0x22,0xda,0x15,0xf3,0xf1,0x51,0x83,0x1f,0x3d,0x49,0x26,0x81,0x6d,0x65,0xa6,0x9c,
+ 0x09,0x01,0xfa,0x10,0x26,0x76,0xec,0x46,0x77,0xa6,0xc1,0xf5,0xc7,0xa3,0x2d,0xf9,
+ 0x60,0xa1,0x8f,0x94,0x17,0x58,0x0d,0xc9,0x55,0x50,0x2a,0xeb,0x44,0x5e,0xea,0x69,
+ 0xc9,0x76,0x67,0x9c,0x8e,0xd1,0x9c,0x4f,0x9d,0x9e,0x0a,0xec,0x44,0x6b,0x7e,0x01,
+ 0x2d,0x53,0xf2,0xd6,0x7c,0x27,0x30,0x3d,0x40,0x6c,0x3c,0xef,0x82,0xd1,0x7f,0xe2,
+ 0xd2,0x9b,0xb6,0x96,0x08,0xd2,0xe0,0x8a,0x28,0xeb,0x02,0x03,0x01,0x00,0x01,0x02,
+ 0x82,0x01,0x00,0x0b,0x89,0xcc,0x5c,0xd5,0x0e,0xc8,0xc3,0x57,0x9b,0x71,0xee,0xa9,
+ 0x3c,0x9f,0x24,0xf2,0x50,0x88,0xed,0x79,0xa3,0x9c,0xf5,0x4a,0xb0,0x65,0xc6,0xfe,
+ 0x1c,0xed,0x25,0x13,0xd9,0xd3,0x63,0x6d,0x60,0x49,0x8c,0x5b,0xaf,0x1b,0x1b,0x5a,
+ 0x9d,0x47,0x14,0xf9,0x4a,0xa2,0x12,0xfd,0x00,0x09,0xdb,0xb5,0x9a,0x60,0x7b,0xc3,
+ 0x1b,0x8c,0x8e,0x02,0x2c,0x5a,0x1a,0x53,0xf3,0xa4,0x9c,0x90,0xa7,0xde,0x39,0xf1,
+ 0xf7,0x57,0xa7,0xa9,0x61,0x65,0xee,0x2e,0xe1,0x4a,0x6d,0x64,0xde,0x72,0x7b,0xd0,
+ 0xfd,0x88,0x10,0xba,0xd5,0x9d,0x52,0x17,0x2a,0x4a,0x00,0x45,0xec,0x55,0x00,0x1f,
+ 0x6d,0x33,0x58,0xef,0xfd,0x1b,0x96,0xea,0xc4,0x44,0x82,0xb2,0x89,0x53,0xe8,0x02,
+ 0xba,0x0c,0x28,0xff,0xd1,0xda,0xdc,0xea,0xae,0x80,0xbe,0x33,0x86,0xbc,0x38,0xe9,
+ 0x1c,0xa9,0x39,0xc5,0x28,0x14,0x53,0x5a,0x52,0x3e,0xff,0xb8,0xc6,0x77,0x7c,0xe2,
+ 0xf9,0x50,0x9a,0x58,0x46,0x4e,0xdf,0x11,0x0f,0x4d,0x70,0xf3,0xe7,0xe7,0x9a,0x8a,
+ 0x9f,0x58,0x05,0x54,0xda,0x60,0x52,0xec,0xa8,0x10,0x60,0x9c,0x83,0xf0,0xd7,0x15,
+ 0xaf,0xf9,0x44,0xe8,0x3e,0x68,0xb2,0x06,0xa5,0x6d,0x6d,0xc1,0x8d,0x55,0xa3,0x6e,
+ 0x7e,0xe4,0x86,0x2a,0x6e,0x23,0xe0,0xf5,0xe6,0x08,0x05,0xb5,0x1a,0x6d,0x9c,0xf4,
+ 0xbd,0x18,0x20,0x58,0x43,0x67,0x72,0xde,0x47,0x56,0xee,0x94,0xc6,0x70,0xc1,0xda,
+ 0x15,0x2a,0xb9,0xb7,0x6a,0x10,0xc4,0x02,0x6e,0xae,0x93,0xe8,0x5e,0x8f,0x55,0x80,
+ 0x4e,0x9a,0x75,0x02,0x81,0x81,0x00,0xc4,0x25,0x05,0xab,0x8d,0x6b,0xa0,0xac,0x82,
+ 0x44,0xe2,0x13,0x06,0x2e,0x1c,0x7b,0x6b,0x37,0x69,0x93,0x9e,0x33,0x41,0xb1,0xf0,
+ 0x54,0x6e,0xe1,0x52,0x98,0x83,0x36,0x2b,0xe4,0x86,0x85,0x19,0x53,0x1f,0xd7,0x2f,
+ 0xbb,0x76,0xef,0x8d,0xb1,0x42,0xd3,0xfc,0xba,0xc7,0xb6,0xe4,0x73,0x42,0x83,0x1d,
+ 0x08,0xf9,0x17,0x83,0xd3,0xb7,0xe7,0xb4,0x26,0x74,0x59,0xb6,0x07,0xe1,0x1f,0x97,
+ 0x1e,0x66,0x77,0xe2,0x7a,0x3e,0xb2,0x43,0x2a,0x60,0x34,0xa6,0x2e,0x4a,0x13,0xb9,
+ 0x4f,0xc3,0x64,0xc5,0xee,0x04,0x40,0xf4,0xa5,0x01,0x45,0xba,0x9e,0x09,0x22,0xd9,
+ 0x99,0x0c,0x0e,0x23,0xd9,0x43,0x8b,0x01,0x1a,0x3f,0xd4,0xa8,0x8d,0x9a,0xfc,0x9c,
+ 0x05,0x1d,0x6d,0x7b,0x18,0xe0,0x95,0x02,0x81,0x81,0x00,0x91,0x10,0x4b,0x84,0xdc,
+ 0x10,0x67,0x22,0x84,0x60,0x96,0x2e,0x11,0x1a,0xe9,0x1c,0xb7,0x2f,0xa4,0x4c,0xf4,
+ 0xd0,0x57,0xa2,0x4b,0xbc,0xa2,0x02,0x0f,0x33,0x1b,0x1f,0x19,0x19,0x68,0x8d,0xb6,
+ 0x8a,0x36,0xe3,0xeb,0x2c,0x8c,0xba,0x69,0xb4,0x17,0x97,0xfe,0x0b,0x76,0x2a,0x97,
+ 0x87,0x0c,0xdf,0x1e,0x7a,0xbc,0xc0,0x86,0x27,0x31,0xb9,0x9d,0xc2,0xf2,0xb7,0xcc,
+ 0x83,0x6a,0x5a,0xa1,0xab,0x05,0x60,0xa0,0x04,0x90,0xe2,0xc4,0x03,0xb4,0xd8,0x30,
+ 0xaa,0x93,0xd8,0x90,0x4e,0x3c,0x33,0x1f,0x43,0xa2,0x3a,0x2c,0x34,0xb9,0x01,0x89,
+ 0xbb,0xdc,0x0b,0x2e,0x4f,0x89,0x1b,0xf8,0x77,0x4c,0x4c,0x25,0xc5,0xca,0x38,0x00,
+ 0xd4,0x3a,0xaa,0x7c,0xf6,0xb6,0xad,0x69,0x0d,0x03,0x7f,0x02,0x81,0x81,0x00,0xa3,
+ 0xcc,0xef,0x21,0x46,0xe6,0xdc,0xb5,0x73,0xcc,0xa6,0xa7,0x90,0x7f,0xad,0x95,0x7c,
+ 0x02,0x38,0x8e,0xe8,0x8c,0x91,0x8e,0x51,0xcf,0x91,0x11,0x66,0x72,0xab,0x10,0xf0,
+ 0x32,0xd6,0x0c,0x0d,0x0c,0x18,0x09,0x12,0x79,0x91,0x67,0x98,0x82,0xb1,0xf6,0x6a,
+ 0x96,0x68,0xf6,0x59,0x6d,0xcf,0xdb,0xc2,0xc1,0x9d,0x93,0x7f,0xa9,0xad,0x69,0x38,
+ 0x4e,0xec,0xd7,0x86,0x66,0xaa,0x20,0x41,0x89,0x47,0xb5,0x52,0x53,0x18,0x4c,0xb2,
+ 0x3e,0x8f,0x3d,0x28,0x92,0x7b,0x96,0x61,0x29,0x35,0x59,0xd0,0xd9,0x66,0x80,0x00,
+ 0x4e,0x53,0xf3,0xb1,0x57,0x0c,0xf6,0x27,0x95,0xe2,0x35,0x64,0xc6,0xa9,0xdb,0x49,
+ 0xbe,0x6c,0x13,0xe1,0xf6,0xef,0xb9,0x89,0x69,0xd4,0x1b,0x7b,0xb3,0x58,0xc9,0x02,
+ 0x81,0x80,0x40,0x28,0x3d,0xce,0x37,0xea,0x05,0x43,0x2d,0xda,0xed,0xf0,0xd7,0xdd,
+ 0xd8,0x05,0xbc,0x3b,0x14,0xe6,0x78,0x4c,0x00,0xc6,0x25,0xca,0xfa,0xb8,0x00,0x72,
+ 0xf0,0xe6,0xd3,0x19,0xfa,0xb4,0xda,0x6b,0xcc,0x95,0x06,0xf9,0x00,0x10,0x9e,0x19,
+ 0x69,0x69,0xee,0x90,0xb1,0x25,0x6b,0x38,0xee,0x87,0x6b,0x9a,0x8b,0x0a,0x77,0x0a,
+ 0xb4,0xa2,0x4c,0x54,0xe1,0x36,0x4a,0xfc,0x40,0x38,0x6f,0x52,0x0d,0x21,0xcc,0x03,
+ 0xd8,0xf4,0x82,0x0e,0xc5,0x97,0xec,0x06,0x35,0x37,0x4d,0xb3,0x5c,0x4a,0x9b,0xe4,
+ 0x34,0xc6,0x97,0xb0,0x85,0xb6,0x59,0x6d,0x3d,0x87,0xb0,0x66,0xba,0xd4,0x25,0x12,
+ 0xd6,0x2a,0xc3,0x75,0xf3,0xd6,0xca,0xff,0x12,0x27,0x3e,0xf7,0x7a,0x99,0xbd,0x61,
+ 0x65,0x0f,0x02,0x81,0x81,0x00,0xb2,0xcb,0x21,0xf9,0x77,0x44,0x20,0xee,0xe9,0x60,
+ 0xf2,0x32,0x7e,0xd0,0xb2,0x8b,0xa7,0x96,0x20,0x20,0xf2,0x88,0xbd,0xbe,0x1f,0x92,
+ 0x59,0x26,0x7c,0x26,0x64,0x13,0xfc,0x9a,0x1c,0xd6,0x48,0xbf,0xe3,0xad,0x2d,0x89,
+ 0xd4,0x11,0x9b,0xed,0x38,0x99,0x3e,0xf4,0xe3,0x54,0xa3,0x0c,0x2a,0x91,0xdc,0xf9,
+ 0x38,0x94,0xbe,0xd7,0x90,0xc2,0x8d,0xcc,0x5a,0x28,0xbd,0x46,0x4e,0xd7,0x86,0x52,
+ 0x95,0xb1,0x39,0xb9,0x30,0x33,0x1f,0xe8,0xe7,0x37,0xfe,0x37,0xa5,0x20,0x82,0x1a,
+ 0xfd,0xc3,0x30,0xd0,0xdc,0x8d,0x71,0x66,0x30,0xb4,0x9a,0xb2,0xd6,0x03,0xfe,0xc5,
+ 0x4b,0xfd,0xd2,0x1b,0x3e,0x4e,0xc6,0xb0,0xe8,0x6c,0x83,0x44,0x6b,0xaa,0x05,0x51,
+ 0xd3,0xb2,0x04,0xca,0xf6,0xf3,
+};
+
+char public_key_buffer[] = {
+// 0x30,0x82,0x01,0x21,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,
+// 0x01,0x05,0x00,0x03,0x82,0x01,0x0e,0x00,
+ 0x30,0x82,0x01,0x09,0x02,0x82,0x01,0x00,
+ 0x6f,0x25,0x74,0x63,0x2a,0x2f,0x5d,0xd4,0x54,0x03,0xbe,0xd5,0x34,0x71,0xe0,0x30,
+ 0x37,0xe5,0x2e,0x39,0xda,0xe7,0x04,0xd4,0xe2,0x5b,0x43,0xc3,0x6a,0x50,0x61,0xe8,
+ 0x4b,0x5d,0x58,0x30,0xa4,0xcc,0x6d,0xab,0xdf,0x8b,0x75,0x8c,0x22,0x43,0xd4,0xd0,
+ 0x18,0x5e,0x32,0x24,0xba,0x38,0x6f,0xab,0x64,0x86,0x8f,0x54,0x40,0x77,0xcb,0x3a,
+ 0xb5,0x30,0xde,0xb4,0xcd,0x98,0xbb,0xb1,0xdb,0x7a,0xd4,0xc7,0x0e,0xc7,0x99,0xc4,
+ 0x05,0xd5,0xa4,0x96,0x2a,0x3c,0x71,0x0f,0x31,0xa4,0xcd,0xc2,0x15,0x28,0xec,0x16,
+ 0x02,0x28,0x61,0x5e,0x8e,0xcf,0xb6,0x0b,0x8c,0x81,0x79,0x58,0xfc,0x9b,0x5b,0x32,
+ 0x26,0xcb,0xbc,0xf2,0xc9,0x8a,0x76,0x26,0x4e,0x87,0xaa,0x1b,0xd4,0xa7,0xb3,0xcf,
+ 0x96,0x99,0x86,0xcc,0xcb,0x5e,0xb2,0x66,0xc9,0xe0,0x10,0xbe,0xf7,0xd9,0x99,0xa3,
+ 0x49,0x5c,0x41,0x1f,0xa4,0xd0,0xd0,0x48,0x77,0xad,0x0f,0xbc,0x2c,0x2a,0x29,0x34,
+ 0x3f,0x20,0xb5,0x15,0xa1,0xa7,0x22,0xda,0x15,0xf3,0xf1,0x51,0x83,0x1f,0x3d,0x49,
+ 0x26,0x81,0x6d,0x65,0xa6,0x9c,0x09,0x01,0xfa,0x10,0x26,0x76,0xec,0x46,0x77,0xa6,
+ 0xc1,0xf5,0xc7,0xa3,0x2d,0xf9,0x60,0xa1,0x8f,0x94,0x17,0x58,0x0d,0xc9,0x55,0x50,
+ 0x2a,0xeb,0x44,0x5e,0xea,0x69,0xc9,0x76,0x67,0x9c,0x8e,0xd1,0x9c,0x4f,0x9d,0x9e,
+ 0x0a,0xec,0x44,0x6b,0x7e,0x01,0x2d,0x53,0xf2,0xd6,0x7c,0x27,0x30,0x3d,0x40,0x6c,
+ 0x3c,0xef,0x82,0xd1,0x7f,0xe2,0xd2,0x9b,0xb6,0x96,0x08,0xd2,0xe0,0x8a,0x28,0xeb,
+ 0x02,0x03,0x01,0x00,0x01
+
+};
+
+/*
+ * described in Header-File
+ */
+void test_rsa(protected_tester_t *tester)
+{
+ rsa_private_key_t *private_key;
+ rsa_public_key_t *public_key;
+ x509_t *certificate;
+ chunk_t data, signature;
+ chunk_t der_private_key = {private_key_buffer, sizeof(private_key_buffer)};
+ chunk_t der_public_key = {public_key_buffer, sizeof(public_key_buffer)};
+ logger_t *logger;
+ status_t status;
+
+ u_int8_t test_data[] = {
+ 0x01,0x02,0x03,0x04,
+ 0x11,0x12,0x13,0x14,
+ 0x21,0x22,0x23,0x24,
+ 0x31,0x32,0x33,0x34,
+ 0x41,0x42,0x43,0x44,
+ 0x51,0x52,0x53,0x54,
+ 0x61,0x62,0x63,0x64,
+ 0x71,0x72,0x73,0x74,
+ 0x81,0x82,0x83,0x84,
+ };
+ data.ptr = test_data;
+ data.len = sizeof(test_data);
+
+ logger = logger_manager->get_logger(logger_manager, TESTER);
+ logger->disable_level(logger, FULL);
+
+ /* key generation and signing */
+// private_key = rsa_private_key_create(512);
+// tester->assert_true(tester, private_key != NULL, "generating private key");
+//
+// status = private_key->build_emsa_pkcs1_signature(private_key, HASH_MD5, data, &signature);
+// tester->assert_true(tester, status == SUCCESS, "build emsa_pkcs1_signature (genkey)");
+//
+// public_key = private_key->get_public_key(private_key);
+// tester->assert_true(tester, public_key != NULL, "extracting public key");
+//
+// status = public_key->verify_emsa_pkcs1_signature(public_key, data, signature);
+// tester->assert_true(tester, status == SUCCESS, "verify emsa_pkcs1_signature (genkey)");
+//
+// free(signature.ptr);
+//
+// private_key->destroy(private_key);
+// public_key->destroy(public_key);
+
+ /* key setting */
+ private_key = rsa_private_key_create_from_chunk(der_private_key);
+ tester->assert_true(tester, private_key != NULL, "loading private key from chunk");
+ public_key = rsa_public_key_create_from_chunk(der_public_key);
+ tester->assert_true(tester, public_key != NULL, "loading public key from chunk");
+
+ status = private_key->build_emsa_pkcs1_signature(private_key, HASH_MD5, data, &signature);
+ tester->assert_true(tester, status == SUCCESS, "build emsa_pkcs1_signature (setkey)");
+ status = public_key->verify_emsa_pkcs1_signature(public_key, data, signature);
+ tester->assert_true(tester, status == SUCCESS, "verify emsa_pkcs1_signature (setkey)");
+
+ free(signature.ptr);
+
+ /* key comparison */
+ tester->assert_true(tester, private_key->belongs_to(private_key, public_key), "key belongs to");
+
+ private_key->destroy(private_key);
+ private_key = rsa_private_key_create(512);
+ tester->assert_false(tester, private_key->belongs_to(private_key, public_key), "key belongs not to");
+
+ public_key->destroy(public_key);
+ private_key->destroy(private_key);
+
+ /* key loading */
+ private_key = rsa_private_key_create_from_file("alice.der", NULL);
+ tester->assert_true(tester, private_key != NULL, "loading private key from file");
+ certificate = x509_create_from_file("alice-cert.der");
+ tester->assert_true(tester, public_key != NULL, "loading certificate from file");
+ public_key = certificate->get_public_key(certificate);
+ tester->assert_true(tester, public_key != NULL, "loading public key from certificate");
+
+ tester->assert_true(tester, private_key->belongs_to(private_key, public_key), "key belongs to");
+
+ status = private_key->build_emsa_pkcs1_signature(private_key, HASH_SHA1, data, &signature);
+ tester->assert_true(tester, status == SUCCESS, "build emsa_pkcs1_signature (loadkey)");
+ status = public_key->verify_emsa_pkcs1_signature(public_key, data, signature);
+ tester->assert_true(tester, status == SUCCESS, "verify emsa_pkcs1_signature (loadkey)");
+
+ free(signature.ptr);
+
+ certificate->destroy(certificate);
+ public_key->destroy(public_key);
+ private_key->destroy(private_key);
+
+}
diff --git a/programs/charon/testing/rsa_test.h b/programs/charon/testing/rsa_test.h
new file mode 100644
index 000000000..baeccf402
--- /dev/null
+++ b/programs/charon/testing/rsa_test.h
@@ -0,0 +1,41 @@
+/**
+ * @file rsa_test.h
+ *
+ * @brief Tests for the rsa_public_key_t and rsa_private_key classes.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef RSA_TEST_H
+#define RSA_TEST_H
+
+#include <crypto/rsa/rsa_public_key.h>
+#include <crypto/rsa/rsa_private_key.h>
+
+#include <utils/tester.h>
+
+/**
+ * @brief Test function used to test the rsa functionality.
+ *
+ * @param tester associated tester object
+ *
+ * @ingroup testcases
+ */
+void test_rsa(protected_tester_t *tester);
+
+
+#endif /*RSA_TEST_H*/
diff --git a/programs/charon/testing/scheduler_test.c b/programs/charon/testing/scheduler_test.c
new file mode 100644
index 000000000..de7346d83
--- /dev/null
+++ b/programs/charon/testing/scheduler_test.c
@@ -0,0 +1,92 @@
+/**
+ * @file scheduler_test.c
+ *
+ * @brief Tests for the scheduler_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+#include <unistd.h>
+
+#include "scheduler_test.h"
+
+#include <daemon.h>
+#include <threads/scheduler.h>
+#include <queues/event_queue.h>
+#include <queues/job_queue.h>
+#include <queues/jobs/incoming_packet_job.h>
+
+
+/**
+ * @brief implementation of a scheduler test
+ *
+ * This one uses relative time events, which are not that exact.
+ * Test may fail on too slow machines.
+ */
+void test_scheduler(protected_tester_t *tester)
+{
+ int job_count = 5;
+ job_t *jobs[job_count];
+ int current;
+ scheduler_t *scheduler = scheduler_create();
+
+ /* schedule 5 jobs */
+ for (current = 0; current < job_count; current++)
+ {
+ /* misusing for testing only */
+ jobs[current] = (job_t *) incoming_packet_job_create((packet_t*)(current+1));
+ charon->event_queue->add_relative(charon->event_queue, jobs[current], (current+1) * 500);
+ }
+
+
+ for (current = 0; current < job_count; current++)
+ {
+ jobs[current] = NULL;
+ }
+
+ usleep(50 * 1000);
+
+ /* check if times are correct */
+ for (current = 0; current < job_count; current++)
+ {
+ usleep(400 * 1000);
+
+ tester->assert_true(tester, (charon->job_queue->get_count(charon->job_queue) == current ), "job-queue size before event");
+ tester->assert_true(tester, (charon->event_queue->get_count(charon->event_queue) == job_count - current), "event-queue size before event");
+ usleep(100 * 1000);
+
+ tester->assert_true(tester, (charon->job_queue->get_count(charon->job_queue) == current + 1), "job-queue size after event");
+ tester->assert_true(tester, (charon->event_queue->get_count(charon->event_queue) == job_count - current - 1), "event-queue size after event");
+ }
+
+ /* check job order */
+ for (current = 0; current < job_count; current++)
+ {
+ jobs[current] = charon->job_queue->get(charon->job_queue);
+ incoming_packet_job_t *current_job;
+ current_job = (incoming_packet_job_t*) jobs[current];
+ packet_t *packet;
+ packet = current_job->get_packet(current_job);
+
+ tester->assert_true(tester, (((int)packet) == current+1), "job order");
+ jobs[current]->destroy(jobs[current]);
+ }
+
+ /* destruction test */
+ scheduler->destroy(scheduler);
+}
diff --git a/programs/charon/testing/scheduler_test.h b/programs/charon/testing/scheduler_test.h
new file mode 100644
index 000000000..746848e49
--- /dev/null
+++ b/programs/charon/testing/scheduler_test.h
@@ -0,0 +1,37 @@
+/**
+ * @file scheduler_test.h
+ *
+ * @brief Tests for the scheduler_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef SCHEDULER_TEST_H_
+#define SCHEDULER_TEST_H_
+
+#include <utils/tester.h>
+
+/**
+ * @brief Test function for the type scheduler_t.
+ *
+ * @param tester tester object
+ *
+ * @ingroup testcases
+ */
+void test_scheduler(protected_tester_t *tester);
+
+#endif /*SCHEDULER_TEST_H_*/
diff --git a/programs/charon/testing/send_queue_test.c b/programs/charon/testing/send_queue_test.c
new file mode 100644
index 000000000..a56f8e5a2
--- /dev/null
+++ b/programs/charon/testing/send_queue_test.c
@@ -0,0 +1,142 @@
+/**
+ * @file send_queue_test.c
+ *
+ * @brief Tests for the send_queue_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <pthread.h>
+
+#include "send_queue_test.h"
+
+#include <queues/send_queue.h>
+
+
+/**
+ * @brief Informations for the involved test-thread used in this test
+ *
+ */
+typedef struct send_queue_test_s send_queue_test_t;
+
+
+struct send_queue_test_s{
+ /**
+ * Associated protected_tester_t object
+ */
+ protected_tester_t *tester;
+
+ /**
+ * Queue to test
+ */
+ send_queue_t *send_queue;
+
+ /**
+ * number of items to be inserted in the send-queue by each thread
+ */
+ int insert_item_count;
+
+ /**
+ * number of items to be removed by each
+ * receiver thread from the send-queue
+ */
+ int remove_item_count;
+};
+
+/**
+ * @brief sender thread used in the the send_queue test function
+ *
+ * @param testinfo informations for the specific thread.
+ */
+static void test_send_queue_sender(send_queue_test_t * testinfo)
+{
+ int i;
+ for (i = 0; i < testinfo->insert_item_count; i++)
+ {
+ packet_t *packet = packet_create(AF_INET);
+ testinfo->tester->assert_true(testinfo->tester,(packet != NULL), "create packet call check");
+ testinfo->send_queue->add(testinfo->send_queue,packet);
+ }
+}
+
+/**
+ * @brief receiver thread used in the the send_queue test function
+ *
+ * @param testinfo informations for the specific thread.
+ */
+static void test_send_queue_receiver(send_queue_test_t * testinfo)
+{
+ int i;
+ for (i = 0; i < testinfo->remove_item_count; i++)
+ {
+ packet_t *packet;
+ packet = testinfo->send_queue->get(testinfo->send_queue);
+
+ testinfo->tester->assert_true(testinfo->tester,( packet != NULL), "packet not NULL call check");
+
+ packet->destroy(packet);
+ }
+}
+
+/*
+ * description is in header file
+ */
+void test_send_queue(protected_tester_t *tester)
+{
+ int desired_value, i;
+ int sender_count = 10;
+ int receiver_count = 2;
+ pthread_t sender_threads[sender_count];
+ pthread_t receiver_threads[receiver_count];
+ send_queue_t *send_queue = send_queue_create();
+ send_queue_test_t test_infos;
+
+ test_infos.tester = tester;
+ test_infos.send_queue = send_queue;
+ test_infos.insert_item_count = 10000;
+ test_infos.remove_item_count = 10000;
+
+
+ desired_value = test_infos.insert_item_count * sender_count -
+ test_infos.remove_item_count * receiver_count;
+
+ for (i = 0; i < receiver_count;i++)
+ {
+ pthread_create( &receiver_threads[i], NULL,(void*(*)(void*)) &test_send_queue_receiver, (void*) &test_infos);
+ }
+
+ for (i = 0; i < sender_count;i++)
+ {
+ pthread_create( &sender_threads[i], NULL,(void*(*)(void*)) &test_send_queue_sender, (void*) &test_infos);
+ }
+
+
+ /* Wait for all threads */
+ for (i = 0; i < sender_count;i++)
+ {
+ pthread_join(sender_threads[i], NULL);
+ }
+ for (i = 0; i < receiver_count;i++)
+ {
+ pthread_join(receiver_threads[i], NULL);
+ }
+
+
+ /* the send-queue has to have diserd_value count entries*/
+ tester->assert_true(tester,(send_queue->get_count(send_queue) == desired_value), "count value check");
+ send_queue->destroy(send_queue);
+}
diff --git a/programs/charon/testing/send_queue_test.h b/programs/charon/testing/send_queue_test.h
new file mode 100644
index 000000000..138657e10
--- /dev/null
+++ b/programs/charon/testing/send_queue_test.h
@@ -0,0 +1,40 @@
+/**
+ * @file send_queue_test.h
+ *
+ * @brief Tests for the send_queue_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef SEND_QUEUE_TEST_H_
+#define SEND_QUEUE_TEST_H_
+
+#include <utils/tester.h>
+
+/**
+ * @brief Test function used to test the send_queue functionality.
+ *
+ * Tests are performed using different threads to test the multi-threaded
+ * features of the send_queue_t.
+ *
+ * @param tester associated tester object
+ *
+ * @ingroup testcases
+ */
+void test_send_queue(protected_tester_t *tester);
+
+#endif /*SEND_QUEUE_TEST_H_*/
diff --git a/programs/charon/testing/sender_test.c b/programs/charon/testing/sender_test.c
new file mode 100644
index 000000000..391d71fbc
--- /dev/null
+++ b/programs/charon/testing/sender_test.c
@@ -0,0 +1,88 @@
+/**
+ * @file sender_test.h
+ *
+ * @brief Tests for the sender_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+
+#include "sender_test.h"
+
+#include <daemon.h>
+#include <threads/sender.h>
+#include <network/packet.h>
+#include <network/socket.h>
+#include <queues/send_queue.h>
+#include <queues/job_queue.h>
+#include <queues/jobs/incoming_packet_job.h>
+
+/**
+ * Number of packets to send by sender-thread
+ */
+#define NUMBER_OF_PACKETS_TO_SEND 5
+
+void test_sender(protected_tester_t *tester)
+{
+ int i;
+ sender_t *sender;
+ receiver_t *receiver;
+ job_t *job;
+ packet_t *packet;
+ packet_t *received_packet;
+ char test_data[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, /* spi */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05, /* spi */
+ 0x05, /* next payload */
+ 0x20, /* IKE version */
+ 0x00, /* exchange type */
+ 0x00, /* flags */
+ 0x00,0x00,0x00,0x01, /* message id */
+ 0x00,0x00,0x00,0x24, /* length */
+ 0x12,0x34,0x56,0x67, /* some data */
+ 0x12,0x34,0x56,0x67,
+ };
+ chunk_t data = chunk_from_buf(test_data);
+ chunk_t received;
+ sender = sender_create();
+ receiver = receiver_create();
+
+ for (i = 0; i < NUMBER_OF_PACKETS_TO_SEND; i++)
+ {
+ packet = packet_create(AF_INET);
+ packet->set_destination(packet, host_create(AF_INET, "127.0.0.1", 500));
+ packet->set_source(packet, host_create(AF_INET, "127.0.0.1", 500));
+ packet->set_data(packet, chunk_clone(data));
+ charon->send_queue->add(charon->send_queue,packet);
+ }
+
+ for (i = 0; i < NUMBER_OF_PACKETS_TO_SEND; i++)
+ {
+ job = charon->job_queue->get(charon->job_queue);
+ tester->assert_true(tester, (job->get_type(job) == INCOMING_PACKET), "job type check");
+ received_packet = ((incoming_packet_job_t *)(job))->get_packet((incoming_packet_job_t *)(job));
+ received = received_packet->get_data(received_packet);
+ tester->assert_true(tester, received.len == data.len, "received data length check");
+ tester->assert_true(tester, memcmp(received.ptr, data.ptr, data.len) == 0, "received data value check");
+ received_packet->destroy(received_packet);
+ job->destroy(job);
+ }
+
+ sender->destroy(sender);
+ receiver->destroy(receiver);
+}
diff --git a/programs/charon/testing/sender_test.h b/programs/charon/testing/sender_test.h
new file mode 100644
index 000000000..1fdfed69d
--- /dev/null
+++ b/programs/charon/testing/sender_test.h
@@ -0,0 +1,37 @@
+/**
+ * @file sender_test.h
+ *
+ * @brief Tests for the sender_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef SENDER_TEST_H_
+#define SENDER_TEST_H_
+
+#include <utils/tester.h>
+
+/**
+ * @brief Test function for the class sender_t.
+ *
+ * @param tester tester object
+ *
+ * @ingroup testcases
+ */
+void test_sender(protected_tester_t *tester);
+
+#endif /*SENDER_TEST_H_*/
diff --git a/programs/charon/testing/socket_test.c b/programs/charon/testing/socket_test.c
new file mode 100644
index 000000000..9ae1b0fbc
--- /dev/null
+++ b/programs/charon/testing/socket_test.c
@@ -0,0 +1,82 @@
+/**
+ * @file socket_test.c
+ *
+ * @brief Tests for the socket_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "socket_test.h"
+
+#include <network/socket.h>
+#include <utils/logger.h>
+
+/*
+ * Description in header file
+ */
+void test_socket(protected_tester_t *tester)
+{
+ int packet_count = 10;
+ int current;
+ socket_t *skt = socket_create(500);
+ packet_t *pkt = packet_create(AF_INET);
+ char test_data[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, /* spi */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05, /* spi */
+ 0x05, /* next payload */
+ 0x20, /* IKE version */
+ 0x00, /* exchange type */
+ 0x00, /* flags */
+ 0x00,0x00,0x00,0x01, /* message id */
+ 0x00,0x00,0x00,0x24, /* length */
+ 0x12,0x34,0x56,0x67, /* some data */
+ 0x12,0x34,0x56,0x67,
+ };
+ chunk_t data = chunk_from_buf(test_data);
+ chunk_t received;
+
+ /* send to previously bound socket */
+ pkt->set_destination(pkt, host_create(AF_INET, "127.0.0.1", 500));
+ pkt->set_source(pkt, host_create(AF_INET, "127.0.0.1", 500));
+ pkt->set_data(pkt, chunk_clone(data));
+
+ /* send packet_count packets */
+ for (current = 0; current < packet_count; current++)
+ {
+ if (skt->send(skt, pkt) == FAILED)
+ {
+ tester->assert_true(tester, 0, "packet send");
+ }
+ }
+ pkt->destroy(pkt);
+
+
+ /* receive packet_count packets */
+ for (current = 0; current < packet_count; current++)
+ {
+ skt->receive(skt, &pkt);
+ received = pkt->get_data(pkt);
+ tester->assert_false(tester, memcmp(received.ptr, data.ptr, max(received.len, data.len)), "packet exchange");
+ pkt->destroy(pkt);
+ }
+
+ skt->destroy(skt);
+
+}
diff --git a/programs/charon/testing/socket_test.h b/programs/charon/testing/socket_test.h
new file mode 100644
index 000000000..a59995297
--- /dev/null
+++ b/programs/charon/testing/socket_test.h
@@ -0,0 +1,38 @@
+/**
+ * @file socket_test.h
+ *
+ * @brief Tests for the socket_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef SOCKET_TEST_H_
+#define SOCKET_TEST_H_
+
+#include <utils/tester.h>
+
+/**
+ * @brief Test function for the class socket_t.
+ *
+ * @param tester tester object
+ *
+ * @ingroup testcases
+ */
+void test_socket(protected_tester_t *tester);
+
+
+#endif /*SOCKET_TEST_H_*/
diff --git a/programs/charon/testing/testcases.c b/programs/charon/testing/testcases.c
new file mode 100644
index 000000000..e4d92becf
--- /dev/null
+++ b/programs/charon/testing/testcases.c
@@ -0,0 +1,263 @@
+/**
+ * @file tests.c
+ *
+ * @brief Main for all testcases.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#include <stdio.h>
+
+#include <daemon.h>
+
+#include <queues/job_queue.h>
+#include <queues/event_queue.h>
+#include <queues/send_queue.h>
+#include <config/configuration.h>
+#include <sa/ike_sa_manager.h>
+#include <network/socket.h>
+#include <utils/logger_manager.h>
+#include <utils/tester.h>
+#include "linked_list_test.h"
+#include "thread_pool_test.h"
+#include "job_queue_test.h"
+#include "event_queue_test.h"
+#include "send_queue_test.h"
+#include "socket_test.h"
+#include "sender_test.h"
+#include "scheduler_test.h"
+#include "ike_sa_id_test.h"
+#include "ike_sa_test.h"
+#include "ike_sa_manager_test.h"
+#include "generator_test.h"
+#include "parser_test.h"
+#include "packet_test.h"
+#include "diffie_hellman_test.h"
+#include "hasher_test.h"
+#include "hmac_test.h"
+#include "prf_plus_test.h"
+#include "aes_cbc_crypter_test.h"
+#include "hmac_signer_test.h"
+#include "encryption_payload_test.h"
+#include "connection_test.h"
+#include "policy_test.h"
+#include "proposal_test.h"
+#include "rsa_test.h"
+#include "kernel_interface_test.h"
+#include "child_sa_test.h"
+#include "certificate_test.h"
+#include "leak_detective_test.h"
+#include "identification_test.h"
+
+/* output for test messages */
+extern FILE * stderr;
+
+test_t linked_list_test = {test_linked_list,"Linked List"};
+test_t iterator_test = {test_linked_list_iterator,"Linked List Iterator"};
+test_t linked_list_insert_and_remove_test = {test_linked_list_insert_and_remove,"Linked List Insert and remove"};
+test_t event_queue_test = {test_event_queue,"Event-Queue"};
+test_t job_queue_test1 = {test_job_queue,"Job-Queue"};
+test_t send_queue_test = {test_send_queue,"Send-Queue"};
+test_t socket_test = {test_socket,"Socket"};
+test_t thread_pool_test = {test_thread_pool,"Thread Pool"};
+test_t sender_test = {test_sender,"Sender"};
+test_t scheduler_test = {test_scheduler,"Scheduler"};
+test_t ike_sa_id_test = {test_ike_sa_id,"IKE_SA-Identifier"};
+test_t ike_sa_test = {test_ike_sa,"IKE_SA"};
+test_t ike_sa_manager_test = {test_ike_sa_manager, "IKE_SA-Manager"};
+test_t generator_test1 = {test_generator_with_header_payload,"Generator: header payload"};
+test_t generator_test2 = {test_generator_with_transform_attribute,"Generator: transform attribute"};
+test_t generator_test3 = {test_generator_with_transform_substructure,"Generator: transform substructure"};
+test_t generator_test4 = {test_generator_with_proposal_substructure,"Generator: proposal substructure"};
+test_t generator_test5 = {test_generator_with_sa_payload,"Generator: Message with SA Payload"};
+test_t generator_test6 = {test_generator_with_ke_payload,"Generator: KE Payload"};
+test_t generator_test7 = {test_generator_with_notify_payload,"Generator: Notify Payload"};
+test_t generator_test8 = {test_generator_with_nonce_payload,"Generator: Nonce Payload"};
+test_t generator_test9 = {test_generator_with_id_payload,"Generator: ID Payload"};
+test_t generator_test10 = {test_generator_with_auth_payload,"Generator: AUTH Payload"};
+test_t generator_test11 = {test_generator_with_ts_payload,"Generator: TS Payload"};
+test_t generator_test12 = {test_generator_with_cert_payload,"Generator: CERT Payload"};
+test_t generator_test13 = {test_generator_with_certreq_payload,"Generator: CERTREQ Payload"};
+test_t generator_test14 = {test_generator_with_delete_payload,"Generator: DELETE Payload"};
+test_t generator_test15 = {test_generator_with_vendor_id_payload,"Generator: VENDOR ID Payload"};
+test_t generator_test16 = {test_generator_with_cp_payload,"Generator: CP Payload"};
+test_t generator_test17 = {test_generator_with_eap_payload,"Generator: EAP Payload"};
+test_t parser_test1 = {test_parser_with_header_payload, "Parser: header payload"};
+test_t parser_test2 = {test_parser_with_sa_payload, "Parser: sa payload"};
+test_t parser_test3 = {test_parser_with_nonce_payload, "Parser: nonce payload"};
+test_t parser_test4 = {test_parser_with_ke_payload, "Parser: key exchange payload"};
+test_t parser_test5 = {test_parser_with_notify_payload, "Parser: notify payload"};
+test_t parser_test6 = {test_parser_with_id_payload, "Parser: ID payload"};
+test_t parser_test7 = {test_parser_with_auth_payload, "Parser: AUTH payload"};
+test_t parser_test8 = {test_parser_with_ts_payload, "Parser: TS payload"};
+test_t parser_test9 = {test_parser_with_cert_payload, "Parser: CERT payload"};
+test_t parser_test10 = {test_parser_with_certreq_payload, "Parser: CERTREQ payload"};
+test_t parser_test11 = {test_parser_with_delete_payload, "Parser: DELETE payload"};
+test_t parser_test12 = {test_parser_with_vendor_id_payload, "Parser: VENDOR ID payload"};
+test_t parser_test13 = {test_parser_with_cp_payload, "Parser: CP payload"};
+test_t parser_test14 = {test_parser_with_eap_payload, "Parser: EAP payload"};
+test_t packet_test = {test_packet,"Packet"};
+test_t diffie_hellman_test = {test_diffie_hellman,"Diffie Hellman"};
+test_t sha1_hasher_test = {test_sha1_hasher,"SHA1 hasher"};
+test_t md5_hasher_test = {test_md5_hasher,"MD5 hasher"};
+test_t hmac_test1 = {test_hmac_sha1, "HMAC using SHA1"};
+test_t hmac_test2 = {test_hmac_md5, "HMAC using MD5"};
+test_t prf_plus_test = {test_prf_plus, "prf+"};
+test_t aes_cbc_crypter_test = {test_aes_cbc_crypter, "AES CBC"};
+test_t hmac_signer_test1 = {test_hmac_md5_signer, "HMAC MD5 signer test"};
+test_t hmac_signer_test2 = {test_hmac_sha1_signer, "HMAC SHA1 signer test"};
+test_t encryption_payload_test = {test_encryption_payload, "encryption payload test"};
+test_t connection_test = {test_connection, "connection_t test"};
+test_t policy_test = {test_policy, "policy_t test"};
+test_t proposal_test = {test_proposal, "proposal_t test"};
+test_t rsa_test = {test_rsa, "RSA private/public key test"};
+test_t kernel_interface_test = {test_kernel_interface, "Kernel Interface"};
+test_t child_sa_test = {test_child_sa, "Child SA"};
+test_t certificate_test = {test_certificate, "X509 Certificate"};
+test_t leak_detective_test = {test_leak_detective, "LEAK detective"};
+test_t identification_test = {test_identification, "identification"};
+
+
+daemon_t* charon;
+
+static void daemon_kill(daemon_t *this, char* none)
+{
+ //this->socket->destroy(this->socket);
+ this->ike_sa_manager->destroy(this->ike_sa_manager);
+ this->job_queue->destroy(this->job_queue);
+ this->event_queue->destroy(this->event_queue);
+ this->send_queue->destroy(this->send_queue);
+ this->kernel_interface->destroy(this->kernel_interface);
+ //this->configuration->destroy(this->configuration);
+ free(charon);
+}
+
+/**
+ * @brief Create the dummy daemon for testing.
+ *
+ * @return created daemon_t
+ */
+daemon_t *daemon_create()
+{
+ charon = malloc_thing(daemon_t);
+
+ /* assign methods */
+ charon->kill = daemon_kill;
+
+ charon->socket = socket_create(500);
+ charon->ike_sa_manager = ike_sa_manager_create();
+ charon->job_queue = job_queue_create();
+ charon->event_queue = event_queue_create();
+ charon->send_queue = send_queue_create();
+ charon->kernel_interface = kernel_interface_create();
+ //charon->configuration = configuration_create(RETRANSMIT_TIMEOUT,MAX_RETRANSMIT_COUNT,HALF_OPEN_IKE_SA_TIMEOUT);
+ charon->sender = NULL;
+ charon->receiver = NULL;
+ charon->scheduler = NULL;
+ charon->thread_pool = NULL;
+
+ return charon;
+}
+
+
+int main()
+{
+ FILE * test_output = stderr;
+
+ test_t *all_tests[] ={
+ &linked_list_test,
+ &iterator_test,
+ &linked_list_insert_and_remove_test,
+ &thread_pool_test,
+ &job_queue_test1,
+ &event_queue_test,
+ &send_queue_test,
+ &scheduler_test,
+ &socket_test,
+ &sender_test,
+ &ike_sa_id_test,
+ &ike_sa_test,
+ &generator_test1,
+ &generator_test2,
+ &parser_test1,
+ &parser_test2,
+ &parser_test3,
+ &parser_test4,
+ &parser_test5,
+ &parser_test6,
+ &parser_test7,
+ &parser_test8,
+ &parser_test9,
+ &parser_test10,
+ &parser_test11,
+ &parser_test12,
+ &parser_test13,
+ &parser_test14,
+ &generator_test3,
+ &generator_test4,
+ &generator_test5,
+ &generator_test6,
+ &generator_test7,
+ &generator_test8,
+ &generator_test9,
+ &generator_test10,
+ &generator_test11,
+ &generator_test12,
+ &generator_test13,
+ &generator_test14,
+ &generator_test15,
+ &generator_test16,
+ &generator_test17,
+ &ike_sa_manager_test,
+ &packet_test,
+ &diffie_hellman_test,
+ &sha1_hasher_test,
+ &md5_hasher_test,
+ &hmac_test1,
+ &hmac_test2,
+ &prf_plus_test,
+ &aes_cbc_crypter_test,
+ &hmac_signer_test1,
+ &hmac_signer_test2,
+ &encryption_payload_test,
+ &connection_test,
+ &policy_test,
+ &proposal_test,
+ &rsa_test,
+ NULL
+ };
+ /* get rid of compiler warning ;-) */
+ *all_tests = *all_tests;
+
+ daemon_create();
+
+ //logger_manager->enable_log_level(logger_manager, ALL_LOGGERS, FULL);
+ logger_manager->set_output(logger_manager, ALL_LOGGERS, stdout);
+
+ tester_t *tester = tester_create(test_output, FALSE);
+
+ tester->perform_tests(tester,all_tests);
+ //tester->perform_test(tester,&sender_test);
+
+
+ tester->destroy(tester);
+
+ charon->kill(charon, NULL);
+
+ return 0;
+}
diff --git a/programs/charon/testing/thread_pool_test.c b/programs/charon/testing/thread_pool_test.c
new file mode 100644
index 000000000..ee7a5101f
--- /dev/null
+++ b/programs/charon/testing/thread_pool_test.c
@@ -0,0 +1,41 @@
+/**
+ * @file thread_pool_test.c
+ *
+ * @brief Tests for the thread_pool_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stdlib.h>
+
+#include "thread_pool_test.h"
+
+#include <threads/thread_pool.h>
+
+/*
+ * Description in header file
+ */
+void test_thread_pool(protected_tester_t *tester)
+{
+ size_t desired_pool_size = 10;
+ size_t pool_size;
+
+ thread_pool_t *pool = thread_pool_create(desired_pool_size);
+ pool_size = pool->get_pool_size(pool);
+ tester->assert_true(tester, (desired_pool_size == pool_size), "thread creation");
+ pool->destroy(pool);
+}
diff --git a/programs/charon/testing/thread_pool_test.h b/programs/charon/testing/thread_pool_test.h
new file mode 100644
index 000000000..bdae797b7
--- /dev/null
+++ b/programs/charon/testing/thread_pool_test.h
@@ -0,0 +1,37 @@
+/**
+ * @file thread_pool_test.h
+ *
+ * @brief Tests for the thread_pool_t class.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef THREAD_POOL_TEST_H_
+#define THREAD_POOL_TEST_H_
+
+#include <utils/tester.h>
+
+/**
+ * @brief Test function for the class thread_pool_t.
+ *
+ * @param tester tester object
+ *
+ * @ingroup testcases
+ */
+void test_thread_pool(protected_tester_t *tester);
+
+#endif /*THREAD_POOL_TEST_H_*/