summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am1
-rw-r--r--src/Makefile.in497
-rw-r--r--src/_copyright/Makefile.am6
-rw-r--r--src/_copyright/Makefile.in529
-rw-r--r--src/_copyright/_copyright.832
-rw-r--r--src/_copyright/_copyright.c69
-rw-r--r--src/_updown/Makefile.am3
-rw-r--r--src/_updown/Makefile.in421
-rwxr-xr-xsrc/_updown/_updown503
-rw-r--r--src/_updown/_updown.819
-rw-r--r--src/_updown_espmark/Makefile.am2
-rw-r--r--src/_updown_espmark/Makefile.in421
-rw-r--r--src/_updown_espmark/_updown_espmark452
-rw-r--r--src/_updown_espmark/_updown_espmark.818
-rw-r--r--src/charon/Makefile.am87
-rw-r--r--src/charon/Makefile.in1878
-rw-r--r--src/charon/bus/bus.c397
-rw-r--r--src/charon/bus/bus.h366
-rw-r--r--src/charon/bus/listeners/file_logger.c128
-rw-r--r--src/charon/bus/listeners/file_logger.h73
-rw-r--r--src/charon/bus/listeners/sys_logger.c131
-rw-r--r--src/charon/bus/listeners/sys_logger.h75
-rwxr-xr-xsrc/charon/config/configuration.c162
-rwxr-xr-xsrc/charon/config/configuration.h102
-rw-r--r--src/charon/config/connections/connection.c404
-rw-r--r--src/charon/config/connections/connection.h292
-rwxr-xr-xsrc/charon/config/connections/connection_store.h118
-rw-r--r--src/charon/config/connections/local_connection_store.c237
-rw-r--r--src/charon/config/connections/local_connection_store.h62
-rw-r--r--src/charon/config/credentials/local_credential_store.c1363
-rw-r--r--src/charon/config/credentials/local_credential_store.h64
-rw-r--r--src/charon/config/policies/local_policy_store.c282
-rw-r--r--src/charon/config/policies/local_policy_store.h60
-rw-r--r--src/charon/config/policies/policy.c635
-rw-r--r--src/charon/config/policies/policy.h413
-rwxr-xr-xsrc/charon/config/policies/policy_store.h119
-rw-r--r--src/charon/config/proposal.c641
-rw-r--r--src/charon/config/proposal.h266
-rw-r--r--src/charon/config/traffic_selector.c795
-rw-r--r--src/charon/config/traffic_selector.h312
-rw-r--r--src/charon/daemon.c529
-rw-r--r--src/charon/daemon.h403
-rw-r--r--src/charon/encoding/generator.c1063
-rw-r--r--src/charon/encoding/generator.h102
-rw-r--r--src/charon/encoding/message.c1316
-rw-r--r--src/charon/encoding/message.h390
-rw-r--r--src/charon/encoding/parser.c1048
-rw-r--r--src/charon/encoding/parser.h95
-rw-r--r--src/charon/encoding/payloads/auth_payload.c265
-rw-r--r--src/charon/encoding/payloads/auth_payload.h121
-rw-r--r--src/charon/encoding/payloads/cert_payload.c290
-rw-r--r--src/charon/encoding/payloads/cert_payload.h166
-rw-r--r--src/charon/encoding/payloads/certreq_payload.c335
-rw-r--r--src/charon/encoding/payloads/certreq_payload.h144
-rw-r--r--src/charon/encoding/payloads/configuration_attribute.c313
-rw-r--r--src/charon/encoding/payloads/configuration_attribute.h147
-rw-r--r--src/charon/encoding/payloads/cp_payload.c277
-rw-r--r--src/charon/encoding/payloads/cp_payload.h132
-rw-r--r--src/charon/encoding/payloads/delete_payload.c299
-rw-r--r--src/charon/encoding/payloads/delete_payload.h102
-rw-r--r--src/charon/encoding/payloads/eap_payload.c331
-rw-r--r--src/charon/encoding/payloads/eap_payload.h149
-rw-r--r--src/charon/encoding/payloads/encodings.c66
-rw-r--r--src/charon/encoding/payloads/encodings.h537
-rw-r--r--src/charon/encoding/payloads/encryption_payload.c646
-rw-r--r--src/charon/encoding/payloads/encryption_payload.h197
-rw-r--r--src/charon/encoding/payloads/id_payload.c323
-rw-r--r--src/charon/encoding/payloads/id_payload.h172
-rw-r--r--src/charon/encoding/payloads/ike_header.c406
-rw-r--r--src/charon/encoding/payloads/ike_header.h260
-rw-r--r--src/charon/encoding/payloads/ke_payload.c277
-rw-r--r--src/charon/encoding/payloads/ke_payload.h121
-rw-r--r--src/charon/encoding/payloads/nonce_payload.c232
-rw-r--r--src/charon/encoding/payloads/nonce_payload.h99
-rw-r--r--src/charon/encoding/payloads/notify_payload.c481
-rw-r--r--src/charon/encoding/payloads/notify_payload.h224
-rw-r--r--src/charon/encoding/payloads/payload.c161
-rw-r--r--src/charon/encoding/payloads/payload.h282
-rw-r--r--src/charon/encoding/payloads/proposal_substructure.c603
-rw-r--r--src/charon/encoding/payloads/proposal_substructure.h206
-rw-r--r--src/charon/encoding/payloads/sa_payload.c375
-rw-r--r--src/charon/encoding/payloads/sa_payload.h141
-rw-r--r--src/charon/encoding/payloads/traffic_selector_substructure.c283
-rw-r--r--src/charon/encoding/payloads/traffic_selector_substructure.h172
-rw-r--r--src/charon/encoding/payloads/transform_attribute.c332
-rw-r--r--src/charon/encoding/payloads/transform_attribute.h154
-rw-r--r--src/charon/encoding/payloads/transform_substructure.c409
-rw-r--r--src/charon/encoding/payloads/transform_substructure.h198
-rw-r--r--src/charon/encoding/payloads/ts_payload.c341
-rw-r--r--src/charon/encoding/payloads/ts_payload.h153
-rw-r--r--src/charon/encoding/payloads/unknown_payload.c208
-rw-r--r--src/charon/encoding/payloads/unknown_payload.h95
-rw-r--r--src/charon/encoding/payloads/vendor_id_payload.c228
-rw-r--r--src/charon/encoding/payloads/vendor_id_payload.h104
-rw-r--r--src/charon/network/packet.c168
-rw-r--r--src/charon/network/packet.h134
-rw-r--r--src/charon/network/socket.c755
-rw-r--r--src/charon/network/socket.h112
-rw-r--r--src/charon/queues/event_queue.c290
-rw-r--r--src/charon/queues/event_queue.h118
-rw-r--r--src/charon/queues/job_queue.c139
-rw-r--r--src/charon/queues/job_queue.h100
-rw-r--r--src/charon/queues/jobs/acquire_job.c98
-rw-r--r--src/charon/queues/jobs/acquire_job.h60
-rw-r--r--src/charon/queues/jobs/delete_child_sa_job.c113
-rw-r--r--src/charon/queues/jobs/delete_child_sa_job.h68
-rw-r--r--src/charon/queues/jobs/delete_ike_sa_job.c126
-rw-r--r--src/charon/queues/jobs/delete_ike_sa_job.h66
-rw-r--r--src/charon/queues/jobs/initiate_job.c112
-rw-r--r--src/charon/queues/jobs/initiate_job.h61
-rw-r--r--src/charon/queues/jobs/job.c39
-rw-r--r--src/charon/queues/jobs/job.h165
-rw-r--r--src/charon/queues/jobs/process_message_job.c106
-rw-r--r--src/charon/queues/jobs/process_message_job.h58
-rw-r--r--src/charon/queues/jobs/rekey_child_sa_job.c112
-rw-r--r--src/charon/queues/jobs/rekey_child_sa_job.h65
-rw-r--r--src/charon/queues/jobs/rekey_ike_sa_job.c120
-rw-r--r--src/charon/queues/jobs/rekey_ike_sa_job.h60
-rw-r--r--src/charon/queues/jobs/retransmit_job.c109
-rw-r--r--src/charon/queues/jobs/retransmit_job.h64
-rw-r--r--src/charon/queues/jobs/route_job.c125
-rw-r--r--src/charon/queues/jobs/route_job.h59
-rw-r--r--src/charon/queues/jobs/send_dpd_job.c110
-rw-r--r--src/charon/queues/jobs/send_dpd_job.h68
-rw-r--r--src/charon/queues/jobs/send_keepalive_job.c103
-rw-r--r--src/charon/queues/jobs/send_keepalive_job.h67
-rw-r--r--src/charon/sa/authenticators/authenticator.c56
-rw-r--r--src/charon/sa/authenticators/authenticator.h139
-rw-r--r--src/charon/sa/authenticators/eap/eap_identity.c135
-rw-r--r--src/charon/sa/authenticators/eap/eap_identity.h59
-rw-r--r--src/charon/sa/authenticators/eap/eap_method.c245
-rw-r--r--src/charon/sa/authenticators/eap/eap_method.h242
-rw-r--r--src/charon/sa/authenticators/eap/eap_sim.c703
-rw-r--r--src/charon/sa/authenticators/eap/eap_sim.h141
-rw-r--r--src/charon/sa/authenticators/eap_authenticator.c360
-rw-r--r--src/charon/sa/authenticators/eap_authenticator.h156
-rw-r--r--src/charon/sa/authenticators/psk_authenticator.c204
-rw-r--r--src/charon/sa/authenticators/psk_authenticator.h57
-rw-r--r--src/charon/sa/authenticators/rsa_authenticator.c180
-rw-r--r--src/charon/sa/authenticators/rsa_authenticator.h57
-rw-r--r--src/charon/sa/child_sa.c1130
-rw-r--r--src/charon/sa/child_sa.h298
-rw-r--r--src/charon/sa/ike_sa.c2032
-rw-r--r--src/charon/sa/ike_sa.h649
-rw-r--r--src/charon/sa/ike_sa_id.c215
-rw-r--r--src/charon/sa/ike_sa_id.h147
-rw-r--r--src/charon/sa/ike_sa_manager.c914
-rw-r--r--src/charon/sa/ike_sa_manager.h231
-rw-r--r--src/charon/sa/task_manager.c854
-rw-r--r--src/charon/sa/task_manager.h144
-rw-r--r--src/charon/sa/tasks/child_create.c804
-rw-r--r--src/charon/sa/tasks/child_create.h88
-rw-r--r--src/charon/sa/tasks/child_delete.c292
-rw-r--r--src/charon/sa/tasks/child_delete.h66
-rw-r--r--src/charon/sa/tasks/child_rekey.c346
-rw-r--r--src/charon/sa/tasks/child_rekey.h70
-rw-r--r--src/charon/sa/tasks/ike_auth.c750
-rw-r--r--src/charon/sa/tasks/ike_auth.h64
-rw-r--r--src/charon/sa/tasks/ike_cert.c370
-rw-r--r--src/charon/sa/tasks/ike_cert.h61
-rw-r--r--src/charon/sa/tasks/ike_config.c428
-rw-r--r--src/charon/sa/tasks/ike_config.h59
-rw-r--r--src/charon/sa/tasks/ike_delete.c172
-rw-r--r--src/charon/sa/tasks/ike_delete.h57
-rw-r--r--src/charon/sa/tasks/ike_dpd.c106
-rw-r--r--src/charon/sa/tasks/ike_dpd.h58
-rw-r--r--src/charon/sa/tasks/ike_init.c598
-rw-r--r--src/charon/sa/tasks/ike_init.h68
-rw-r--r--src/charon/sa/tasks/ike_natd.c371
-rw-r--r--src/charon/sa/tasks/ike_natd.h57
-rw-r--r--src/charon/sa/tasks/ike_rekey.c329
-rw-r--r--src/charon/sa/tasks/ike_rekey.h69
-rw-r--r--src/charon/sa/tasks/task.c38
-rw-r--r--src/charon/sa/tasks/task.h151
-rw-r--r--src/charon/threads/kernel_interface.c1964
-rw-r--r--src/charon/threads/kernel_interface.h331
-rw-r--r--src/charon/threads/receiver.c372
-rw-r--r--src/charon/threads/receiver.h81
-rw-r--r--src/charon/threads/scheduler.c102
-rw-r--r--src/charon/threads/scheduler.h68
-rw-r--r--src/charon/threads/sender.c149
-rw-r--r--src/charon/threads/sender.h74
-rwxr-xr-xsrc/charon/threads/stroke_interface.c1456
-rw-r--r--src/charon/threads/stroke_interface.h61
-rw-r--r--src/charon/threads/thread_pool.c181
-rw-r--r--src/charon/threads/thread_pool.h87
-rw-r--r--src/ipsec/Makefile.am16
-rw-r--r--src/ipsec/Makefile.in434
-rw-r--r--src/ipsec/ipsec.8342
-rwxr-xr-xsrc/ipsec/ipsec.in294
-rw-r--r--src/libcrypto/Makefile.am11
-rw-r--r--src/libcrypto/Makefile.in761
-rw-r--r--src/libcrypto/include/cbc_generic.h110
-rw-r--r--src/libcrypto/include/hmac_generic.h60
-rw-r--r--src/libcrypto/include/md32_common.h607
-rw-r--r--src/libcrypto/libaes/aes.c1415
-rw-r--r--src/libcrypto/libaes/aes.h97
-rw-r--r--src/libcrypto/libaes/aes_cbc.c13
-rw-r--r--src/libcrypto/libaes/aes_cbc.h4
-rw-r--r--src/libcrypto/libaes/aes_xcbc_mac.c67
-rw-r--r--src/libcrypto/libaes/aes_xcbc_mac.h12
-rw-r--r--src/libcrypto/libblowfish/bf_enc.c306
-rw-r--r--src/libcrypto/libblowfish/bf_locl.h218
-rw-r--r--src/libcrypto/libblowfish/bf_pi.h325
-rw-r--r--src/libcrypto/libblowfish/bf_skey.c122
-rw-r--r--src/libcrypto/libblowfish/blowfish.h133
-rw-r--r--src/libcrypto/libdes/cbc_enc.c135
-rw-r--r--src/libcrypto/libdes/des.h308
-rw-r--r--src/libcrypto/libdes/des_enc.c502
-rw-r--r--src/libcrypto/libdes/des_locl.h515
-rw-r--r--src/libcrypto/libdes/des_opts.c620
-rw-r--r--src/libcrypto/libdes/des_ver.h60
-rw-r--r--src/libcrypto/libdes/destest.c871
-rw-r--r--src/libcrypto/libdes/ecb_enc.c128
-rw-r--r--src/libcrypto/libdes/fcrypt.c152
-rw-r--r--src/libcrypto/libdes/fcrypt_b.c148
-rw-r--r--src/libcrypto/libdes/podd.h75
-rw-r--r--src/libcrypto/libdes/set_key.c246
-rw-r--r--src/libcrypto/libdes/sk.h204
-rw-r--r--src/libcrypto/libdes/speed.c329
-rw-r--r--src/libcrypto/libdes/spr.h204
-rw-r--r--src/libcrypto/libserpent/serpent.c995
-rw-r--r--src/libcrypto/libserpent/serpent.h17
-rw-r--r--src/libcrypto/libserpent/serpent_cbc.c8
-rw-r--r--src/libcrypto/libserpent/serpent_cbc.h3
-rw-r--r--src/libcrypto/libsha2/hmac_sha2.c32
-rw-r--r--src/libcrypto/libsha2/hmac_sha2.h17
-rw-r--r--src/libcrypto/libsha2/sha2.c437
-rw-r--r--src/libcrypto/libsha2/sha2.h52
-rw-r--r--src/libcrypto/libtwofish/twofish.c861
-rw-r--r--src/libcrypto/libtwofish/twofish.h20
-rw-r--r--src/libcrypto/libtwofish/twofish_cbc.c8
-rw-r--r--src/libcrypto/libtwofish/twofish_cbc.h3
-rw-r--r--src/libfreeswan/Makefile.am19
-rw-r--r--src/libfreeswan/Makefile.in574
-rw-r--r--src/libfreeswan/addrtoa.c68
-rw-r--r--src/libfreeswan/addrtot.c302
-rw-r--r--src/libfreeswan/addrtypeof.c94
-rw-r--r--src/libfreeswan/anyaddr.387
-rw-r--r--src/libfreeswan/anyaddr.c146
-rw-r--r--src/libfreeswan/atoaddr.3294
-rw-r--r--src/libfreeswan/atoaddr.c238
-rw-r--r--src/libfreeswan/atoasr.3186
-rw-r--r--src/libfreeswan/atoasr.c212
-rw-r--r--src/libfreeswan/atosa.3218
-rw-r--r--src/libfreeswan/atosa.c200
-rw-r--r--src/libfreeswan/atosubnet.c216
-rw-r--r--src/libfreeswan/atoul.3161
-rw-r--r--src/libfreeswan/atoul.c90
-rw-r--r--src/libfreeswan/copyright.c56
-rw-r--r--src/libfreeswan/datatot.c233
-rw-r--r--src/libfreeswan/freeswan.h470
-rw-r--r--src/libfreeswan/goodmask.357
-rw-r--r--src/libfreeswan/goodmask.c97
-rw-r--r--src/libfreeswan/initaddr.3129
-rw-r--r--src/libfreeswan/initaddr.c51
-rw-r--r--src/libfreeswan/initsaid.c33
-rw-r--r--src/libfreeswan/initsubnet.3137
-rw-r--r--src/libfreeswan/initsubnet.c95
-rw-r--r--src/libfreeswan/internal.h81
-rw-r--r--src/libfreeswan/ipcomp.h61
-rw-r--r--src/libfreeswan/ipsec_ah.h235
-rw-r--r--src/libfreeswan/ipsec_alg.h254
-rw-r--r--src/libfreeswan/ipsec_encap.h143
-rw-r--r--src/libfreeswan/ipsec_eroute.h103
-rw-r--r--src/libfreeswan/ipsec_errs.h53
-rw-r--r--src/libfreeswan/ipsec_esp.h220
-rw-r--r--src/libfreeswan/ipsec_ipe4.h68
-rw-r--r--src/libfreeswan/ipsec_kversion.h227
-rw-r--r--src/libfreeswan/ipsec_life.h112
-rw-r--r--src/libfreeswan/ipsec_md5h.h140
-rw-r--r--src/libfreeswan/ipsec_param.h226
-rw-r--r--src/libfreeswan/ipsec_policy.h225
-rw-r--r--src/libfreeswan/ipsec_proto.h111
-rw-r--r--src/libfreeswan/ipsec_radij.h63
-rw-r--r--src/libfreeswan/ipsec_rcv.h196
-rw-r--r--src/libfreeswan/ipsec_sa.h338
-rw-r--r--src/libfreeswan/ipsec_sha1.h79
-rw-r--r--src/libfreeswan/ipsec_stats.h38
-rw-r--r--src/libfreeswan/ipsec_tunnel.h265
-rw-r--r--src/libfreeswan/ipsec_xform.h274
-rw-r--r--src/libfreeswan/ipsec_xmit.h140
-rw-r--r--src/libfreeswan/keyblobtoid.3103
-rw-r--r--src/libfreeswan/keyblobtoid.c148
-rw-r--r--src/libfreeswan/optionsfrom.3182
-rw-r--r--src/libfreeswan/optionsfrom.c301
-rw-r--r--src/libfreeswan/pfkey.h498
-rw-r--r--src/libfreeswan/pfkey_v2_build.c1435
-rw-r--r--src/libfreeswan/pfkey_v2_debug.c177
-rw-r--r--src/libfreeswan/pfkey_v2_ext_bits.c789
-rw-r--r--src/libfreeswan/pfkey_v2_parse.c1824
-rw-r--r--src/libfreeswan/pfkeyv2.h375
-rw-r--r--src/libfreeswan/portof.370
-rw-r--r--src/libfreeswan/portof.c96
-rw-r--r--src/libfreeswan/prng.3121
-rw-r--r--src/libfreeswan/prng.c202
-rw-r--r--src/libfreeswan/radij.h280
-rw-r--r--src/libfreeswan/rangetoa.c61
-rw-r--r--src/libfreeswan/rangetosubnet.359
-rw-r--r--src/libfreeswan/rangetosubnet.c226
-rw-r--r--src/libfreeswan/sameaddr.3165
-rw-r--r--src/libfreeswan/sameaddr.c190
-rw-r--r--src/libfreeswan/satoa.c102
-rw-r--r--src/libfreeswan/satot.c132
-rw-r--r--src/libfreeswan/subnetof.347
-rw-r--r--src/libfreeswan/subnetof.c60
-rw-r--r--src/libfreeswan/subnettoa.c62
-rw-r--r--src/libfreeswan/subnettot.c56
-rw-r--r--src/libfreeswan/subnettypeof.c109
-rw-r--r--src/libfreeswan/ttoaddr.3377
-rw-r--r--src/libfreeswan/ttoaddr.c426
-rw-r--r--src/libfreeswan/ttodata.3281
-rw-r--r--src/libfreeswan/ttodata.c722
-rw-r--r--src/libfreeswan/ttoprotoport.c103
-rw-r--r--src/libfreeswan/ttosa.3288
-rw-r--r--src/libfreeswan/ttosa.c280
-rw-r--r--src/libfreeswan/ttosubnet.c296
-rw-r--r--src/libfreeswan/ttoul.3192
-rw-r--r--src/libfreeswan/ttoul.c91
-rw-r--r--src/libfreeswan/ultoa.c67
-rw-r--r--src/libfreeswan/ultot.c83
-rw-r--r--src/libfreeswan/version.344
-rw-r--r--src/libfreeswan/version.c43
-rw-r--r--src/libstrongswan/Makefile.am69
-rw-r--r--src/libstrongswan/Makefile.in820
-rw-r--r--src/libstrongswan/asn1/asn1.c733
-rw-r--r--src/libstrongswan/asn1/asn1.h135
-rw-r--r--src/libstrongswan/asn1/oid.c197
-rw-r--r--src/libstrongswan/asn1/oid.h80
-rw-r--r--src/libstrongswan/asn1/oid.pl127
-rw-r--r--src/libstrongswan/asn1/oid.txt184
-rwxr-xr-xsrc/libstrongswan/asn1/pem.c366
-rwxr-xr-xsrc/libstrongswan/asn1/pem.h27
-rw-r--r--src/libstrongswan/asn1/ttodata.c378
-rw-r--r--src/libstrongswan/asn1/ttodata.h28
-rw-r--r--src/libstrongswan/chunk.c410
-rw-r--r--src/libstrongswan/chunk.h154
-rwxr-xr-xsrc/libstrongswan/credential_store.h294
-rw-r--r--src/libstrongswan/crypto/ca.c788
-rw-r--r--src/libstrongswan/crypto/ca.h215
-rw-r--r--src/libstrongswan/crypto/certinfo.c305
-rw-r--r--src/libstrongswan/crypto/certinfo.h203
-rwxr-xr-xsrc/libstrongswan/crypto/crl.c533
-rwxr-xr-xsrc/libstrongswan/crypto/crl.h147
-rw-r--r--src/libstrongswan/crypto/crypters/aes_cbc_crypter.c1620
-rw-r--r--src/libstrongswan/crypto/crypters/aes_cbc_crypter.h61
-rw-r--r--src/libstrongswan/crypto/crypters/crypter.c68
-rw-r--r--src/libstrongswan/crypto/crypters/crypter.h155
-rw-r--r--src/libstrongswan/crypto/crypters/des_crypter.c1535
-rw-r--r--src/libstrongswan/crypto/crypters/des_crypter.h58
-rw-r--r--src/libstrongswan/crypto/diffie_hellman.c612
-rw-r--r--src/libstrongswan/crypto/diffie_hellman.h147
-rw-r--r--src/libstrongswan/crypto/hashers/hasher.c65
-rw-r--r--src/libstrongswan/crypto/hashers/hasher.h159
-rw-r--r--src/libstrongswan/crypto/hashers/md5_hasher.c405
-rw-r--r--src/libstrongswan/crypto/hashers/md5_hasher.h60
-rw-r--r--src/libstrongswan/crypto/hashers/sha1_hasher.c280
-rw-r--r--src/libstrongswan/crypto/hashers/sha1_hasher.h60
-rw-r--r--src/libstrongswan/crypto/hashers/sha2_hasher.c672
-rw-r--r--src/libstrongswan/crypto/hashers/sha2_hasher.h62
-rw-r--r--src/libstrongswan/crypto/hmac.c215
-rw-r--r--src/libstrongswan/crypto/hmac.h117
-rw-r--r--src/libstrongswan/crypto/ocsp.c924
-rw-r--r--src/libstrongswan/crypto/ocsp.h86
-rw-r--r--src/libstrongswan/crypto/prf_plus.c156
-rw-r--r--src/libstrongswan/crypto/prf_plus.h92
-rw-r--r--src/libstrongswan/crypto/prfs/fips_prf.c258
-rw-r--r--src/libstrongswan/crypto/prfs/fips_prf.h80
-rw-r--r--src/libstrongswan/crypto/prfs/hmac_prf.c118
-rw-r--r--src/libstrongswan/crypto/prfs/hmac_prf.h65
-rw-r--r--src/libstrongswan/crypto/prfs/prf.c70
-rw-r--r--src/libstrongswan/crypto/prfs/prf.h142
-rw-r--r--src/libstrongswan/crypto/rsa/rsa_private_key.c774
-rw-r--r--src/libstrongswan/crypto/rsa/rsa_private_key.h184
-rw-r--r--src/libstrongswan/crypto/rsa/rsa_public_key.c497
-rw-r--r--src/libstrongswan/crypto/rsa/rsa_public_key.h164
-rw-r--r--src/libstrongswan/crypto/signers/hmac_signer.c174
-rw-r--r--src/libstrongswan/crypto/signers/hmac_signer.h68
-rw-r--r--src/libstrongswan/crypto/signers/signer.c65
-rw-r--r--src/libstrongswan/crypto/signers/signer.h147
-rwxr-xr-xsrc/libstrongswan/crypto/x509.c1354
-rwxr-xr-xsrc/libstrongswan/crypto/x509.h290
-rw-r--r--src/libstrongswan/debug.c41
-rw-r--r--src/libstrongswan/debug.h60
-rw-r--r--src/libstrongswan/enum.c73
-rw-r--r--src/libstrongswan/enum.h106
-rw-r--r--src/libstrongswan/library.c184
-rw-r--r--src/libstrongswan/library.h301
-rw-r--r--src/libstrongswan/printf_hook.c118
-rw-r--r--src/libstrongswan/printf_hook.h76
-rw-r--r--src/libstrongswan/utils/fetcher.c421
-rw-r--r--src/libstrongswan/utils/fetcher.h95
-rw-r--r--src/libstrongswan/utils/host.c526
-rw-r--r--src/libstrongswan/utils/host.h231
-rw-r--r--src/libstrongswan/utils/identification.c1144
-rw-r--r--src/libstrongswan/utils/identification.h261
-rw-r--r--src/libstrongswan/utils/iterator.h166
-rw-r--r--src/libstrongswan/utils/leak_detective.c459
-rw-r--r--src/libstrongswan/utils/leak_detective.h35
-rw-r--r--src/libstrongswan/utils/lexparser.c137
-rw-r--r--src/libstrongswan/utils/lexparser.h57
-rw-r--r--src/libstrongswan/utils/linked_list.c763
-rw-r--r--src/libstrongswan/utils/linked_list.h232
-rw-r--r--src/libstrongswan/utils/randomizer.c165
-rw-r--r--src/libstrongswan/utils/randomizer.h114
-rw-r--r--src/openac/Makefile.am98
-rw-r--r--src/openac/Makefile.in624
-rw-r--r--src/openac/build.c242
-rw-r--r--src/openac/build.h47
-rw-r--r--src/openac/loglite.c295
-rw-r--r--src/openac/openac.8180
-rwxr-xr-xsrc/openac/openac.c438
-rw-r--r--src/pluto/Makefile.am140
-rw-r--r--src/pluto/Makefile.in878
-rw-r--r--src/pluto/TODO129
-rw-r--r--src/pluto/ac.c1018
-rw-r--r--src/pluto/ac.h103
-rw-r--r--src/pluto/adns.c615
-rw-r--r--src/pluto/adns.h75
-rw-r--r--src/pluto/alg/ike_alg_aes.c68
-rw-r--r--src/pluto/alg/ike_alg_blowfish.c52
-rw-r--r--src/pluto/alg/ike_alg_serpent.c70
-rw-r--r--src/pluto/alg/ike_alg_sha2.c634
-rw-r--r--src/pluto/alg/ike_alg_twofish.c85
-rw-r--r--src/pluto/alg/ike_alginit.c7
-rw-r--r--src/pluto/alg_info.c1205
-rw-r--r--src/pluto/alg_info.h85
-rw-r--r--src/pluto/asn1.c770
-rw-r--r--src/pluto/asn1.h141
-rw-r--r--src/pluto/ca.c694
-rw-r--r--src/pluto/ca.h70
-rw-r--r--src/pluto/certs.c287
-rw-r--r--src/pluto/certs.h80
-rw-r--r--src/pluto/connections.c4406
-rw-r--r--src/pluto/connections.h367
-rw-r--r--src/pluto/constants.c1353
-rw-r--r--src/pluto/constants.h1269
-rw-r--r--src/pluto/cookie.c67
-rw-r--r--src/pluto/cookie.h24
-rw-r--r--src/pluto/crl.c763
-rw-r--r--src/pluto/crl.h87
-rw-r--r--src/pluto/crypto.c627
-rw-r--r--src/pluto/crypto.h108
-rw-r--r--src/pluto/db_ops.c439
-rw-r--r--src/pluto/db_ops.h56
-rw-r--r--src/pluto/defs.c374
-rw-r--r--src/pluto/defs.h145
-rw-r--r--src/pluto/demux.c2499
-rw-r--r--src/pluto/demux.h93
-rw-r--r--src/pluto/dnskey.c1962
-rw-r--r--src/pluto/dnskey.h84
-rw-r--r--src/pluto/dsa.c476
-rw-r--r--src/pluto/dsa.h32
-rw-r--r--src/pluto/elgamal.c613
-rw-r--r--src/pluto/elgamal.h35
-rw-r--r--src/pluto/fetch.c1081
-rw-r--r--src/pluto/fetch.h79
-rw-r--r--src/pluto/foodgroups.c462
-rw-r--r--src/pluto/foodgroups.h24
-rw-r--r--src/pluto/gcryptfix.c283
-rw-r--r--src/pluto/gcryptfix.h111
-rw-r--r--src/pluto/id.c509
-rw-r--r--src/pluto/id.h67
-rw-r--r--src/pluto/ike_alg.c592
-rw-r--r--src/pluto/ike_alg.h94
-rw-r--r--src/pluto/ipsec.secrets.5175
-rw-r--r--src/pluto/ipsec_doi.c5630
-rw-r--r--src/pluto/ipsec_doi.h104
-rw-r--r--src/pluto/kameipsec.h47
-rw-r--r--src/pluto/kernel.c2995
-rw-r--r--src/pluto/kernel.h198
-rw-r--r--src/pluto/kernel_alg.c775
-rw-r--r--src/pluto/kernel_alg.h46
-rw-r--r--src/pluto/kernel_netlink.c1219
-rw-r--r--src/pluto/kernel_netlink.h20
-rw-r--r--src/pluto/kernel_noklips.c126
-rw-r--r--src/pluto/kernel_noklips.h19
-rw-r--r--src/pluto/kernel_pfkey.c926
-rw-r--r--src/pluto/kernel_pfkey.h23
-rw-r--r--src/pluto/keys.c1514
-rw-r--r--src/pluto/keys.h113
-rw-r--r--src/pluto/lex.c213
-rw-r--r--src/pluto/lex.h52
-rw-r--r--src/pluto/linux26/netlink.h90
-rw-r--r--src/pluto/linux26/rtnetlink.h562
-rw-r--r--src/pluto/linux26/xfrm.h233
-rw-r--r--src/pluto/log.c841
-rw-r--r--src/pluto/log.h236
-rw-r--r--src/pluto/md2.c237
-rw-r--r--src/pluto/md2.h72
-rw-r--r--src/pluto/md5.c385
-rw-r--r--src/pluto/md5.h75
-rw-r--r--src/pluto/modecfg.c1078
-rw-r--r--src/pluto/modecfg.h47
-rw-r--r--src/pluto/mp_defs.c70
-rw-r--r--src/pluto/mp_defs.h36
-rw-r--r--src/pluto/nat_traversal.c866
-rw-r--r--src/pluto/nat_traversal.h154
-rw-r--r--src/pluto/ocsp.c1568
-rw-r--r--src/pluto/ocsp.h85
-rw-r--r--src/pluto/oid.c197
-rw-r--r--src/pluto/oid.h78
-rw-r--r--src/pluto/oid.pl123
-rw-r--r--src/pluto/oid.txt184
-rw-r--r--src/pluto/packet.c1244
-rw-r--r--src/pluto/packet.h655
-rw-r--r--src/pluto/pem.c463
-rw-r--r--src/pluto/pem.h18
-rw-r--r--src/pluto/pgp.c647
-rw-r--r--src/pluto/pgp.h54
-rw-r--r--src/pluto/pkcs1.c674
-rw-r--r--src/pluto/pkcs1.h88
-rw-r--r--src/pluto/pkcs7.c862
-rw-r--r--src/pluto/pkcs7.h51
-rw-r--r--src/pluto/pluto.81649
-rw-r--r--src/pluto/plutomain.c655
-rw-r--r--src/pluto/primegen.c593
-rw-r--r--src/pluto/rcv_whack.c685
-rw-r--r--src/pluto/rcv_whack.h17
-rw-r--r--src/pluto/rnd.c250
-rw-r--r--src/pluto/rnd.h21
-rw-r--r--src/pluto/rsaref/pkcs11.h299
-rw-r--r--src/pluto/rsaref/pkcs11f.h912
-rw-r--r--src/pluto/rsaref/pkcs11t.h1685
-rw-r--r--src/pluto/rsaref/unix.h24
-rw-r--r--src/pluto/server.c996
-rw-r--r--src/pluto/server.h58
-rw-r--r--src/pluto/sha1.c193
-rw-r--r--src/pluto/sha1.h16
-rw-r--r--src/pluto/smallprime.c122
-rw-r--r--src/pluto/smartcard.c1956
-rw-r--r--src/pluto/smartcard.h100
-rw-r--r--src/pluto/spdb.c2314
-rw-r--r--src/pluto/spdb.h112
-rw-r--r--src/pluto/state.c1012
-rw-r--r--src/pluto/state.h273
-rw-r--r--src/pluto/timer.c532
-rw-r--r--src/pluto/timer.h34
-rw-r--r--src/pluto/vendor.c528
-rw-r--r--src/pluto/vendor.h131
-rw-r--r--src/pluto/virtual.c334
-rw-r--r--src/pluto/virtual.h31
-rw-r--r--src/pluto/x509.c2241
-rw-r--r--src/pluto/x509.h138
-rw-r--r--src/pluto/xauth.c79
-rw-r--r--src/pluto/xauth.h41
-rw-r--r--src/scepclient/Makefile.am103
-rw-r--r--src/scepclient/Makefile.in630
-rw-r--r--src/scepclient/pkcs10.c220
-rw-r--r--src/scepclient/pkcs10.h57
-rw-r--r--src/scepclient/rsakey.c349
-rw-r--r--src/scepclient/rsakey.h31
-rw-r--r--src/scepclient/scep.c598
-rw-r--r--src/scepclient/scep.h93
-rw-r--r--src/scepclient/scepclient.8288
-rw-r--r--src/scepclient/scepclient.c1036
-rw-r--r--src/starter/Makefile.am37
-rw-r--r--src/starter/Makefile.in581
-rw-r--r--src/starter/README104
-rw-r--r--src/starter/args.c632
-rw-r--r--src/starter/args.h34
-rw-r--r--src/starter/cmp.c105
-rw-r--r--src/starter/cmp.h29
-rw-r--r--src/starter/confread.c936
-rw-r--r--src/starter/confread.h210
-rw-r--r--src/starter/exec.c54
-rw-r--r--src/starter/exec.h23
-rw-r--r--src/starter/files.h40
-rw-r--r--src/starter/interfaces.c595
-rw-r--r--src/starter/interfaces.h41
-rw-r--r--src/starter/invokecharon.c251
-rw-r--r--src/starter/invokecharon.h31
-rw-r--r--src/starter/invokepluto.c286
-rw-r--r--src/starter/invokepluto.h28
-rw-r--r--src/starter/ipsec.conf42
-rw-r--r--src/starter/ipsec.conf.51062
-rw-r--r--src/starter/keywords.c261
-rw-r--r--src/starter/keywords.h176
-rw-r--r--src/starter/keywords.txt118
-rw-r--r--src/starter/lex.yy.c1966
-rw-r--r--src/starter/netkey.c85
-rw-r--r--src/starter/netkey.h24
-rw-r--r--src/starter/parser.h57
-rw-r--r--src/starter/parser.l190
-rw-r--r--src/starter/parser.y283
-rw-r--r--src/starter/starter.c643
-rw-r--r--src/starter/starterstroke.c295
-rw-r--r--src/starter/starterstroke.h29
-rw-r--r--src/starter/starterwhack.c369
-rw-r--r--src/starter/starterwhack.h32
-rw-r--r--src/starter/y.tab.c1832
-rw-r--r--src/starter/y.tab.h82
-rw-r--r--src/stroke/Makefile.am9
-rw-r--r--src/stroke/Makefile.in483
-rw-r--r--src/stroke/stroke.c421
-rw-r--r--src/stroke/stroke.h226
-rw-r--r--src/stroke/stroke_keywords.c179
-rw-r--r--src/stroke/stroke_keywords.h55
-rw-r--r--src/stroke/stroke_keywords.txt50
-rw-r--r--src/whack/Makefile.am8
-rw-r--r--src/whack/Makefile.in478
-rw-r--r--src/whack/whack.c1905
-rw-r--r--src/whack/whack.h318
603 files changed, 199836 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 000000000..a3f90f39e
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = libfreeswan libcrypto libstrongswan pluto whack charon stroke starter openac scepclient ipsec _updown _updown_espmark _copyright
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 000000000..6fa95d413
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,497 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_CLEAN_FILES =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+ html-recursive info-recursive install-data-recursive \
+ install-exec-recursive install-info-recursive \
+ install-recursive installcheck-recursive installdirs-recursive \
+ pdf-recursive ps-recursive uninstall-info-recursive \
+ uninstall-recursive
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_EAP_SIM_FALSE = @BUILD_EAP_SIM_FALSE@
+BUILD_EAP_SIM_TRUE = @BUILD_EAP_SIM_TRUE@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GPERF = @GPERF@
+GREP = @GREP@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+USE_CISCO_QUIRKS_FALSE = @USE_CISCO_QUIRKS_FALSE@
+USE_CISCO_QUIRKS_TRUE = @USE_CISCO_QUIRKS_TRUE@
+USE_LEAK_DETECTIVE_FALSE = @USE_LEAK_DETECTIVE_FALSE@
+USE_LEAK_DETECTIVE_TRUE = @USE_LEAK_DETECTIVE_TRUE@
+USE_LIBCURL_FALSE = @USE_LIBCURL_FALSE@
+USE_LIBCURL_TRUE = @USE_LIBCURL_TRUE@
+USE_LIBLDAP_FALSE = @USE_LIBLDAP_FALSE@
+USE_LIBLDAP_TRUE = @USE_LIBLDAP_TRUE@
+USE_NAT_TRANSPORT_FALSE = @USE_NAT_TRANSPORT_FALSE@
+USE_NAT_TRANSPORT_TRUE = @USE_NAT_TRANSPORT_TRUE@
+USE_SMARTCARD_FALSE = @USE_SMARTCARD_FALSE@
+USE_SMARTCARD_TRUE = @USE_SMARTCARD_TRUE@
+USE_VENDORID_FALSE = @USE_VENDORID_FALSE@
+USE_VENDORID_TRUE = @USE_VENDORID_TRUE@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+confdir = @confdir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+eapdir = @eapdir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+ipsecdir = @ipsecdir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+piddir = @piddir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+SUBDIRS = libfreeswan libcrypto libstrongswan pluto whack charon stroke starter openac scepclient ipsec _updown _updown_espmark _copyright
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+ list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d "$(distdir)/$$subdir" \
+ || $(mkdir_p) "$(distdir)/$$subdir" \
+ || exit 1; \
+ distdir=`$(am__cd) $(distdir) && pwd`; \
+ top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
+ (cd $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$top_distdir" \
+ distdir="$$distdir/$$subdir" \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-libtool \
+ distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-recursive
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-info-am
+
+uninstall-info: uninstall-info-recursive
+
+.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am \
+ clean clean-generic clean-libtool clean-recursive ctags \
+ ctags-recursive distclean distclean-generic distclean-libtool \
+ distclean-recursive distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-exec install-exec-am install-info \
+ install-info-am install-man install-strip installcheck \
+ installcheck-am installdirs installdirs-am maintainer-clean \
+ maintainer-clean-generic maintainer-clean-recursive \
+ mostlyclean mostlyclean-generic mostlyclean-libtool \
+ mostlyclean-recursive pdf pdf-am ps ps-am tags tags-recursive \
+ uninstall uninstall-am uninstall-info-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/_copyright/Makefile.am b/src/_copyright/Makefile.am
new file mode 100644
index 000000000..d8dcfb3f1
--- /dev/null
+++ b/src/_copyright/Makefile.am
@@ -0,0 +1,6 @@
+ipsec_PROGRAMS = _copyright
+_copyright_SOURCES = _copyright.c
+dist_man8_MANS = _copyright.8
+
+INCLUDES = -I$(top_srcdir)/src/libfreeswan
+_copyright_LDADD = $(top_srcdir)/src/libfreeswan/libfreeswan.a
diff --git a/src/_copyright/Makefile.in b/src/_copyright/Makefile.in
new file mode 100644
index 000000000..7e78b9185
--- /dev/null
+++ b/src/_copyright/Makefile.in
@@ -0,0 +1,529 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+ipsec_PROGRAMS = _copyright$(EXEEXT)
+subdir = src/_copyright
+DIST_COMMON = $(dist_man8_MANS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_CLEAN_FILES =
+am__installdirs = "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(man8dir)"
+ipsecPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(ipsec_PROGRAMS)
+am__copyright_OBJECTS = _copyright.$(OBJEXT)
+_copyright_OBJECTS = $(am__copyright_OBJECTS)
+_copyright_DEPENDENCIES = $(top_srcdir)/src/libfreeswan/libfreeswan.a
+DEFAULT_INCLUDES = -I. -I$(srcdir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(_copyright_SOURCES)
+DIST_SOURCES = $(_copyright_SOURCES)
+man8dir = $(mandir)/man8
+NROFF = nroff
+MANS = $(dist_man8_MANS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_EAP_SIM_FALSE = @BUILD_EAP_SIM_FALSE@
+BUILD_EAP_SIM_TRUE = @BUILD_EAP_SIM_TRUE@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GPERF = @GPERF@
+GREP = @GREP@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+USE_CISCO_QUIRKS_FALSE = @USE_CISCO_QUIRKS_FALSE@
+USE_CISCO_QUIRKS_TRUE = @USE_CISCO_QUIRKS_TRUE@
+USE_LEAK_DETECTIVE_FALSE = @USE_LEAK_DETECTIVE_FALSE@
+USE_LEAK_DETECTIVE_TRUE = @USE_LEAK_DETECTIVE_TRUE@
+USE_LIBCURL_FALSE = @USE_LIBCURL_FALSE@
+USE_LIBCURL_TRUE = @USE_LIBCURL_TRUE@
+USE_LIBLDAP_FALSE = @USE_LIBLDAP_FALSE@
+USE_LIBLDAP_TRUE = @USE_LIBLDAP_TRUE@
+USE_NAT_TRANSPORT_FALSE = @USE_NAT_TRANSPORT_FALSE@
+USE_NAT_TRANSPORT_TRUE = @USE_NAT_TRANSPORT_TRUE@
+USE_SMARTCARD_FALSE = @USE_SMARTCARD_FALSE@
+USE_SMARTCARD_TRUE = @USE_SMARTCARD_TRUE@
+USE_VENDORID_FALSE = @USE_VENDORID_FALSE@
+USE_VENDORID_TRUE = @USE_VENDORID_TRUE@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+confdir = @confdir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+eapdir = @eapdir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+ipsecdir = @ipsecdir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+piddir = @piddir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+_copyright_SOURCES = _copyright.c
+dist_man8_MANS = _copyright.8
+INCLUDES = -I$(top_srcdir)/src/libfreeswan
+_copyright_LDADD = $(top_srcdir)/src/libfreeswan/libfreeswan.a
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/_copyright/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/_copyright/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-ipsecPROGRAMS: $(ipsec_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(ipsecdir)" || $(mkdir_p) "$(DESTDIR)$(ipsecdir)"
+ @list='$(ipsec_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ || test -f $$p1 \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(ipsecPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(ipsecdir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(ipsecPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(ipsecdir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-ipsecPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(ipsec_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(ipsecdir)/$$f'"; \
+ rm -f "$(DESTDIR)$(ipsecdir)/$$f"; \
+ done
+
+clean-ipsecPROGRAMS:
+ @list='$(ipsec_PROGRAMS)'; for p in $$list; do \
+ f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f $$p $$f"; \
+ rm -f $$p $$f ; \
+ done
+_copyright$(EXEEXT): $(_copyright_OBJECTS) $(_copyright_DEPENDENCIES)
+ @rm -f _copyright$(EXEEXT)
+ $(LINK) $(_copyright_LDFLAGS) $(_copyright_OBJECTS) $(_copyright_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_copyright.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+install-man8: $(man8_MANS) $(man_MANS)
+ @$(NORMAL_INSTALL)
+ test -z "$(man8dir)" || $(mkdir_p) "$(DESTDIR)$(man8dir)"
+ @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 8*) ;; \
+ *) ext='8' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst"; \
+ done
+uninstall-man8:
+ @$(NORMAL_UNINSTALL)
+ @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 8*) ;; \
+ *) ext='8' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f '$(DESTDIR)$(man8dir)/$$inst'"; \
+ rm -f "$(DESTDIR)$(man8dir)/$$inst"; \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS) $(MANS)
+installdirs:
+ for dir in "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(man8dir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-ipsecPROGRAMS clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-ipsecPROGRAMS install-man
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man: install-man8
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-ipsecPROGRAMS uninstall-man
+
+uninstall-man: uninstall-man8
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-ipsecPROGRAMS clean-libtool ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am \
+ install-ipsecPROGRAMS install-man install-man8 install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-info-am \
+ uninstall-ipsecPROGRAMS uninstall-man uninstall-man8
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/_copyright/_copyright.8 b/src/_copyright/_copyright.8
new file mode 100644
index 000000000..87e4adc98
--- /dev/null
+++ b/src/_copyright/_copyright.8
@@ -0,0 +1,32 @@
+.TH _COPYRIGHT 8 "25 Apr 2002"
+.\"
+.\" RCSID $Id: _copyright.8,v 1.1 2004/03/15 20:35:27 as Exp $
+.\"
+.SH NAME
+ipsec _copyright \- prints FreeSWAN copyright
+.SH DESCRIPTION
+.I _copyright
+outputs the FreeSWAN copyright, and version numbers for "ipsec --copyright"
+.SH "SEE ALSO"
+ipsec(8)
+.SH HISTORY
+Man page written for the Linux FreeS/WAN project
+<http://www.freeswan.org/>
+by Michael Richardson. Program written by Henry Spencer.
+.\"
+.\" $Log: _copyright.8,v $
+.\" Revision 1.1 2004/03/15 20:35:27 as
+.\" added files from freeswan-2.04-x509-1.5.3
+.\"
+.\" Revision 1.2 2002/04/29 22:39:31 mcr
+.\" added basic man page for all internal commands.
+.\"
+.\" Revision 1.1 2002/04/26 01:21:43 mcr
+.\" while tracking down a missing (not installed) /etc/ipsec.conf,
+.\" MCR has decided that it is not okay for each program subdir to have
+.\" some subset (determined with -f) of possible files.
+.\" Each subdir that defines $PROGRAM, MUST have a PROGRAM.8 file as well as a PROGRAM file.
+.\" Optional PROGRAM.5 files have been added to the makefiles.
+.\"
+.\"
+.\"
diff --git a/src/_copyright/_copyright.c b/src/_copyright/_copyright.c
new file mode 100644
index 000000000..0fb360f40
--- /dev/null
+++ b/src/_copyright/_copyright.c
@@ -0,0 +1,69 @@
+/*
+ * copyright reporter
+ * (just avoids having the info in more than one place in the source)
+ * Copyright (C) 2001 Henry Spencer.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: _copyright.c,v 1.1 2004/03/15 20:35:27 as Exp $
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <freeswan.h>
+
+char usage[] = "Usage: ipsec _copyright";
+struct option opts[] = {
+ {"help", 0, NULL, 'h',},
+ {"version", 0, NULL, 'v',},
+ {0, 0, NULL, 0, },
+};
+
+char me[] = "ipsec _copyright"; /* for messages */
+
+int
+main(int argc, char *argv[])
+{
+ int opt;
+ extern int optind;
+ int errflg = 0;
+ const char *version = ipsec_version_code();
+ const char **notice = ipsec_copyright_notice();
+ const char **co;
+
+ while ((opt = getopt_long(argc, argv, "", opts, NULL)) != EOF)
+ switch (opt) {
+ case 'h': /* help */
+ printf("%s\n", usage);
+ exit(0);
+ break;
+ case 'v': /* version */
+ printf("%s %s\n", me, version);
+ exit(0);
+ break;
+ case '?':
+ default:
+ errflg = 1;
+ break;
+ }
+ if (errflg || optind != argc) {
+ fprintf(stderr, "%s\n", usage);
+ exit(2);
+ }
+
+ for (co = notice; *co != NULL; co++)
+ printf("%s\n", *co);
+ exit(0);
+}
diff --git a/src/_updown/Makefile.am b/src/_updown/Makefile.am
new file mode 100644
index 000000000..27a467c4f
--- /dev/null
+++ b/src/_updown/Makefile.am
@@ -0,0 +1,3 @@
+dist_ipsec_SCRIPTS = _updown
+dist_man8_MANS = _updown.8
+
diff --git a/src/_updown/Makefile.in b/src/_updown/Makefile.in
new file mode 100644
index 000000000..ccb176fbc
--- /dev/null
+++ b/src/_updown/Makefile.in
@@ -0,0 +1,421 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/_updown
+DIST_COMMON = $(dist_ipsec_SCRIPTS) $(dist_man8_MANS) \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_CLEAN_FILES =
+am__installdirs = "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(man8dir)"
+dist_ipsecSCRIPT_INSTALL = $(INSTALL_SCRIPT)
+SCRIPTS = $(dist_ipsec_SCRIPTS)
+SOURCES =
+DIST_SOURCES =
+man8dir = $(mandir)/man8
+NROFF = nroff
+MANS = $(dist_man8_MANS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_EAP_SIM_FALSE = @BUILD_EAP_SIM_FALSE@
+BUILD_EAP_SIM_TRUE = @BUILD_EAP_SIM_TRUE@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GPERF = @GPERF@
+GREP = @GREP@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+USE_CISCO_QUIRKS_FALSE = @USE_CISCO_QUIRKS_FALSE@
+USE_CISCO_QUIRKS_TRUE = @USE_CISCO_QUIRKS_TRUE@
+USE_LEAK_DETECTIVE_FALSE = @USE_LEAK_DETECTIVE_FALSE@
+USE_LEAK_DETECTIVE_TRUE = @USE_LEAK_DETECTIVE_TRUE@
+USE_LIBCURL_FALSE = @USE_LIBCURL_FALSE@
+USE_LIBCURL_TRUE = @USE_LIBCURL_TRUE@
+USE_LIBLDAP_FALSE = @USE_LIBLDAP_FALSE@
+USE_LIBLDAP_TRUE = @USE_LIBLDAP_TRUE@
+USE_NAT_TRANSPORT_FALSE = @USE_NAT_TRANSPORT_FALSE@
+USE_NAT_TRANSPORT_TRUE = @USE_NAT_TRANSPORT_TRUE@
+USE_SMARTCARD_FALSE = @USE_SMARTCARD_FALSE@
+USE_SMARTCARD_TRUE = @USE_SMARTCARD_TRUE@
+USE_VENDORID_FALSE = @USE_VENDORID_FALSE@
+USE_VENDORID_TRUE = @USE_VENDORID_TRUE@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+confdir = @confdir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+eapdir = @eapdir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+ipsecdir = @ipsecdir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+piddir = @piddir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+dist_ipsec_SCRIPTS = _updown
+dist_man8_MANS = _updown.8
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/_updown/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/_updown/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-dist_ipsecSCRIPTS: $(dist_ipsec_SCRIPTS)
+ @$(NORMAL_INSTALL)
+ test -z "$(ipsecdir)" || $(mkdir_p) "$(DESTDIR)$(ipsecdir)"
+ @list='$(dist_ipsec_SCRIPTS)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ if test -f $$d$$p; then \
+ f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
+ echo " $(dist_ipsecSCRIPT_INSTALL) '$$d$$p' '$(DESTDIR)$(ipsecdir)/$$f'"; \
+ $(dist_ipsecSCRIPT_INSTALL) "$$d$$p" "$(DESTDIR)$(ipsecdir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-dist_ipsecSCRIPTS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_ipsec_SCRIPTS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
+ echo " rm -f '$(DESTDIR)$(ipsecdir)/$$f'"; \
+ rm -f "$(DESTDIR)$(ipsecdir)/$$f"; \
+ done
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+install-man8: $(man8_MANS) $(man_MANS)
+ @$(NORMAL_INSTALL)
+ test -z "$(man8dir)" || $(mkdir_p) "$(DESTDIR)$(man8dir)"
+ @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 8*) ;; \
+ *) ext='8' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst"; \
+ done
+uninstall-man8:
+ @$(NORMAL_UNINSTALL)
+ @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 8*) ;; \
+ *) ext='8' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f '$(DESTDIR)$(man8dir)/$$inst'"; \
+ rm -f "$(DESTDIR)$(man8dir)/$$inst"; \
+ done
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(SCRIPTS) $(MANS)
+installdirs:
+ for dir in "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(man8dir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-libtool
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-dist_ipsecSCRIPTS install-man
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man: install-man8
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-dist_ipsecSCRIPTS uninstall-info-am \
+ uninstall-man
+
+uninstall-man: uninstall-man8
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ distclean distclean-generic distclean-libtool distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dist_ipsecSCRIPTS \
+ install-exec install-exec-am install-info install-info-am \
+ install-man install-man8 install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am \
+ uninstall-dist_ipsecSCRIPTS uninstall-info-am uninstall-man \
+ uninstall-man8
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/_updown/_updown b/src/_updown/_updown
new file mode 100755
index 000000000..8db74f737
--- /dev/null
+++ b/src/_updown/_updown
@@ -0,0 +1,503 @@
+#! /bin/sh
+# iproute2 version, default updown script
+#
+# Copyright (C) 2003-2004 Nigel Meteringham
+# Copyright (C) 2003-2004 Tuomo Soini
+# Copyright (C) 2002-2004 Michael Richardson
+# Copyright (C) 2005-2006 Andreas Steffen <andreas.steffen@strongswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT 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: _updown.in,v 1.2 2006/04/17 15:06:29 as Exp $
+
+# CAUTION: Installing a new version of strongSwan will install a new
+# copy of this script, wiping out any custom changes you make. If
+# you need changes, make a copy of this under another name, and customize
+# that, and use the (left/right)updown parameters in ipsec.conf to make
+# strongSwan use yours instead of this default one.
+
+# things that this script gets (from ipsec_pluto(8) man page)
+#
+# PLUTO_VERSION
+# indicates what version of this interface is being
+# used. This document describes version 1.1. This
+# is upwardly compatible with version 1.0.
+#
+# PLUTO_VERB
+# specifies the name of the operation to be performed
+# (prepare-host, prepare-client, up-host, up-client,
+# down-host, or down-client). If the address family
+# for security gateway to security gateway communica­
+# tions is IPv6, then a suffix of -v6 is added to the
+# verb.
+#
+# PLUTO_CONNECTION
+# is the name of the connection for which we are
+# routing.
+#
+# PLUTO_NEXT_HOP
+# is the next hop to which packets bound for the peer
+# must be sent.
+#
+# PLUTO_INTERFACE
+# is the name of the ipsec interface to be used.
+#
+# PLUTO_REQID
+# is the requid of the ESP policy
+#
+# PLUTO_ME
+# is the IP address of our host.
+#
+# PLUTO_MY_ID
+# is the ID of our host.
+#
+# PLUTO_MY_CLIENT
+# is the IP address / count of our client subnet. If
+# the client is just the host, this will be the
+# host's own IP address / max (where max is 32 for
+# IPv4 and 128 for IPv6).
+#
+# PLUTO_MY_CLIENT_NET
+# is the IP address of our client net. If the client
+# is just the host, this will be the host's own IP
+# address.
+#
+# PLUTO_MY_CLIENT_MASK
+# is the mask for our client net. If the client is
+# just the host, this will be 255.255.255.255.
+#
+# PLUTO_MY_SOURCEIP
+# if non-empty, then the source address for the route will be
+# set to this IP address.
+#
+# PLUTO_MY_PROTOCOL
+# is the IP protocol that will be transported.
+#
+# PLUTO_MY_PORT
+# is the UDP/TCP port to which the IPsec SA is
+# restricted on our side.
+#
+# PLUTO_PEER
+# is the IP address of our peer.
+#
+# PLUTO_PEER_ID
+# is the ID of our peer.
+#
+# PLUTO_PEER_CA
+# is the CA which issued the cert of our peer.
+#
+# PLUTO_PEER_CLIENT
+# is the IP address / count of the peer's client sub­
+# net. If the client is just the peer, this will be
+# the peer's own IP address / max (where max is 32
+# for IPv4 and 128 for IPv6).
+#
+# PLUTO_PEER_CLIENT_NET
+# is the IP address of the peer's client net. If the
+# client is just the peer, this will be the peer's
+# own IP address.
+#
+# PLUTO_PEER_CLIENT_MASK
+# is the mask for the peer's client net. If the
+# client is just the peer, this will be
+# 255.255.255.255.
+#
+# PLUTO_PEER_PROTOCOL
+# is the IP protocol that will be transported.
+#
+# PLUTO_PEER_PORT
+# is the UDP/TCP port to which the IPsec SA is
+# restricted on the peer side.
+#
+
+# uncomment to log VPN connections
+VPN_LOGGING=1
+#
+# tag put in front of each log entry:
+TAG=vpn
+#
+# syslog facility and priority used:
+FAC_PRIO=local0.notice
+#
+# to create a special vpn logging file, put the following line into
+# the syslog configuration file /etc/syslog.conf:
+#
+# local0.notice -/var/log/vpn
+#
+
+# check interface version
+case "$PLUTO_VERSION" in
+1.[0|1]) # Older Pluto?!? Play it safe, script may be using new features.
+ echo "$0: obsolete interface version \`$PLUTO_VERSION'," >&2
+ echo "$0: called by obsolete Pluto?" >&2
+ exit 2
+ ;;
+1.*) ;;
+*) echo "$0: unknown interface version \`$PLUTO_VERSION'" >&2
+ exit 2
+ ;;
+esac
+
+# check parameter(s)
+case "$1:$*" in
+':') # no parameters
+ ;;
+iptables:iptables) # due to (left/right)firewall; for default script only
+ ;;
+custom:*) # custom parameters (see above CAUTION comment)
+ ;;
+*) echo "$0: unknown parameters \`$*'" >&2
+ exit 2
+ ;;
+esac
+
+# utility functions for route manipulation
+# Meddling with this stuff should not be necessary and requires great care.
+uproute() {
+ doroute add
+ ip route flush cache
+}
+downroute() {
+ doroute delete
+ ip route flush cache
+}
+
+addsource() {
+ st=0
+ if ! ip -o route get ${PLUTO_MY_SOURCEIP%/*} | grep -q ^local
+ then
+ it="ip addr add ${PLUTO_MY_SOURCEIP%/*}/32 dev $PLUTO_INTERFACE"
+ oops="`eval $it 2>&1`"
+ st=$?
+ if test " $oops" = " " -a " $st" != " 0"
+ then
+ oops="silent error, exit status $st"
+ fi
+ if test " $oops" != " " -o " $st" != " 0"
+ then
+ echo "$0: addsource \`$it' failed ($oops)" >&2
+ fi
+ fi
+ return $st
+}
+
+doroute() {
+ st=0
+ parms="$PLUTO_PEER_CLIENT"
+
+ parms2=
+ if [ -n "$PLUTO_NEXT_HOP" ]
+ then
+ parms2="via $PLUTO_NEXT_HOP"
+ fi
+ parms2="$parms2 dev $PLUTO_INTERFACE"
+
+ if [ -z "$PLUTO_MY_SOURCEIP" ]
+ then
+ if [ -f /etc/sysconfig/defaultsource ]
+ then
+ . /etc/sysconfig/defaultsource
+ fi
+
+ if [ -f /etc/conf.d/defaultsource ]
+ then
+ . /etc/conf.d/defaultsource
+ fi
+
+ if [ -n "$DEFAULTSOURCE" ]
+ then
+ PLUTO_MY_SOURCEIP=$DEFAULTSOURCE
+ fi
+ fi
+
+ parms3=
+ if test "$1" = "add" -a -n "$PLUTO_MY_SOURCEIP"
+ then
+ addsource
+ parms3="$parms3 src ${PLUTO_MY_SOURCEIP%/*}"
+ fi
+
+ case "$PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK" in
+ "0.0.0.0/0.0.0.0")
+ # opportunistic encryption work around
+ # need to provide route that eclipses default, without
+ # replacing it.
+ it="ip route $1 0.0.0.0/1 $parms2 $parms3 &&
+ ip route $1 128.0.0.0/1 $parms2 $parms3"
+ ;;
+ *) it="ip route $1 $parms $parms2 $parms3"
+ ;;
+ esac
+ oops="`eval $it 2>&1`"
+ st=$?
+ if test " $oops" = " " -a " $st" != " 0"
+ then
+ oops="silent error, exit status $st"
+ fi
+ if test " $oops" != " " -o " $st" != " 0"
+ then
+ echo "$0: doroute \`$it' failed ($oops)" >&2
+ fi
+ return $st
+}
+
+# in the presence of KLIPS and ipsecN interfaces do not use IPSEC_POLICY
+if [ `echo "$PLUTO_INTERFACE" | grep "ipsec"` ]
+then
+ IPSEC_POLICY_IN=""
+ IPSEC_POLICY_OUT=""
+else
+ IPSEC_POLICY="-m policy --pol ipsec --proto esp --reqid $PLUTO_REQID"
+ IPSEC_POLICY_IN="$IPSEC_POLICY --dir in"
+ IPSEC_POLICY_OUT="$IPSEC_POLICY --dir out"
+fi
+
+# are there port numbers?
+if [ "$PLUTO_MY_PORT" != 0 ]
+then
+ S_MY_PORT="--sport $PLUTO_MY_PORT"
+ D_MY_PORT="--dport $PLUTO_MY_PORT"
+fi
+if [ "$PLUTO_PEER_PORT" != 0 ]
+then
+ S_PEER_PORT="--sport $PLUTO_PEER_PORT"
+ D_PEER_PORT="--dport $PLUTO_PEER_PORT"
+fi
+
+# the big choice
+case "$PLUTO_VERB:$1" in
+prepare-host:*|prepare-client:*)
+ # delete possibly-existing route (preliminary to adding a route)
+ case "$PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK" in
+ "0.0.0.0/0.0.0.0")
+ # need to provide route that eclipses default, without
+ # replacing it.
+ parms1="0.0.0.0/1"
+ parms2="128.0.0.0/1"
+ it="ip route delete $parms1 2>&1 ; ip route delete $parms2 2>&1"
+ oops="`ip route delete $parms1 2>&1 ; ip route delete $parms2 2>&1`"
+ ;;
+ *)
+ parms="$PLUTO_PEER_CLIENT"
+ it="ip route delete $parms 2>&1"
+ oops="`ip route delete $parms 2>&1`"
+ ;;
+ esac
+ status="$?"
+ if test " $oops" = " " -a " $status" != " 0"
+ then
+ oops="silent error, exit status $status"
+ fi
+ case "$oops" in
+ *'RTNETLINK answers: No such process'*)
+ # This is what route (currently -- not documented!) gives
+ # for "could not find such a route".
+ oops=
+ status=0
+ ;;
+ esac
+ if test " $oops" != " " -o " $status" != " 0"
+ then
+ echo "$0: \`$it' failed ($oops)" >&2
+ fi
+ exit $status
+ ;;
+route-host:*|route-client:*)
+ # connection to me or my client subnet being routed
+ uproute
+ ;;
+unroute-host:*|unroute-client:*)
+ # connection to me or my client subnet being unrouted
+ downroute
+ ;;
+up-host:)
+ # connection to me coming up
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+down-host:)
+ # connection to me going down
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+up-client:)
+ # connection to my client subnet coming up
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+down-client:)
+ # connection to my client subnet going down
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+up-host:iptables)
+ # connection to me, with (left/right)firewall=yes, coming up
+ # This is used only by the default updown script, not by your custom
+ # ones, so do not mess with it; see CAUTION comment up at top.
+ iptables -I INPUT 1 -i $PLUTO_INTERFACE -p $PLUTO_MY_PROTOCOL \
+ -s $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $S_PEER_PORT \
+ -d $PLUTO_ME $D_MY_PORT $IPSEC_POLICY_IN -j ACCEPT
+ iptables -I OUTPUT 1 -o $PLUTO_INTERFACE -p $PLUTO_PEER_PROTOCOL \
+ -s $PLUTO_ME $S_MY_PORT $IPSEC_POLICY_OUT \
+ -d $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $D_PEER_PORT -j ACCEPT
+ #
+ # log IPsec host connection setup
+ if [ $VPN_LOGGING ]
+ then
+ if [ "$PLUTO_PEER_CLIENT" == "$PLUTO_PEER/32" ]
+ then
+ logger -t $TAG -p $FAC_PRIO \
+ "+ `echo -e $PLUTO_PEER_ID` $PLUTO_PEER -- $PLUTO_ME"
+ else
+ logger -t $TAG -p $FAC_PRIO \
+ "+ `echo -e $PLUTO_PEER_ID` $PLUTO_PEER_CLIENT == $PLUTO_PEER -- $PLUTO_ME"
+ fi
+ fi
+ ;;
+down-host:iptables)
+ # connection to me, with (left/right)firewall=yes, going down
+ # This is used only by the default updown script, not by your custom
+ # ones, so do not mess with it; see CAUTION comment up at top.
+ iptables -D INPUT -i $PLUTO_INTERFACE -p $PLUTO_MY_PROTOCOL \
+ -s $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $S_PEER_PORT \
+ -d $PLUTO_ME $D_MY_PORT $IPSEC_POLICY_IN -j ACCEPT
+ iptables -D OUTPUT -o $PLUTO_INTERFACE -p $PLUTO_PEER_PROTOCOL \
+ -s $PLUTO_ME $S_MY_PORT $IPSEC_POLICY_OUT \
+ -d $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $D_PEER_PORT -j ACCEPT
+ #
+ # log IPsec host connection teardown
+ if [ $VPN_LOGGING ]
+ then
+ if [ "$PLUTO_PEER_CLIENT" == "$PLUTO_PEER/32" ]
+ then
+ logger -t $TAG -p $FAC_PRIO -- \
+ "- `echo -e $PLUTO_PEER_ID` $PLUTO_PEER -- $PLUTO_ME"
+ else
+ logger -t $TAG -p $FAC_PRIO -- \
+ "- `echo -e $PLUTO_PEER_ID` $PLUTO_PEER_CLIENT == $PLUTO_PEER -- $PLUTO_ME"
+ fi
+ fi
+ ;;
+up-client:iptables)
+ # connection to client subnet, with (left/right)firewall=yes, coming up
+ # This is used only by the default updown script, not by your custom
+ # ones, so do not mess with it; see CAUTION comment up at top.
+ if [ "$PLUTO_PEER_CLIENT" != "$PLUTO_MY_SOURCEIP/32" ]
+ then
+ iptables -I FORWARD 1 -o $PLUTO_INTERFACE -p $PLUTO_PEER_PROTOCOL \
+ -s $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK $S_MY_PORT \
+ -d $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $D_PEER_PORT \
+ $IPSEC_POLICY_OUT -j ACCEPT
+ iptables -I FORWARD 1 -i $PLUTO_INTERFACE -p $PLUTO_MY_PROTOCOL \
+ -s $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $S_PEER_PORT \
+ -d $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK $D_MY_PORT \
+ $IPSEC_POLICY_IN -j ACCEPT
+ fi
+ #
+ # a virtual IP requires an INPUT and OUTPUT rule on the host
+ # or sometimes host access via the internal IP is needed
+ if [ -n "$PLUTO_MY_SOURCEIP" -o -n "$PLUTO_HOST_ACCESS" ]
+ then
+ iptables -I INPUT 1 -i $PLUTO_INTERFACE -p $PLUTO_MY_PROTOCOL \
+ -s $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $S_PEER_PORT \
+ -d $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK $D_MY_PORT \
+ $IPSEC_POLICY_IN -j ACCEPT
+ iptables -I OUTPUT 1 -o $PLUTO_INTERFACE -p $PLUTO_PEER_PROTOCOL \
+ -s $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK $S_MY_PORT \
+ -d $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $D_PEER_PORT \
+ $IPSEC_POLICY_OUT -j ACCEPT
+ fi
+ #
+ # log IPsec client connection setup
+ if [ $VPN_LOGGING ]
+ then
+ if [ "$PLUTO_PEER_CLIENT" == "$PLUTO_PEER/32" ]
+ then
+ logger -t $TAG -p $FAC_PRIO \
+ "+ `echo -e $PLUTO_PEER_ID` $PLUTO_PEER -- $PLUTO_ME == $PLUTO_MY_CLIENT"
+ else
+ logger -t $TAG -p $FAC_PRIO \
+ "+ `echo -e $PLUTO_PEER_ID` $PLUTO_PEER_CLIENT == $PLUTO_PEER -- $PLUTO_ME == $PLUTO_MY_CLIENT"
+ fi
+ fi
+ ;;
+down-client:iptables)
+ # connection to client subnet, with (left/right)firewall=yes, going down
+ # This is used only by the default updown script, not by your custom
+ # ones, so do not mess with it; see CAUTION comment up at top.
+ if [ "$PLUTO_PEER_CLIENT" != "$PLUTO_MY_SOURCEIP/32" ]
+ then
+ iptables -D FORWARD -o $PLUTO_INTERFACE -p $PLUTO_PEER_PROTOCOL \
+ -s $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK $S_MY_PORT \
+ -d $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $D_PEER_PORT \
+ $IPSEC_POLICY_OUT -j ACCEPT
+ iptables -D FORWARD -i $PLUTO_INTERFACE -p $PLUTO_MY_PROTOCOL \
+ -s $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $S_PEER_PORT \
+ -d $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK $D_MY_PORT \
+ $IPSEC_POLICY_IN -j ACCEPT
+ fi
+ #
+ # a virtual IP requires an INPUT and OUTPUT rule on the host
+ # or sometimes host access via the internal IP is needed
+ if [ -n "$PLUTO_MY_SOURCEIP" -o -n "$PLUTO_HOST_ACCESS" ]
+ then
+ iptables -D INPUT -i $PLUTO_INTERFACE -p $PLUTO_MY_PROTOCOL \
+ -s $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $S_PEER_PORT \
+ -d $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK $D_MY_PORT \
+ $IPSEC_POLICY_IN -j ACCEPT
+ iptables -D OUTPUT -o $PLUTO_INTERFACE -p $PLUTO_PEER_PROTOCOL \
+ -s $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK $S_MY_PORT \
+ -d $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $D_PEER_PORT \
+ $IPSEC_POLICY_OUT -j ACCEPT
+ fi
+ #
+ # log IPsec client connection teardown
+ if [ $VPN_LOGGING ]
+ then
+ if [ "$PLUTO_PEER_CLIENT" == "$PLUTO_PEER/32" ]
+ then
+ logger -t $TAG -p $FAC_PRIO -- \
+ "- `echo -e $PLUTO_PEER_ID` $PLUTO_PEER -- $PLUTO_ME == $PLUTO_MY_CLIENT"
+ else
+ logger -t $TAG -p $FAC_PRIO -- \
+ "- `echo -e $PLUTO_PEER_ID` $PLUTO_PEER_CLIENT == $PLUTO_PEER -- $PLUTO_ME == $PLUTO_MY_CLIENT"
+ fi
+ fi
+ ;;
+#
+# IPv6
+#
+prepare-host-v6:*|prepare-client-v6:*)
+ ;;
+route-host-v6:*|route-client-v6:*)
+ # connection to me or my client subnet being routed
+ #uproute_v6
+ ;;
+unroute-host-v6:*|unroute-client-v6:*)
+ # connection to me or my client subnet being unrouted
+ #downroute_v6
+ ;;
+up-host-v6:*)
+ # connection to me coming up
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+down-host-v6:*)
+ # connection to me going down
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+up-client-v6:)
+ # connection to my client subnet coming up
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+down-client-v6:)
+ # connection to my client subnet going down
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+*) echo "$0: unknown verb \`$PLUTO_VERB' or parameter \`$1'" >&2
+ exit 1
+ ;;
+esac
diff --git a/src/_updown/_updown.8 b/src/_updown/_updown.8
new file mode 100644
index 000000000..5107d3694
--- /dev/null
+++ b/src/_updown/_updown.8
@@ -0,0 +1,19 @@
+.TH _UPDOWN 8 "27 Apr 2006"
+.\"
+.\" RCSID $Id: _updown.8,v 1.2 2006/04/17 06:48:49 as Exp $
+.\"
+.SH NAME
+ipsec _updown \- route and firewall manipulation script
+.SH SYNOPSIS
+.I _updown
+is invoked by pluto when it has brought up a new connection. This script
+is used to insert the appropriate routing entries for IPsec operation.
+It can also be used to insert and delete dynamic iptables firewall rules.
+The interface to the script is documented in the pluto man page.
+.SH "SEE ALSO"
+ipsec(8), ipsec_pluto(8).
+.SH HISTORY
+Man page written for the Linux FreeS/WAN project <http://www.freeswan.org/>
+by Michael Richardson. Original program written by Henry Spencer. Extended
+for the Linux strongSwan project <http://www.strongswan.org/> by Andreas
+Steffen.
diff --git a/src/_updown_espmark/Makefile.am b/src/_updown_espmark/Makefile.am
new file mode 100644
index 000000000..456702690
--- /dev/null
+++ b/src/_updown_espmark/Makefile.am
@@ -0,0 +1,2 @@
+dist_ipsec_SCRIPTS = _updown_espmark
+dist_man8_MANS = _updown_espmark.8
diff --git a/src/_updown_espmark/Makefile.in b/src/_updown_espmark/Makefile.in
new file mode 100644
index 000000000..0286c8f58
--- /dev/null
+++ b/src/_updown_espmark/Makefile.in
@@ -0,0 +1,421 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/_updown_espmark
+DIST_COMMON = $(dist_ipsec_SCRIPTS) $(dist_man8_MANS) \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_CLEAN_FILES =
+am__installdirs = "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(man8dir)"
+dist_ipsecSCRIPT_INSTALL = $(INSTALL_SCRIPT)
+SCRIPTS = $(dist_ipsec_SCRIPTS)
+SOURCES =
+DIST_SOURCES =
+man8dir = $(mandir)/man8
+NROFF = nroff
+MANS = $(dist_man8_MANS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_EAP_SIM_FALSE = @BUILD_EAP_SIM_FALSE@
+BUILD_EAP_SIM_TRUE = @BUILD_EAP_SIM_TRUE@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GPERF = @GPERF@
+GREP = @GREP@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+USE_CISCO_QUIRKS_FALSE = @USE_CISCO_QUIRKS_FALSE@
+USE_CISCO_QUIRKS_TRUE = @USE_CISCO_QUIRKS_TRUE@
+USE_LEAK_DETECTIVE_FALSE = @USE_LEAK_DETECTIVE_FALSE@
+USE_LEAK_DETECTIVE_TRUE = @USE_LEAK_DETECTIVE_TRUE@
+USE_LIBCURL_FALSE = @USE_LIBCURL_FALSE@
+USE_LIBCURL_TRUE = @USE_LIBCURL_TRUE@
+USE_LIBLDAP_FALSE = @USE_LIBLDAP_FALSE@
+USE_LIBLDAP_TRUE = @USE_LIBLDAP_TRUE@
+USE_NAT_TRANSPORT_FALSE = @USE_NAT_TRANSPORT_FALSE@
+USE_NAT_TRANSPORT_TRUE = @USE_NAT_TRANSPORT_TRUE@
+USE_SMARTCARD_FALSE = @USE_SMARTCARD_FALSE@
+USE_SMARTCARD_TRUE = @USE_SMARTCARD_TRUE@
+USE_VENDORID_FALSE = @USE_VENDORID_FALSE@
+USE_VENDORID_TRUE = @USE_VENDORID_TRUE@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+confdir = @confdir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+eapdir = @eapdir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+ipsecdir = @ipsecdir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+piddir = @piddir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+dist_ipsec_SCRIPTS = _updown_espmark
+dist_man8_MANS = _updown_espmark.8
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/_updown_espmark/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/_updown_espmark/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-dist_ipsecSCRIPTS: $(dist_ipsec_SCRIPTS)
+ @$(NORMAL_INSTALL)
+ test -z "$(ipsecdir)" || $(mkdir_p) "$(DESTDIR)$(ipsecdir)"
+ @list='$(dist_ipsec_SCRIPTS)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ if test -f $$d$$p; then \
+ f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
+ echo " $(dist_ipsecSCRIPT_INSTALL) '$$d$$p' '$(DESTDIR)$(ipsecdir)/$$f'"; \
+ $(dist_ipsecSCRIPT_INSTALL) "$$d$$p" "$(DESTDIR)$(ipsecdir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-dist_ipsecSCRIPTS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_ipsec_SCRIPTS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
+ echo " rm -f '$(DESTDIR)$(ipsecdir)/$$f'"; \
+ rm -f "$(DESTDIR)$(ipsecdir)/$$f"; \
+ done
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+install-man8: $(man8_MANS) $(man_MANS)
+ @$(NORMAL_INSTALL)
+ test -z "$(man8dir)" || $(mkdir_p) "$(DESTDIR)$(man8dir)"
+ @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 8*) ;; \
+ *) ext='8' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst"; \
+ done
+uninstall-man8:
+ @$(NORMAL_UNINSTALL)
+ @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 8*) ;; \
+ *) ext='8' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f '$(DESTDIR)$(man8dir)/$$inst'"; \
+ rm -f "$(DESTDIR)$(man8dir)/$$inst"; \
+ done
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(SCRIPTS) $(MANS)
+installdirs:
+ for dir in "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(man8dir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-libtool
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-dist_ipsecSCRIPTS install-man
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man: install-man8
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-dist_ipsecSCRIPTS uninstall-info-am \
+ uninstall-man
+
+uninstall-man: uninstall-man8
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ distclean distclean-generic distclean-libtool distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dist_ipsecSCRIPTS \
+ install-exec install-exec-am install-info install-info-am \
+ install-man install-man8 install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am \
+ uninstall-dist_ipsecSCRIPTS uninstall-info-am uninstall-man \
+ uninstall-man8
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/_updown_espmark/_updown_espmark b/src/_updown_espmark/_updown_espmark
new file mode 100644
index 000000000..3627d470d
--- /dev/null
+++ b/src/_updown_espmark/_updown_espmark
@@ -0,0 +1,452 @@
+#! /bin/sh
+# iproute2 version, default updown script
+#
+# Copyright (C) 2003-2004 Nigel Meteringham
+# Copyright (C) 2003-2004 Tuomo Soini
+# Copyright (C) 2002-2004 Michael Richardson
+# Copyright (C) 2005 Andreas Steffen <andreas.steffen@strongsec.com>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT 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: _updown_espmark.in,v 1.4 2005/09/14 14:33:05 as Exp $
+
+
+
+# CAUTION: Installing a new version of strongSwan will install a new
+# copy of this script, wiping out any custom changes you make. If
+# you need changes, make a copy of this under another name, and customize
+# that, and use the (left/right)updown parameters in ipsec.conf to make
+# FreeS/WAN use yours instead of this default one.
+
+# things that this script gets (from ipsec_pluto(8) man page)
+#
+#
+# PLUTO_VERSION
+# indicates what version of this interface is being
+# used. This document describes version 1.1. This
+# is upwardly compatible with version 1.0.
+#
+# PLUTO_VERB
+# specifies the name of the operation to be performed
+# (prepare-host, prepare-client, up-host, up-client,
+# down-host, or down-client). If the address family
+# for security gateway to security gateway communica­
+# tions is IPv6, then a suffix of -v6 is added to the
+# verb.
+#
+# PLUTO_CONNECTION
+# is the name of the connection for which we are
+# routing.
+#
+# PLUTO_NEXT_HOP
+# is the next hop to which packets bound for the peer
+# must be sent.
+#
+# PLUTO_INTERFACE
+# is the name of the ipsec interface to be used.
+#
+# PLUTO_ME
+# is the IP address of our host.
+#
+# PLUTO_MY_ID
+# is the ID of our host.
+#
+# PLUTO_MY_CLIENT
+# is the IP address / count of our client subnet. If
+# the client is just the host, this will be the
+# host's own IP address / max (where max is 32 for
+# IPv4 and 128 for IPv6).
+#
+# PLUTO_MY_CLIENT_NET
+# is the IP address of our client net. If the client
+# is just the host, this will be the host's own IP
+# address.
+#
+# PLUTO_MY_CLIENT_MASK
+# is the mask for our client net. If the client is
+# just the host, this will be 255.255.255.255.
+#
+# PLUTO_MY_SOURCEIP
+# if non-empty, then the source address for the route will be
+# set to this IP address.
+#
+# PLUTO_MY_PROTOCOL
+# is the IP protocol that will be transported.
+#
+# PLUTO_MY_PORT
+# is the UDP/TCP port to which the IPsec SA is
+# restricted on our side.
+#
+# PLUTO_PEER
+# is the IP address of our peer.
+#
+# PLUTO_PEER_ID
+# is the ID of our peer.
+#
+# PLUTO_PEER_CA
+# is the CA which issued the cert of our peer.
+#
+# PLUTO_PEER_CLIENT
+# is the IP address / count of the peer's client sub­
+# net. If the client is just the peer, this will be
+# the peer's own IP address / max (where max is 32
+# for IPv4 and 128 for IPv6).
+#
+# PLUTO_PEER_CLIENT_NET
+# is the IP address of the peer's client net. If the
+# client is just the peer, this will be the peer's
+# own IP address.
+#
+# PLUTO_PEER_CLIENT_MASK
+# is the mask for the peer's client net. If the
+# client is just the peer, this will be
+# 255.255.255.255.
+#
+# PLUTO_PEER_PROTOCOL
+# is the IP protocol that will be transported.
+#
+# PLUTO_PEER_PORT
+# is the UDP/TCP port to which the IPsec SA is
+# restricted on the peer side.
+#
+
+# logging of VPN connections
+#
+# tag put in front of each log entry:
+TAG=vpn
+#
+# syslog facility and priority used:
+FAC_PRIO=local0.notice
+#
+# to create a special vpn logging file, put the following line into
+# the syslog configuration file /etc/syslog.conf:
+#
+# local0.notice -/var/log/vpn
+#
+
+# check interface version
+case "$PLUTO_VERSION" in
+1.[0]) # Older Pluto?!? Play it safe, script may be using new features.
+ echo "$0: obsolete interface version \`$PLUTO_VERSION'," >&2
+ echo "$0: called by obsolete Pluto?" >&2
+ exit 2
+ ;;
+1.*) ;;
+*) echo "$0: unknown interface version \`$PLUTO_VERSION'" >&2
+ exit 2
+ ;;
+esac
+
+# check parameter(s)
+case "$1:$*" in
+':') # no parameters
+ ;;
+ipfwadm:ipfwadm) # due to (left/right)firewall; for default script only
+ ;;
+custom:*) # custom parameters (see above CAUTION comment)
+ ;;
+*) echo "$0: unknown parameters \`$*'" >&2
+ exit 2
+ ;;
+esac
+
+# utility functions for route manipulation
+# Meddling with this stuff should not be necessary and requires great care.
+uproute() {
+ doroute add
+ ip route flush cache
+}
+downroute() {
+ doroute delete
+ ip route flush cache
+}
+
+addsource() {
+ st=0
+ if ! ip -o route get ${PLUTO_MY_SOURCEIP%/*} | grep -q ^local
+ then
+ it="ip addr add ${PLUTO_MY_SOURCEIP%/*}/32 dev $PLUTO_INTERFACE"
+ oops="`eval $it 2>&1`"
+ st=$?
+ if test " $oops" = " " -a " $st" != " 0"
+ then
+ oops="silent error, exit status $st"
+ fi
+ if test " $oops" != " " -o " $st" != " 0"
+ then
+ echo "$0: addsource \`$it' failed ($oops)" >&2
+ fi
+ fi
+ return $st
+}
+
+doroute() {
+ st=0
+ parms="$PLUTO_PEER_CLIENT"
+
+ parms2=
+ if [ -n "$PLUTO_NEXT_HOP" ]
+ then
+ parms2="via $PLUTO_NEXT_HOP"
+ fi
+ parms2="$parms2 dev $PLUTO_INTERFACE"
+
+ if [ -z "$PLUTO_MY_SOURCEIP" ]
+ then
+ if [ -f /etc/sysconfig/defaultsource ]
+ then
+ . /etc/sysconfig/defaultsource
+ fi
+
+ if [ -f /etc/conf.d/defaultsource ]
+ then
+ . /etc/conf.d/defaultsource
+ fi
+
+ if [ -n "$DEFAULTSOURCE" ]
+ then
+ PLUTO_MY_SOURCEIP=$DEFAULTSOURCE
+ fi
+ fi
+
+ parms3=
+ if test "$1" = "add" -a -n "$PLUTO_MY_SOURCEIP"
+ then
+ addsource
+ parms3="$parms3 src ${PLUTO_MY_SOURCEIP%/*}"
+ fi
+
+ case "$PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK" in
+ "0.0.0.0/0.0.0.0")
+ # opportunistic encryption work around
+ # need to provide route that eclipses default, without
+ # replacing it.
+ it="ip route $1 0.0.0.0/1 $parms2 $parms3 &&
+ ip route $1 128.0.0.0/1 $parms2 $parms3"
+ ;;
+ *) it="ip route $1 $parms $parms2 $parms3"
+ ;;
+ esac
+ oops="`eval $it 2>&1`"
+ st=$?
+ if test " $oops" = " " -a " $st" != " 0"
+ then
+ oops="silent error, exit status $st"
+ fi
+ if test " $oops" != " " -o " $st" != " 0"
+ then
+ echo "$0: doroute \`$it' failed ($oops)" >&2
+ fi
+ return $st
+}
+
+# define ESP mark
+ESP_MARK=50
+
+# add the following static rule to the INPUT chain in the mangle table
+# iptables -t mangle -A INPUT -p 50 -j MARK --set-mark 50
+
+# NAT traversal via UDP encapsulation is supported with the rule
+# iptables -t mangle -A INPUT -p udp --dport 4500 -j MARK --set-mark 50
+
+# in the presence of KLIPS and ipsecN interfaces do not use ESP mark rules
+if [ `echo "$PLUTO_INTERFACE" | grep "ipsec"` ]
+then
+ CHECK_MARK=""
+else
+ CHECK_MARK="-m mark --mark $ESP_MARK"
+fi
+
+# are there port numbers?
+if [ "$PLUTO_MY_PORT" != 0 ]
+then
+ S_MY_PORT="--sport $PLUTO_MY_PORT"
+ D_MY_PORT="--dport $PLUTO_MY_PORT"
+fi
+if [ "$PLUTO_PEER_PORT" != 0 ]
+then
+ S_PEER_PORT="--sport $PLUTO_PEER_PORT"
+ D_PEER_PORT="--dport $PLUTO_PEER_PORT"
+fi
+
+# the big choice
+case "$PLUTO_VERB:$1" in
+prepare-host:*|prepare-client:*)
+ # delete possibly-existing route (preliminary to adding a route)
+ case "$PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK" in
+ "0.0.0.0/0.0.0.0")
+ # need to provide route that eclipses default, without
+ # replacing it.
+ parms1="0.0.0.0/1"
+ parms2="128.0.0.0/1"
+ it="ip route delete $parms1 2>&1 ; ip route delete $parms2 2>&1"
+ oops="`ip route delete $parms1 2>&1 ; ip route delete $parms2 2>&1`"
+ ;;
+ *)
+ parms="$PLUTO_PEER_CLIENT"
+ it="ip route delete $parms 2>&1"
+ oops="`ip route delete $parms 2>&1`"
+ ;;
+ esac
+ status="$?"
+ if test " $oops" = " " -a " $status" != " 0"
+ then
+ oops="silent error, exit status $status"
+ fi
+ case "$oops" in
+ *'RTNETLINK answers: No such process'*)
+ # This is what route (currently -- not documented!) gives
+ # for "could not find such a route".
+ oops=
+ status=0
+ ;;
+ esac
+ if test " $oops" != " " -o " $status" != " 0"
+ then
+ echo "$0: \`$it' failed ($oops)" >&2
+ fi
+ exit $status
+ ;;
+route-host:*|route-client:*)
+ # connection to me or my client subnet being routed
+ uproute
+ ;;
+unroute-host:*|unroute-client:*)
+ # connection to me or my client subnet being unrouted
+ downroute
+ ;;
+up-host:*)
+ # connection to me coming up
+ # If you are doing a custom version, firewall commands go here.
+ iptables -I INPUT 1 -i $PLUTO_INTERFACE -p $PLUTO_MY_PROTOCOL \
+ -s $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $S_PEER_PORT \
+ -d $PLUTO_ME $D_MY_PORT $CHECK_MARK -j ACCEPT
+ iptables -I OUTPUT 1 -o $PLUTO_INTERFACE -p $PLUTO_PEER_PROTOCOL \
+ -s $PLUTO_ME $S_MY_PORT \
+ -d $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $D_PEER_PORT -j ACCEPT
+ #
+ if [ "$PLUTO_PEER_CLIENT" == "$PLUTO_PEER/32" ]
+ then
+ logger -t $TAG -p $FAC_PRIO \
+ "+ `echo -e $PLUTO_PEER_ID` $PLUTO_PEER -- $PLUTO_ME"
+ else
+ logger -t $TAG -p $FAC_PRIO \
+ "+ `echo -e $PLUTO_PEER_ID` $PLUTO_PEER_CLIENT == $PLUTO_PEER -- $PLUTO_ME"
+ fi
+ ;;
+down-host:*)
+ # connection to me going down
+ # If you are doing a custom version, firewall commands go here.
+ # connection to me going down
+ # If you are doing a custom version, firewall commands go here.
+ iptables -D INPUT -i $PLUTO_INTERFACE -p $PLUTO_MY_PROTOCOL \
+ -s $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $S_PEER_PORT \
+ -d $PLUTO_ME $D_MY_PORT $CHECK_MARK -j ACCEPT
+ iptables -D OUTPUT -o $PLUTO_INTERFACE -p $PLUTO_PEER_PROTOCOL \
+ -s $PLUTO_ME $S_MY_PORT \
+ -d $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $D_PEER_PORT -j ACCEPT
+ #
+ if [ "$PLUTO_PEER_CLIENT" == "$PLUTO_PEER/32" ]
+ then
+ logger -t $TAG -p $FAC_PRIO -- \
+ "- `echo -e $PLUTO_PEER_ID` $PLUTO_PEER -- $PLUTO_ME"
+ else
+ logger -t $TAG -p $FAC_PRIO -- \
+ "- `echo -e $PLUTO_PEER_ID` $PLUTO_PEER_CLIENT == $PLUTO_PEER -- $PLUTO_ME"
+ fi
+ ;;
+up-client:)
+ # connection to my client subnet coming up
+ # If you are doing a custom version, firewall commands go here.
+ iptables -I FORWARD 1 -o $PLUTO_INTERFACE -p $PLUTO_PEER_PROTOCOL \
+ -s $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK $S_MY_PORT \
+ -d $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $D_PEER_PORT -j ACCEPT
+ iptables -I FORWARD 1 -i $PLUTO_INTERFACE -p $PLUTO_MY_PROTOCOL \
+ -s $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $S_PEER_PORT \
+ -d $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK $D_MY_PORT \
+ $CHECK_MARK -j ACCEPT
+ #
+ if [ "$PLUTO_PEER_CLIENT" == "$PLUTO_PEER/32" ]
+ then
+ logger -t $TAG -p $FAC_PRIO \
+ "+ `echo -e $PLUTO_PEER_ID` $PLUTO_PEER -- $PLUTO_ME == $PLUTO_MY_CLIENT"
+ else
+ logger -t $TAG -p $FAC_PRIO \
+ "+ `echo -e $PLUTO_PEER_ID` $PLUTO_PEER_CLIENT == $PLUTO_PEER -- $PLUTO_ME == $PLUTO_MY_CLIENT"
+ fi
+ ;;
+down-client:)
+ # connection to my client subnet going down
+ # If you are doing a custom version, firewall commands go here.
+ iptables -D FORWARD -o $PLUTO_INTERFACE -p $PLUTO_PEER_PROTOCOL \
+ -s $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK $S_MY_PORT \
+ -d $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $D_PEER_PORT -j ACCEPT
+ iptables -D FORWARD -i $PLUTO_INTERFACE -p $PLUTO_MY_PROTOCOL \
+ -s $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $S_PEER_PORT \
+ -d $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK $D_MY_PORT \
+ $CHECK_MARK -j ACCEPT
+ #
+ if [ "$PLUTO_PEER_CLIENT" == "$PLUTO_PEER/32" ]
+ then
+ logger -t $TAG -p $FAC_PRIO -- \
+ "- `echo -e $PLUTO_PEER_ID` $PLUTO_PEER -- $PLUTO_ME == $PLUTO_MY_CLIENT"
+ else
+ logger -t $TAG -p $FAC_PRIO -- \
+ "- `echo -e $PLUTO_PEER_ID` $PLUTO_PEER_CLIENT == $PLUTO_PEER -- $PLUTO_ME == $PLUTO_MY_CLIENT"
+ fi
+ ;;
+up-client:ipfwadm)
+ # connection to client subnet, with (left/right)firewall=yes, coming up
+ # This is used only by the default updown script, not by your custom
+ # ones, so do not mess with it; see CAUTION comment up at top.
+ ipfwadm -F -i accept -b -S $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK \
+ -D $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK
+ ;;
+down-client:ipfwadm)
+ # connection to client subnet, with (left/right)firewall=yes, going down
+ # This is used only by the default updown script, not by your custom
+ # ones, so do not mess with it; see CAUTION comment up at top.
+ ipfwadm -F -d accept -b -S $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK \
+ -D $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK
+ ;;
+#
+# IPv6
+#
+prepare-host-v6:*|prepare-client-v6:*)
+ ;;
+route-host-v6:*|route-client-v6:*)
+ # connection to me or my client subnet being routed
+ #uproute_v6
+ ;;
+unroute-host-v6:*|unroute-client-v6:*)
+ # connection to me or my client subnet being unrouted
+ #downroute_v6
+ ;;
+up-host-v6:*)
+ # connection to me coming up
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+down-host-v6:*)
+ # connection to me going down
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+up-client-v6:)
+ # connection to my client subnet coming up
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+down-client-v6:)
+ # connection to my client subnet going down
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+*) echo "$0: unknown verb \`$PLUTO_VERB' or parameter \`$1'" >&2
+ exit 1
+ ;;
+esac
diff --git a/src/_updown_espmark/_updown_espmark.8 b/src/_updown_espmark/_updown_espmark.8
new file mode 100644
index 000000000..91eaa5cb7
--- /dev/null
+++ b/src/_updown_espmark/_updown_espmark.8
@@ -0,0 +1,18 @@
+.TH _UPDOWN_ESPMARK 8 "7 Apr 2005"
+.\"
+.\" RCSID $Id: _updown_espmark.8,v 1.1 2005/04/07 21:34:19 as Exp $
+.\"
+.SH NAME
+ipsec _updown_espmark \- manages routes and firewall rules
+.SH SYNOPSIS
+.I _updown_espmark
+is invoked by pluto when it has brought up a new connection. This script
+is used to insert the appropriate routing and iptables firewall entries for
+IPsec operation. The incoming ESP traffic must be marked by a static rule
+in the mangle table. The default value for the mark is 50.
+The interface to the script is documented in the pluto man page.
+.SH "SEE ALSO"
+ipsec(8), ipsec_pluto(8).
+.SH HISTORY
+Man page written for the Linux strongSwan project <http://www.strongswan.org/>
+by Andreas Steffen. Original program written by Henry Spencer.
diff --git a/src/charon/Makefile.am b/src/charon/Makefile.am
new file mode 100644
index 000000000..9522b6e6d
--- /dev/null
+++ b/src/charon/Makefile.am
@@ -0,0 +1,87 @@
+# SUBDIRS = . testing
+
+eap_LTLIBRARIES = libeapidentity.la
+
+# always build EAP Identity module
+libeapidentity_la_SOURCES = sa/authenticators/eap/eap_identity.h sa/authenticators/eap/eap_identity.c
+libeapidentity_la_LDFLAGS = -module
+
+# build optional EAP modules
+if BUILD_EAP_SIM
+ eap_LTLIBRARIES += libeapsim.la
+ libeapsim_la_SOURCES = sa/authenticators/eap/eap_sim.h sa/authenticators/eap/eap_sim.c
+ libeapsim_la_LDFLAGS = -module
+endif
+
+ipsec_PROGRAMS = charon
+
+charon_SOURCES = \
+bus/bus.c bus/bus.h \
+bus/listeners/sys_logger.c bus/listeners/sys_logger.h \
+bus/listeners/file_logger.c bus/listeners/file_logger.h \
+config/connections/connection.c config/connections/connection.h \
+config/connections/local_connection_store.c config/connections/local_connection_store.h config/connections/connection_store.h \
+config/policies/policy.c config/policies/policy.h \
+config/policies/local_policy_store.c config/policies/policy_store.h config/policies/local_policy_store.h \
+config/credentials/local_credential_store.c config/credentials/local_credential_store.h \
+config/traffic_selector.c config/traffic_selector.h \
+config/proposal.c config/proposal.h config/configuration.c config/configuration.h \
+sa/authenticators/eap_authenticator.h sa/authenticators/eap_authenticator.c \
+sa/authenticators/eap/eap_method.h sa/authenticators/eap/eap_method.c \
+sa/child_sa.c sa/child_sa.h sa/ike_sa.c sa/ike_sa.h sa/ike_sa_manager.c sa/ike_sa_manager.h \
+sa/ike_sa_id.c sa/ike_sa_id.h sa/tasks/task.c sa/tasks/task.h \
+sa/tasks/ike_init.c sa/tasks/ike_init.h \
+sa/tasks/ike_natd.c sa/tasks/ike_natd.h \
+sa/tasks/ike_auth.c sa/tasks/ike_auth.h \
+sa/tasks/ike_config.c sa/tasks/ike_config.h \
+sa/tasks/ike_cert.c sa/tasks/ike_cert.h \
+sa/tasks/ike_rekey.c sa/tasks/ike_rekey.h \
+sa/tasks/ike_delete.c sa/tasks/ike_delete.h \
+sa/tasks/ike_dpd.c sa/tasks/ike_dpd.h \
+sa/tasks/child_create.c sa/tasks/child_create.h \
+sa/tasks/child_delete.c sa/tasks/child_delete.h \
+sa/tasks/child_rekey.c sa/tasks/child_rekey.h \
+sa/authenticators/authenticator.c sa/authenticators/authenticator.h \
+sa/authenticators/rsa_authenticator.c sa/authenticators/rsa_authenticator.h \
+sa/authenticators/psk_authenticator.c sa/authenticators/psk_authenticator.h \
+sa/task_manager.c sa/task_manager.h encoding/payloads/encryption_payload.c \
+encoding/payloads/cert_payload.c encoding/payloads/payload.h encoding/payloads/traffic_selector_substructure.c \
+encoding/payloads/configuration_attribute.h encoding/payloads/proposal_substructure.h \
+encoding/payloads/transform_attribute.c encoding/payloads/transform_attribute.h \
+encoding/payloads/configuration_attribute.c encoding/payloads/transform_substructure.c \
+encoding/payloads/encryption_payload.h encoding/payloads/auth_payload.c encoding/payloads/ike_header.c \
+encoding/payloads/transform_substructure.h encoding/payloads/nonce_payload.c encoding/payloads/cert_payload.h \
+encoding/payloads/eap_payload.c encoding/payloads/ike_header.h encoding/payloads/auth_payload.h \
+encoding/payloads/ts_payload.c encoding/payloads/traffic_selector_substructure.h encoding/payloads/nonce_payload.h \
+encoding/payloads/notify_payload.c encoding/payloads/eap_payload.h encoding/payloads/notify_payload.h \
+encoding/payloads/ts_payload.h encoding/payloads/id_payload.c encoding/payloads/ke_payload.c \
+encoding/payloads/unknown_payload.c encoding/payloads/encodings.c encoding/payloads/id_payload.h \
+encoding/payloads/cp_payload.c encoding/payloads/delete_payload.c encoding/payloads/sa_payload.c \
+encoding/payloads/ke_payload.h encoding/payloads/unknown_payload.h encoding/payloads/encodings.h \
+encoding/payloads/certreq_payload.c encoding/payloads/cp_payload.h encoding/payloads/delete_payload.h \
+encoding/payloads/sa_payload.h encoding/payloads/vendor_id_payload.c encoding/payloads/certreq_payload.h \
+encoding/payloads/vendor_id_payload.h encoding/payloads/proposal_substructure.c encoding/payloads/payload.c \
+encoding/parser.h encoding/message.c encoding/generator.c encoding/message.h encoding/generator.h \
+encoding/parser.c daemon.c daemon.h network/packet.c \
+network/socket.c network/packet.h network/socket.h queues/jobs/job.h queues/jobs/job.c \
+queues/jobs/retransmit_job.h queues/jobs/initiate_job.h \
+queues/jobs/process_message_job.h queues/jobs/process_message_job.c \
+queues/jobs/delete_ike_sa_job.c queues/jobs/delete_ike_sa_job.h \
+queues/jobs/retransmit_job.c queues/jobs/initiate_job.c \
+queues/jobs/send_keepalive_job.c queues/jobs/send_keepalive_job.h \
+queues/jobs/rekey_child_sa_job.c queues/jobs/rekey_child_sa_job.h queues/jobs/delete_child_sa_job.c queues/jobs/delete_child_sa_job.h \
+queues/jobs/send_dpd_job.c queues/jobs/send_dpd_job.h queues/jobs/route_job.c queues/jobs/route_job.h \
+queues/jobs/acquire_job.c queues/jobs/acquire_job.h queues/jobs/rekey_ike_sa_job.c queues/jobs/rekey_ike_sa_job.h \
+queues/job_queue.c queues/event_queue.c queues/job_queue.h queues/event_queue.h \
+threads/kernel_interface.c threads/thread_pool.c threads/scheduler.c threads/sender.c \
+threads/sender.h threads/kernel_interface.h threads/scheduler.h threads/receiver.c threads/stroke_interface.c \
+threads/thread_pool.h threads/receiver.h threads/stroke_interface.h
+
+INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon -I$(top_srcdir)/src/stroke
+AM_CFLAGS = -rdynamic -DIPSEC_CONFDIR=\"${confdir}\" -DIPSEC_PIDDIR=\"${piddir}\" -DIPSEC_EAPDIR=\"${eapdir}\"
+charon_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la -lgmp -lpthread -lm -ldl
+
+if USE_LIBCURL
+ charon_LDADD += -lcurl
+endif
+
diff --git a/src/charon/Makefile.in b/src/charon/Makefile.in
new file mode 100644
index 000000000..0f2979d32
--- /dev/null
+++ b/src/charon/Makefile.in
@@ -0,0 +1,1878 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# SUBDIRS = . testing
+
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+
+# build optional EAP modules
+@BUILD_EAP_SIM_TRUE@am__append_1 = libeapsim.la
+ipsec_PROGRAMS = charon$(EXEEXT)
+@USE_LIBCURL_TRUE@am__append_2 = -lcurl
+subdir = src/charon
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_CLEAN_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(eapdir)" "$(DESTDIR)$(ipsecdir)"
+eapLTLIBRARIES_INSTALL = $(INSTALL)
+LTLIBRARIES = $(eap_LTLIBRARIES)
+libeapidentity_la_LIBADD =
+am_libeapidentity_la_OBJECTS = eap_identity.lo
+libeapidentity_la_OBJECTS = $(am_libeapidentity_la_OBJECTS)
+libeapsim_la_LIBADD =
+am__libeapsim_la_SOURCES_DIST = sa/authenticators/eap/eap_sim.h \
+ sa/authenticators/eap/eap_sim.c
+@BUILD_EAP_SIM_TRUE@am_libeapsim_la_OBJECTS = eap_sim.lo
+libeapsim_la_OBJECTS = $(am_libeapsim_la_OBJECTS)
+@BUILD_EAP_SIM_TRUE@am_libeapsim_la_rpath = -rpath $(eapdir)
+ipsecPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(ipsec_PROGRAMS)
+am_charon_OBJECTS = bus.$(OBJEXT) sys_logger.$(OBJEXT) \
+ file_logger.$(OBJEXT) connection.$(OBJEXT) \
+ local_connection_store.$(OBJEXT) policy.$(OBJEXT) \
+ local_policy_store.$(OBJEXT) local_credential_store.$(OBJEXT) \
+ traffic_selector.$(OBJEXT) proposal.$(OBJEXT) \
+ configuration.$(OBJEXT) eap_authenticator.$(OBJEXT) \
+ eap_method.$(OBJEXT) child_sa.$(OBJEXT) ike_sa.$(OBJEXT) \
+ ike_sa_manager.$(OBJEXT) ike_sa_id.$(OBJEXT) task.$(OBJEXT) \
+ ike_init.$(OBJEXT) ike_natd.$(OBJEXT) ike_auth.$(OBJEXT) \
+ ike_config.$(OBJEXT) ike_cert.$(OBJEXT) ike_rekey.$(OBJEXT) \
+ ike_delete.$(OBJEXT) ike_dpd.$(OBJEXT) child_create.$(OBJEXT) \
+ child_delete.$(OBJEXT) child_rekey.$(OBJEXT) \
+ authenticator.$(OBJEXT) rsa_authenticator.$(OBJEXT) \
+ psk_authenticator.$(OBJEXT) task_manager.$(OBJEXT) \
+ encryption_payload.$(OBJEXT) cert_payload.$(OBJEXT) \
+ traffic_selector_substructure.$(OBJEXT) \
+ transform_attribute.$(OBJEXT) \
+ configuration_attribute.$(OBJEXT) \
+ transform_substructure.$(OBJEXT) auth_payload.$(OBJEXT) \
+ ike_header.$(OBJEXT) nonce_payload.$(OBJEXT) \
+ eap_payload.$(OBJEXT) ts_payload.$(OBJEXT) \
+ notify_payload.$(OBJEXT) id_payload.$(OBJEXT) \
+ ke_payload.$(OBJEXT) unknown_payload.$(OBJEXT) \
+ encodings.$(OBJEXT) cp_payload.$(OBJEXT) \
+ delete_payload.$(OBJEXT) sa_payload.$(OBJEXT) \
+ certreq_payload.$(OBJEXT) vendor_id_payload.$(OBJEXT) \
+ proposal_substructure.$(OBJEXT) payload.$(OBJEXT) \
+ message.$(OBJEXT) generator.$(OBJEXT) parser.$(OBJEXT) \
+ daemon.$(OBJEXT) packet.$(OBJEXT) socket.$(OBJEXT) \
+ job.$(OBJEXT) process_message_job.$(OBJEXT) \
+ delete_ike_sa_job.$(OBJEXT) retransmit_job.$(OBJEXT) \
+ initiate_job.$(OBJEXT) send_keepalive_job.$(OBJEXT) \
+ rekey_child_sa_job.$(OBJEXT) delete_child_sa_job.$(OBJEXT) \
+ send_dpd_job.$(OBJEXT) route_job.$(OBJEXT) \
+ acquire_job.$(OBJEXT) rekey_ike_sa_job.$(OBJEXT) \
+ job_queue.$(OBJEXT) event_queue.$(OBJEXT) \
+ kernel_interface.$(OBJEXT) thread_pool.$(OBJEXT) \
+ scheduler.$(OBJEXT) sender.$(OBJEXT) receiver.$(OBJEXT) \
+ stroke_interface.$(OBJEXT)
+charon_OBJECTS = $(am_charon_OBJECTS)
+am__DEPENDENCIES_1 =
+charon_DEPENDENCIES = \
+ $(top_builddir)/src/libstrongswan/libstrongswan.la \
+ $(am__DEPENDENCIES_1)
+DEFAULT_INCLUDES = -I. -I$(srcdir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libeapidentity_la_SOURCES) $(libeapsim_la_SOURCES) \
+ $(charon_SOURCES)
+DIST_SOURCES = $(libeapidentity_la_SOURCES) \
+ $(am__libeapsim_la_SOURCES_DIST) $(charon_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_EAP_SIM_FALSE = @BUILD_EAP_SIM_FALSE@
+BUILD_EAP_SIM_TRUE = @BUILD_EAP_SIM_TRUE@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GPERF = @GPERF@
+GREP = @GREP@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+USE_CISCO_QUIRKS_FALSE = @USE_CISCO_QUIRKS_FALSE@
+USE_CISCO_QUIRKS_TRUE = @USE_CISCO_QUIRKS_TRUE@
+USE_LEAK_DETECTIVE_FALSE = @USE_LEAK_DETECTIVE_FALSE@
+USE_LEAK_DETECTIVE_TRUE = @USE_LEAK_DETECTIVE_TRUE@
+USE_LIBCURL_FALSE = @USE_LIBCURL_FALSE@
+USE_LIBCURL_TRUE = @USE_LIBCURL_TRUE@
+USE_LIBLDAP_FALSE = @USE_LIBLDAP_FALSE@
+USE_LIBLDAP_TRUE = @USE_LIBLDAP_TRUE@
+USE_NAT_TRANSPORT_FALSE = @USE_NAT_TRANSPORT_FALSE@
+USE_NAT_TRANSPORT_TRUE = @USE_NAT_TRANSPORT_TRUE@
+USE_SMARTCARD_FALSE = @USE_SMARTCARD_FALSE@
+USE_SMARTCARD_TRUE = @USE_SMARTCARD_TRUE@
+USE_VENDORID_FALSE = @USE_VENDORID_FALSE@
+USE_VENDORID_TRUE = @USE_VENDORID_TRUE@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+confdir = @confdir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+eapdir = @eapdir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+ipsecdir = @ipsecdir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+piddir = @piddir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+eap_LTLIBRARIES = libeapidentity.la $(am__append_1)
+
+# always build EAP Identity module
+libeapidentity_la_SOURCES = sa/authenticators/eap/eap_identity.h sa/authenticators/eap/eap_identity.c
+libeapidentity_la_LDFLAGS = -module
+@BUILD_EAP_SIM_TRUE@libeapsim_la_SOURCES = sa/authenticators/eap/eap_sim.h sa/authenticators/eap/eap_sim.c
+@BUILD_EAP_SIM_TRUE@libeapsim_la_LDFLAGS = -module
+charon_SOURCES = \
+bus/bus.c bus/bus.h \
+bus/listeners/sys_logger.c bus/listeners/sys_logger.h \
+bus/listeners/file_logger.c bus/listeners/file_logger.h \
+config/connections/connection.c config/connections/connection.h \
+config/connections/local_connection_store.c config/connections/local_connection_store.h config/connections/connection_store.h \
+config/policies/policy.c config/policies/policy.h \
+config/policies/local_policy_store.c config/policies/policy_store.h config/policies/local_policy_store.h \
+config/credentials/local_credential_store.c config/credentials/local_credential_store.h \
+config/traffic_selector.c config/traffic_selector.h \
+config/proposal.c config/proposal.h config/configuration.c config/configuration.h \
+sa/authenticators/eap_authenticator.h sa/authenticators/eap_authenticator.c \
+sa/authenticators/eap/eap_method.h sa/authenticators/eap/eap_method.c \
+sa/child_sa.c sa/child_sa.h sa/ike_sa.c sa/ike_sa.h sa/ike_sa_manager.c sa/ike_sa_manager.h \
+sa/ike_sa_id.c sa/ike_sa_id.h sa/tasks/task.c sa/tasks/task.h \
+sa/tasks/ike_init.c sa/tasks/ike_init.h \
+sa/tasks/ike_natd.c sa/tasks/ike_natd.h \
+sa/tasks/ike_auth.c sa/tasks/ike_auth.h \
+sa/tasks/ike_config.c sa/tasks/ike_config.h \
+sa/tasks/ike_cert.c sa/tasks/ike_cert.h \
+sa/tasks/ike_rekey.c sa/tasks/ike_rekey.h \
+sa/tasks/ike_delete.c sa/tasks/ike_delete.h \
+sa/tasks/ike_dpd.c sa/tasks/ike_dpd.h \
+sa/tasks/child_create.c sa/tasks/child_create.h \
+sa/tasks/child_delete.c sa/tasks/child_delete.h \
+sa/tasks/child_rekey.c sa/tasks/child_rekey.h \
+sa/authenticators/authenticator.c sa/authenticators/authenticator.h \
+sa/authenticators/rsa_authenticator.c sa/authenticators/rsa_authenticator.h \
+sa/authenticators/psk_authenticator.c sa/authenticators/psk_authenticator.h \
+sa/task_manager.c sa/task_manager.h encoding/payloads/encryption_payload.c \
+encoding/payloads/cert_payload.c encoding/payloads/payload.h encoding/payloads/traffic_selector_substructure.c \
+encoding/payloads/configuration_attribute.h encoding/payloads/proposal_substructure.h \
+encoding/payloads/transform_attribute.c encoding/payloads/transform_attribute.h \
+encoding/payloads/configuration_attribute.c encoding/payloads/transform_substructure.c \
+encoding/payloads/encryption_payload.h encoding/payloads/auth_payload.c encoding/payloads/ike_header.c \
+encoding/payloads/transform_substructure.h encoding/payloads/nonce_payload.c encoding/payloads/cert_payload.h \
+encoding/payloads/eap_payload.c encoding/payloads/ike_header.h encoding/payloads/auth_payload.h \
+encoding/payloads/ts_payload.c encoding/payloads/traffic_selector_substructure.h encoding/payloads/nonce_payload.h \
+encoding/payloads/notify_payload.c encoding/payloads/eap_payload.h encoding/payloads/notify_payload.h \
+encoding/payloads/ts_payload.h encoding/payloads/id_payload.c encoding/payloads/ke_payload.c \
+encoding/payloads/unknown_payload.c encoding/payloads/encodings.c encoding/payloads/id_payload.h \
+encoding/payloads/cp_payload.c encoding/payloads/delete_payload.c encoding/payloads/sa_payload.c \
+encoding/payloads/ke_payload.h encoding/payloads/unknown_payload.h encoding/payloads/encodings.h \
+encoding/payloads/certreq_payload.c encoding/payloads/cp_payload.h encoding/payloads/delete_payload.h \
+encoding/payloads/sa_payload.h encoding/payloads/vendor_id_payload.c encoding/payloads/certreq_payload.h \
+encoding/payloads/vendor_id_payload.h encoding/payloads/proposal_substructure.c encoding/payloads/payload.c \
+encoding/parser.h encoding/message.c encoding/generator.c encoding/message.h encoding/generator.h \
+encoding/parser.c daemon.c daemon.h network/packet.c \
+network/socket.c network/packet.h network/socket.h queues/jobs/job.h queues/jobs/job.c \
+queues/jobs/retransmit_job.h queues/jobs/initiate_job.h \
+queues/jobs/process_message_job.h queues/jobs/process_message_job.c \
+queues/jobs/delete_ike_sa_job.c queues/jobs/delete_ike_sa_job.h \
+queues/jobs/retransmit_job.c queues/jobs/initiate_job.c \
+queues/jobs/send_keepalive_job.c queues/jobs/send_keepalive_job.h \
+queues/jobs/rekey_child_sa_job.c queues/jobs/rekey_child_sa_job.h queues/jobs/delete_child_sa_job.c queues/jobs/delete_child_sa_job.h \
+queues/jobs/send_dpd_job.c queues/jobs/send_dpd_job.h queues/jobs/route_job.c queues/jobs/route_job.h \
+queues/jobs/acquire_job.c queues/jobs/acquire_job.h queues/jobs/rekey_ike_sa_job.c queues/jobs/rekey_ike_sa_job.h \
+queues/job_queue.c queues/event_queue.c queues/job_queue.h queues/event_queue.h \
+threads/kernel_interface.c threads/thread_pool.c threads/scheduler.c threads/sender.c \
+threads/sender.h threads/kernel_interface.h threads/scheduler.h threads/receiver.c threads/stroke_interface.c \
+threads/thread_pool.h threads/receiver.h threads/stroke_interface.h
+
+INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon -I$(top_srcdir)/src/stroke
+AM_CFLAGS = -rdynamic -DIPSEC_CONFDIR=\"${confdir}\" -DIPSEC_PIDDIR=\"${piddir}\" -DIPSEC_EAPDIR=\"${eapdir}\"
+charon_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la \
+ -lgmp -lpthread -lm -ldl $(am__append_2)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/charon/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/charon/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-eapLTLIBRARIES: $(eap_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(eapdir)" || $(mkdir_p) "$(DESTDIR)$(eapdir)"
+ @list='$(eap_LTLIBRARIES)'; for p in $$list; do \
+ if test -f $$p; then \
+ f=$(am__strip_dir) \
+ echo " $(LIBTOOL) --mode=install $(eapLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(eapdir)/$$f'"; \
+ $(LIBTOOL) --mode=install $(eapLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(eapdir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-eapLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @set -x; list='$(eap_LTLIBRARIES)'; for p in $$list; do \
+ p=$(am__strip_dir) \
+ echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(eapdir)/$$p'"; \
+ $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(eapdir)/$$p"; \
+ done
+
+clean-eapLTLIBRARIES:
+ -test -z "$(eap_LTLIBRARIES)" || rm -f $(eap_LTLIBRARIES)
+ @list='$(eap_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libeapidentity.la: $(libeapidentity_la_OBJECTS) $(libeapidentity_la_DEPENDENCIES)
+ $(LINK) -rpath $(eapdir) $(libeapidentity_la_LDFLAGS) $(libeapidentity_la_OBJECTS) $(libeapidentity_la_LIBADD) $(LIBS)
+libeapsim.la: $(libeapsim_la_OBJECTS) $(libeapsim_la_DEPENDENCIES)
+ $(LINK) $(am_libeapsim_la_rpath) $(libeapsim_la_LDFLAGS) $(libeapsim_la_OBJECTS) $(libeapsim_la_LIBADD) $(LIBS)
+install-ipsecPROGRAMS: $(ipsec_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(ipsecdir)" || $(mkdir_p) "$(DESTDIR)$(ipsecdir)"
+ @list='$(ipsec_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ || test -f $$p1 \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(ipsecPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(ipsecdir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(ipsecPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(ipsecdir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-ipsecPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(ipsec_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(ipsecdir)/$$f'"; \
+ rm -f "$(DESTDIR)$(ipsecdir)/$$f"; \
+ done
+
+clean-ipsecPROGRAMS:
+ @list='$(ipsec_PROGRAMS)'; for p in $$list; do \
+ f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f $$p $$f"; \
+ rm -f $$p $$f ; \
+ done
+charon$(EXEEXT): $(charon_OBJECTS) $(charon_DEPENDENCIES)
+ @rm -f charon$(EXEEXT)
+ $(LINK) $(charon_LDFLAGS) $(charon_OBJECTS) $(charon_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/acquire_job.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/auth_payload.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/authenticator.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bus.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cert_payload.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/certreq_payload.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/child_create.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/child_delete.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/child_rekey.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/child_sa.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/configuration.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/configuration_attribute.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/connection.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cp_payload.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemon.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/delete_child_sa_job.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/delete_ike_sa_job.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/delete_payload.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_authenticator.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_identity.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_method.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_payload.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_sim.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/encodings.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/encryption_payload.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event_queue.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_logger.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/generator.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/id_payload.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_auth.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_cert.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_config.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_delete.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_dpd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_header.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_init.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_natd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_rekey.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_sa.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_sa_id.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_sa_manager.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/initiate_job.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/job.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/job_queue.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ke_payload.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kernel_interface.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/local_connection_store.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/local_credential_store.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/local_policy_store.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/message.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nonce_payload.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/notify_payload.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/packet.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/payload.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/policy.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/process_message_job.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proposal.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proposal_substructure.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/psk_authenticator.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/receiver.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rekey_child_sa_job.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rekey_ike_sa_job.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/retransmit_job.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/route_job.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rsa_authenticator.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sa_payload.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scheduler.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/send_dpd_job.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/send_keepalive_job.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sender.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stroke_interface.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sys_logger.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/task.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/task_manager.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread_pool.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/traffic_selector.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/traffic_selector_substructure.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transform_attribute.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transform_substructure.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ts_payload.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unknown_payload.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vendor_id_payload.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+eap_identity.lo: sa/authenticators/eap/eap_identity.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eap_identity.lo -MD -MP -MF "$(DEPDIR)/eap_identity.Tpo" -c -o eap_identity.lo `test -f 'sa/authenticators/eap/eap_identity.c' || echo '$(srcdir)/'`sa/authenticators/eap/eap_identity.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/eap_identity.Tpo" "$(DEPDIR)/eap_identity.Plo"; else rm -f "$(DEPDIR)/eap_identity.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/authenticators/eap/eap_identity.c' object='eap_identity.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o eap_identity.lo `test -f 'sa/authenticators/eap/eap_identity.c' || echo '$(srcdir)/'`sa/authenticators/eap/eap_identity.c
+
+eap_sim.lo: sa/authenticators/eap/eap_sim.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eap_sim.lo -MD -MP -MF "$(DEPDIR)/eap_sim.Tpo" -c -o eap_sim.lo `test -f 'sa/authenticators/eap/eap_sim.c' || echo '$(srcdir)/'`sa/authenticators/eap/eap_sim.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/eap_sim.Tpo" "$(DEPDIR)/eap_sim.Plo"; else rm -f "$(DEPDIR)/eap_sim.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/authenticators/eap/eap_sim.c' object='eap_sim.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o eap_sim.lo `test -f 'sa/authenticators/eap/eap_sim.c' || echo '$(srcdir)/'`sa/authenticators/eap/eap_sim.c
+
+bus.o: bus/bus.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT bus.o -MD -MP -MF "$(DEPDIR)/bus.Tpo" -c -o bus.o `test -f 'bus/bus.c' || echo '$(srcdir)/'`bus/bus.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/bus.Tpo" "$(DEPDIR)/bus.Po"; else rm -f "$(DEPDIR)/bus.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='bus/bus.c' object='bus.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o bus.o `test -f 'bus/bus.c' || echo '$(srcdir)/'`bus/bus.c
+
+bus.obj: bus/bus.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT bus.obj -MD -MP -MF "$(DEPDIR)/bus.Tpo" -c -o bus.obj `if test -f 'bus/bus.c'; then $(CYGPATH_W) 'bus/bus.c'; else $(CYGPATH_W) '$(srcdir)/bus/bus.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/bus.Tpo" "$(DEPDIR)/bus.Po"; else rm -f "$(DEPDIR)/bus.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='bus/bus.c' object='bus.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o bus.obj `if test -f 'bus/bus.c'; then $(CYGPATH_W) 'bus/bus.c'; else $(CYGPATH_W) '$(srcdir)/bus/bus.c'; fi`
+
+sys_logger.o: bus/listeners/sys_logger.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sys_logger.o -MD -MP -MF "$(DEPDIR)/sys_logger.Tpo" -c -o sys_logger.o `test -f 'bus/listeners/sys_logger.c' || echo '$(srcdir)/'`bus/listeners/sys_logger.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/sys_logger.Tpo" "$(DEPDIR)/sys_logger.Po"; else rm -f "$(DEPDIR)/sys_logger.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='bus/listeners/sys_logger.c' object='sys_logger.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sys_logger.o `test -f 'bus/listeners/sys_logger.c' || echo '$(srcdir)/'`bus/listeners/sys_logger.c
+
+sys_logger.obj: bus/listeners/sys_logger.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sys_logger.obj -MD -MP -MF "$(DEPDIR)/sys_logger.Tpo" -c -o sys_logger.obj `if test -f 'bus/listeners/sys_logger.c'; then $(CYGPATH_W) 'bus/listeners/sys_logger.c'; else $(CYGPATH_W) '$(srcdir)/bus/listeners/sys_logger.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/sys_logger.Tpo" "$(DEPDIR)/sys_logger.Po"; else rm -f "$(DEPDIR)/sys_logger.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='bus/listeners/sys_logger.c' object='sys_logger.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sys_logger.obj `if test -f 'bus/listeners/sys_logger.c'; then $(CYGPATH_W) 'bus/listeners/sys_logger.c'; else $(CYGPATH_W) '$(srcdir)/bus/listeners/sys_logger.c'; fi`
+
+file_logger.o: bus/listeners/file_logger.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT file_logger.o -MD -MP -MF "$(DEPDIR)/file_logger.Tpo" -c -o file_logger.o `test -f 'bus/listeners/file_logger.c' || echo '$(srcdir)/'`bus/listeners/file_logger.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/file_logger.Tpo" "$(DEPDIR)/file_logger.Po"; else rm -f "$(DEPDIR)/file_logger.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='bus/listeners/file_logger.c' object='file_logger.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o file_logger.o `test -f 'bus/listeners/file_logger.c' || echo '$(srcdir)/'`bus/listeners/file_logger.c
+
+file_logger.obj: bus/listeners/file_logger.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT file_logger.obj -MD -MP -MF "$(DEPDIR)/file_logger.Tpo" -c -o file_logger.obj `if test -f 'bus/listeners/file_logger.c'; then $(CYGPATH_W) 'bus/listeners/file_logger.c'; else $(CYGPATH_W) '$(srcdir)/bus/listeners/file_logger.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/file_logger.Tpo" "$(DEPDIR)/file_logger.Po"; else rm -f "$(DEPDIR)/file_logger.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='bus/listeners/file_logger.c' object='file_logger.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o file_logger.obj `if test -f 'bus/listeners/file_logger.c'; then $(CYGPATH_W) 'bus/listeners/file_logger.c'; else $(CYGPATH_W) '$(srcdir)/bus/listeners/file_logger.c'; fi`
+
+connection.o: config/connections/connection.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT connection.o -MD -MP -MF "$(DEPDIR)/connection.Tpo" -c -o connection.o `test -f 'config/connections/connection.c' || echo '$(srcdir)/'`config/connections/connection.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/connection.Tpo" "$(DEPDIR)/connection.Po"; else rm -f "$(DEPDIR)/connection.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config/connections/connection.c' object='connection.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o connection.o `test -f 'config/connections/connection.c' || echo '$(srcdir)/'`config/connections/connection.c
+
+connection.obj: config/connections/connection.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT connection.obj -MD -MP -MF "$(DEPDIR)/connection.Tpo" -c -o connection.obj `if test -f 'config/connections/connection.c'; then $(CYGPATH_W) 'config/connections/connection.c'; else $(CYGPATH_W) '$(srcdir)/config/connections/connection.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/connection.Tpo" "$(DEPDIR)/connection.Po"; else rm -f "$(DEPDIR)/connection.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config/connections/connection.c' object='connection.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o connection.obj `if test -f 'config/connections/connection.c'; then $(CYGPATH_W) 'config/connections/connection.c'; else $(CYGPATH_W) '$(srcdir)/config/connections/connection.c'; fi`
+
+local_connection_store.o: config/connections/local_connection_store.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT local_connection_store.o -MD -MP -MF "$(DEPDIR)/local_connection_store.Tpo" -c -o local_connection_store.o `test -f 'config/connections/local_connection_store.c' || echo '$(srcdir)/'`config/connections/local_connection_store.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/local_connection_store.Tpo" "$(DEPDIR)/local_connection_store.Po"; else rm -f "$(DEPDIR)/local_connection_store.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config/connections/local_connection_store.c' object='local_connection_store.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o local_connection_store.o `test -f 'config/connections/local_connection_store.c' || echo '$(srcdir)/'`config/connections/local_connection_store.c
+
+local_connection_store.obj: config/connections/local_connection_store.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT local_connection_store.obj -MD -MP -MF "$(DEPDIR)/local_connection_store.Tpo" -c -o local_connection_store.obj `if test -f 'config/connections/local_connection_store.c'; then $(CYGPATH_W) 'config/connections/local_connection_store.c'; else $(CYGPATH_W) '$(srcdir)/config/connections/local_connection_store.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/local_connection_store.Tpo" "$(DEPDIR)/local_connection_store.Po"; else rm -f "$(DEPDIR)/local_connection_store.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config/connections/local_connection_store.c' object='local_connection_store.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o local_connection_store.obj `if test -f 'config/connections/local_connection_store.c'; then $(CYGPATH_W) 'config/connections/local_connection_store.c'; else $(CYGPATH_W) '$(srcdir)/config/connections/local_connection_store.c'; fi`
+
+policy.o: config/policies/policy.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT policy.o -MD -MP -MF "$(DEPDIR)/policy.Tpo" -c -o policy.o `test -f 'config/policies/policy.c' || echo '$(srcdir)/'`config/policies/policy.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/policy.Tpo" "$(DEPDIR)/policy.Po"; else rm -f "$(DEPDIR)/policy.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config/policies/policy.c' object='policy.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o policy.o `test -f 'config/policies/policy.c' || echo '$(srcdir)/'`config/policies/policy.c
+
+policy.obj: config/policies/policy.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT policy.obj -MD -MP -MF "$(DEPDIR)/policy.Tpo" -c -o policy.obj `if test -f 'config/policies/policy.c'; then $(CYGPATH_W) 'config/policies/policy.c'; else $(CYGPATH_W) '$(srcdir)/config/policies/policy.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/policy.Tpo" "$(DEPDIR)/policy.Po"; else rm -f "$(DEPDIR)/policy.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config/policies/policy.c' object='policy.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o policy.obj `if test -f 'config/policies/policy.c'; then $(CYGPATH_W) 'config/policies/policy.c'; else $(CYGPATH_W) '$(srcdir)/config/policies/policy.c'; fi`
+
+local_policy_store.o: config/policies/local_policy_store.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT local_policy_store.o -MD -MP -MF "$(DEPDIR)/local_policy_store.Tpo" -c -o local_policy_store.o `test -f 'config/policies/local_policy_store.c' || echo '$(srcdir)/'`config/policies/local_policy_store.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/local_policy_store.Tpo" "$(DEPDIR)/local_policy_store.Po"; else rm -f "$(DEPDIR)/local_policy_store.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config/policies/local_policy_store.c' object='local_policy_store.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o local_policy_store.o `test -f 'config/policies/local_policy_store.c' || echo '$(srcdir)/'`config/policies/local_policy_store.c
+
+local_policy_store.obj: config/policies/local_policy_store.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT local_policy_store.obj -MD -MP -MF "$(DEPDIR)/local_policy_store.Tpo" -c -o local_policy_store.obj `if test -f 'config/policies/local_policy_store.c'; then $(CYGPATH_W) 'config/policies/local_policy_store.c'; else $(CYGPATH_W) '$(srcdir)/config/policies/local_policy_store.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/local_policy_store.Tpo" "$(DEPDIR)/local_policy_store.Po"; else rm -f "$(DEPDIR)/local_policy_store.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config/policies/local_policy_store.c' object='local_policy_store.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o local_policy_store.obj `if test -f 'config/policies/local_policy_store.c'; then $(CYGPATH_W) 'config/policies/local_policy_store.c'; else $(CYGPATH_W) '$(srcdir)/config/policies/local_policy_store.c'; fi`
+
+local_credential_store.o: config/credentials/local_credential_store.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT local_credential_store.o -MD -MP -MF "$(DEPDIR)/local_credential_store.Tpo" -c -o local_credential_store.o `test -f 'config/credentials/local_credential_store.c' || echo '$(srcdir)/'`config/credentials/local_credential_store.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/local_credential_store.Tpo" "$(DEPDIR)/local_credential_store.Po"; else rm -f "$(DEPDIR)/local_credential_store.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config/credentials/local_credential_store.c' object='local_credential_store.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o local_credential_store.o `test -f 'config/credentials/local_credential_store.c' || echo '$(srcdir)/'`config/credentials/local_credential_store.c
+
+local_credential_store.obj: config/credentials/local_credential_store.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT local_credential_store.obj -MD -MP -MF "$(DEPDIR)/local_credential_store.Tpo" -c -o local_credential_store.obj `if test -f 'config/credentials/local_credential_store.c'; then $(CYGPATH_W) 'config/credentials/local_credential_store.c'; else $(CYGPATH_W) '$(srcdir)/config/credentials/local_credential_store.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/local_credential_store.Tpo" "$(DEPDIR)/local_credential_store.Po"; else rm -f "$(DEPDIR)/local_credential_store.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config/credentials/local_credential_store.c' object='local_credential_store.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o local_credential_store.obj `if test -f 'config/credentials/local_credential_store.c'; then $(CYGPATH_W) 'config/credentials/local_credential_store.c'; else $(CYGPATH_W) '$(srcdir)/config/credentials/local_credential_store.c'; fi`
+
+traffic_selector.o: config/traffic_selector.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT traffic_selector.o -MD -MP -MF "$(DEPDIR)/traffic_selector.Tpo" -c -o traffic_selector.o `test -f 'config/traffic_selector.c' || echo '$(srcdir)/'`config/traffic_selector.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/traffic_selector.Tpo" "$(DEPDIR)/traffic_selector.Po"; else rm -f "$(DEPDIR)/traffic_selector.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config/traffic_selector.c' object='traffic_selector.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o traffic_selector.o `test -f 'config/traffic_selector.c' || echo '$(srcdir)/'`config/traffic_selector.c
+
+traffic_selector.obj: config/traffic_selector.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT traffic_selector.obj -MD -MP -MF "$(DEPDIR)/traffic_selector.Tpo" -c -o traffic_selector.obj `if test -f 'config/traffic_selector.c'; then $(CYGPATH_W) 'config/traffic_selector.c'; else $(CYGPATH_W) '$(srcdir)/config/traffic_selector.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/traffic_selector.Tpo" "$(DEPDIR)/traffic_selector.Po"; else rm -f "$(DEPDIR)/traffic_selector.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config/traffic_selector.c' object='traffic_selector.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o traffic_selector.obj `if test -f 'config/traffic_selector.c'; then $(CYGPATH_W) 'config/traffic_selector.c'; else $(CYGPATH_W) '$(srcdir)/config/traffic_selector.c'; fi`
+
+proposal.o: config/proposal.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT proposal.o -MD -MP -MF "$(DEPDIR)/proposal.Tpo" -c -o proposal.o `test -f 'config/proposal.c' || echo '$(srcdir)/'`config/proposal.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/proposal.Tpo" "$(DEPDIR)/proposal.Po"; else rm -f "$(DEPDIR)/proposal.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config/proposal.c' object='proposal.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o proposal.o `test -f 'config/proposal.c' || echo '$(srcdir)/'`config/proposal.c
+
+proposal.obj: config/proposal.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT proposal.obj -MD -MP -MF "$(DEPDIR)/proposal.Tpo" -c -o proposal.obj `if test -f 'config/proposal.c'; then $(CYGPATH_W) 'config/proposal.c'; else $(CYGPATH_W) '$(srcdir)/config/proposal.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/proposal.Tpo" "$(DEPDIR)/proposal.Po"; else rm -f "$(DEPDIR)/proposal.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config/proposal.c' object='proposal.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o proposal.obj `if test -f 'config/proposal.c'; then $(CYGPATH_W) 'config/proposal.c'; else $(CYGPATH_W) '$(srcdir)/config/proposal.c'; fi`
+
+configuration.o: config/configuration.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT configuration.o -MD -MP -MF "$(DEPDIR)/configuration.Tpo" -c -o configuration.o `test -f 'config/configuration.c' || echo '$(srcdir)/'`config/configuration.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/configuration.Tpo" "$(DEPDIR)/configuration.Po"; else rm -f "$(DEPDIR)/configuration.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config/configuration.c' object='configuration.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o configuration.o `test -f 'config/configuration.c' || echo '$(srcdir)/'`config/configuration.c
+
+configuration.obj: config/configuration.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT configuration.obj -MD -MP -MF "$(DEPDIR)/configuration.Tpo" -c -o configuration.obj `if test -f 'config/configuration.c'; then $(CYGPATH_W) 'config/configuration.c'; else $(CYGPATH_W) '$(srcdir)/config/configuration.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/configuration.Tpo" "$(DEPDIR)/configuration.Po"; else rm -f "$(DEPDIR)/configuration.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config/configuration.c' object='configuration.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o configuration.obj `if test -f 'config/configuration.c'; then $(CYGPATH_W) 'config/configuration.c'; else $(CYGPATH_W) '$(srcdir)/config/configuration.c'; fi`
+
+eap_authenticator.o: sa/authenticators/eap_authenticator.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eap_authenticator.o -MD -MP -MF "$(DEPDIR)/eap_authenticator.Tpo" -c -o eap_authenticator.o `test -f 'sa/authenticators/eap_authenticator.c' || echo '$(srcdir)/'`sa/authenticators/eap_authenticator.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/eap_authenticator.Tpo" "$(DEPDIR)/eap_authenticator.Po"; else rm -f "$(DEPDIR)/eap_authenticator.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/authenticators/eap_authenticator.c' object='eap_authenticator.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o eap_authenticator.o `test -f 'sa/authenticators/eap_authenticator.c' || echo '$(srcdir)/'`sa/authenticators/eap_authenticator.c
+
+eap_authenticator.obj: sa/authenticators/eap_authenticator.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eap_authenticator.obj -MD -MP -MF "$(DEPDIR)/eap_authenticator.Tpo" -c -o eap_authenticator.obj `if test -f 'sa/authenticators/eap_authenticator.c'; then $(CYGPATH_W) 'sa/authenticators/eap_authenticator.c'; else $(CYGPATH_W) '$(srcdir)/sa/authenticators/eap_authenticator.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/eap_authenticator.Tpo" "$(DEPDIR)/eap_authenticator.Po"; else rm -f "$(DEPDIR)/eap_authenticator.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/authenticators/eap_authenticator.c' object='eap_authenticator.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o eap_authenticator.obj `if test -f 'sa/authenticators/eap_authenticator.c'; then $(CYGPATH_W) 'sa/authenticators/eap_authenticator.c'; else $(CYGPATH_W) '$(srcdir)/sa/authenticators/eap_authenticator.c'; fi`
+
+eap_method.o: sa/authenticators/eap/eap_method.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eap_method.o -MD -MP -MF "$(DEPDIR)/eap_method.Tpo" -c -o eap_method.o `test -f 'sa/authenticators/eap/eap_method.c' || echo '$(srcdir)/'`sa/authenticators/eap/eap_method.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/eap_method.Tpo" "$(DEPDIR)/eap_method.Po"; else rm -f "$(DEPDIR)/eap_method.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/authenticators/eap/eap_method.c' object='eap_method.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o eap_method.o `test -f 'sa/authenticators/eap/eap_method.c' || echo '$(srcdir)/'`sa/authenticators/eap/eap_method.c
+
+eap_method.obj: sa/authenticators/eap/eap_method.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eap_method.obj -MD -MP -MF "$(DEPDIR)/eap_method.Tpo" -c -o eap_method.obj `if test -f 'sa/authenticators/eap/eap_method.c'; then $(CYGPATH_W) 'sa/authenticators/eap/eap_method.c'; else $(CYGPATH_W) '$(srcdir)/sa/authenticators/eap/eap_method.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/eap_method.Tpo" "$(DEPDIR)/eap_method.Po"; else rm -f "$(DEPDIR)/eap_method.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/authenticators/eap/eap_method.c' object='eap_method.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o eap_method.obj `if test -f 'sa/authenticators/eap/eap_method.c'; then $(CYGPATH_W) 'sa/authenticators/eap/eap_method.c'; else $(CYGPATH_W) '$(srcdir)/sa/authenticators/eap/eap_method.c'; fi`
+
+child_sa.o: sa/child_sa.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT child_sa.o -MD -MP -MF "$(DEPDIR)/child_sa.Tpo" -c -o child_sa.o `test -f 'sa/child_sa.c' || echo '$(srcdir)/'`sa/child_sa.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/child_sa.Tpo" "$(DEPDIR)/child_sa.Po"; else rm -f "$(DEPDIR)/child_sa.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/child_sa.c' object='child_sa.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o child_sa.o `test -f 'sa/child_sa.c' || echo '$(srcdir)/'`sa/child_sa.c
+
+child_sa.obj: sa/child_sa.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT child_sa.obj -MD -MP -MF "$(DEPDIR)/child_sa.Tpo" -c -o child_sa.obj `if test -f 'sa/child_sa.c'; then $(CYGPATH_W) 'sa/child_sa.c'; else $(CYGPATH_W) '$(srcdir)/sa/child_sa.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/child_sa.Tpo" "$(DEPDIR)/child_sa.Po"; else rm -f "$(DEPDIR)/child_sa.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/child_sa.c' object='child_sa.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o child_sa.obj `if test -f 'sa/child_sa.c'; then $(CYGPATH_W) 'sa/child_sa.c'; else $(CYGPATH_W) '$(srcdir)/sa/child_sa.c'; fi`
+
+ike_sa.o: sa/ike_sa.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_sa.o -MD -MP -MF "$(DEPDIR)/ike_sa.Tpo" -c -o ike_sa.o `test -f 'sa/ike_sa.c' || echo '$(srcdir)/'`sa/ike_sa.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_sa.Tpo" "$(DEPDIR)/ike_sa.Po"; else rm -f "$(DEPDIR)/ike_sa.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ike_sa.c' object='ike_sa.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_sa.o `test -f 'sa/ike_sa.c' || echo '$(srcdir)/'`sa/ike_sa.c
+
+ike_sa.obj: sa/ike_sa.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_sa.obj -MD -MP -MF "$(DEPDIR)/ike_sa.Tpo" -c -o ike_sa.obj `if test -f 'sa/ike_sa.c'; then $(CYGPATH_W) 'sa/ike_sa.c'; else $(CYGPATH_W) '$(srcdir)/sa/ike_sa.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_sa.Tpo" "$(DEPDIR)/ike_sa.Po"; else rm -f "$(DEPDIR)/ike_sa.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ike_sa.c' object='ike_sa.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_sa.obj `if test -f 'sa/ike_sa.c'; then $(CYGPATH_W) 'sa/ike_sa.c'; else $(CYGPATH_W) '$(srcdir)/sa/ike_sa.c'; fi`
+
+ike_sa_manager.o: sa/ike_sa_manager.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_sa_manager.o -MD -MP -MF "$(DEPDIR)/ike_sa_manager.Tpo" -c -o ike_sa_manager.o `test -f 'sa/ike_sa_manager.c' || echo '$(srcdir)/'`sa/ike_sa_manager.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_sa_manager.Tpo" "$(DEPDIR)/ike_sa_manager.Po"; else rm -f "$(DEPDIR)/ike_sa_manager.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ike_sa_manager.c' object='ike_sa_manager.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_sa_manager.o `test -f 'sa/ike_sa_manager.c' || echo '$(srcdir)/'`sa/ike_sa_manager.c
+
+ike_sa_manager.obj: sa/ike_sa_manager.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_sa_manager.obj -MD -MP -MF "$(DEPDIR)/ike_sa_manager.Tpo" -c -o ike_sa_manager.obj `if test -f 'sa/ike_sa_manager.c'; then $(CYGPATH_W) 'sa/ike_sa_manager.c'; else $(CYGPATH_W) '$(srcdir)/sa/ike_sa_manager.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_sa_manager.Tpo" "$(DEPDIR)/ike_sa_manager.Po"; else rm -f "$(DEPDIR)/ike_sa_manager.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ike_sa_manager.c' object='ike_sa_manager.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_sa_manager.obj `if test -f 'sa/ike_sa_manager.c'; then $(CYGPATH_W) 'sa/ike_sa_manager.c'; else $(CYGPATH_W) '$(srcdir)/sa/ike_sa_manager.c'; fi`
+
+ike_sa_id.o: sa/ike_sa_id.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_sa_id.o -MD -MP -MF "$(DEPDIR)/ike_sa_id.Tpo" -c -o ike_sa_id.o `test -f 'sa/ike_sa_id.c' || echo '$(srcdir)/'`sa/ike_sa_id.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_sa_id.Tpo" "$(DEPDIR)/ike_sa_id.Po"; else rm -f "$(DEPDIR)/ike_sa_id.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ike_sa_id.c' object='ike_sa_id.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_sa_id.o `test -f 'sa/ike_sa_id.c' || echo '$(srcdir)/'`sa/ike_sa_id.c
+
+ike_sa_id.obj: sa/ike_sa_id.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_sa_id.obj -MD -MP -MF "$(DEPDIR)/ike_sa_id.Tpo" -c -o ike_sa_id.obj `if test -f 'sa/ike_sa_id.c'; then $(CYGPATH_W) 'sa/ike_sa_id.c'; else $(CYGPATH_W) '$(srcdir)/sa/ike_sa_id.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_sa_id.Tpo" "$(DEPDIR)/ike_sa_id.Po"; else rm -f "$(DEPDIR)/ike_sa_id.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ike_sa_id.c' object='ike_sa_id.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_sa_id.obj `if test -f 'sa/ike_sa_id.c'; then $(CYGPATH_W) 'sa/ike_sa_id.c'; else $(CYGPATH_W) '$(srcdir)/sa/ike_sa_id.c'; fi`
+
+task.o: sa/tasks/task.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT task.o -MD -MP -MF "$(DEPDIR)/task.Tpo" -c -o task.o `test -f 'sa/tasks/task.c' || echo '$(srcdir)/'`sa/tasks/task.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/task.Tpo" "$(DEPDIR)/task.Po"; else rm -f "$(DEPDIR)/task.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/task.c' object='task.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o task.o `test -f 'sa/tasks/task.c' || echo '$(srcdir)/'`sa/tasks/task.c
+
+task.obj: sa/tasks/task.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT task.obj -MD -MP -MF "$(DEPDIR)/task.Tpo" -c -o task.obj `if test -f 'sa/tasks/task.c'; then $(CYGPATH_W) 'sa/tasks/task.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/task.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/task.Tpo" "$(DEPDIR)/task.Po"; else rm -f "$(DEPDIR)/task.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/task.c' object='task.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o task.obj `if test -f 'sa/tasks/task.c'; then $(CYGPATH_W) 'sa/tasks/task.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/task.c'; fi`
+
+ike_init.o: sa/tasks/ike_init.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_init.o -MD -MP -MF "$(DEPDIR)/ike_init.Tpo" -c -o ike_init.o `test -f 'sa/tasks/ike_init.c' || echo '$(srcdir)/'`sa/tasks/ike_init.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_init.Tpo" "$(DEPDIR)/ike_init.Po"; else rm -f "$(DEPDIR)/ike_init.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_init.c' object='ike_init.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_init.o `test -f 'sa/tasks/ike_init.c' || echo '$(srcdir)/'`sa/tasks/ike_init.c
+
+ike_init.obj: sa/tasks/ike_init.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_init.obj -MD -MP -MF "$(DEPDIR)/ike_init.Tpo" -c -o ike_init.obj `if test -f 'sa/tasks/ike_init.c'; then $(CYGPATH_W) 'sa/tasks/ike_init.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/ike_init.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_init.Tpo" "$(DEPDIR)/ike_init.Po"; else rm -f "$(DEPDIR)/ike_init.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_init.c' object='ike_init.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_init.obj `if test -f 'sa/tasks/ike_init.c'; then $(CYGPATH_W) 'sa/tasks/ike_init.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/ike_init.c'; fi`
+
+ike_natd.o: sa/tasks/ike_natd.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_natd.o -MD -MP -MF "$(DEPDIR)/ike_natd.Tpo" -c -o ike_natd.o `test -f 'sa/tasks/ike_natd.c' || echo '$(srcdir)/'`sa/tasks/ike_natd.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_natd.Tpo" "$(DEPDIR)/ike_natd.Po"; else rm -f "$(DEPDIR)/ike_natd.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_natd.c' object='ike_natd.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_natd.o `test -f 'sa/tasks/ike_natd.c' || echo '$(srcdir)/'`sa/tasks/ike_natd.c
+
+ike_natd.obj: sa/tasks/ike_natd.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_natd.obj -MD -MP -MF "$(DEPDIR)/ike_natd.Tpo" -c -o ike_natd.obj `if test -f 'sa/tasks/ike_natd.c'; then $(CYGPATH_W) 'sa/tasks/ike_natd.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/ike_natd.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_natd.Tpo" "$(DEPDIR)/ike_natd.Po"; else rm -f "$(DEPDIR)/ike_natd.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_natd.c' object='ike_natd.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_natd.obj `if test -f 'sa/tasks/ike_natd.c'; then $(CYGPATH_W) 'sa/tasks/ike_natd.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/ike_natd.c'; fi`
+
+ike_auth.o: sa/tasks/ike_auth.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_auth.o -MD -MP -MF "$(DEPDIR)/ike_auth.Tpo" -c -o ike_auth.o `test -f 'sa/tasks/ike_auth.c' || echo '$(srcdir)/'`sa/tasks/ike_auth.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_auth.Tpo" "$(DEPDIR)/ike_auth.Po"; else rm -f "$(DEPDIR)/ike_auth.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_auth.c' object='ike_auth.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_auth.o `test -f 'sa/tasks/ike_auth.c' || echo '$(srcdir)/'`sa/tasks/ike_auth.c
+
+ike_auth.obj: sa/tasks/ike_auth.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_auth.obj -MD -MP -MF "$(DEPDIR)/ike_auth.Tpo" -c -o ike_auth.obj `if test -f 'sa/tasks/ike_auth.c'; then $(CYGPATH_W) 'sa/tasks/ike_auth.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/ike_auth.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_auth.Tpo" "$(DEPDIR)/ike_auth.Po"; else rm -f "$(DEPDIR)/ike_auth.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_auth.c' object='ike_auth.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_auth.obj `if test -f 'sa/tasks/ike_auth.c'; then $(CYGPATH_W) 'sa/tasks/ike_auth.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/ike_auth.c'; fi`
+
+ike_config.o: sa/tasks/ike_config.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_config.o -MD -MP -MF "$(DEPDIR)/ike_config.Tpo" -c -o ike_config.o `test -f 'sa/tasks/ike_config.c' || echo '$(srcdir)/'`sa/tasks/ike_config.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_config.Tpo" "$(DEPDIR)/ike_config.Po"; else rm -f "$(DEPDIR)/ike_config.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_config.c' object='ike_config.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_config.o `test -f 'sa/tasks/ike_config.c' || echo '$(srcdir)/'`sa/tasks/ike_config.c
+
+ike_config.obj: sa/tasks/ike_config.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_config.obj -MD -MP -MF "$(DEPDIR)/ike_config.Tpo" -c -o ike_config.obj `if test -f 'sa/tasks/ike_config.c'; then $(CYGPATH_W) 'sa/tasks/ike_config.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/ike_config.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_config.Tpo" "$(DEPDIR)/ike_config.Po"; else rm -f "$(DEPDIR)/ike_config.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_config.c' object='ike_config.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_config.obj `if test -f 'sa/tasks/ike_config.c'; then $(CYGPATH_W) 'sa/tasks/ike_config.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/ike_config.c'; fi`
+
+ike_cert.o: sa/tasks/ike_cert.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_cert.o -MD -MP -MF "$(DEPDIR)/ike_cert.Tpo" -c -o ike_cert.o `test -f 'sa/tasks/ike_cert.c' || echo '$(srcdir)/'`sa/tasks/ike_cert.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_cert.Tpo" "$(DEPDIR)/ike_cert.Po"; else rm -f "$(DEPDIR)/ike_cert.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_cert.c' object='ike_cert.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_cert.o `test -f 'sa/tasks/ike_cert.c' || echo '$(srcdir)/'`sa/tasks/ike_cert.c
+
+ike_cert.obj: sa/tasks/ike_cert.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_cert.obj -MD -MP -MF "$(DEPDIR)/ike_cert.Tpo" -c -o ike_cert.obj `if test -f 'sa/tasks/ike_cert.c'; then $(CYGPATH_W) 'sa/tasks/ike_cert.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/ike_cert.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_cert.Tpo" "$(DEPDIR)/ike_cert.Po"; else rm -f "$(DEPDIR)/ike_cert.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_cert.c' object='ike_cert.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_cert.obj `if test -f 'sa/tasks/ike_cert.c'; then $(CYGPATH_W) 'sa/tasks/ike_cert.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/ike_cert.c'; fi`
+
+ike_rekey.o: sa/tasks/ike_rekey.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_rekey.o -MD -MP -MF "$(DEPDIR)/ike_rekey.Tpo" -c -o ike_rekey.o `test -f 'sa/tasks/ike_rekey.c' || echo '$(srcdir)/'`sa/tasks/ike_rekey.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_rekey.Tpo" "$(DEPDIR)/ike_rekey.Po"; else rm -f "$(DEPDIR)/ike_rekey.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_rekey.c' object='ike_rekey.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_rekey.o `test -f 'sa/tasks/ike_rekey.c' || echo '$(srcdir)/'`sa/tasks/ike_rekey.c
+
+ike_rekey.obj: sa/tasks/ike_rekey.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_rekey.obj -MD -MP -MF "$(DEPDIR)/ike_rekey.Tpo" -c -o ike_rekey.obj `if test -f 'sa/tasks/ike_rekey.c'; then $(CYGPATH_W) 'sa/tasks/ike_rekey.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/ike_rekey.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_rekey.Tpo" "$(DEPDIR)/ike_rekey.Po"; else rm -f "$(DEPDIR)/ike_rekey.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_rekey.c' object='ike_rekey.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_rekey.obj `if test -f 'sa/tasks/ike_rekey.c'; then $(CYGPATH_W) 'sa/tasks/ike_rekey.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/ike_rekey.c'; fi`
+
+ike_delete.o: sa/tasks/ike_delete.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_delete.o -MD -MP -MF "$(DEPDIR)/ike_delete.Tpo" -c -o ike_delete.o `test -f 'sa/tasks/ike_delete.c' || echo '$(srcdir)/'`sa/tasks/ike_delete.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_delete.Tpo" "$(DEPDIR)/ike_delete.Po"; else rm -f "$(DEPDIR)/ike_delete.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_delete.c' object='ike_delete.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_delete.o `test -f 'sa/tasks/ike_delete.c' || echo '$(srcdir)/'`sa/tasks/ike_delete.c
+
+ike_delete.obj: sa/tasks/ike_delete.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_delete.obj -MD -MP -MF "$(DEPDIR)/ike_delete.Tpo" -c -o ike_delete.obj `if test -f 'sa/tasks/ike_delete.c'; then $(CYGPATH_W) 'sa/tasks/ike_delete.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/ike_delete.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_delete.Tpo" "$(DEPDIR)/ike_delete.Po"; else rm -f "$(DEPDIR)/ike_delete.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_delete.c' object='ike_delete.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_delete.obj `if test -f 'sa/tasks/ike_delete.c'; then $(CYGPATH_W) 'sa/tasks/ike_delete.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/ike_delete.c'; fi`
+
+ike_dpd.o: sa/tasks/ike_dpd.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_dpd.o -MD -MP -MF "$(DEPDIR)/ike_dpd.Tpo" -c -o ike_dpd.o `test -f 'sa/tasks/ike_dpd.c' || echo '$(srcdir)/'`sa/tasks/ike_dpd.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_dpd.Tpo" "$(DEPDIR)/ike_dpd.Po"; else rm -f "$(DEPDIR)/ike_dpd.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_dpd.c' object='ike_dpd.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_dpd.o `test -f 'sa/tasks/ike_dpd.c' || echo '$(srcdir)/'`sa/tasks/ike_dpd.c
+
+ike_dpd.obj: sa/tasks/ike_dpd.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_dpd.obj -MD -MP -MF "$(DEPDIR)/ike_dpd.Tpo" -c -o ike_dpd.obj `if test -f 'sa/tasks/ike_dpd.c'; then $(CYGPATH_W) 'sa/tasks/ike_dpd.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/ike_dpd.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_dpd.Tpo" "$(DEPDIR)/ike_dpd.Po"; else rm -f "$(DEPDIR)/ike_dpd.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_dpd.c' object='ike_dpd.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_dpd.obj `if test -f 'sa/tasks/ike_dpd.c'; then $(CYGPATH_W) 'sa/tasks/ike_dpd.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/ike_dpd.c'; fi`
+
+child_create.o: sa/tasks/child_create.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT child_create.o -MD -MP -MF "$(DEPDIR)/child_create.Tpo" -c -o child_create.o `test -f 'sa/tasks/child_create.c' || echo '$(srcdir)/'`sa/tasks/child_create.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/child_create.Tpo" "$(DEPDIR)/child_create.Po"; else rm -f "$(DEPDIR)/child_create.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/child_create.c' object='child_create.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o child_create.o `test -f 'sa/tasks/child_create.c' || echo '$(srcdir)/'`sa/tasks/child_create.c
+
+child_create.obj: sa/tasks/child_create.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT child_create.obj -MD -MP -MF "$(DEPDIR)/child_create.Tpo" -c -o child_create.obj `if test -f 'sa/tasks/child_create.c'; then $(CYGPATH_W) 'sa/tasks/child_create.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/child_create.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/child_create.Tpo" "$(DEPDIR)/child_create.Po"; else rm -f "$(DEPDIR)/child_create.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/child_create.c' object='child_create.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o child_create.obj `if test -f 'sa/tasks/child_create.c'; then $(CYGPATH_W) 'sa/tasks/child_create.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/child_create.c'; fi`
+
+child_delete.o: sa/tasks/child_delete.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT child_delete.o -MD -MP -MF "$(DEPDIR)/child_delete.Tpo" -c -o child_delete.o `test -f 'sa/tasks/child_delete.c' || echo '$(srcdir)/'`sa/tasks/child_delete.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/child_delete.Tpo" "$(DEPDIR)/child_delete.Po"; else rm -f "$(DEPDIR)/child_delete.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/child_delete.c' object='child_delete.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o child_delete.o `test -f 'sa/tasks/child_delete.c' || echo '$(srcdir)/'`sa/tasks/child_delete.c
+
+child_delete.obj: sa/tasks/child_delete.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT child_delete.obj -MD -MP -MF "$(DEPDIR)/child_delete.Tpo" -c -o child_delete.obj `if test -f 'sa/tasks/child_delete.c'; then $(CYGPATH_W) 'sa/tasks/child_delete.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/child_delete.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/child_delete.Tpo" "$(DEPDIR)/child_delete.Po"; else rm -f "$(DEPDIR)/child_delete.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/child_delete.c' object='child_delete.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o child_delete.obj `if test -f 'sa/tasks/child_delete.c'; then $(CYGPATH_W) 'sa/tasks/child_delete.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/child_delete.c'; fi`
+
+child_rekey.o: sa/tasks/child_rekey.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT child_rekey.o -MD -MP -MF "$(DEPDIR)/child_rekey.Tpo" -c -o child_rekey.o `test -f 'sa/tasks/child_rekey.c' || echo '$(srcdir)/'`sa/tasks/child_rekey.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/child_rekey.Tpo" "$(DEPDIR)/child_rekey.Po"; else rm -f "$(DEPDIR)/child_rekey.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/child_rekey.c' object='child_rekey.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o child_rekey.o `test -f 'sa/tasks/child_rekey.c' || echo '$(srcdir)/'`sa/tasks/child_rekey.c
+
+child_rekey.obj: sa/tasks/child_rekey.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT child_rekey.obj -MD -MP -MF "$(DEPDIR)/child_rekey.Tpo" -c -o child_rekey.obj `if test -f 'sa/tasks/child_rekey.c'; then $(CYGPATH_W) 'sa/tasks/child_rekey.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/child_rekey.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/child_rekey.Tpo" "$(DEPDIR)/child_rekey.Po"; else rm -f "$(DEPDIR)/child_rekey.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/child_rekey.c' object='child_rekey.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o child_rekey.obj `if test -f 'sa/tasks/child_rekey.c'; then $(CYGPATH_W) 'sa/tasks/child_rekey.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/child_rekey.c'; fi`
+
+authenticator.o: sa/authenticators/authenticator.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT authenticator.o -MD -MP -MF "$(DEPDIR)/authenticator.Tpo" -c -o authenticator.o `test -f 'sa/authenticators/authenticator.c' || echo '$(srcdir)/'`sa/authenticators/authenticator.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/authenticator.Tpo" "$(DEPDIR)/authenticator.Po"; else rm -f "$(DEPDIR)/authenticator.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/authenticators/authenticator.c' object='authenticator.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o authenticator.o `test -f 'sa/authenticators/authenticator.c' || echo '$(srcdir)/'`sa/authenticators/authenticator.c
+
+authenticator.obj: sa/authenticators/authenticator.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT authenticator.obj -MD -MP -MF "$(DEPDIR)/authenticator.Tpo" -c -o authenticator.obj `if test -f 'sa/authenticators/authenticator.c'; then $(CYGPATH_W) 'sa/authenticators/authenticator.c'; else $(CYGPATH_W) '$(srcdir)/sa/authenticators/authenticator.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/authenticator.Tpo" "$(DEPDIR)/authenticator.Po"; else rm -f "$(DEPDIR)/authenticator.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/authenticators/authenticator.c' object='authenticator.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o authenticator.obj `if test -f 'sa/authenticators/authenticator.c'; then $(CYGPATH_W) 'sa/authenticators/authenticator.c'; else $(CYGPATH_W) '$(srcdir)/sa/authenticators/authenticator.c'; fi`
+
+rsa_authenticator.o: sa/authenticators/rsa_authenticator.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rsa_authenticator.o -MD -MP -MF "$(DEPDIR)/rsa_authenticator.Tpo" -c -o rsa_authenticator.o `test -f 'sa/authenticators/rsa_authenticator.c' || echo '$(srcdir)/'`sa/authenticators/rsa_authenticator.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/rsa_authenticator.Tpo" "$(DEPDIR)/rsa_authenticator.Po"; else rm -f "$(DEPDIR)/rsa_authenticator.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/authenticators/rsa_authenticator.c' object='rsa_authenticator.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rsa_authenticator.o `test -f 'sa/authenticators/rsa_authenticator.c' || echo '$(srcdir)/'`sa/authenticators/rsa_authenticator.c
+
+rsa_authenticator.obj: sa/authenticators/rsa_authenticator.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rsa_authenticator.obj -MD -MP -MF "$(DEPDIR)/rsa_authenticator.Tpo" -c -o rsa_authenticator.obj `if test -f 'sa/authenticators/rsa_authenticator.c'; then $(CYGPATH_W) 'sa/authenticators/rsa_authenticator.c'; else $(CYGPATH_W) '$(srcdir)/sa/authenticators/rsa_authenticator.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/rsa_authenticator.Tpo" "$(DEPDIR)/rsa_authenticator.Po"; else rm -f "$(DEPDIR)/rsa_authenticator.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/authenticators/rsa_authenticator.c' object='rsa_authenticator.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rsa_authenticator.obj `if test -f 'sa/authenticators/rsa_authenticator.c'; then $(CYGPATH_W) 'sa/authenticators/rsa_authenticator.c'; else $(CYGPATH_W) '$(srcdir)/sa/authenticators/rsa_authenticator.c'; fi`
+
+psk_authenticator.o: sa/authenticators/psk_authenticator.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT psk_authenticator.o -MD -MP -MF "$(DEPDIR)/psk_authenticator.Tpo" -c -o psk_authenticator.o `test -f 'sa/authenticators/psk_authenticator.c' || echo '$(srcdir)/'`sa/authenticators/psk_authenticator.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/psk_authenticator.Tpo" "$(DEPDIR)/psk_authenticator.Po"; else rm -f "$(DEPDIR)/psk_authenticator.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/authenticators/psk_authenticator.c' object='psk_authenticator.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o psk_authenticator.o `test -f 'sa/authenticators/psk_authenticator.c' || echo '$(srcdir)/'`sa/authenticators/psk_authenticator.c
+
+psk_authenticator.obj: sa/authenticators/psk_authenticator.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT psk_authenticator.obj -MD -MP -MF "$(DEPDIR)/psk_authenticator.Tpo" -c -o psk_authenticator.obj `if test -f 'sa/authenticators/psk_authenticator.c'; then $(CYGPATH_W) 'sa/authenticators/psk_authenticator.c'; else $(CYGPATH_W) '$(srcdir)/sa/authenticators/psk_authenticator.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/psk_authenticator.Tpo" "$(DEPDIR)/psk_authenticator.Po"; else rm -f "$(DEPDIR)/psk_authenticator.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/authenticators/psk_authenticator.c' object='psk_authenticator.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o psk_authenticator.obj `if test -f 'sa/authenticators/psk_authenticator.c'; then $(CYGPATH_W) 'sa/authenticators/psk_authenticator.c'; else $(CYGPATH_W) '$(srcdir)/sa/authenticators/psk_authenticator.c'; fi`
+
+task_manager.o: sa/task_manager.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT task_manager.o -MD -MP -MF "$(DEPDIR)/task_manager.Tpo" -c -o task_manager.o `test -f 'sa/task_manager.c' || echo '$(srcdir)/'`sa/task_manager.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/task_manager.Tpo" "$(DEPDIR)/task_manager.Po"; else rm -f "$(DEPDIR)/task_manager.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/task_manager.c' object='task_manager.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o task_manager.o `test -f 'sa/task_manager.c' || echo '$(srcdir)/'`sa/task_manager.c
+
+task_manager.obj: sa/task_manager.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT task_manager.obj -MD -MP -MF "$(DEPDIR)/task_manager.Tpo" -c -o task_manager.obj `if test -f 'sa/task_manager.c'; then $(CYGPATH_W) 'sa/task_manager.c'; else $(CYGPATH_W) '$(srcdir)/sa/task_manager.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/task_manager.Tpo" "$(DEPDIR)/task_manager.Po"; else rm -f "$(DEPDIR)/task_manager.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/task_manager.c' object='task_manager.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o task_manager.obj `if test -f 'sa/task_manager.c'; then $(CYGPATH_W) 'sa/task_manager.c'; else $(CYGPATH_W) '$(srcdir)/sa/task_manager.c'; fi`
+
+encryption_payload.o: encoding/payloads/encryption_payload.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT encryption_payload.o -MD -MP -MF "$(DEPDIR)/encryption_payload.Tpo" -c -o encryption_payload.o `test -f 'encoding/payloads/encryption_payload.c' || echo '$(srcdir)/'`encoding/payloads/encryption_payload.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/encryption_payload.Tpo" "$(DEPDIR)/encryption_payload.Po"; else rm -f "$(DEPDIR)/encryption_payload.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/encryption_payload.c' object='encryption_payload.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o encryption_payload.o `test -f 'encoding/payloads/encryption_payload.c' || echo '$(srcdir)/'`encoding/payloads/encryption_payload.c
+
+encryption_payload.obj: encoding/payloads/encryption_payload.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT encryption_payload.obj -MD -MP -MF "$(DEPDIR)/encryption_payload.Tpo" -c -o encryption_payload.obj `if test -f 'encoding/payloads/encryption_payload.c'; then $(CYGPATH_W) 'encoding/payloads/encryption_payload.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/encryption_payload.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/encryption_payload.Tpo" "$(DEPDIR)/encryption_payload.Po"; else rm -f "$(DEPDIR)/encryption_payload.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/encryption_payload.c' object='encryption_payload.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o encryption_payload.obj `if test -f 'encoding/payloads/encryption_payload.c'; then $(CYGPATH_W) 'encoding/payloads/encryption_payload.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/encryption_payload.c'; fi`
+
+cert_payload.o: encoding/payloads/cert_payload.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cert_payload.o -MD -MP -MF "$(DEPDIR)/cert_payload.Tpo" -c -o cert_payload.o `test -f 'encoding/payloads/cert_payload.c' || echo '$(srcdir)/'`encoding/payloads/cert_payload.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/cert_payload.Tpo" "$(DEPDIR)/cert_payload.Po"; else rm -f "$(DEPDIR)/cert_payload.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/cert_payload.c' object='cert_payload.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cert_payload.o `test -f 'encoding/payloads/cert_payload.c' || echo '$(srcdir)/'`encoding/payloads/cert_payload.c
+
+cert_payload.obj: encoding/payloads/cert_payload.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cert_payload.obj -MD -MP -MF "$(DEPDIR)/cert_payload.Tpo" -c -o cert_payload.obj `if test -f 'encoding/payloads/cert_payload.c'; then $(CYGPATH_W) 'encoding/payloads/cert_payload.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/cert_payload.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/cert_payload.Tpo" "$(DEPDIR)/cert_payload.Po"; else rm -f "$(DEPDIR)/cert_payload.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/cert_payload.c' object='cert_payload.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cert_payload.obj `if test -f 'encoding/payloads/cert_payload.c'; then $(CYGPATH_W) 'encoding/payloads/cert_payload.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/cert_payload.c'; fi`
+
+traffic_selector_substructure.o: encoding/payloads/traffic_selector_substructure.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT traffic_selector_substructure.o -MD -MP -MF "$(DEPDIR)/traffic_selector_substructure.Tpo" -c -o traffic_selector_substructure.o `test -f 'encoding/payloads/traffic_selector_substructure.c' || echo '$(srcdir)/'`encoding/payloads/traffic_selector_substructure.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/traffic_selector_substructure.Tpo" "$(DEPDIR)/traffic_selector_substructure.Po"; else rm -f "$(DEPDIR)/traffic_selector_substructure.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/traffic_selector_substructure.c' object='traffic_selector_substructure.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o traffic_selector_substructure.o `test -f 'encoding/payloads/traffic_selector_substructure.c' || echo '$(srcdir)/'`encoding/payloads/traffic_selector_substructure.c
+
+traffic_selector_substructure.obj: encoding/payloads/traffic_selector_substructure.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT traffic_selector_substructure.obj -MD -MP -MF "$(DEPDIR)/traffic_selector_substructure.Tpo" -c -o traffic_selector_substructure.obj `if test -f 'encoding/payloads/traffic_selector_substructure.c'; then $(CYGPATH_W) 'encoding/payloads/traffic_selector_substructure.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/traffic_selector_substructure.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/traffic_selector_substructure.Tpo" "$(DEPDIR)/traffic_selector_substructure.Po"; else rm -f "$(DEPDIR)/traffic_selector_substructure.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/traffic_selector_substructure.c' object='traffic_selector_substructure.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o traffic_selector_substructure.obj `if test -f 'encoding/payloads/traffic_selector_substructure.c'; then $(CYGPATH_W) 'encoding/payloads/traffic_selector_substructure.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/traffic_selector_substructure.c'; fi`
+
+transform_attribute.o: encoding/payloads/transform_attribute.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT transform_attribute.o -MD -MP -MF "$(DEPDIR)/transform_attribute.Tpo" -c -o transform_attribute.o `test -f 'encoding/payloads/transform_attribute.c' || echo '$(srcdir)/'`encoding/payloads/transform_attribute.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/transform_attribute.Tpo" "$(DEPDIR)/transform_attribute.Po"; else rm -f "$(DEPDIR)/transform_attribute.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/transform_attribute.c' object='transform_attribute.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o transform_attribute.o `test -f 'encoding/payloads/transform_attribute.c' || echo '$(srcdir)/'`encoding/payloads/transform_attribute.c
+
+transform_attribute.obj: encoding/payloads/transform_attribute.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT transform_attribute.obj -MD -MP -MF "$(DEPDIR)/transform_attribute.Tpo" -c -o transform_attribute.obj `if test -f 'encoding/payloads/transform_attribute.c'; then $(CYGPATH_W) 'encoding/payloads/transform_attribute.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/transform_attribute.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/transform_attribute.Tpo" "$(DEPDIR)/transform_attribute.Po"; else rm -f "$(DEPDIR)/transform_attribute.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/transform_attribute.c' object='transform_attribute.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o transform_attribute.obj `if test -f 'encoding/payloads/transform_attribute.c'; then $(CYGPATH_W) 'encoding/payloads/transform_attribute.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/transform_attribute.c'; fi`
+
+configuration_attribute.o: encoding/payloads/configuration_attribute.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT configuration_attribute.o -MD -MP -MF "$(DEPDIR)/configuration_attribute.Tpo" -c -o configuration_attribute.o `test -f 'encoding/payloads/configuration_attribute.c' || echo '$(srcdir)/'`encoding/payloads/configuration_attribute.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/configuration_attribute.Tpo" "$(DEPDIR)/configuration_attribute.Po"; else rm -f "$(DEPDIR)/configuration_attribute.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/configuration_attribute.c' object='configuration_attribute.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o configuration_attribute.o `test -f 'encoding/payloads/configuration_attribute.c' || echo '$(srcdir)/'`encoding/payloads/configuration_attribute.c
+
+configuration_attribute.obj: encoding/payloads/configuration_attribute.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT configuration_attribute.obj -MD -MP -MF "$(DEPDIR)/configuration_attribute.Tpo" -c -o configuration_attribute.obj `if test -f 'encoding/payloads/configuration_attribute.c'; then $(CYGPATH_W) 'encoding/payloads/configuration_attribute.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/configuration_attribute.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/configuration_attribute.Tpo" "$(DEPDIR)/configuration_attribute.Po"; else rm -f "$(DEPDIR)/configuration_attribute.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/configuration_attribute.c' object='configuration_attribute.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o configuration_attribute.obj `if test -f 'encoding/payloads/configuration_attribute.c'; then $(CYGPATH_W) 'encoding/payloads/configuration_attribute.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/configuration_attribute.c'; fi`
+
+transform_substructure.o: encoding/payloads/transform_substructure.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT transform_substructure.o -MD -MP -MF "$(DEPDIR)/transform_substructure.Tpo" -c -o transform_substructure.o `test -f 'encoding/payloads/transform_substructure.c' || echo '$(srcdir)/'`encoding/payloads/transform_substructure.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/transform_substructure.Tpo" "$(DEPDIR)/transform_substructure.Po"; else rm -f "$(DEPDIR)/transform_substructure.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/transform_substructure.c' object='transform_substructure.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o transform_substructure.o `test -f 'encoding/payloads/transform_substructure.c' || echo '$(srcdir)/'`encoding/payloads/transform_substructure.c
+
+transform_substructure.obj: encoding/payloads/transform_substructure.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT transform_substructure.obj -MD -MP -MF "$(DEPDIR)/transform_substructure.Tpo" -c -o transform_substructure.obj `if test -f 'encoding/payloads/transform_substructure.c'; then $(CYGPATH_W) 'encoding/payloads/transform_substructure.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/transform_substructure.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/transform_substructure.Tpo" "$(DEPDIR)/transform_substructure.Po"; else rm -f "$(DEPDIR)/transform_substructure.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/transform_substructure.c' object='transform_substructure.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o transform_substructure.obj `if test -f 'encoding/payloads/transform_substructure.c'; then $(CYGPATH_W) 'encoding/payloads/transform_substructure.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/transform_substructure.c'; fi`
+
+auth_payload.o: encoding/payloads/auth_payload.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT auth_payload.o -MD -MP -MF "$(DEPDIR)/auth_payload.Tpo" -c -o auth_payload.o `test -f 'encoding/payloads/auth_payload.c' || echo '$(srcdir)/'`encoding/payloads/auth_payload.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/auth_payload.Tpo" "$(DEPDIR)/auth_payload.Po"; else rm -f "$(DEPDIR)/auth_payload.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/auth_payload.c' object='auth_payload.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o auth_payload.o `test -f 'encoding/payloads/auth_payload.c' || echo '$(srcdir)/'`encoding/payloads/auth_payload.c
+
+auth_payload.obj: encoding/payloads/auth_payload.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT auth_payload.obj -MD -MP -MF "$(DEPDIR)/auth_payload.Tpo" -c -o auth_payload.obj `if test -f 'encoding/payloads/auth_payload.c'; then $(CYGPATH_W) 'encoding/payloads/auth_payload.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/auth_payload.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/auth_payload.Tpo" "$(DEPDIR)/auth_payload.Po"; else rm -f "$(DEPDIR)/auth_payload.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/auth_payload.c' object='auth_payload.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o auth_payload.obj `if test -f 'encoding/payloads/auth_payload.c'; then $(CYGPATH_W) 'encoding/payloads/auth_payload.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/auth_payload.c'; fi`
+
+ike_header.o: encoding/payloads/ike_header.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_header.o -MD -MP -MF "$(DEPDIR)/ike_header.Tpo" -c -o ike_header.o `test -f 'encoding/payloads/ike_header.c' || echo '$(srcdir)/'`encoding/payloads/ike_header.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_header.Tpo" "$(DEPDIR)/ike_header.Po"; else rm -f "$(DEPDIR)/ike_header.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/ike_header.c' object='ike_header.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_header.o `test -f 'encoding/payloads/ike_header.c' || echo '$(srcdir)/'`encoding/payloads/ike_header.c
+
+ike_header.obj: encoding/payloads/ike_header.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_header.obj -MD -MP -MF "$(DEPDIR)/ike_header.Tpo" -c -o ike_header.obj `if test -f 'encoding/payloads/ike_header.c'; then $(CYGPATH_W) 'encoding/payloads/ike_header.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/ike_header.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_header.Tpo" "$(DEPDIR)/ike_header.Po"; else rm -f "$(DEPDIR)/ike_header.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/ike_header.c' object='ike_header.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_header.obj `if test -f 'encoding/payloads/ike_header.c'; then $(CYGPATH_W) 'encoding/payloads/ike_header.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/ike_header.c'; fi`
+
+nonce_payload.o: encoding/payloads/nonce_payload.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nonce_payload.o -MD -MP -MF "$(DEPDIR)/nonce_payload.Tpo" -c -o nonce_payload.o `test -f 'encoding/payloads/nonce_payload.c' || echo '$(srcdir)/'`encoding/payloads/nonce_payload.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/nonce_payload.Tpo" "$(DEPDIR)/nonce_payload.Po"; else rm -f "$(DEPDIR)/nonce_payload.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/nonce_payload.c' object='nonce_payload.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nonce_payload.o `test -f 'encoding/payloads/nonce_payload.c' || echo '$(srcdir)/'`encoding/payloads/nonce_payload.c
+
+nonce_payload.obj: encoding/payloads/nonce_payload.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nonce_payload.obj -MD -MP -MF "$(DEPDIR)/nonce_payload.Tpo" -c -o nonce_payload.obj `if test -f 'encoding/payloads/nonce_payload.c'; then $(CYGPATH_W) 'encoding/payloads/nonce_payload.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/nonce_payload.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/nonce_payload.Tpo" "$(DEPDIR)/nonce_payload.Po"; else rm -f "$(DEPDIR)/nonce_payload.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/nonce_payload.c' object='nonce_payload.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nonce_payload.obj `if test -f 'encoding/payloads/nonce_payload.c'; then $(CYGPATH_W) 'encoding/payloads/nonce_payload.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/nonce_payload.c'; fi`
+
+eap_payload.o: encoding/payloads/eap_payload.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eap_payload.o -MD -MP -MF "$(DEPDIR)/eap_payload.Tpo" -c -o eap_payload.o `test -f 'encoding/payloads/eap_payload.c' || echo '$(srcdir)/'`encoding/payloads/eap_payload.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/eap_payload.Tpo" "$(DEPDIR)/eap_payload.Po"; else rm -f "$(DEPDIR)/eap_payload.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/eap_payload.c' object='eap_payload.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o eap_payload.o `test -f 'encoding/payloads/eap_payload.c' || echo '$(srcdir)/'`encoding/payloads/eap_payload.c
+
+eap_payload.obj: encoding/payloads/eap_payload.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eap_payload.obj -MD -MP -MF "$(DEPDIR)/eap_payload.Tpo" -c -o eap_payload.obj `if test -f 'encoding/payloads/eap_payload.c'; then $(CYGPATH_W) 'encoding/payloads/eap_payload.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/eap_payload.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/eap_payload.Tpo" "$(DEPDIR)/eap_payload.Po"; else rm -f "$(DEPDIR)/eap_payload.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/eap_payload.c' object='eap_payload.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o eap_payload.obj `if test -f 'encoding/payloads/eap_payload.c'; then $(CYGPATH_W) 'encoding/payloads/eap_payload.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/eap_payload.c'; fi`
+
+ts_payload.o: encoding/payloads/ts_payload.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ts_payload.o -MD -MP -MF "$(DEPDIR)/ts_payload.Tpo" -c -o ts_payload.o `test -f 'encoding/payloads/ts_payload.c' || echo '$(srcdir)/'`encoding/payloads/ts_payload.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ts_payload.Tpo" "$(DEPDIR)/ts_payload.Po"; else rm -f "$(DEPDIR)/ts_payload.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/ts_payload.c' object='ts_payload.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ts_payload.o `test -f 'encoding/payloads/ts_payload.c' || echo '$(srcdir)/'`encoding/payloads/ts_payload.c
+
+ts_payload.obj: encoding/payloads/ts_payload.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ts_payload.obj -MD -MP -MF "$(DEPDIR)/ts_payload.Tpo" -c -o ts_payload.obj `if test -f 'encoding/payloads/ts_payload.c'; then $(CYGPATH_W) 'encoding/payloads/ts_payload.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/ts_payload.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ts_payload.Tpo" "$(DEPDIR)/ts_payload.Po"; else rm -f "$(DEPDIR)/ts_payload.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/ts_payload.c' object='ts_payload.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ts_payload.obj `if test -f 'encoding/payloads/ts_payload.c'; then $(CYGPATH_W) 'encoding/payloads/ts_payload.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/ts_payload.c'; fi`
+
+notify_payload.o: encoding/payloads/notify_payload.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT notify_payload.o -MD -MP -MF "$(DEPDIR)/notify_payload.Tpo" -c -o notify_payload.o `test -f 'encoding/payloads/notify_payload.c' || echo '$(srcdir)/'`encoding/payloads/notify_payload.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/notify_payload.Tpo" "$(DEPDIR)/notify_payload.Po"; else rm -f "$(DEPDIR)/notify_payload.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/notify_payload.c' object='notify_payload.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o notify_payload.o `test -f 'encoding/payloads/notify_payload.c' || echo '$(srcdir)/'`encoding/payloads/notify_payload.c
+
+notify_payload.obj: encoding/payloads/notify_payload.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT notify_payload.obj -MD -MP -MF "$(DEPDIR)/notify_payload.Tpo" -c -o notify_payload.obj `if test -f 'encoding/payloads/notify_payload.c'; then $(CYGPATH_W) 'encoding/payloads/notify_payload.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/notify_payload.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/notify_payload.Tpo" "$(DEPDIR)/notify_payload.Po"; else rm -f "$(DEPDIR)/notify_payload.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/notify_payload.c' object='notify_payload.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o notify_payload.obj `if test -f 'encoding/payloads/notify_payload.c'; then $(CYGPATH_W) 'encoding/payloads/notify_payload.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/notify_payload.c'; fi`
+
+id_payload.o: encoding/payloads/id_payload.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT id_payload.o -MD -MP -MF "$(DEPDIR)/id_payload.Tpo" -c -o id_payload.o `test -f 'encoding/payloads/id_payload.c' || echo '$(srcdir)/'`encoding/payloads/id_payload.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/id_payload.Tpo" "$(DEPDIR)/id_payload.Po"; else rm -f "$(DEPDIR)/id_payload.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/id_payload.c' object='id_payload.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o id_payload.o `test -f 'encoding/payloads/id_payload.c' || echo '$(srcdir)/'`encoding/payloads/id_payload.c
+
+id_payload.obj: encoding/payloads/id_payload.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT id_payload.obj -MD -MP -MF "$(DEPDIR)/id_payload.Tpo" -c -o id_payload.obj `if test -f 'encoding/payloads/id_payload.c'; then $(CYGPATH_W) 'encoding/payloads/id_payload.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/id_payload.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/id_payload.Tpo" "$(DEPDIR)/id_payload.Po"; else rm -f "$(DEPDIR)/id_payload.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/id_payload.c' object='id_payload.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o id_payload.obj `if test -f 'encoding/payloads/id_payload.c'; then $(CYGPATH_W) 'encoding/payloads/id_payload.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/id_payload.c'; fi`
+
+ke_payload.o: encoding/payloads/ke_payload.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ke_payload.o -MD -MP -MF "$(DEPDIR)/ke_payload.Tpo" -c -o ke_payload.o `test -f 'encoding/payloads/ke_payload.c' || echo '$(srcdir)/'`encoding/payloads/ke_payload.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ke_payload.Tpo" "$(DEPDIR)/ke_payload.Po"; else rm -f "$(DEPDIR)/ke_payload.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/ke_payload.c' object='ke_payload.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ke_payload.o `test -f 'encoding/payloads/ke_payload.c' || echo '$(srcdir)/'`encoding/payloads/ke_payload.c
+
+ke_payload.obj: encoding/payloads/ke_payload.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ke_payload.obj -MD -MP -MF "$(DEPDIR)/ke_payload.Tpo" -c -o ke_payload.obj `if test -f 'encoding/payloads/ke_payload.c'; then $(CYGPATH_W) 'encoding/payloads/ke_payload.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/ke_payload.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ke_payload.Tpo" "$(DEPDIR)/ke_payload.Po"; else rm -f "$(DEPDIR)/ke_payload.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/ke_payload.c' object='ke_payload.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ke_payload.obj `if test -f 'encoding/payloads/ke_payload.c'; then $(CYGPATH_W) 'encoding/payloads/ke_payload.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/ke_payload.c'; fi`
+
+unknown_payload.o: encoding/payloads/unknown_payload.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unknown_payload.o -MD -MP -MF "$(DEPDIR)/unknown_payload.Tpo" -c -o unknown_payload.o `test -f 'encoding/payloads/unknown_payload.c' || echo '$(srcdir)/'`encoding/payloads/unknown_payload.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/unknown_payload.Tpo" "$(DEPDIR)/unknown_payload.Po"; else rm -f "$(DEPDIR)/unknown_payload.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/unknown_payload.c' object='unknown_payload.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unknown_payload.o `test -f 'encoding/payloads/unknown_payload.c' || echo '$(srcdir)/'`encoding/payloads/unknown_payload.c
+
+unknown_payload.obj: encoding/payloads/unknown_payload.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unknown_payload.obj -MD -MP -MF "$(DEPDIR)/unknown_payload.Tpo" -c -o unknown_payload.obj `if test -f 'encoding/payloads/unknown_payload.c'; then $(CYGPATH_W) 'encoding/payloads/unknown_payload.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/unknown_payload.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/unknown_payload.Tpo" "$(DEPDIR)/unknown_payload.Po"; else rm -f "$(DEPDIR)/unknown_payload.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/unknown_payload.c' object='unknown_payload.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unknown_payload.obj `if test -f 'encoding/payloads/unknown_payload.c'; then $(CYGPATH_W) 'encoding/payloads/unknown_payload.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/unknown_payload.c'; fi`
+
+encodings.o: encoding/payloads/encodings.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT encodings.o -MD -MP -MF "$(DEPDIR)/encodings.Tpo" -c -o encodings.o `test -f 'encoding/payloads/encodings.c' || echo '$(srcdir)/'`encoding/payloads/encodings.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/encodings.Tpo" "$(DEPDIR)/encodings.Po"; else rm -f "$(DEPDIR)/encodings.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/encodings.c' object='encodings.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o encodings.o `test -f 'encoding/payloads/encodings.c' || echo '$(srcdir)/'`encoding/payloads/encodings.c
+
+encodings.obj: encoding/payloads/encodings.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT encodings.obj -MD -MP -MF "$(DEPDIR)/encodings.Tpo" -c -o encodings.obj `if test -f 'encoding/payloads/encodings.c'; then $(CYGPATH_W) 'encoding/payloads/encodings.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/encodings.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/encodings.Tpo" "$(DEPDIR)/encodings.Po"; else rm -f "$(DEPDIR)/encodings.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/encodings.c' object='encodings.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o encodings.obj `if test -f 'encoding/payloads/encodings.c'; then $(CYGPATH_W) 'encoding/payloads/encodings.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/encodings.c'; fi`
+
+cp_payload.o: encoding/payloads/cp_payload.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cp_payload.o -MD -MP -MF "$(DEPDIR)/cp_payload.Tpo" -c -o cp_payload.o `test -f 'encoding/payloads/cp_payload.c' || echo '$(srcdir)/'`encoding/payloads/cp_payload.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/cp_payload.Tpo" "$(DEPDIR)/cp_payload.Po"; else rm -f "$(DEPDIR)/cp_payload.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/cp_payload.c' object='cp_payload.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cp_payload.o `test -f 'encoding/payloads/cp_payload.c' || echo '$(srcdir)/'`encoding/payloads/cp_payload.c
+
+cp_payload.obj: encoding/payloads/cp_payload.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cp_payload.obj -MD -MP -MF "$(DEPDIR)/cp_payload.Tpo" -c -o cp_payload.obj `if test -f 'encoding/payloads/cp_payload.c'; then $(CYGPATH_W) 'encoding/payloads/cp_payload.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/cp_payload.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/cp_payload.Tpo" "$(DEPDIR)/cp_payload.Po"; else rm -f "$(DEPDIR)/cp_payload.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/cp_payload.c' object='cp_payload.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cp_payload.obj `if test -f 'encoding/payloads/cp_payload.c'; then $(CYGPATH_W) 'encoding/payloads/cp_payload.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/cp_payload.c'; fi`
+
+delete_payload.o: encoding/payloads/delete_payload.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT delete_payload.o -MD -MP -MF "$(DEPDIR)/delete_payload.Tpo" -c -o delete_payload.o `test -f 'encoding/payloads/delete_payload.c' || echo '$(srcdir)/'`encoding/payloads/delete_payload.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/delete_payload.Tpo" "$(DEPDIR)/delete_payload.Po"; else rm -f "$(DEPDIR)/delete_payload.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/delete_payload.c' object='delete_payload.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o delete_payload.o `test -f 'encoding/payloads/delete_payload.c' || echo '$(srcdir)/'`encoding/payloads/delete_payload.c
+
+delete_payload.obj: encoding/payloads/delete_payload.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT delete_payload.obj -MD -MP -MF "$(DEPDIR)/delete_payload.Tpo" -c -o delete_payload.obj `if test -f 'encoding/payloads/delete_payload.c'; then $(CYGPATH_W) 'encoding/payloads/delete_payload.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/delete_payload.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/delete_payload.Tpo" "$(DEPDIR)/delete_payload.Po"; else rm -f "$(DEPDIR)/delete_payload.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/delete_payload.c' object='delete_payload.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o delete_payload.obj `if test -f 'encoding/payloads/delete_payload.c'; then $(CYGPATH_W) 'encoding/payloads/delete_payload.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/delete_payload.c'; fi`
+
+sa_payload.o: encoding/payloads/sa_payload.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sa_payload.o -MD -MP -MF "$(DEPDIR)/sa_payload.Tpo" -c -o sa_payload.o `test -f 'encoding/payloads/sa_payload.c' || echo '$(srcdir)/'`encoding/payloads/sa_payload.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/sa_payload.Tpo" "$(DEPDIR)/sa_payload.Po"; else rm -f "$(DEPDIR)/sa_payload.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/sa_payload.c' object='sa_payload.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sa_payload.o `test -f 'encoding/payloads/sa_payload.c' || echo '$(srcdir)/'`encoding/payloads/sa_payload.c
+
+sa_payload.obj: encoding/payloads/sa_payload.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sa_payload.obj -MD -MP -MF "$(DEPDIR)/sa_payload.Tpo" -c -o sa_payload.obj `if test -f 'encoding/payloads/sa_payload.c'; then $(CYGPATH_W) 'encoding/payloads/sa_payload.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/sa_payload.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/sa_payload.Tpo" "$(DEPDIR)/sa_payload.Po"; else rm -f "$(DEPDIR)/sa_payload.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/sa_payload.c' object='sa_payload.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sa_payload.obj `if test -f 'encoding/payloads/sa_payload.c'; then $(CYGPATH_W) 'encoding/payloads/sa_payload.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/sa_payload.c'; fi`
+
+certreq_payload.o: encoding/payloads/certreq_payload.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT certreq_payload.o -MD -MP -MF "$(DEPDIR)/certreq_payload.Tpo" -c -o certreq_payload.o `test -f 'encoding/payloads/certreq_payload.c' || echo '$(srcdir)/'`encoding/payloads/certreq_payload.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/certreq_payload.Tpo" "$(DEPDIR)/certreq_payload.Po"; else rm -f "$(DEPDIR)/certreq_payload.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/certreq_payload.c' object='certreq_payload.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o certreq_payload.o `test -f 'encoding/payloads/certreq_payload.c' || echo '$(srcdir)/'`encoding/payloads/certreq_payload.c
+
+certreq_payload.obj: encoding/payloads/certreq_payload.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT certreq_payload.obj -MD -MP -MF "$(DEPDIR)/certreq_payload.Tpo" -c -o certreq_payload.obj `if test -f 'encoding/payloads/certreq_payload.c'; then $(CYGPATH_W) 'encoding/payloads/certreq_payload.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/certreq_payload.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/certreq_payload.Tpo" "$(DEPDIR)/certreq_payload.Po"; else rm -f "$(DEPDIR)/certreq_payload.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/certreq_payload.c' object='certreq_payload.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o certreq_payload.obj `if test -f 'encoding/payloads/certreq_payload.c'; then $(CYGPATH_W) 'encoding/payloads/certreq_payload.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/certreq_payload.c'; fi`
+
+vendor_id_payload.o: encoding/payloads/vendor_id_payload.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT vendor_id_payload.o -MD -MP -MF "$(DEPDIR)/vendor_id_payload.Tpo" -c -o vendor_id_payload.o `test -f 'encoding/payloads/vendor_id_payload.c' || echo '$(srcdir)/'`encoding/payloads/vendor_id_payload.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/vendor_id_payload.Tpo" "$(DEPDIR)/vendor_id_payload.Po"; else rm -f "$(DEPDIR)/vendor_id_payload.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/vendor_id_payload.c' object='vendor_id_payload.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o vendor_id_payload.o `test -f 'encoding/payloads/vendor_id_payload.c' || echo '$(srcdir)/'`encoding/payloads/vendor_id_payload.c
+
+vendor_id_payload.obj: encoding/payloads/vendor_id_payload.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT vendor_id_payload.obj -MD -MP -MF "$(DEPDIR)/vendor_id_payload.Tpo" -c -o vendor_id_payload.obj `if test -f 'encoding/payloads/vendor_id_payload.c'; then $(CYGPATH_W) 'encoding/payloads/vendor_id_payload.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/vendor_id_payload.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/vendor_id_payload.Tpo" "$(DEPDIR)/vendor_id_payload.Po"; else rm -f "$(DEPDIR)/vendor_id_payload.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/vendor_id_payload.c' object='vendor_id_payload.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o vendor_id_payload.obj `if test -f 'encoding/payloads/vendor_id_payload.c'; then $(CYGPATH_W) 'encoding/payloads/vendor_id_payload.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/vendor_id_payload.c'; fi`
+
+proposal_substructure.o: encoding/payloads/proposal_substructure.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT proposal_substructure.o -MD -MP -MF "$(DEPDIR)/proposal_substructure.Tpo" -c -o proposal_substructure.o `test -f 'encoding/payloads/proposal_substructure.c' || echo '$(srcdir)/'`encoding/payloads/proposal_substructure.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/proposal_substructure.Tpo" "$(DEPDIR)/proposal_substructure.Po"; else rm -f "$(DEPDIR)/proposal_substructure.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/proposal_substructure.c' object='proposal_substructure.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o proposal_substructure.o `test -f 'encoding/payloads/proposal_substructure.c' || echo '$(srcdir)/'`encoding/payloads/proposal_substructure.c
+
+proposal_substructure.obj: encoding/payloads/proposal_substructure.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT proposal_substructure.obj -MD -MP -MF "$(DEPDIR)/proposal_substructure.Tpo" -c -o proposal_substructure.obj `if test -f 'encoding/payloads/proposal_substructure.c'; then $(CYGPATH_W) 'encoding/payloads/proposal_substructure.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/proposal_substructure.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/proposal_substructure.Tpo" "$(DEPDIR)/proposal_substructure.Po"; else rm -f "$(DEPDIR)/proposal_substructure.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/proposal_substructure.c' object='proposal_substructure.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o proposal_substructure.obj `if test -f 'encoding/payloads/proposal_substructure.c'; then $(CYGPATH_W) 'encoding/payloads/proposal_substructure.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/proposal_substructure.c'; fi`
+
+payload.o: encoding/payloads/payload.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT payload.o -MD -MP -MF "$(DEPDIR)/payload.Tpo" -c -o payload.o `test -f 'encoding/payloads/payload.c' || echo '$(srcdir)/'`encoding/payloads/payload.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/payload.Tpo" "$(DEPDIR)/payload.Po"; else rm -f "$(DEPDIR)/payload.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/payload.c' object='payload.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o payload.o `test -f 'encoding/payloads/payload.c' || echo '$(srcdir)/'`encoding/payloads/payload.c
+
+payload.obj: encoding/payloads/payload.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT payload.obj -MD -MP -MF "$(DEPDIR)/payload.Tpo" -c -o payload.obj `if test -f 'encoding/payloads/payload.c'; then $(CYGPATH_W) 'encoding/payloads/payload.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/payload.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/payload.Tpo" "$(DEPDIR)/payload.Po"; else rm -f "$(DEPDIR)/payload.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/payload.c' object='payload.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o payload.obj `if test -f 'encoding/payloads/payload.c'; then $(CYGPATH_W) 'encoding/payloads/payload.c'; else $(CYGPATH_W) '$(srcdir)/encoding/payloads/payload.c'; fi`
+
+message.o: encoding/message.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT message.o -MD -MP -MF "$(DEPDIR)/message.Tpo" -c -o message.o `test -f 'encoding/message.c' || echo '$(srcdir)/'`encoding/message.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/message.Tpo" "$(DEPDIR)/message.Po"; else rm -f "$(DEPDIR)/message.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/message.c' object='message.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o message.o `test -f 'encoding/message.c' || echo '$(srcdir)/'`encoding/message.c
+
+message.obj: encoding/message.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT message.obj -MD -MP -MF "$(DEPDIR)/message.Tpo" -c -o message.obj `if test -f 'encoding/message.c'; then $(CYGPATH_W) 'encoding/message.c'; else $(CYGPATH_W) '$(srcdir)/encoding/message.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/message.Tpo" "$(DEPDIR)/message.Po"; else rm -f "$(DEPDIR)/message.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/message.c' object='message.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o message.obj `if test -f 'encoding/message.c'; then $(CYGPATH_W) 'encoding/message.c'; else $(CYGPATH_W) '$(srcdir)/encoding/message.c'; fi`
+
+generator.o: encoding/generator.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT generator.o -MD -MP -MF "$(DEPDIR)/generator.Tpo" -c -o generator.o `test -f 'encoding/generator.c' || echo '$(srcdir)/'`encoding/generator.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/generator.Tpo" "$(DEPDIR)/generator.Po"; else rm -f "$(DEPDIR)/generator.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/generator.c' object='generator.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o generator.o `test -f 'encoding/generator.c' || echo '$(srcdir)/'`encoding/generator.c
+
+generator.obj: encoding/generator.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT generator.obj -MD -MP -MF "$(DEPDIR)/generator.Tpo" -c -o generator.obj `if test -f 'encoding/generator.c'; then $(CYGPATH_W) 'encoding/generator.c'; else $(CYGPATH_W) '$(srcdir)/encoding/generator.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/generator.Tpo" "$(DEPDIR)/generator.Po"; else rm -f "$(DEPDIR)/generator.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/generator.c' object='generator.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o generator.obj `if test -f 'encoding/generator.c'; then $(CYGPATH_W) 'encoding/generator.c'; else $(CYGPATH_W) '$(srcdir)/encoding/generator.c'; fi`
+
+parser.o: encoding/parser.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT parser.o -MD -MP -MF "$(DEPDIR)/parser.Tpo" -c -o parser.o `test -f 'encoding/parser.c' || echo '$(srcdir)/'`encoding/parser.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/parser.Tpo" "$(DEPDIR)/parser.Po"; else rm -f "$(DEPDIR)/parser.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/parser.c' object='parser.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o parser.o `test -f 'encoding/parser.c' || echo '$(srcdir)/'`encoding/parser.c
+
+parser.obj: encoding/parser.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT parser.obj -MD -MP -MF "$(DEPDIR)/parser.Tpo" -c -o parser.obj `if test -f 'encoding/parser.c'; then $(CYGPATH_W) 'encoding/parser.c'; else $(CYGPATH_W) '$(srcdir)/encoding/parser.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/parser.Tpo" "$(DEPDIR)/parser.Po"; else rm -f "$(DEPDIR)/parser.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/parser.c' object='parser.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o parser.obj `if test -f 'encoding/parser.c'; then $(CYGPATH_W) 'encoding/parser.c'; else $(CYGPATH_W) '$(srcdir)/encoding/parser.c'; fi`
+
+packet.o: network/packet.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT packet.o -MD -MP -MF "$(DEPDIR)/packet.Tpo" -c -o packet.o `test -f 'network/packet.c' || echo '$(srcdir)/'`network/packet.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/packet.Tpo" "$(DEPDIR)/packet.Po"; else rm -f "$(DEPDIR)/packet.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='network/packet.c' object='packet.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o packet.o `test -f 'network/packet.c' || echo '$(srcdir)/'`network/packet.c
+
+packet.obj: network/packet.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT packet.obj -MD -MP -MF "$(DEPDIR)/packet.Tpo" -c -o packet.obj `if test -f 'network/packet.c'; then $(CYGPATH_W) 'network/packet.c'; else $(CYGPATH_W) '$(srcdir)/network/packet.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/packet.Tpo" "$(DEPDIR)/packet.Po"; else rm -f "$(DEPDIR)/packet.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='network/packet.c' object='packet.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o packet.obj `if test -f 'network/packet.c'; then $(CYGPATH_W) 'network/packet.c'; else $(CYGPATH_W) '$(srcdir)/network/packet.c'; fi`
+
+socket.o: network/socket.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT socket.o -MD -MP -MF "$(DEPDIR)/socket.Tpo" -c -o socket.o `test -f 'network/socket.c' || echo '$(srcdir)/'`network/socket.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/socket.Tpo" "$(DEPDIR)/socket.Po"; else rm -f "$(DEPDIR)/socket.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='network/socket.c' object='socket.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o socket.o `test -f 'network/socket.c' || echo '$(srcdir)/'`network/socket.c
+
+socket.obj: network/socket.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT socket.obj -MD -MP -MF "$(DEPDIR)/socket.Tpo" -c -o socket.obj `if test -f 'network/socket.c'; then $(CYGPATH_W) 'network/socket.c'; else $(CYGPATH_W) '$(srcdir)/network/socket.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/socket.Tpo" "$(DEPDIR)/socket.Po"; else rm -f "$(DEPDIR)/socket.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='network/socket.c' object='socket.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o socket.obj `if test -f 'network/socket.c'; then $(CYGPATH_W) 'network/socket.c'; else $(CYGPATH_W) '$(srcdir)/network/socket.c'; fi`
+
+job.o: queues/jobs/job.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT job.o -MD -MP -MF "$(DEPDIR)/job.Tpo" -c -o job.o `test -f 'queues/jobs/job.c' || echo '$(srcdir)/'`queues/jobs/job.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/job.Tpo" "$(DEPDIR)/job.Po"; else rm -f "$(DEPDIR)/job.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='queues/jobs/job.c' object='job.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o job.o `test -f 'queues/jobs/job.c' || echo '$(srcdir)/'`queues/jobs/job.c
+
+job.obj: queues/jobs/job.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT job.obj -MD -MP -MF "$(DEPDIR)/job.Tpo" -c -o job.obj `if test -f 'queues/jobs/job.c'; then $(CYGPATH_W) 'queues/jobs/job.c'; else $(CYGPATH_W) '$(srcdir)/queues/jobs/job.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/job.Tpo" "$(DEPDIR)/job.Po"; else rm -f "$(DEPDIR)/job.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='queues/jobs/job.c' object='job.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o job.obj `if test -f 'queues/jobs/job.c'; then $(CYGPATH_W) 'queues/jobs/job.c'; else $(CYGPATH_W) '$(srcdir)/queues/jobs/job.c'; fi`
+
+process_message_job.o: queues/jobs/process_message_job.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT process_message_job.o -MD -MP -MF "$(DEPDIR)/process_message_job.Tpo" -c -o process_message_job.o `test -f 'queues/jobs/process_message_job.c' || echo '$(srcdir)/'`queues/jobs/process_message_job.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/process_message_job.Tpo" "$(DEPDIR)/process_message_job.Po"; else rm -f "$(DEPDIR)/process_message_job.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='queues/jobs/process_message_job.c' object='process_message_job.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o process_message_job.o `test -f 'queues/jobs/process_message_job.c' || echo '$(srcdir)/'`queues/jobs/process_message_job.c
+
+process_message_job.obj: queues/jobs/process_message_job.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT process_message_job.obj -MD -MP -MF "$(DEPDIR)/process_message_job.Tpo" -c -o process_message_job.obj `if test -f 'queues/jobs/process_message_job.c'; then $(CYGPATH_W) 'queues/jobs/process_message_job.c'; else $(CYGPATH_W) '$(srcdir)/queues/jobs/process_message_job.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/process_message_job.Tpo" "$(DEPDIR)/process_message_job.Po"; else rm -f "$(DEPDIR)/process_message_job.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='queues/jobs/process_message_job.c' object='process_message_job.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o process_message_job.obj `if test -f 'queues/jobs/process_message_job.c'; then $(CYGPATH_W) 'queues/jobs/process_message_job.c'; else $(CYGPATH_W) '$(srcdir)/queues/jobs/process_message_job.c'; fi`
+
+delete_ike_sa_job.o: queues/jobs/delete_ike_sa_job.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT delete_ike_sa_job.o -MD -MP -MF "$(DEPDIR)/delete_ike_sa_job.Tpo" -c -o delete_ike_sa_job.o `test -f 'queues/jobs/delete_ike_sa_job.c' || echo '$(srcdir)/'`queues/jobs/delete_ike_sa_job.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/delete_ike_sa_job.Tpo" "$(DEPDIR)/delete_ike_sa_job.Po"; else rm -f "$(DEPDIR)/delete_ike_sa_job.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='queues/jobs/delete_ike_sa_job.c' object='delete_ike_sa_job.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o delete_ike_sa_job.o `test -f 'queues/jobs/delete_ike_sa_job.c' || echo '$(srcdir)/'`queues/jobs/delete_ike_sa_job.c
+
+delete_ike_sa_job.obj: queues/jobs/delete_ike_sa_job.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT delete_ike_sa_job.obj -MD -MP -MF "$(DEPDIR)/delete_ike_sa_job.Tpo" -c -o delete_ike_sa_job.obj `if test -f 'queues/jobs/delete_ike_sa_job.c'; then $(CYGPATH_W) 'queues/jobs/delete_ike_sa_job.c'; else $(CYGPATH_W) '$(srcdir)/queues/jobs/delete_ike_sa_job.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/delete_ike_sa_job.Tpo" "$(DEPDIR)/delete_ike_sa_job.Po"; else rm -f "$(DEPDIR)/delete_ike_sa_job.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='queues/jobs/delete_ike_sa_job.c' object='delete_ike_sa_job.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o delete_ike_sa_job.obj `if test -f 'queues/jobs/delete_ike_sa_job.c'; then $(CYGPATH_W) 'queues/jobs/delete_ike_sa_job.c'; else $(CYGPATH_W) '$(srcdir)/queues/jobs/delete_ike_sa_job.c'; fi`
+
+retransmit_job.o: queues/jobs/retransmit_job.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT retransmit_job.o -MD -MP -MF "$(DEPDIR)/retransmit_job.Tpo" -c -o retransmit_job.o `test -f 'queues/jobs/retransmit_job.c' || echo '$(srcdir)/'`queues/jobs/retransmit_job.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/retransmit_job.Tpo" "$(DEPDIR)/retransmit_job.Po"; else rm -f "$(DEPDIR)/retransmit_job.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='queues/jobs/retransmit_job.c' object='retransmit_job.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o retransmit_job.o `test -f 'queues/jobs/retransmit_job.c' || echo '$(srcdir)/'`queues/jobs/retransmit_job.c
+
+retransmit_job.obj: queues/jobs/retransmit_job.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT retransmit_job.obj -MD -MP -MF "$(DEPDIR)/retransmit_job.Tpo" -c -o retransmit_job.obj `if test -f 'queues/jobs/retransmit_job.c'; then $(CYGPATH_W) 'queues/jobs/retransmit_job.c'; else $(CYGPATH_W) '$(srcdir)/queues/jobs/retransmit_job.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/retransmit_job.Tpo" "$(DEPDIR)/retransmit_job.Po"; else rm -f "$(DEPDIR)/retransmit_job.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='queues/jobs/retransmit_job.c' object='retransmit_job.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o retransmit_job.obj `if test -f 'queues/jobs/retransmit_job.c'; then $(CYGPATH_W) 'queues/jobs/retransmit_job.c'; else $(CYGPATH_W) '$(srcdir)/queues/jobs/retransmit_job.c'; fi`
+
+initiate_job.o: queues/jobs/initiate_job.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT initiate_job.o -MD -MP -MF "$(DEPDIR)/initiate_job.Tpo" -c -o initiate_job.o `test -f 'queues/jobs/initiate_job.c' || echo '$(srcdir)/'`queues/jobs/initiate_job.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/initiate_job.Tpo" "$(DEPDIR)/initiate_job.Po"; else rm -f "$(DEPDIR)/initiate_job.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='queues/jobs/initiate_job.c' object='initiate_job.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o initiate_job.o `test -f 'queues/jobs/initiate_job.c' || echo '$(srcdir)/'`queues/jobs/initiate_job.c
+
+initiate_job.obj: queues/jobs/initiate_job.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT initiate_job.obj -MD -MP -MF "$(DEPDIR)/initiate_job.Tpo" -c -o initiate_job.obj `if test -f 'queues/jobs/initiate_job.c'; then $(CYGPATH_W) 'queues/jobs/initiate_job.c'; else $(CYGPATH_W) '$(srcdir)/queues/jobs/initiate_job.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/initiate_job.Tpo" "$(DEPDIR)/initiate_job.Po"; else rm -f "$(DEPDIR)/initiate_job.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='queues/jobs/initiate_job.c' object='initiate_job.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o initiate_job.obj `if test -f 'queues/jobs/initiate_job.c'; then $(CYGPATH_W) 'queues/jobs/initiate_job.c'; else $(CYGPATH_W) '$(srcdir)/queues/jobs/initiate_job.c'; fi`
+
+send_keepalive_job.o: queues/jobs/send_keepalive_job.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT send_keepalive_job.o -MD -MP -MF "$(DEPDIR)/send_keepalive_job.Tpo" -c -o send_keepalive_job.o `test -f 'queues/jobs/send_keepalive_job.c' || echo '$(srcdir)/'`queues/jobs/send_keepalive_job.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/send_keepalive_job.Tpo" "$(DEPDIR)/send_keepalive_job.Po"; else rm -f "$(DEPDIR)/send_keepalive_job.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='queues/jobs/send_keepalive_job.c' object='send_keepalive_job.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o send_keepalive_job.o `test -f 'queues/jobs/send_keepalive_job.c' || echo '$(srcdir)/'`queues/jobs/send_keepalive_job.c
+
+send_keepalive_job.obj: queues/jobs/send_keepalive_job.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT send_keepalive_job.obj -MD -MP -MF "$(DEPDIR)/send_keepalive_job.Tpo" -c -o send_keepalive_job.obj `if test -f 'queues/jobs/send_keepalive_job.c'; then $(CYGPATH_W) 'queues/jobs/send_keepalive_job.c'; else $(CYGPATH_W) '$(srcdir)/queues/jobs/send_keepalive_job.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/send_keepalive_job.Tpo" "$(DEPDIR)/send_keepalive_job.Po"; else rm -f "$(DEPDIR)/send_keepalive_job.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='queues/jobs/send_keepalive_job.c' object='send_keepalive_job.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o send_keepalive_job.obj `if test -f 'queues/jobs/send_keepalive_job.c'; then $(CYGPATH_W) 'queues/jobs/send_keepalive_job.c'; else $(CYGPATH_W) '$(srcdir)/queues/jobs/send_keepalive_job.c'; fi`
+
+rekey_child_sa_job.o: queues/jobs/rekey_child_sa_job.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rekey_child_sa_job.o -MD -MP -MF "$(DEPDIR)/rekey_child_sa_job.Tpo" -c -o rekey_child_sa_job.o `test -f 'queues/jobs/rekey_child_sa_job.c' || echo '$(srcdir)/'`queues/jobs/rekey_child_sa_job.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/rekey_child_sa_job.Tpo" "$(DEPDIR)/rekey_child_sa_job.Po"; else rm -f "$(DEPDIR)/rekey_child_sa_job.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='queues/jobs/rekey_child_sa_job.c' object='rekey_child_sa_job.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rekey_child_sa_job.o `test -f 'queues/jobs/rekey_child_sa_job.c' || echo '$(srcdir)/'`queues/jobs/rekey_child_sa_job.c
+
+rekey_child_sa_job.obj: queues/jobs/rekey_child_sa_job.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rekey_child_sa_job.obj -MD -MP -MF "$(DEPDIR)/rekey_child_sa_job.Tpo" -c -o rekey_child_sa_job.obj `if test -f 'queues/jobs/rekey_child_sa_job.c'; then $(CYGPATH_W) 'queues/jobs/rekey_child_sa_job.c'; else $(CYGPATH_W) '$(srcdir)/queues/jobs/rekey_child_sa_job.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/rekey_child_sa_job.Tpo" "$(DEPDIR)/rekey_child_sa_job.Po"; else rm -f "$(DEPDIR)/rekey_child_sa_job.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='queues/jobs/rekey_child_sa_job.c' object='rekey_child_sa_job.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rekey_child_sa_job.obj `if test -f 'queues/jobs/rekey_child_sa_job.c'; then $(CYGPATH_W) 'queues/jobs/rekey_child_sa_job.c'; else $(CYGPATH_W) '$(srcdir)/queues/jobs/rekey_child_sa_job.c'; fi`
+
+delete_child_sa_job.o: queues/jobs/delete_child_sa_job.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT delete_child_sa_job.o -MD -MP -MF "$(DEPDIR)/delete_child_sa_job.Tpo" -c -o delete_child_sa_job.o `test -f 'queues/jobs/delete_child_sa_job.c' || echo '$(srcdir)/'`queues/jobs/delete_child_sa_job.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/delete_child_sa_job.Tpo" "$(DEPDIR)/delete_child_sa_job.Po"; else rm -f "$(DEPDIR)/delete_child_sa_job.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='queues/jobs/delete_child_sa_job.c' object='delete_child_sa_job.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o delete_child_sa_job.o `test -f 'queues/jobs/delete_child_sa_job.c' || echo '$(srcdir)/'`queues/jobs/delete_child_sa_job.c
+
+delete_child_sa_job.obj: queues/jobs/delete_child_sa_job.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT delete_child_sa_job.obj -MD -MP -MF "$(DEPDIR)/delete_child_sa_job.Tpo" -c -o delete_child_sa_job.obj `if test -f 'queues/jobs/delete_child_sa_job.c'; then $(CYGPATH_W) 'queues/jobs/delete_child_sa_job.c'; else $(CYGPATH_W) '$(srcdir)/queues/jobs/delete_child_sa_job.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/delete_child_sa_job.Tpo" "$(DEPDIR)/delete_child_sa_job.Po"; else rm -f "$(DEPDIR)/delete_child_sa_job.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='queues/jobs/delete_child_sa_job.c' object='delete_child_sa_job.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o delete_child_sa_job.obj `if test -f 'queues/jobs/delete_child_sa_job.c'; then $(CYGPATH_W) 'queues/jobs/delete_child_sa_job.c'; else $(CYGPATH_W) '$(srcdir)/queues/jobs/delete_child_sa_job.c'; fi`
+
+send_dpd_job.o: queues/jobs/send_dpd_job.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT send_dpd_job.o -MD -MP -MF "$(DEPDIR)/send_dpd_job.Tpo" -c -o send_dpd_job.o `test -f 'queues/jobs/send_dpd_job.c' || echo '$(srcdir)/'`queues/jobs/send_dpd_job.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/send_dpd_job.Tpo" "$(DEPDIR)/send_dpd_job.Po"; else rm -f "$(DEPDIR)/send_dpd_job.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='queues/jobs/send_dpd_job.c' object='send_dpd_job.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o send_dpd_job.o `test -f 'queues/jobs/send_dpd_job.c' || echo '$(srcdir)/'`queues/jobs/send_dpd_job.c
+
+send_dpd_job.obj: queues/jobs/send_dpd_job.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT send_dpd_job.obj -MD -MP -MF "$(DEPDIR)/send_dpd_job.Tpo" -c -o send_dpd_job.obj `if test -f 'queues/jobs/send_dpd_job.c'; then $(CYGPATH_W) 'queues/jobs/send_dpd_job.c'; else $(CYGPATH_W) '$(srcdir)/queues/jobs/send_dpd_job.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/send_dpd_job.Tpo" "$(DEPDIR)/send_dpd_job.Po"; else rm -f "$(DEPDIR)/send_dpd_job.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='queues/jobs/send_dpd_job.c' object='send_dpd_job.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o send_dpd_job.obj `if test -f 'queues/jobs/send_dpd_job.c'; then $(CYGPATH_W) 'queues/jobs/send_dpd_job.c'; else $(CYGPATH_W) '$(srcdir)/queues/jobs/send_dpd_job.c'; fi`
+
+route_job.o: queues/jobs/route_job.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT route_job.o -MD -MP -MF "$(DEPDIR)/route_job.Tpo" -c -o route_job.o `test -f 'queues/jobs/route_job.c' || echo '$(srcdir)/'`queues/jobs/route_job.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/route_job.Tpo" "$(DEPDIR)/route_job.Po"; else rm -f "$(DEPDIR)/route_job.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='queues/jobs/route_job.c' object='route_job.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o route_job.o `test -f 'queues/jobs/route_job.c' || echo '$(srcdir)/'`queues/jobs/route_job.c
+
+route_job.obj: queues/jobs/route_job.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT route_job.obj -MD -MP -MF "$(DEPDIR)/route_job.Tpo" -c -o route_job.obj `if test -f 'queues/jobs/route_job.c'; then $(CYGPATH_W) 'queues/jobs/route_job.c'; else $(CYGPATH_W) '$(srcdir)/queues/jobs/route_job.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/route_job.Tpo" "$(DEPDIR)/route_job.Po"; else rm -f "$(DEPDIR)/route_job.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='queues/jobs/route_job.c' object='route_job.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o route_job.obj `if test -f 'queues/jobs/route_job.c'; then $(CYGPATH_W) 'queues/jobs/route_job.c'; else $(CYGPATH_W) '$(srcdir)/queues/jobs/route_job.c'; fi`
+
+acquire_job.o: queues/jobs/acquire_job.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT acquire_job.o -MD -MP -MF "$(DEPDIR)/acquire_job.Tpo" -c -o acquire_job.o `test -f 'queues/jobs/acquire_job.c' || echo '$(srcdir)/'`queues/jobs/acquire_job.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/acquire_job.Tpo" "$(DEPDIR)/acquire_job.Po"; else rm -f "$(DEPDIR)/acquire_job.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='queues/jobs/acquire_job.c' object='acquire_job.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o acquire_job.o `test -f 'queues/jobs/acquire_job.c' || echo '$(srcdir)/'`queues/jobs/acquire_job.c
+
+acquire_job.obj: queues/jobs/acquire_job.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT acquire_job.obj -MD -MP -MF "$(DEPDIR)/acquire_job.Tpo" -c -o acquire_job.obj `if test -f 'queues/jobs/acquire_job.c'; then $(CYGPATH_W) 'queues/jobs/acquire_job.c'; else $(CYGPATH_W) '$(srcdir)/queues/jobs/acquire_job.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/acquire_job.Tpo" "$(DEPDIR)/acquire_job.Po"; else rm -f "$(DEPDIR)/acquire_job.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='queues/jobs/acquire_job.c' object='acquire_job.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o acquire_job.obj `if test -f 'queues/jobs/acquire_job.c'; then $(CYGPATH_W) 'queues/jobs/acquire_job.c'; else $(CYGPATH_W) '$(srcdir)/queues/jobs/acquire_job.c'; fi`
+
+rekey_ike_sa_job.o: queues/jobs/rekey_ike_sa_job.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rekey_ike_sa_job.o -MD -MP -MF "$(DEPDIR)/rekey_ike_sa_job.Tpo" -c -o rekey_ike_sa_job.o `test -f 'queues/jobs/rekey_ike_sa_job.c' || echo '$(srcdir)/'`queues/jobs/rekey_ike_sa_job.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/rekey_ike_sa_job.Tpo" "$(DEPDIR)/rekey_ike_sa_job.Po"; else rm -f "$(DEPDIR)/rekey_ike_sa_job.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='queues/jobs/rekey_ike_sa_job.c' object='rekey_ike_sa_job.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rekey_ike_sa_job.o `test -f 'queues/jobs/rekey_ike_sa_job.c' || echo '$(srcdir)/'`queues/jobs/rekey_ike_sa_job.c
+
+rekey_ike_sa_job.obj: queues/jobs/rekey_ike_sa_job.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rekey_ike_sa_job.obj -MD -MP -MF "$(DEPDIR)/rekey_ike_sa_job.Tpo" -c -o rekey_ike_sa_job.obj `if test -f 'queues/jobs/rekey_ike_sa_job.c'; then $(CYGPATH_W) 'queues/jobs/rekey_ike_sa_job.c'; else $(CYGPATH_W) '$(srcdir)/queues/jobs/rekey_ike_sa_job.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/rekey_ike_sa_job.Tpo" "$(DEPDIR)/rekey_ike_sa_job.Po"; else rm -f "$(DEPDIR)/rekey_ike_sa_job.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='queues/jobs/rekey_ike_sa_job.c' object='rekey_ike_sa_job.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rekey_ike_sa_job.obj `if test -f 'queues/jobs/rekey_ike_sa_job.c'; then $(CYGPATH_W) 'queues/jobs/rekey_ike_sa_job.c'; else $(CYGPATH_W) '$(srcdir)/queues/jobs/rekey_ike_sa_job.c'; fi`
+
+job_queue.o: queues/job_queue.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT job_queue.o -MD -MP -MF "$(DEPDIR)/job_queue.Tpo" -c -o job_queue.o `test -f 'queues/job_queue.c' || echo '$(srcdir)/'`queues/job_queue.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/job_queue.Tpo" "$(DEPDIR)/job_queue.Po"; else rm -f "$(DEPDIR)/job_queue.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='queues/job_queue.c' object='job_queue.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o job_queue.o `test -f 'queues/job_queue.c' || echo '$(srcdir)/'`queues/job_queue.c
+
+job_queue.obj: queues/job_queue.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT job_queue.obj -MD -MP -MF "$(DEPDIR)/job_queue.Tpo" -c -o job_queue.obj `if test -f 'queues/job_queue.c'; then $(CYGPATH_W) 'queues/job_queue.c'; else $(CYGPATH_W) '$(srcdir)/queues/job_queue.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/job_queue.Tpo" "$(DEPDIR)/job_queue.Po"; else rm -f "$(DEPDIR)/job_queue.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='queues/job_queue.c' object='job_queue.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o job_queue.obj `if test -f 'queues/job_queue.c'; then $(CYGPATH_W) 'queues/job_queue.c'; else $(CYGPATH_W) '$(srcdir)/queues/job_queue.c'; fi`
+
+event_queue.o: queues/event_queue.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT event_queue.o -MD -MP -MF "$(DEPDIR)/event_queue.Tpo" -c -o event_queue.o `test -f 'queues/event_queue.c' || echo '$(srcdir)/'`queues/event_queue.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/event_queue.Tpo" "$(DEPDIR)/event_queue.Po"; else rm -f "$(DEPDIR)/event_queue.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='queues/event_queue.c' object='event_queue.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o event_queue.o `test -f 'queues/event_queue.c' || echo '$(srcdir)/'`queues/event_queue.c
+
+event_queue.obj: queues/event_queue.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT event_queue.obj -MD -MP -MF "$(DEPDIR)/event_queue.Tpo" -c -o event_queue.obj `if test -f 'queues/event_queue.c'; then $(CYGPATH_W) 'queues/event_queue.c'; else $(CYGPATH_W) '$(srcdir)/queues/event_queue.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/event_queue.Tpo" "$(DEPDIR)/event_queue.Po"; else rm -f "$(DEPDIR)/event_queue.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='queues/event_queue.c' object='event_queue.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o event_queue.obj `if test -f 'queues/event_queue.c'; then $(CYGPATH_W) 'queues/event_queue.c'; else $(CYGPATH_W) '$(srcdir)/queues/event_queue.c'; fi`
+
+kernel_interface.o: threads/kernel_interface.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT kernel_interface.o -MD -MP -MF "$(DEPDIR)/kernel_interface.Tpo" -c -o kernel_interface.o `test -f 'threads/kernel_interface.c' || echo '$(srcdir)/'`threads/kernel_interface.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/kernel_interface.Tpo" "$(DEPDIR)/kernel_interface.Po"; else rm -f "$(DEPDIR)/kernel_interface.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='threads/kernel_interface.c' object='kernel_interface.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o kernel_interface.o `test -f 'threads/kernel_interface.c' || echo '$(srcdir)/'`threads/kernel_interface.c
+
+kernel_interface.obj: threads/kernel_interface.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT kernel_interface.obj -MD -MP -MF "$(DEPDIR)/kernel_interface.Tpo" -c -o kernel_interface.obj `if test -f 'threads/kernel_interface.c'; then $(CYGPATH_W) 'threads/kernel_interface.c'; else $(CYGPATH_W) '$(srcdir)/threads/kernel_interface.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/kernel_interface.Tpo" "$(DEPDIR)/kernel_interface.Po"; else rm -f "$(DEPDIR)/kernel_interface.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='threads/kernel_interface.c' object='kernel_interface.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o kernel_interface.obj `if test -f 'threads/kernel_interface.c'; then $(CYGPATH_W) 'threads/kernel_interface.c'; else $(CYGPATH_W) '$(srcdir)/threads/kernel_interface.c'; fi`
+
+thread_pool.o: threads/thread_pool.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT thread_pool.o -MD -MP -MF "$(DEPDIR)/thread_pool.Tpo" -c -o thread_pool.o `test -f 'threads/thread_pool.c' || echo '$(srcdir)/'`threads/thread_pool.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/thread_pool.Tpo" "$(DEPDIR)/thread_pool.Po"; else rm -f "$(DEPDIR)/thread_pool.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='threads/thread_pool.c' object='thread_pool.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o thread_pool.o `test -f 'threads/thread_pool.c' || echo '$(srcdir)/'`threads/thread_pool.c
+
+thread_pool.obj: threads/thread_pool.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT thread_pool.obj -MD -MP -MF "$(DEPDIR)/thread_pool.Tpo" -c -o thread_pool.obj `if test -f 'threads/thread_pool.c'; then $(CYGPATH_W) 'threads/thread_pool.c'; else $(CYGPATH_W) '$(srcdir)/threads/thread_pool.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/thread_pool.Tpo" "$(DEPDIR)/thread_pool.Po"; else rm -f "$(DEPDIR)/thread_pool.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='threads/thread_pool.c' object='thread_pool.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o thread_pool.obj `if test -f 'threads/thread_pool.c'; then $(CYGPATH_W) 'threads/thread_pool.c'; else $(CYGPATH_W) '$(srcdir)/threads/thread_pool.c'; fi`
+
+scheduler.o: threads/scheduler.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT scheduler.o -MD -MP -MF "$(DEPDIR)/scheduler.Tpo" -c -o scheduler.o `test -f 'threads/scheduler.c' || echo '$(srcdir)/'`threads/scheduler.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/scheduler.Tpo" "$(DEPDIR)/scheduler.Po"; else rm -f "$(DEPDIR)/scheduler.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='threads/scheduler.c' object='scheduler.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o scheduler.o `test -f 'threads/scheduler.c' || echo '$(srcdir)/'`threads/scheduler.c
+
+scheduler.obj: threads/scheduler.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT scheduler.obj -MD -MP -MF "$(DEPDIR)/scheduler.Tpo" -c -o scheduler.obj `if test -f 'threads/scheduler.c'; then $(CYGPATH_W) 'threads/scheduler.c'; else $(CYGPATH_W) '$(srcdir)/threads/scheduler.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/scheduler.Tpo" "$(DEPDIR)/scheduler.Po"; else rm -f "$(DEPDIR)/scheduler.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='threads/scheduler.c' object='scheduler.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o scheduler.obj `if test -f 'threads/scheduler.c'; then $(CYGPATH_W) 'threads/scheduler.c'; else $(CYGPATH_W) '$(srcdir)/threads/scheduler.c'; fi`
+
+sender.o: threads/sender.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sender.o -MD -MP -MF "$(DEPDIR)/sender.Tpo" -c -o sender.o `test -f 'threads/sender.c' || echo '$(srcdir)/'`threads/sender.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/sender.Tpo" "$(DEPDIR)/sender.Po"; else rm -f "$(DEPDIR)/sender.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='threads/sender.c' object='sender.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sender.o `test -f 'threads/sender.c' || echo '$(srcdir)/'`threads/sender.c
+
+sender.obj: threads/sender.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sender.obj -MD -MP -MF "$(DEPDIR)/sender.Tpo" -c -o sender.obj `if test -f 'threads/sender.c'; then $(CYGPATH_W) 'threads/sender.c'; else $(CYGPATH_W) '$(srcdir)/threads/sender.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/sender.Tpo" "$(DEPDIR)/sender.Po"; else rm -f "$(DEPDIR)/sender.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='threads/sender.c' object='sender.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sender.obj `if test -f 'threads/sender.c'; then $(CYGPATH_W) 'threads/sender.c'; else $(CYGPATH_W) '$(srcdir)/threads/sender.c'; fi`
+
+receiver.o: threads/receiver.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT receiver.o -MD -MP -MF "$(DEPDIR)/receiver.Tpo" -c -o receiver.o `test -f 'threads/receiver.c' || echo '$(srcdir)/'`threads/receiver.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/receiver.Tpo" "$(DEPDIR)/receiver.Po"; else rm -f "$(DEPDIR)/receiver.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='threads/receiver.c' object='receiver.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o receiver.o `test -f 'threads/receiver.c' || echo '$(srcdir)/'`threads/receiver.c
+
+receiver.obj: threads/receiver.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT receiver.obj -MD -MP -MF "$(DEPDIR)/receiver.Tpo" -c -o receiver.obj `if test -f 'threads/receiver.c'; then $(CYGPATH_W) 'threads/receiver.c'; else $(CYGPATH_W) '$(srcdir)/threads/receiver.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/receiver.Tpo" "$(DEPDIR)/receiver.Po"; else rm -f "$(DEPDIR)/receiver.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='threads/receiver.c' object='receiver.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o receiver.obj `if test -f 'threads/receiver.c'; then $(CYGPATH_W) 'threads/receiver.c'; else $(CYGPATH_W) '$(srcdir)/threads/receiver.c'; fi`
+
+stroke_interface.o: threads/stroke_interface.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stroke_interface.o -MD -MP -MF "$(DEPDIR)/stroke_interface.Tpo" -c -o stroke_interface.o `test -f 'threads/stroke_interface.c' || echo '$(srcdir)/'`threads/stroke_interface.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/stroke_interface.Tpo" "$(DEPDIR)/stroke_interface.Po"; else rm -f "$(DEPDIR)/stroke_interface.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='threads/stroke_interface.c' object='stroke_interface.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stroke_interface.o `test -f 'threads/stroke_interface.c' || echo '$(srcdir)/'`threads/stroke_interface.c
+
+stroke_interface.obj: threads/stroke_interface.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stroke_interface.obj -MD -MP -MF "$(DEPDIR)/stroke_interface.Tpo" -c -o stroke_interface.obj `if test -f 'threads/stroke_interface.c'; then $(CYGPATH_W) 'threads/stroke_interface.c'; else $(CYGPATH_W) '$(srcdir)/threads/stroke_interface.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/stroke_interface.Tpo" "$(DEPDIR)/stroke_interface.Po"; else rm -f "$(DEPDIR)/stroke_interface.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='threads/stroke_interface.c' object='stroke_interface.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stroke_interface.obj `if test -f 'threads/stroke_interface.c'; then $(CYGPATH_W) 'threads/stroke_interface.c'; else $(CYGPATH_W) '$(srcdir)/threads/stroke_interface.c'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS)
+installdirs:
+ for dir in "$(DESTDIR)$(eapdir)" "$(DESTDIR)$(ipsecdir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-eapLTLIBRARIES clean-generic clean-ipsecPROGRAMS \
+ clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-eapLTLIBRARIES install-ipsecPROGRAMS
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-eapLTLIBRARIES uninstall-info-am \
+ uninstall-ipsecPROGRAMS
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean \
+ clean-eapLTLIBRARIES clean-generic clean-ipsecPROGRAMS \
+ clean-libtool ctags distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-eapLTLIBRARIES \
+ install-exec install-exec-am install-info install-info-am \
+ install-ipsecPROGRAMS install-man install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-eapLTLIBRARIES \
+ uninstall-info-am uninstall-ipsecPROGRAMS
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/charon/bus/bus.c b/src/charon/bus/bus.c
new file mode 100644
index 000000000..740663d5c
--- /dev/null
+++ b/src/charon/bus/bus.c
@@ -0,0 +1,397 @@
+/**
+ * @file bus.c
+ *
+ * @brief Implementation of bus_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 "bus.h"
+
+#include <pthread.h>
+
+ENUM(signal_names, SIG_ANY, SIG_MAX,
+ /** should not get printed */
+ "SIG_ANY",
+ /** debugging message types */
+ "DMN",
+ "MGR",
+ "IKE",
+ "CHD",
+ "JOB",
+ "CFG",
+ "KNL",
+ "NET",
+ "ENC",
+ "LIB",
+ /** should not get printed */
+ "SIG_DBG_MAX",
+ /** all level0 signals are AUDIT signals */
+ "AUD", "AUD", "AUD",
+ "AUD", "AUD", "AUD",
+ "AUD", "AUD", "AUD",
+ "AUD", "AUD", "AUD",
+ "AUD", "AUD", "AUD",
+ "AUD", "AUD", "AUD",
+ "AUD", "AUD", "AUD",
+ "AUD", "AUD", "AUD",
+ /** should not get printed */
+ "SIG_MAX",
+);
+
+typedef struct active_listener_t active_listener_t;
+
+/**
+ * information for a active listener
+ */
+struct active_listener_t {
+
+ /**
+ * associated thread
+ */
+ pthread_t id;
+
+ /**
+ * condvar to wait for a signal
+ */
+ pthread_cond_t cond;
+
+ /**
+ * state of the thread
+ */
+ enum {
+ /** not registered, do not wait for thread */
+ UNREGISTERED,
+ /** registered, if a signal occurs, wait until it is LISTENING */
+ REGISTERED,
+ /** listening, deliver signal */
+ LISTENING,
+ } state;
+
+ /**
+ * currently processed signals type
+ */
+ signal_t signal;
+
+ /**
+ * verbosity level of the signal
+ */
+ level_t level;
+
+ /**
+ * current processed signals thread number
+ */
+ int thread;
+
+ /**
+ * currently processed signals ike_sa
+ */
+ ike_sa_t *ike_sa;
+
+ /**
+ * currently processed signals format string
+ */
+ char *format;
+
+ /**
+ * currently processed signals format varargs
+ */
+ va_list args;
+
+};
+
+typedef struct private_bus_t private_bus_t;
+
+/**
+ * Private data of a bus_t object.
+ */
+struct private_bus_t {
+ /**
+ * Public part of a bus_t object.
+ */
+ bus_t public;
+
+ /**
+ * List of registered listeners implementing the bus_t interface
+ */
+ linked_list_t *listeners;
+
+ /**
+ * List of active listeners with listener_state TRUE
+ */
+ linked_list_t *active_listeners;
+
+ /**
+ * mutex to synchronize active listeners
+ */
+ pthread_mutex_t mutex;
+
+ /**
+ * Thread local storage for a unique, simple thread ID
+ */
+ pthread_key_t thread_id;
+
+ /**
+ * Thread local storage the threads IKE_SA
+ */
+ pthread_key_t thread_sa;
+
+};
+
+/**
+ * Get a unique thread number for a calling thread. Since
+ * pthread_self returns large and ugly numbers, use this function
+ * for logging; these numbers are incremental starting at 1
+ */
+static int get_thread_number(private_bus_t *this)
+{
+ static long current_num = 0;
+ static long stored_num;
+
+ stored_num = (long)pthread_getspecific(this->thread_id);
+ if (stored_num == 0)
+ { /* first call of current thread */
+ pthread_setspecific(this->thread_id, (void*)++current_num);
+ return current_num;
+ }
+ else
+ {
+ return stored_num;
+ }
+}
+
+/**
+ * Implementation of bus_t.add_listener.
+ */
+static void add_listener(private_bus_t *this, bus_listener_t *listener)
+{
+ pthread_mutex_lock(&this->mutex);
+ this->listeners->insert_last(this->listeners, listener);
+ pthread_mutex_unlock(&this->mutex);
+}
+
+/**
+ * Get the listener object for the calling thread
+ */
+static active_listener_t *get_active_listener(private_bus_t *this)
+{
+ active_listener_t *current, *found = NULL;
+ iterator_t *iterator;
+
+ /* if the thread was here once before, we have a active_listener record */
+ iterator = this->active_listeners->create_iterator(this->active_listeners, TRUE);
+ while (iterator->iterate(iterator, (void**)&current))
+ {
+ if (current->id == pthread_self())
+ {
+ found = current;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+
+ if (found == NULL)
+ {
+ /* create a new object for a never-seen thread */
+ found = malloc_thing(active_listener_t);
+ found->id = pthread_self();
+ pthread_cond_init(&found->cond, NULL);
+ this->active_listeners->insert_last(this->active_listeners, found);
+ }
+
+ return found;
+}
+
+/**
+ * Implementation of bus_t.listen.
+ */
+static signal_t listen_(private_bus_t *this, level_t *level, int *thread,
+ ike_sa_t **ike_sa, char** format, va_list* args)
+{
+ active_listener_t *listener;
+
+ pthread_mutex_lock(&this->mutex);
+ listener = get_active_listener(this);
+ /* go "listening", say hello to a thread which have a signal for us */
+ listener->state = LISTENING;
+ pthread_cond_broadcast(&listener->cond);
+ /* wait until it has us delivered a signal, and go back to "registered" */
+ pthread_cond_wait(&listener->cond, &this->mutex);
+ pthread_mutex_unlock(&this->mutex);
+
+ /* return signal values */
+ *level = listener->level;
+ *thread = listener->thread;
+ *ike_sa = listener->ike_sa;
+ *format = listener->format;
+ va_copy(*args, listener->args);
+ va_end(listener->args);
+
+ return listener->signal;
+}
+
+/**
+ * Implementation of bus_t.set_listen_state.
+ */
+static void set_listen_state(private_bus_t *this, bool active)
+{
+ active_listener_t *listener;
+
+ pthread_mutex_lock(&this->mutex);
+
+ listener = get_active_listener(this);
+ if (active)
+ {
+ listener->state = REGISTERED;
+ }
+ else
+ {
+ listener->state = UNREGISTERED;
+ /* say hello to signal emitter; we are finished processing the signal */
+ pthread_cond_signal(&listener->cond);
+ }
+
+ pthread_mutex_unlock(&this->mutex);
+}
+
+
+/**
+ * Implementation of bus_t.set_sa.
+ */
+static void set_sa(private_bus_t *this, ike_sa_t *ike_sa)
+{
+ pthread_setspecific(this->thread_sa, ike_sa);
+}
+
+/**
+ * Implementation of bus_t.vsignal.
+ */
+static void vsignal(private_bus_t *this, signal_t signal, level_t level,
+ char* format, va_list args)
+{
+ iterator_t *iterator;
+ bus_listener_t *listener;
+ active_listener_t *active_listener;
+ ike_sa_t *ike_sa;
+ long thread;
+
+ ike_sa = pthread_getspecific(this->thread_sa);
+ thread = get_thread_number(this);
+
+ pthread_mutex_lock(&this->mutex);
+
+ /* do the job for all passive bus_listeners */
+ iterator = this->listeners->create_iterator(this->listeners, TRUE);
+ while (iterator->iterate(iterator, (void**)&listener))
+ {
+ va_list args_copy;
+
+ va_copy(args_copy, args);
+ if (!listener->signal(listener, signal, level, thread,
+ ike_sa, format, args_copy))
+ {
+ /* unregister listener if requested */
+ iterator->remove(iterator);
+ }
+ va_end(args_copy);
+ }
+ iterator->destroy(iterator);
+
+ /* wake up all active listeners */
+ iterator = this->active_listeners->create_iterator(this->active_listeners, TRUE);
+ while (iterator->iterate(iterator, (void**)&active_listener))
+ {
+ /* wait until it is back */
+ while (active_listener->state == REGISTERED)
+ {
+ pthread_cond_wait(&active_listener->cond, &this->mutex);
+ }
+ /* if thread is listening now, give it the signal to process */
+ if (active_listener->state == LISTENING)
+ {
+ active_listener->level = level;
+ active_listener->thread = thread;
+ active_listener->ike_sa = ike_sa;
+ active_listener->signal = signal;
+ active_listener->format = format;
+ va_copy(active_listener->args, args);
+ active_listener->state = REGISTERED;
+ pthread_cond_signal(&active_listener->cond);
+ }
+ }
+
+ /* we must wait now until all are not in state REGISTERED,
+ * as they may still use our arguments */
+ iterator->reset(iterator);
+ while (iterator->iterate(iterator, (void**)&active_listener))
+ {
+ while (active_listener->state == REGISTERED)
+ {
+ pthread_cond_wait(&active_listener->cond, &this->mutex);
+ }
+ }
+ iterator->destroy(iterator);
+
+ pthread_mutex_unlock(&this->mutex);
+}
+
+/**
+ * Implementation of bus_t.signal.
+ */
+static void signal_(private_bus_t *this, signal_t signal, level_t level,
+ char* format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ vsignal(this, signal, level, format, args);
+ va_end(args);
+}
+
+/**
+ * Implementation of bus_t.destroy.
+ */
+static void destroy(private_bus_t *this)
+{
+ this->active_listeners->destroy_function(this->active_listeners, free);
+ this->listeners->destroy(this->listeners);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+bus_t *bus_create()
+{
+ private_bus_t *this = malloc_thing(private_bus_t);
+
+ this->public.add_listener = (void(*)(bus_t*,bus_listener_t*))add_listener;
+ this->public.listen = (signal_t(*)(bus_t*,level_t*,int*,ike_sa_t**,char**,va_list*))listen_;
+ this->public.set_listen_state = (void(*)(bus_t*,bool))set_listen_state;
+ this->public.set_sa = (void(*)(bus_t*,ike_sa_t*))set_sa;
+ this->public.signal = (void(*)(bus_t*,signal_t,level_t,char*,...))signal_;
+ this->public.vsignal = (void(*)(bus_t*,signal_t,level_t,char*,va_list))vsignal;
+ this->public.destroy = (void(*)(bus_t*)) destroy;
+
+ this->listeners = linked_list_create();
+ this->active_listeners = linked_list_create();
+ pthread_mutex_init(&this->mutex, NULL);
+ pthread_key_create(&this->thread_id, NULL);
+ pthread_key_create(&this->thread_sa, NULL);
+
+ return &(this->public);
+}
diff --git a/src/charon/bus/bus.h b/src/charon/bus/bus.h
new file mode 100644
index 000000000..200525fb7
--- /dev/null
+++ b/src/charon/bus/bus.h
@@ -0,0 +1,366 @@
+/**
+ * @file bus.h
+ *
+ * @brief Interface of bus_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 BUS_H_
+#define BUS_H_
+
+typedef enum signal_t signal_t;
+typedef enum level_t level_t;
+typedef struct bus_listener_t bus_listener_t;
+typedef struct bus_t bus_t;
+
+#include <stdarg.h>
+
+#include <sa/ike_sa.h>
+#include <sa/child_sa.h>
+
+
+/**
+ * @brief signals emitted by the daemon.
+ *
+ * Signaling is for different purporses. First, it allows debugging via
+ * "debugging signal messages", sencondly, it allows to follow certain
+ * mechanisms currently going on in the daemon. As we are multithreaded,
+ * and of multiple transactions are involved, it's not possible to follow
+ * one connection setup without further infrastructure. These infrastructure
+ * is provided by the bus and the signals the daemon emits to the bus.
+ *
+ * There are different scenarios to follow these signals, but all have
+ * the same scheme. First, a START signal is emitted to indicate the daemon
+ * has started to
+ *
+ * @ingroup bus
+ */
+enum signal_t {
+ /** pseudo signal, representing any other signal */
+ SIG_ANY,
+
+ /** debugging message from daemon main loop */
+ DBG_DMN,
+ /** debugging message from IKE_SA_MANAGER */
+ DBG_MGR,
+ /** debugging message from an IKE_SA */
+ DBG_IKE,
+ /** debugging message from a CHILD_SA */
+ DBG_CHD,
+ /** debugging message from job processing */
+ DBG_JOB,
+ /** debugging message from configuration backends */
+ DBG_CFG,
+ /** debugging message from kernel interface */
+ DBG_KNL,
+ /** debugging message from networking */
+ DBG_NET,
+ /** debugging message from message encoding/decoding */
+ DBG_ENC,
+ /** debugging message from libstrongswan via logging hook */
+ DBG_LIB,
+
+ /** number of debug signals */
+ DBG_MAX,
+
+ /** signals for IKE_SA establishment */
+ IKE_UP_START,
+ IKE_UP_SUCCESS,
+ IKE_UP_FAILED,
+
+ /** signals for IKE_SA delete */
+ IKE_DOWN_START,
+ IKE_DOWN_SUCCESS,
+ IKE_DOWN_FAILED,
+
+ /** signals for IKE_SA rekeying */
+ IKE_REKEY_START,
+ IKE_REKEY_SUCCESS,
+ IKE_REKEY_FAILED,
+
+ /** signals for CHILD_SA establishment */
+ CHILD_UP_START,
+ CHILD_UP_SUCCESS,
+ CHILD_UP_FAILED,
+
+ /** signals for CHILD_SA delete */
+ CHILD_DOWN_START,
+ CHILD_DOWN_SUCCESS,
+ CHILD_DOWN_FAILED,
+
+ /** signals for CHILD_SA rekeying */
+ CHILD_REKEY_START,
+ CHILD_REKEY_SUCCESS,
+ CHILD_REKEY_FAILED,
+
+ /** signals for CHILD_SA routing */
+ CHILD_ROUTE_START,
+ CHILD_ROUTE_SUCCESS,
+ CHILD_ROUTE_FAILED,
+
+ /** signals for CHILD_SA routing */
+ CHILD_UNROUTE_START,
+ CHILD_UNROUTE_SUCCESS,
+ CHILD_UNROUTE_FAILED,
+
+ SIG_MAX
+};
+
+/**
+ * short names of signals using 3 chars
+ */
+extern enum_name_t *signal_names;
+
+/**
+ * Signal levels used to control output verbosity.
+ */
+enum level_t {
+ /** numerical levels from 0 to 4 */
+ LEVEL_0 = 0,
+ LEVEL_1 = 1,
+ LEVEL_2 = 2,
+ LEVEL_3 = 3,
+ LEVEL_4 = 4,
+ /** absolutely silent, no signal is emitted with this level */
+ LEVEL_SILENT = -1,
+ /** alias for numberical levels */
+ LEVEL_AUDIT = LEVEL_0,
+ LEVEL_CTRL = LEVEL_1,
+ LEVEL_CTRLMORE = LEVEL_2,
+ LEVEL_RAW = LEVEL_3,
+ LEVEL_PRIVATE = LEVEL_4,
+};
+
+#ifndef DEBUG_LEVEL
+# define DEBUG_LEVEL 4
+#endif /* DEBUG_LEVEL */
+
+#if DEBUG_LEVEL >= 1
+/**
+ * @brief Log a debug message via the signal bus.
+ *
+ * @param signal signal_t signal description
+ * @param format printf() style format string
+ * @param ... printf() style agument list
+ */
+# define DBG1(sig, format, ...) charon->bus->signal(charon->bus, sig, LEVEL_1, format, ##__VA_ARGS__)
+#endif /* DEBUG_LEVEL */
+#if DEBUG_LEVEL >= 2
+#define DBG2(sig, format, ...) charon->bus->signal(charon->bus, sig, LEVEL_2, format, ##__VA_ARGS__)
+#endif /* DEBUG_LEVEL */
+#if DEBUG_LEVEL >= 3
+#define DBG3(sig, format, ...) charon->bus->signal(charon->bus, sig, LEVEL_3, format, ##__VA_ARGS__)
+#endif /* DEBUG_LEVEL */
+#if DEBUG_LEVEL >= 4
+#define DBG4(sig, format, ...) charon->bus->signal(charon->bus, sig, LEVEL_4, format, ##__VA_ARGS__)
+#endif /* DEBUG_LEVEL */
+
+#ifndef DBG1
+# define DBG1(...) {}
+#endif /* DBG1 */
+#ifndef DBG2
+# define DBG2(...) {}
+#endif /* DBG2 */
+#ifndef DBG3
+# define DBG3(...) {}
+#endif /* DBG3 */
+#ifndef DBG4
+# define DBG4(...) {}
+#endif /* DBG4 */
+
+/**
+ * @brief Raise a signal for an occured event.
+ *
+ * @param sig signal_t signal description
+ * @param format printf() style format string
+ * @param ... printf() style agument list
+ */
+#define SIG(sig, format, ...) charon->bus->signal(charon->bus, sig, LEVEL_0, format, ##__VA_ARGS__)
+
+/**
+ * @brief Get the type of a signal.
+ *
+ * A signal may be a debugging signal with a specific context. They have
+ * a level specific for their context > 0. All audit signals use the
+ * type 0. This allows filtering of singals by their type.
+ *
+ * @param signal signal to get the type from
+ * @return type of the signal, between 0..(DBG_MAX-1)
+ */
+#define SIG_TYPE(sig) (sig > DBG_MAX ? SIG_ANY : sig)
+
+
+/**
+ * @brief Interface for registering at the signal bus.
+ *
+ * To receive signals from the bus, the client implementing the
+ * bus_listener_t interface registers itself at the signal bus.
+ *
+ * @ingroup bus
+ */
+struct bus_listener_t {
+
+ /**
+ * @brief Send a signal to a bus listener.
+ *
+ * A numerical identification for the thread is included, as the
+ * associated IKE_SA, if any. Signal specifies the type of
+ * the event occured. The format string specifies
+ * an additional informational or error message with a printf() like
+ * variable argument list. This is in the va_list form, as forwarding
+ * a "..." parameters to functions is not (cleanly) possible.
+ * The implementing signal function returns TRUE to stay registered
+ * to the bus, or FALSE to unregister itself.
+ *
+ * @param this listener
+ * @param singal kind of the signal (up, down, rekeyed, ...)
+ * @param level verbosity level of the signal
+ * @param thread ID of the thread raised this signal
+ * @param ike_sa IKE_SA associated to the event
+ * @param format printf() style format string
+ * @param args vprintf() style va_list argument list
+ " @return TRUE to stay registered, FALSE to unregister
+ */
+ bool (*signal) (bus_listener_t *this, signal_t signal, level_t level,
+ int thread, ike_sa_t *ike_sa, char* format, va_list args);
+};
+
+/**
+ * @brief Signal bus which sends signals to registered listeners.
+ *
+ * The signal bus is not much more than a multiplexer. A listener interested
+ * in receiving event signals registers at the bus. Any signals sent to
+ * are delivered to all registered listeners.
+ * To deliver signals to threads, the blocking listen() call may be used
+ * to wait for a signal.
+ *
+ * @ingroup bus
+ */
+struct bus_t {
+
+ /**
+ * @brief Register a listener to the bus.
+ *
+ * A registered listener receives all signals which are sent to the bus.
+ * The listener is passive; the thread which emitted the signal
+ * processes the listener routine.
+ *
+ * @param this bus
+ * @param listener listener to register.
+ */
+ void (*add_listener) (bus_t *this, bus_listener_t *listener);
+
+ /**
+ * @brief Listen actively on the bus.
+ *
+ * As we are fully multithreaded, we must provide a mechanism
+ * for active threads to listen to the bus. With the listen() method,
+ * a thread waits until a signal occurs, and then processes it.
+ * To prevent the listen() calling thread to miss signals emitted while
+ * it processes a signal, registration is required. This is done through
+ * the set_listen_state() method, see below.
+ *
+ * @param this bus
+ * @param level verbosity level of the signal
+ * @param thread receives thread number emitted the signal
+ * @param ike_sa receives the IKE_SA involved in the signal, or NULL
+ * @param format receives the format string supplied with the signal
+ * @param va_list receives the variable argument list for format
+ * @return the emitted signal type
+ */
+ signal_t (*listen) (bus_t *this, level_t* level, int *thread,
+ ike_sa_t **ike_sa, char** format, va_list* args);
+
+ /**
+ * @brief Set the listening state of the calling thread.
+ *
+ * To prevent message loss for active listeners using listen(), threads
+ * must register themself to the bus before starting to listen(). When
+ * a signal occurs, the emitter waits until all threads with listen_state
+ * TRUE are waiting in the listen() method to process the signal.
+ * It is important that a thread with liste_state TRUE calls listen()
+ * periodically, or sets it's listening state to FALSE; otherwise
+ * all signal emitting threads get blocked on the bus.
+ *
+ * @param this bus
+ * @param active TRUE to set to listening
+ */
+ void (*set_listen_state) (bus_t *this, bool active);
+
+ /**
+ * @brief Set the IKE_SA the calling thread is using.
+ *
+ * To associate an received signal to an IKE_SA without passing it as
+ * parameter each time, the thread registers it's used IKE_SA each
+ * time it checked it out. Before checking it in, the thread unregisters
+ * the IKE_SA (by passing NULL). This IKE_SA is stored per-thread, so each
+ * thread has one IKE_SA registered (or not).
+ *
+ * @param this bus
+ * @param ike_sa ike_sa to register, or NULL to unregister
+ */
+ void (*set_sa) (bus_t *this, ike_sa_t *ike_sa);
+
+ /**
+ * @brief Send a signal to the bus.
+ *
+ * The signal specifies the type of the event occured. The format string
+ * specifies an additional informational or error message with a
+ * printf() like variable argument list.
+ * Some useful macros are available to shorten this call.
+ * @see SIG(), DBG1()
+ *
+ * @param this bus
+ * @param singal kind of the signal (up, down, rekeyed, ...)
+ * @param level verbosity level of the signal
+ * @param format printf() style format string
+ * @param ... printf() style argument list
+ */
+ void (*signal) (bus_t *this, signal_t signal, level_t level, char* format, ...);
+
+ /**
+ * @brief Send a signal to the bus using va_list arguments.
+ *
+ * Same as bus_t.signal(), but uses va_list argument list.
+ *
+ * @param this bus
+ * @param singal kind of the signal (up, down, rekeyed, ...)
+ * @param level verbosity level of the signal
+ * @param format printf() style format string
+ * @param args va_list arguments
+ */
+ void (*vsignal) (bus_t *this, signal_t signal, level_t level, char* format, va_list args);
+
+ /**
+ * @brief Destroy the signal bus.
+ *
+ * @param this bus to destroy
+ */
+ void (*destroy) (bus_t *this);
+};
+
+/**
+ * @brief Create the signal bus which multiplexes signals to its listeners.
+ *
+ * @return signal bus instance
+ *
+ * @ingroup bus
+ */
+bus_t *bus_create();
+
+#endif /* BUS_H_ */
diff --git a/src/charon/bus/listeners/file_logger.c b/src/charon/bus/listeners/file_logger.c
new file mode 100644
index 000000000..14f9f72cf
--- /dev/null
+++ b/src/charon/bus/listeners/file_logger.c
@@ -0,0 +1,128 @@
+/**
+ * @file file_logger.c
+ *
+ * @brief Implementation of file_logger_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 <stdio.h>
+#include <string.h>
+
+#include "file_logger.h"
+
+
+typedef struct private_file_logger_t private_file_logger_t;
+
+/**
+ * Private data of a file_logger_t object
+ */
+struct private_file_logger_t {
+
+ /**
+ * Public data.
+ */
+ file_logger_t public;
+
+ /**
+ * output file
+ */
+ FILE *out;
+
+ /**
+ * Maximum level to log
+ */
+ level_t levels[DBG_MAX];
+};
+
+
+/**
+ * Implementation of bus_listener_t.signal.
+ */
+static bool signal_(private_file_logger_t *this, signal_t signal, level_t level,
+ int thread, ike_sa_t* ike_sa, char *format, va_list args)
+{
+ if (level <= this->levels[SIG_TYPE(signal)])
+ {
+ char buffer[8192];
+ char *current = buffer, *next;
+
+ /* write in memory buffer first */
+ vsnprintf(buffer, sizeof(buffer), format, args);
+
+ /* prepend a prefix in front of every line */
+ while (current)
+ {
+ next = strchr(current, '\n');
+ if (next)
+ {
+ *(next++) = '\0';
+ }
+ fprintf(this->out, "%.2d[%N] %s\n", thread, signal_names, signal, current);
+ current = next;
+ }
+ }
+ /* always stay registered */
+ return TRUE;
+}
+
+/**
+ * Implementation of file_logger_t.set_level.
+ */
+static void set_level(private_file_logger_t *this, signal_t signal, level_t level)
+{
+ if (signal == SIG_ANY)
+ {
+ int i;
+ for (i = 0; i < DBG_MAX; i++)
+ {
+ this->levels[i] = level;
+ }
+ }
+ else
+ {
+
+ this->levels[SIG_TYPE(signal)] = level;
+ }
+}
+
+/**
+ * Implementation of file_logger_t.destroy.
+ */
+static void destroy(private_file_logger_t *this)
+{
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+file_logger_t *file_logger_create(FILE *out)
+{
+ private_file_logger_t *this = malloc_thing(private_file_logger_t);
+
+ /* public functions */
+ this->public.listener.signal = (bool(*)(bus_listener_t*,signal_t,level_t,int,ike_sa_t*,char*,va_list))signal_;
+ this->public.set_level = (void(*)(file_logger_t*,signal_t,level_t))set_level;
+ this->public.destroy = (void(*)(file_logger_t*))destroy;
+
+ /* private variables */
+ this->out = out;
+ set_level(this, SIG_ANY, LEVEL_SILENT);
+
+ return &this->public;
+}
diff --git a/src/charon/bus/listeners/file_logger.h b/src/charon/bus/listeners/file_logger.h
new file mode 100644
index 000000000..d67daba25
--- /dev/null
+++ b/src/charon/bus/listeners/file_logger.h
@@ -0,0 +1,73 @@
+/**
+ * @file file_logger.h
+ *
+ * @brief Interface of file_logger_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 FILE_LOGGER_H_
+#define FILE_LOGGER_H_
+
+typedef struct file_logger_t file_logger_t;
+
+#include <bus/bus.h>
+
+/**
+ * @brief Logger to files which implements bus_listener_t.
+ *
+ * @b Constructors:
+ * - file_logger_create()
+ *
+ * @ingroup listeners
+ */
+struct file_logger_t {
+
+ /**
+ * Implements the bus_listener_t interface.
+ */
+ bus_listener_t listener;
+
+ /**
+ * @brief Set the loglevel for a signal type.
+ *
+ * @param this stream_logger_t object
+ * @param singal type of signal
+ * @param level max level to log (0..4)
+ */
+ void (*set_level) (file_logger_t *this, signal_t signal, level_t level);
+
+ /**
+ * @brief Destroys a file_logger_t object.
+ *
+ * @param this file_logger_t object
+ */
+ void (*destroy) (file_logger_t *this);
+};
+
+/**
+ * @brief Constructor to create a file_logger_t object.
+ *
+ * @param out FILE to write to
+ * @return file_logger_t object
+ *
+ * @ingroup listeners
+ */
+file_logger_t *file_logger_create(FILE *out);
+
+
+#endif /* FILE_LOGGER_H_ */
diff --git a/src/charon/bus/listeners/sys_logger.c b/src/charon/bus/listeners/sys_logger.c
new file mode 100644
index 000000000..d26d14dc0
--- /dev/null
+++ b/src/charon/bus/listeners/sys_logger.c
@@ -0,0 +1,131 @@
+/**
+ * @file sys_logger.c
+ *
+ * @brief Implementation of sys_logger_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 <stdio.h>
+#include <string.h>
+#include <pthread.h>
+
+#include "sys_logger.h"
+
+
+typedef struct private_sys_logger_t private_sys_logger_t;
+
+/**
+ * Private data of a sys_logger_t object
+ */
+struct private_sys_logger_t {
+
+ /**
+ * Public data.
+ */
+ sys_logger_t public;
+
+ /**
+ * syslog facility to use
+ */
+ int facility;
+
+ /**
+ * Maximum level to log
+ */
+ level_t levels[DBG_MAX];
+};
+
+
+/**
+ * Implementation of bus_listener_t.signal.
+ */
+static bool signal_(private_sys_logger_t *this, signal_t signal, level_t level,
+ int thread, ike_sa_t* ike_sa, char *format, va_list args)
+{
+ if (level <= this->levels[SIG_TYPE(signal)])
+ {
+ char buffer[8192];
+ char *current = buffer, *next;
+
+ /* write in memory buffer first */
+ vsnprintf(buffer, sizeof(buffer), format, args);
+
+ /* do a syslog with every line */
+ while (current)
+ {
+ next = strchr(current, '\n');
+ if (next)
+ {
+ *(next++) = '\0';
+ }
+ syslog(this->facility|LOG_INFO, "%.2d[%N] %s\n",
+ thread, signal_names, signal, current);
+ current = next;
+ }
+ }
+ /* always stay registered */
+ return TRUE;
+}
+
+/**
+ * Implementation of sys_logger_t.set_level.
+ */
+static void set_level(private_sys_logger_t *this, signal_t signal, level_t level)
+{
+ if (signal == SIG_ANY)
+ {
+ int i;
+ for (i = 0; i < DBG_MAX; i++)
+ {
+ this->levels[i] = level;
+ }
+ }
+ else
+ {
+
+ this->levels[SIG_TYPE(signal)] = level;
+ }
+}
+
+/**
+ * Implementation of sys_logger_t.destroy.
+ */
+static void destroy(private_sys_logger_t *this)
+{
+ closelog();
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+sys_logger_t *sys_logger_create(int facility)
+{
+ private_sys_logger_t *this = malloc_thing(private_sys_logger_t);
+
+ /* public functions */
+ this->public.listener.signal = (bool(*)(bus_listener_t*,signal_t,level_t,int,ike_sa_t*,char*,va_list))signal_;
+ this->public.set_level = (void(*)(sys_logger_t*,signal_t,level_t))set_level;
+ this->public.destroy = (void(*)(sys_logger_t*))destroy;
+
+ /* private variables */
+ this->facility = facility;
+ set_level(this, SIG_ANY, LEVEL_SILENT);
+
+ return &this->public;
+}
diff --git a/src/charon/bus/listeners/sys_logger.h b/src/charon/bus/listeners/sys_logger.h
new file mode 100644
index 000000000..091217313
--- /dev/null
+++ b/src/charon/bus/listeners/sys_logger.h
@@ -0,0 +1,75 @@
+/**
+ * @file sys_logger.h
+ *
+ * @brief Interface of sys_logger_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 SYS_LOGGER_H_
+#define SYS_LOGGER_H_
+
+typedef struct sys_logger_t sys_logger_t;
+
+#include <syslog.h>
+
+#include <bus/bus.h>
+
+/**
+ * @brief Logger for syslog which implements bus_listener_t.
+ *
+ * @b Constructors:
+ * - sys_logger_create()
+ *
+ * @ingroup listeners
+ */
+struct sys_logger_t {
+
+ /**
+ * Implements the bus_listener_t interface.
+ */
+ bus_listener_t listener;
+
+ /**
+ * @brief Set the loglevel for a signal type.
+ *
+ * @param this stream_logger_t object
+ * @param singal type of signal
+ * @param level max level to log
+ */
+ void (*set_level) (sys_logger_t *this, signal_t signal, level_t level);
+
+ /**
+ * @brief Destroys a sys_logger_t object.
+ *
+ * @param this sys_logger_t object
+ */
+ void (*destroy) (sys_logger_t *this);
+};
+
+/**
+ * @brief Constructor to create a sys_logger_t object.
+ *
+ * @param facility syslog facility to use
+ * @return sys_logger_t object
+ *
+ * @ingroup listeners
+ */
+sys_logger_t *sys_logger_create(int facility);
+
+
+#endif /* SYS_LOGGER_H_ */
diff --git a/src/charon/config/configuration.c b/src/charon/config/configuration.c
new file mode 100755
index 000000000..488ba9a5e
--- /dev/null
+++ b/src/charon/config/configuration.c
@@ -0,0 +1,162 @@
+/**
+ * @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 <math.h>
+
+#include "configuration.h"
+
+#include <library.h>
+
+/**
+ * Timeout in milliseconds after that a half open IKE_SA gets deleted.
+ */
+#define HALF_OPEN_IKE_SA_TIMEOUT 30000
+
+/**
+ * Retransmission uses a backoff algorithm. The timeout is calculated using
+ * TIMEOUT * (BASE ** try).
+ * When try reaches TRIES, retransmission is given up.
+ *
+ * Using an initial TIMEOUT of 4s, a BASE of 1.8, and 5 TRIES gives us:
+ *
+ * | relative | absolute
+ * ---------------------------------------------------------
+ * 4s * (1.8 ** (0 % 5)) = 4s 4s
+ * 4s * (1.8 ** (1 % 5)) = 7s 11s
+ * 4s * (1.8 ** (2 % 5)) = 13s 24s
+ * 4s * (1.8 ** (3 % 5)) = 23s 47s
+ * 4s * (1.8 ** (4 % 5)) = 42s 89s
+ * 4s * (1.8 ** (5 % 5)) = 76s 165s
+ *
+ * The peer is considered dead after 2min 45s when no reply comes in.
+ */
+
+/**
+ * First retransmit timeout in milliseconds.
+ * Timeout value is increasing in each retransmit round.
+ */
+#define RETRANSMIT_TIMEOUT 4000
+
+/**
+ * Base which is raised to the power of the retransmission count.
+ */
+#define RETRANSMIT_BASE 1.8
+
+/**
+ * Number of retransmits done in a retransmit sequence
+ */
+#define RETRANSMIT_TRIES 5
+
+/**
+ * Keepalive interval in seconds.
+ */
+#define KEEPALIVE_INTERVAL 20
+
+/**
+ * retry interval in seconds.
+ */
+#define RETRY_INTERVAL 30
+
+/**
+ * jitter to user for retrying
+ */
+#define RETRY_JITTER 20
+
+
+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 u_int32_t get_retransmit_timeout (private_configuration_t *this,
+ u_int32_t retransmit_count)
+{
+ if (retransmit_count > RETRANSMIT_TRIES)
+ {
+ /* give up */
+ return 0;
+ }
+ return (u_int32_t)
+ (RETRANSMIT_TIMEOUT * pow(RETRANSMIT_BASE, retransmit_count));
+}
+
+/**
+ * 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.get_keepalive_interval.
+ */
+static u_int32_t get_keepalive_interval (private_configuration_t *this)
+{
+ return KEEPALIVE_INTERVAL;
+}
+
+/**
+ * Implementation of configuration_t.get_retry_interval.
+ */
+static u_int32_t get_retry_interval (private_configuration_t *this)
+{
+ return RETRY_INTERVAL - (random() % RETRY_JITTER);
+}
+
+/**
+ * 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 = (u_int32_t (*) (configuration_t*,u_int32_t))get_retransmit_timeout;
+ this->public.get_half_open_ike_sa_timeout = (u_int32_t (*) (configuration_t*)) get_half_open_ike_sa_timeout;
+ this->public.get_keepalive_interval = (u_int32_t (*) (configuration_t*)) get_keepalive_interval;
+ this->public.get_retry_interval = (u_int32_t (*) (configuration_t*)) get_retry_interval;
+
+ return (&this->public);
+}
diff --git a/src/charon/config/configuration.h b/src/charon/config/configuration.h
new file mode 100755
index 000000000..c1207171d
--- /dev/null
+++ b/src/charon/config/configuration.h
@@ -0,0 +1,102 @@
+/**
+ * @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_
+
+typedef struct configuration_t configuration_t;
+
+#include <library.h>
+
+/**
+ * @brief The interface for various daemon related configs.
+ *
+ * @b Constructors:
+ * - configuration_create()
+ *
+ * @ingroup config
+ */
+struct configuration_t {
+
+ /**
+ * @brief Returns the retransmit timeout.
+ *
+ * A return value of zero means the request should not be
+ * retransmitted again.
+ *
+ * @param this calling object
+ * @param retransmitted number of times a message was retransmitted so far
+ * @return time in milliseconds, when to do next retransmit
+ */
+ u_int32_t (*get_retransmit_timeout) (configuration_t *this,
+ u_int32_t retransmitted);
+
+ /**
+ * @brief Returns the timeout for an half open IKE_SA in ms.
+ *
+ * Half open means that the IKE_SA is still on a not established state
+ *
+ * @param this calling object
+ * @return timeout in milliseconds (ms)
+ */
+ u_int32_t (*get_half_open_ike_sa_timeout) (configuration_t *this);
+
+ /**
+ * @brief Returns the keepalive interval in s.
+ *
+ * The keepalive interval defines the idle time after which a
+ * NAT keepalive packet should be sent.
+ *
+ * @param this calling object
+ * @return interval in s
+ */
+ u_int32_t (*get_keepalive_interval) (configuration_t *this);
+
+ /**
+ * @brief Returns the interval to retry a failed action again.
+ *
+ * In some situations, the protocol may be in a state where processing
+ * is not possible and an action must be retried (e.g. rekeying).
+ *
+ * @param this calling object
+ * @return interval in s
+ */
+ u_int32_t (*get_retry_interval) (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(void);
+
+#endif /*CONFIGURATION_H_*/
diff --git a/src/charon/config/connections/connection.c b/src/charon/config/connections/connection.c
new file mode 100644
index 000000000..ffe508992
--- /dev/null
+++ b/src/charon/config/connections/connection.c
@@ -0,0 +1,404 @@
+/**
+ * @file connection.c
+ *
+ * @brief Implementation of connection_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <config/connections/connection.h>
+#include <utils/linked_list.h>
+
+ENUM(cert_policy_names, CERT_ALWAYS_SEND, CERT_NEVER_SEND,
+ "CERT_ALWAYS_SEND",
+ "CERT_SEND_IF_ASKED",
+ "CERT_NEVER_SEND"
+);
+
+typedef struct private_connection_t private_connection_t;
+
+/**
+ * Private data of an connection_t object
+ */
+struct private_connection_t {
+
+ /**
+ * Public part
+ */
+ connection_t public;
+
+ /**
+ * Number of references hold by others to this connection
+ */
+ refcount_t refcount;
+
+ /**
+ * Name of the connection
+ */
+ char *name;
+
+ /**
+ * Does charon handle this connection? Or can he ignore it?
+ */
+ bool ikev2;
+
+ /**
+ * should we send a certificate request?
+ */
+ cert_policy_t certreq_policy;
+
+ /**
+ * should we send a certificates?
+ */
+ cert_policy_t cert_policy;
+
+ /**
+ * ID of us
+ */
+ identification_t *my_id;
+
+ /**
+ * Host information of my host.
+ */
+ host_t *my_host;
+
+ /**
+ * Host information of other host.
+ */
+ host_t *other_host;
+
+ /**
+ * Interval to send DPD liveness checks on inactivity
+ */
+ u_int32_t dpd_delay;
+
+ /**
+ * Number of retransmission sequences to send bevore giving up
+ */
+ u_int32_t keyingtries;
+
+ /**
+ * Supported proposals
+ */
+ linked_list_t *proposals;
+
+ /**
+ * Time before an SA gets invalid
+ */
+ u_int32_t soft_lifetime;
+
+ /**
+ * Time before an SA gets rekeyed
+ */
+ u_int32_t hard_lifetime;
+
+ /**
+ * Use full reauthentication instead of rekeying
+ */
+ bool reauth;
+
+ /**
+ * Time, which specifies the range of a random value
+ * substracted from soft_lifetime.
+ */
+ u_int32_t jitter;
+};
+
+/**
+ * Implementation of connection_t.get_name.
+ */
+static char *get_name (private_connection_t *this)
+{
+ return this->name;
+}
+
+/**
+ * Implementation of connection_t.is_ikev2.
+ */
+static bool is_ikev2 (private_connection_t *this)
+{
+ return this->ikev2;
+}
+
+/**
+ * Implementation of connection_t.get_certreq_policy.
+ */
+static cert_policy_t get_certreq_policy (private_connection_t *this)
+{
+ return this->certreq_policy;
+}
+
+/**
+ * Implementation of connection_t.get_cert_policy.
+ */
+static cert_policy_t get_cert_policy (private_connection_t *this)
+{
+ return this->cert_policy;
+}
+
+/**
+ * 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.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)
+{
+ iterator_t *iterator;
+ proposal_t *current;
+ linked_list_t *proposals = linked_list_create();
+
+ iterator = this->proposals->create_iterator(this->proposals, TRUE);
+ while (iterator->iterate(iterator, (void**)&current))
+ {
+ current = current->clone(current);
+ proposals->insert_last(proposals, (void*)current);
+ }
+ iterator->destroy(iterator);
+
+ return 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->iterate(stored_iter, (void**)&stored))
+ {
+ supplied_iter->reset(supplied_iter);
+
+ while (supplied_iter->iterate(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.get_dpd_delay.
+ */
+static u_int32_t get_dpd_delay(private_connection_t *this)
+{
+ return this->dpd_delay;
+}
+
+/**
+ * Implementation of connection_t.get_keyingtries.
+ */
+static u_int32_t get_keyingtries(private_connection_t *this)
+{
+ return this->keyingtries;
+}
+
+/**
+ * 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;
+ diffie_hellman_group_t dh_group = MODP_NONE;
+
+ iterator = this->proposals->create_iterator(this->proposals, TRUE);
+ while (iterator->iterate(iterator, (void**)&proposal))
+ {
+ if (proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP, &algo))
+ {
+ dh_group = algo->algorithm;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ return dh_group;
+}
+
+/**
+ * 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->iterate(prop_iter, (void**)&proposal))
+ {
+ alg_iter = proposal->create_algorithm_iterator(proposal, DIFFIE_HELLMAN_GROUP);
+ while (alg_iter->iterate(alg_iter, (void**)&algo))
+ {
+ if (algo->algorithm == dh_group)
+ {
+ prop_iter->destroy(prop_iter);
+ alg_iter->destroy(alg_iter);
+ return TRUE;
+ }
+ }
+ alg_iter->destroy(alg_iter);
+ }
+ prop_iter->destroy(prop_iter);
+ return FALSE;
+}
+/**
+ * Implementation of connection_t.get_soft_lifetime
+ */
+static u_int32_t get_soft_lifetime(private_connection_t *this)
+{
+ if (this->jitter == 0)
+ {
+ return this->soft_lifetime ;
+ }
+ return this->soft_lifetime - (random() % this->jitter);
+}
+
+/**
+ * Implementation of connection_t.get_hard_lifetime.
+ */
+static u_int32_t get_hard_lifetime(private_connection_t *this)
+{
+ return this->hard_lifetime;
+}
+
+/**
+ * Implementation of connection_t.get_reauth.
+ */
+static bool get_reauth(private_connection_t *this)
+{
+ return this->reauth;
+}
+
+/**
+ * Implementation of connection_t.get_ref.
+ */
+static void get_ref(private_connection_t *this)
+{
+ ref_get(&this->refcount);
+}
+
+/**
+ * Implementation of connection_t.destroy.
+ */
+static void destroy(private_connection_t *this)
+{
+ if (ref_put(&this->refcount))
+ {
+ this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
+ this->my_host->destroy(this->my_host);
+ this->other_host->destroy(this->other_host);
+ free(this->name);
+ free(this);
+ }
+}
+
+/**
+ * Described in header.
+ */
+connection_t * connection_create(char *name, bool ikev2,
+ cert_policy_t cert_policy,
+ cert_policy_t certreq_policy,
+ host_t *my_host, host_t *other_host,
+ u_int32_t dpd_delay, bool reauth,
+ u_int32_t keyingtries,
+ u_int32_t hard_lifetime,
+ u_int32_t soft_lifetime, u_int32_t jitter)
+{
+ private_connection_t *this = malloc_thing(private_connection_t);
+
+ /* public functions */
+ this->public.get_name = (char*(*)(connection_t*))get_name;
+ this->public.is_ikev2 = (bool(*)(connection_t*))is_ikev2;
+ this->public.get_cert_policy = (cert_policy_t(*)(connection_t*))get_cert_policy;
+ this->public.get_certreq_policy = (cert_policy_t(*)(connection_t*))get_certreq_policy;
+ this->public.get_my_host = (host_t*(*)(connection_t*))get_my_host;
+ 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_dpd_delay = (u_int32_t(*)(connection_t*)) get_dpd_delay;
+ this->public.get_reauth = (bool(*)(connection_t*)) get_reauth;
+ this->public.get_keyingtries = (u_int32_t(*)(connection_t*)) get_keyingtries;
+ 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.get_soft_lifetime = (u_int32_t (*) (connection_t *))get_soft_lifetime;
+ this->public.get_hard_lifetime = (u_int32_t (*) (connection_t *))get_hard_lifetime;
+ this->public.get_ref = (void(*)(connection_t*))get_ref;
+ this->public.destroy = (void(*)(connection_t*))destroy;
+
+ /* private variables */
+ this->refcount = 1;
+ this->name = strdup(name);
+ this->ikev2 = ikev2;
+ this->cert_policy = cert_policy;
+ this->certreq_policy = certreq_policy;
+ this->my_host = my_host;
+ this->other_host = other_host;
+ this->dpd_delay = dpd_delay;
+ this->reauth = reauth;
+ this->keyingtries = keyingtries;
+ this->hard_lifetime = hard_lifetime;
+ this->soft_lifetime = soft_lifetime;
+ this->jitter = jitter;
+
+ this->proposals = linked_list_create();
+
+ return &this->public;
+}
diff --git a/src/charon/config/connections/connection.h b/src/charon/config/connections/connection.h
new file mode 100644
index 000000000..d0788876f
--- /dev/null
+++ b/src/charon/config/connections/connection.h
@@ -0,0 +1,292 @@
+/**
+ * @file connection.h
+ *
+ * @brief Interface of connection_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef enum cert_policy_t cert_policy_t;
+typedef struct connection_t connection_t;
+
+#include <library.h>
+#include <utils/host.h>
+#include <utils/linked_list.h>
+#include <utils/identification.h>
+#include <config/proposal.h>
+#include <crypto/diffie_hellman.h>
+
+
+/**
+ * Certificate sending policy. This is also used for certificate
+ * requests when using this definition for the other peer. If
+ * it is CERT_NEVER_SEND, a certreq is omitted, otherwise its
+ * included.
+ *
+ * @ingroup config
+ *
+ * @warning These definitions must be the same as in pluto/starter,
+ * as they are sent over the stroke socket.
+ */
+enum cert_policy_t {
+ /** always send certificates, even when not requested */
+ CERT_ALWAYS_SEND = 0,
+ /** send certificate upon cert request */
+ CERT_SEND_IF_ASKED = 1,
+ /** never send a certificate, even when requested */
+ CERT_NEVER_SEND = 2,
+};
+
+/**
+ * enum strings for cert_policy_t
+ *
+ * @ingroup config
+ */
+extern enum_name_t *cert_policy_names;
+
+/**
+ * @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 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 Returns a list of all supported proposals.
+ *
+ * Returned list and its proposals must be destroyed after usage.
+ *
+ * @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 DPD check interval.
+ *
+ * @param this calling object
+ * @return dpd_delay in seconds
+ */
+ u_int32_t (*get_dpd_delay) (connection_t *this);
+
+ /**
+ * @brief Should a full reauthentication be done instead of rekeying?
+ *
+ * @param this calling object
+ * @return TRUE to use full reauthentication
+ */
+ bool (*get_reauth) (connection_t *this);
+
+ /**
+ * @brief Get the max number of retransmission sequences.
+ *
+ * @param this calling object
+ * @return max number of retransmission sequences
+ */
+ u_int32_t (*get_keyingtries) (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 Check if the connection is marked as an IKEv2 connection.
+ *
+ * Since all connections (IKEv1+2) are loaded, but charon handles
+ * only those marked with IKEv2, this flag can tell us if we must
+ * ignore a connection on initiaton. Then pluto will do it for us.
+ *
+ * @param this calling object
+ * @return - TRUE, if this is an IKEv2 connection
+ */
+ bool (*is_ikev2) (connection_t *this);
+
+ /**
+ * @brief Should be sent a certificate request for this connection?
+ *
+ * A certificate request contains serials of our trusted CA certificates.
+ * This flag says if such a request is sent on connection setup to
+ * the peer. It should be omitted when CERT_SEND_NEVER, sended otherwise.
+ *
+ * @param this calling object
+ * @return certificate request sending policy
+ */
+ cert_policy_t (*get_certreq_policy) (connection_t *this);
+
+ /**
+ * @brief Should be sent a certificate for this connection?
+ *
+ * Return the policy used to send the certificate.
+ *
+ * @param this calling object
+ * @return certificate sending policy
+ */
+ cert_policy_t (*get_cert_policy) (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 Get the lifetime of a connection, before IKE_SA rekeying starts.
+ *
+ * A call to this function automatically adds a jitter to
+ * avoid simultanous rekeying.
+ *
+ * @param this calling object
+ * @return lifetime in seconds
+ */
+ u_int32_t (*get_soft_lifetime) (connection_t *this);
+
+ /**
+ * @brief Get the lifetime of a connection, before IKE_SA gets deleted.
+ *
+ * @param this calling object
+ * @return lifetime in seconds
+ */
+ u_int32_t (*get_hard_lifetime) (connection_t *this);
+
+ /**
+ * @brief Get a new reference to this connection.
+ *
+ * Get a new reference to this connection by increasing
+ * it's internal reference counter.
+ * Do not call get_ref or any other function until you
+ * already have a reference. Otherwise the object may get
+ * destroyed while calling get_ref(),
+ *
+ * @param this calling object
+ */
+ void (*get_ref) (connection_t *this);
+
+ /**
+ * @brief Destroys a connection_t object.
+ *
+ * Decrements the internal reference counter and
+ * destroys the connection when it reaches zero.
+ *
+ * @param this calling object
+ */
+ void (*destroy) (connection_t *this);
+};
+
+/**
+ * @brief Creates a connection_t object.
+ *
+ * Supplied hosts become owned by connection, so
+ * do not modify or destroy them after a call to
+ * connection_create(). Name gets cloned internally.
+ * The retrasmit sequence number says how fast we give up when the peer
+ * does not respond. A high value may bridge-over temporary connection
+ * problems, a small value can detect dead peers faster.
+ *
+ * @param name connection identifier
+ * @param ikev2 TRUE if this is an IKEv2 connection
+ * @param cert_policy certificate send policy
+ * @param cert_req_policy certificate request send policy
+ * @param my_host host_t representing local address
+ * @param other_host host_t representing remote address
+ * @param dpd_delay interval of DPD liveness checks
+ * @param reauth use full reauthentication instead of rekeying
+ * @param keyingtries number of retransmit sequences to use
+ * @param hard_lifetime lifetime before deleting an IKE_SA
+ * @param soft_lifetime lifetime before rekeying an IKE_SA
+ * @param jitter range of randomization time
+ * @return connection_t object.
+ *
+ * @ingroup config
+ */
+connection_t * connection_create(char *name, bool ikev2,
+ cert_policy_t cert_pol, cert_policy_t req_pol,
+ host_t *my_host, host_t *other_host,
+ u_int32_t dpd_delay, bool reauth,
+ u_int32_t keyingtries,
+ u_int32_t hard_lifetime, u_int32_t soft_lifetime,
+ u_int32_t jitter);
+
+#endif /* CONNECTION_H_ */
diff --git a/src/charon/config/connections/connection_store.h b/src/charon/config/connections/connection_store.h
new file mode 100755
index 000000000..70f209d3b
--- /dev/null
+++ b/src/charon/config/connections/connection_store.h
@@ -0,0 +1,118 @@
+/**
+ * @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_
+
+typedef struct connection_store_t connection_store_t;
+
+#include <library.h>
+#include <config/connections/connection.h>
+#include <utils/iterator.h>
+
+/**
+ * @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 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 Delete a connection from the store.
+ *
+ * Remove a connection from the connection store, identified
+ * by the connections name.
+ *
+ * @param this calling object
+ * @param name name of the connection to delete
+ * @return
+ * - SUCCESS, or
+ * - NOT_FOUND
+ */
+ status_t (*delete_connection) (connection_store_t *this, char *name);
+
+ /**
+ * @brief Get an iterator for the stored connections.
+ *
+ * @param this calling object
+ * @return iterator over all stored connections
+ */
+ iterator_t* (*create_iterator) (connection_store_t *this);
+
+ /**
+ * @brief Destroys a connection_store_t object.
+ *
+ * @param this calling object
+ */
+ void (*destroy) (connection_store_t *this);
+};
+
+#endif /* CONNECTION_STORE_H_ */
diff --git a/src/charon/config/connections/local_connection_store.c b/src/charon/config/connections/local_connection_store.c
new file mode 100644
index 000000000..df4ec230a
--- /dev/null
+++ b/src/charon/config/connections/local_connection_store.c
@@ -0,0 +1,237 @@
+/**
+ * @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 <daemon.h>
+#include <utils/linked_list.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;
+
+ /**
+ * Mutex to exclusivly access connection list
+ */
+ pthread_mutex_t mutex;
+};
+
+
+/**
+ * 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)
+{
+ typedef enum {
+ PRIO_UNDEFINED= 0x00,
+ PRIO_ADDR_ANY= 0x01,
+ PRIO_ADDR_MATCH= 0x02
+ } prio_t;
+
+ prio_t best_prio = PRIO_UNDEFINED;
+
+ iterator_t *iterator;
+ connection_t *candidate;
+ connection_t *found = NULL;
+
+ DBG2(DBG_CFG, "looking for connection for host pair %H...%H",
+ my_host, other_host);
+
+ pthread_mutex_lock(&(this->mutex));
+ iterator = this->connections->create_iterator(this->connections, TRUE);
+ /* determine closest matching connection */
+ while (iterator->iterate(iterator, (void**)&candidate))
+ {
+ host_t *candidate_my_host;
+ host_t *candidate_other_host;
+
+ candidate_my_host = candidate->get_my_host(candidate);
+ candidate_other_host = candidate->get_other_host(candidate);
+
+ /* my_host addresses must match*/
+ if (my_host->ip_equals(my_host, candidate_my_host))
+ {
+ prio_t prio = PRIO_UNDEFINED;
+
+ /* exact match of peer host address or wildcard address? */
+ if (other_host->ip_equals(other_host, candidate_other_host))
+ {
+ prio |= PRIO_ADDR_MATCH;
+ }
+ else if (candidate_other_host->is_anyaddr(candidate_other_host))
+ {
+ prio |= PRIO_ADDR_ANY;
+ }
+
+ DBG2(DBG_CFG, "candidate connection \"%s\": %H...%H (prio=%d)",
+ candidate->get_name(candidate),
+ candidate_my_host, candidate_other_host, prio);
+
+ if (prio > best_prio)
+ {
+ found = candidate;
+ best_prio = prio;
+ }
+ }
+ }
+ iterator->destroy(iterator);
+
+ if (found)
+ {
+ DBG2(DBG_CFG, "found matching connection \"%s\": %H...%H (prio=%d)",
+ found->get_name(found), found->get_my_host(found),
+ found->get_other_host(found), best_prio);
+
+ /* give out a new reference to it */
+ found->get_ref(found);
+ }
+ pthread_mutex_unlock(&(this->mutex));
+ 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;
+
+ pthread_mutex_lock(&(this->mutex));
+ iterator = this->connections->create_iterator(this->connections, TRUE);
+ while (iterator->iterate(iterator, (void**)&current))
+ {
+ if (strcmp(name, current->get_name(current)) == 0)
+ {
+ found = current;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ pthread_mutex_unlock(&(this->mutex));
+
+ if (found)
+ {
+ /* get a new reference for it */
+ found->get_ref(found);
+ }
+ return found;
+}
+
+/**
+ * Implementation of connection_store_t.delete_connection.
+ */
+static status_t delete_connection(private_local_connection_store_t *this, char *name)
+{
+ iterator_t *iterator;
+ connection_t *current;
+ bool found = FALSE;
+
+ pthread_mutex_lock(&(this->mutex));
+ iterator = this->connections->create_iterator(this->connections, TRUE);
+ while (iterator->iterate(iterator, (void **)&current))
+ {
+ if (strcmp(current->get_name(current), name) == 0)
+ {
+ /* remove connection from list, and destroy it */
+ iterator->remove(iterator);
+ current->destroy(current);
+ found = TRUE;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ pthread_mutex_unlock(&(this->mutex));
+ if (found)
+ {
+ return SUCCESS;
+ }
+ return NOT_FOUND;
+}
+
+/**
+ * Implementation of connection_store_t.add_connection.
+ */
+static status_t add_connection(private_local_connection_store_t *this, connection_t *connection)
+{
+ pthread_mutex_lock(&(this->mutex));
+ this->connections->insert_last(this->connections, connection);
+ pthread_mutex_unlock(&(this->mutex));
+ return SUCCESS;
+}
+
+/**
+ * Implementation of connection_store_t.create_iterator.
+ */
+static iterator_t* create_iterator(private_local_connection_store_t *this)
+{
+ return this->connections->create_iterator_locked(this->connections,
+ &this->mutex);
+}
+
+/**
+ * Implementation of connection_store_t.destroy.
+ */
+static void destroy (private_local_connection_store_t *this)
+{
+ pthread_mutex_lock(&(this->mutex));
+ this->connections->destroy_offset(this->connections, offsetof(connection_t, destroy));
+ pthread_mutex_unlock(&(this->mutex));
+ free(this);
+}
+
+/**
+ * Described in header.
+ */
+local_connection_store_t * local_connection_store_create(void)
+{
+ 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_name = (connection_t*(*)(connection_store_t*,char*))get_connection_by_name;
+ this->public.connection_store.delete_connection = (status_t(*)(connection_store_t*,char*))delete_connection;
+ this->public.connection_store.add_connection = (status_t(*)(connection_store_t*,connection_t*))add_connection;
+ this->public.connection_store.create_iterator = (iterator_t*(*)(connection_store_t*))create_iterator;
+ this->public.connection_store.destroy = (void(*)(connection_store_t*))destroy;
+
+ /* private variables */
+ this->connections = linked_list_create();
+ pthread_mutex_init(&(this->mutex), NULL);
+
+ return (&this->public);
+}
diff --git a/src/charon/config/connections/local_connection_store.h b/src/charon/config/connections/local_connection_store.h
new file mode 100644
index 000000000..e78ed809a
--- /dev/null
+++ b/src/charon/config/connections/local_connection_store.h
@@ -0,0 +1,62 @@
+/**
+ * @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_
+
+typedef struct local_connection_store_t local_connection_store_t;
+
+#include <library.h>
+#include <config/connections/connection_store.h>
+
+/**
+ * @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(void);
+
+#endif /* LOCAL_CONNECTION_H_ */
diff --git a/src/charon/config/credentials/local_credential_store.c b/src/charon/config/credentials/local_credential_store.c
new file mode 100644
index 000000000..b7b71b9e7
--- /dev/null
+++ b/src/charon/config/credentials/local_credential_store.c
@@ -0,0 +1,1363 @@
+/**
+ * @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 <string.h>
+#include <pthread.h>
+
+#include <library.h>
+#include <utils/lexparser.h>
+#include <utils/linked_list.h>
+#include <crypto/rsa/rsa_public_key.h>
+#include <crypto/certinfo.h>
+#include <crypto/x509.h>
+#include <crypto/ca.h>
+#include <crypto/crl.h>
+#include <asn1/ttodata.h>
+
+#include "local_credential_store.h"
+
+#define PATH_BUF 256
+#define MAX_CA_PATH_LEN 7
+
+typedef struct shared_key_t shared_key_t;
+
+/**
+ * Private date of a shared_key_t object
+ */
+struct shared_key_t {
+
+ /**
+ * shared secret
+ */
+ chunk_t secret;
+
+ /**
+ * list of peer IDs
+ */
+ linked_list_t *peers;
+};
+
+
+/**
+ * Implementation of shared_key_t.destroy.
+ */
+static void shared_key_destroy(shared_key_t *this)
+{
+ this->peers->destroy_offset(this->peers, offsetof(identification_t, destroy));
+ chunk_free(&this->secret);
+ free(this);
+}
+
+/**
+ * @brief Creates a shared_key_t object.
+ *
+ * @param shared_key shared key value
+ * @return shared_key_t object
+ *
+ * @ingroup config
+ */
+static shared_key_t *shared_key_create(chunk_t secret)
+{
+ shared_key_t *this = malloc_thing(shared_key_t);
+
+ /* private data */
+ this->secret = chunk_clone(secret);
+ this->peers = linked_list_create();
+
+ return (this);
+}
+
+/* ------------------------------------------------------------------------ *
+ * the ca_info_t object as a central control element
+
++--------------------------------------------------------+
+| local_credential_store_t |
++--------------------------------------------------------+
+ | |
++---------------------------+ +-------------------------+
+| linked_list_t *auth_certs | | linked_list_t *ca_infos |
++---------------------------+ +-------------------------+
+ | |
+ | +------------------------- +
+ | | ca_info_t |
+ | +--------------------------+
++---------------+ | char *name |
+| x509_t |<--| x509_t *cacert | +----------------------+
++---------------+ | linked_list_t *certinfos |-->| certinfo_t |
+| chunk_t keyid | | linked_list_t *ocspuris | +----------------------+
++---------------+ | crl_t *crl | | chunk_t serialNumber |
+ | | linked_list_t *crluris | | cert_status_t status |
+ | | pthread_mutex_t mutex | | time_t thisUpdate |
++---------------+ +--------------------------+ | time_t nextUpdate |
+| x509_t | | | bool once |
++---------------+ | +----------------------+
+| chunk_t keyid | | |
++---------------+ +------------------------- + +----------------------+
+ | | ca_info_t | | certinfo_t |
+ | +--------------------------+ +----------------------+
++---------------+ | char *name | | chunk_t serialNumber |
+| x509_t |<--| x509_t *cacert | | cert_status_t status |
++---------------+ | linked_list_t *certinfos | | time_t thisUpdate |
+| chunk_t keyid | | linked_list_t *ocspuris | | time_t nextUpdate |
++---------------+ | crl_t *crl | | bool once |
+ | | linked_list_t *crluris | +----------------------+
+ | | pthread_mutex_t mutex; | |
+ | +--------------------------+
+ | |
+
+ * ------------------------------------------------------------------------ */
+
+typedef struct private_local_credential_store_t private_local_credential_store_t;
+
+/**
+ * Private data of an local_credential_store_t object
+ */
+struct private_local_credential_store_t {
+
+ /**
+ * Public part
+ */
+ local_credential_store_t public;
+
+ /**
+ * list of shared keys
+ */
+ linked_list_t *shared_keys;
+
+ /**
+ * list of EAP keys
+ */
+ linked_list_t *eap_keys;
+
+ /**
+ * list of key_entry_t's with private keys
+ */
+ linked_list_t *private_keys;
+
+ /**
+ * list of X.509 certificates with public keys
+ */
+ linked_list_t *certs;
+
+ /**
+ * list of X.509 authority certificates with public keys
+ */
+ linked_list_t *auth_certs;
+
+ /**
+ * list of X.509 CA information records
+ */
+ linked_list_t *ca_infos;
+
+ /**
+ * enforce strict crl policy
+ */
+ bool strict;
+};
+
+
+/**
+ * Get a key from a list with shared_key_t's
+ */
+static status_t get_key(linked_list_t *keys,
+ identification_t *my_id,
+ identification_t *other_id, chunk_t *secret)
+{
+ typedef enum {
+ PRIO_UNDEFINED= 0x00,
+ PRIO_ANY_MATCH= 0x01,
+ PRIO_MY_MATCH= 0x02,
+ PRIO_OTHER_MATCH= 0x04,
+ } prio_t;
+
+ prio_t best_prio = PRIO_UNDEFINED;
+ chunk_t found = chunk_empty;
+ shared_key_t *shared_key;
+
+ iterator_t *iterator = keys->create_iterator(keys, TRUE);
+
+ while (iterator->iterate(iterator, (void**)&shared_key))
+ {
+ iterator_t *peer_iterator;
+ identification_t *peer_id;
+ prio_t prio = PRIO_UNDEFINED;
+
+ peer_iterator = shared_key->peers->create_iterator(shared_key->peers, TRUE);
+
+ if (peer_iterator->get_count(peer_iterator) == 0)
+ {
+ /* this is a wildcard shared key */
+ prio = PRIO_ANY_MATCH;
+ }
+ else
+ {
+ while (peer_iterator->iterate(peer_iterator, (void**)&peer_id))
+ {
+ if (my_id->equals(my_id, peer_id))
+ {
+ prio |= PRIO_MY_MATCH;
+ }
+ if (other_id->equals(other_id, peer_id))
+ {
+ prio |= PRIO_OTHER_MATCH;
+ }
+ }
+ }
+ peer_iterator->destroy(peer_iterator);
+
+ if (prio > best_prio)
+ {
+ best_prio = prio;
+ found = shared_key->secret;
+ }
+ }
+ iterator->destroy(iterator);
+
+ if (best_prio == PRIO_UNDEFINED)
+ {
+ return NOT_FOUND;
+ }
+ else
+ {
+ *secret = chunk_clone(found);
+ return SUCCESS;
+ }
+}
+
+
+/**
+ * Implementation of local_credential_store_t.get_shared_key.
+ */
+static status_t get_shared_key(private_local_credential_store_t *this,
+ identification_t *my_id,
+ identification_t *other_id, chunk_t *secret)
+{
+ return get_key(this->shared_keys, my_id, other_id, secret);
+}
+
+/**
+ * Implementation of local_credential_store_t.get_eap_key.
+ */
+static status_t get_eap_key(private_local_credential_store_t *this,
+ identification_t *my_id,
+ identification_t *other_id, chunk_t *secret)
+{
+ return get_key(this->eap_keys, my_id, other_id, secret);
+}
+
+/**
+ * Implementation of credential_store_t.get_certificate.
+ */
+static x509_t* get_certificate(private_local_credential_store_t *this,
+ identification_t *id)
+{
+ x509_t *found = NULL;
+ x509_t *current_cert;
+
+ iterator_t *iterator = this->certs->create_iterator(this->certs, TRUE);
+
+ while (iterator->iterate(iterator, (void**)&current_cert))
+ {
+ if (id->equals(id, current_cert->get_subject(current_cert)) ||
+ current_cert->equals_subjectAltName(current_cert, id))
+ {
+ found = current_cert;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ return found;
+}
+
+/**
+ * Implementation of local_credential_store_t.get_rsa_public_key.
+ */
+static rsa_public_key_t *get_rsa_public_key(private_local_credential_store_t *this,
+ identification_t *id)
+{
+ x509_t *cert = get_certificate(this, id);
+
+ return (cert == NULL)? NULL:cert->get_public_key(cert);
+}
+
+/**
+ * Implementation of local_credential_store_t.get_trusted_public_key.
+ */
+static rsa_public_key_t *get_trusted_public_key(private_local_credential_store_t *this,
+ identification_t *id)
+{
+ cert_status_t status;
+ err_t ugh;
+
+ x509_t *cert = get_certificate(this, id);
+
+ if (cert == NULL)
+ return NULL;
+
+ ugh = cert->is_valid(cert, NULL);
+ if (ugh != NULL)
+ {
+ DBG1(DBG_CFG, "certificate %s", ugh);
+ return NULL;
+ }
+
+ status = cert->get_status(cert);
+ if (status == CERT_REVOKED || status == CERT_UNTRUSTED || (this->strict && status != CERT_GOOD))
+ {
+ DBG1(DBG_CFG, "certificate status: %N", cert_status_names, status);
+ return NULL;
+ }
+ if (status == CERT_GOOD && cert->get_until(cert) < time(NULL))
+ {
+ DBG1(DBG_CFG, "certificate is good but crl is stale");
+ return NULL;
+ }
+
+ return cert->get_public_key(cert);
+}
+
+/**
+ * Implementation of local_credential_store_t.get_rsa_private_key.
+ */
+static rsa_private_key_t *get_rsa_private_key(private_local_credential_store_t *this,
+ rsa_public_key_t *pubkey)
+{
+ rsa_private_key_t *found = NULL, *current;
+
+ iterator_t *iterator = this->private_keys->create_iterator(this->private_keys, TRUE);
+
+ while (iterator->iterate(iterator, (void**)&current))
+ {
+ if (current->belongs_to(current, pubkey))
+ {
+ found = current->clone(current);
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ return found;
+}
+
+/**
+ * Implementation of local_credential_store_t.has_rsa_private_key.
+ */
+static bool has_rsa_private_key(private_local_credential_store_t *this, rsa_public_key_t *pubkey)
+{
+ bool found = FALSE;
+ rsa_private_key_t *current;
+
+ iterator_t *iterator = this->private_keys->create_iterator(this->private_keys, TRUE);
+
+ while (iterator->iterate(iterator, (void**)&current))
+ {
+ if (current->belongs_to(current, pubkey))
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ return found;
+}
+
+/**
+ * Implementation of credential_store_t.get_auth_certificate.
+ */
+static x509_t* get_auth_certificate(private_local_credential_store_t *this,
+ u_int auth_flags,
+ identification_t *id)
+{
+ x509_t *found = NULL;
+ x509_t *current_cert;
+
+ iterator_t *iterator = this->auth_certs->create_iterator(this->auth_certs, TRUE);
+
+ while (iterator->iterate(iterator, (void**)&current_cert))
+ {
+ if (current_cert->has_authority_flag(current_cert, auth_flags)
+ && id->equals(id, current_cert->get_subject(current_cert)))
+ {
+ found = current_cert;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+
+ return found;
+}
+
+/**
+ * Implementation of credential_store_t.get_ca_certificate_by_keyid.
+ */
+static x509_t* get_ca_certificate_by_keyid(private_local_credential_store_t *this,
+ chunk_t keyid)
+{
+ x509_t *found = NULL;
+ x509_t *current_cert;
+
+ iterator_t *iterator = this->auth_certs->create_iterator(this->auth_certs, TRUE);
+
+ while (iterator->iterate(iterator, (void**)&current_cert))
+ {
+ rsa_public_key_t *pubkey = current_cert->get_public_key(current_cert);
+
+ if (current_cert->has_authority_flag(current_cert, AUTH_CA)
+ && chunk_equals(keyid, pubkey->get_keyid(pubkey)))
+ {
+ found = current_cert;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+
+ return found;
+}
+
+/**
+ * Implementation of credential_store_t.get_issuer.
+ */
+static ca_info_t* get_issuer(private_local_credential_store_t *this, const x509_t *cert)
+{
+ ca_info_t *found = NULL;
+ ca_info_t *ca_info;
+
+ iterator_t *iterator = this->ca_infos->create_iterator(this->ca_infos, TRUE);
+
+ while (iterator->iterate(iterator, (void**)&ca_info))
+ {
+ if (ca_info->is_cert_issuer(ca_info, cert))
+ {
+ found = ca_info;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+
+ return found;
+}
+
+/**
+ * Find an exact copy of a certificate in a linked list
+ */
+static x509_t* find_certificate(linked_list_t *certs, x509_t *cert)
+{
+ x509_t *found_cert = NULL, *current_cert;
+
+ iterator_t *iterator = certs->create_iterator(certs, TRUE);
+
+ while (iterator->iterate(iterator, (void**)&current_cert))
+ {
+ if (cert->equals(cert, current_cert))
+ {
+ found_cert = current_cert;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+
+ return found_cert;
+}
+
+/**
+ * Adds crl and ocsp uris to the corresponding issuer info record
+ */
+static void add_uris(ca_info_t *issuer, x509_t *cert)
+{
+ iterator_t *iterator;
+ identification_t *uri;
+
+ /* add any crl distribution points to the issuer ca info record */
+ iterator = cert->create_crluri_iterator(cert);
+
+ while (iterator->iterate(iterator, (void**)&uri))
+ {
+ issuer->add_crluri(issuer, uri->get_encoding(uri));
+ }
+ iterator->destroy(iterator);
+
+ /* add any ocsp access points to the issuer ca info record */
+ iterator = cert->create_ocspuri_iterator(cert);
+
+ while (iterator->iterate(iterator, (void**)&uri))
+ {
+ issuer->add_ocspuri(issuer, uri->get_encoding(uri));
+ }
+ iterator->destroy(iterator);
+}
+
+/**
+ * Implementation of credential_store_t.is_trusted
+ */
+static bool is_trusted(private_local_credential_store_t *this, x509_t *cert)
+{
+ int pathlen;
+ time_t until = UNDEFINED_TIME;
+ x509_t *cert_to_be_trusted = cert;
+
+ DBG2(DBG_CFG, "establishing trust in certificate:");
+
+ for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++)
+ {
+ err_t ugh = NULL;
+ ca_info_t *issuer;
+ x509_t *issuer_cert;
+ rsa_public_key_t *issuer_public_key;
+ bool valid_signature;
+
+ DBG2(DBG_CFG, "subject: '%D'", cert->get_subject(cert));
+ DBG2(DBG_CFG, "issuer: '%D'", cert->get_issuer(cert));
+
+ ugh = cert->is_valid(cert, &until);
+ if (ugh != NULL)
+ {
+ DBG1(DBG_CFG, "certificate %s", ugh);
+ return FALSE;
+ }
+ DBG2(DBG_CFG, "certificate is valid");
+
+ issuer = get_issuer(this, cert);
+ if (issuer == NULL)
+ {
+ DBG1(DBG_CFG, "issuer not found");
+ return FALSE;
+ }
+ DBG2(DBG_CFG, "issuer found");
+
+ issuer_cert = issuer->get_certificate(issuer);
+ issuer_public_key = issuer_cert->get_public_key(issuer_cert);
+ valid_signature = cert->verify(cert, issuer_public_key);
+
+ if (!valid_signature)
+ {
+ DBG1(DBG_CFG, "certificate signature is invalid");
+ return FALSE;
+ }
+ DBG2(DBG_CFG, "certificate signature is valid");
+
+ /* check if cert is a self-signed root ca */
+ if (pathlen > 0 && cert->is_self_signed(cert))
+ {
+ DBG2(DBG_CFG, "reached self-signed root ca");
+ cert_to_be_trusted->set_until(cert_to_be_trusted, until);
+ cert_to_be_trusted->set_status(cert_to_be_trusted, CERT_GOOD);
+ return TRUE;
+ }
+ else
+ {
+ /* go up one step in the trust chain */
+ cert = issuer_cert;
+ }
+ }
+ DBG1(DBG_CFG, "maximum ca path length of %d levels exceeded", MAX_CA_PATH_LEN);
+ return FALSE;
+}
+
+/**
+ * Implementation of credential_store_t.verify.
+ */
+static bool verify(private_local_credential_store_t *this, x509_t *cert, bool *found)
+{
+ int pathlen;
+ time_t until = UNDEFINED_TIME;
+
+ x509_t *end_cert = cert;
+ x509_t *cert_copy = find_certificate(this->certs, end_cert);
+
+ DBG2(DBG_CFG, "verifying end entity certificate:");
+
+ *found = (cert_copy != NULL);
+ if (*found)
+ {
+ DBG2(DBG_CFG,
+ "end entitity certificate is already in credential store");
+ }
+
+ for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++)
+ {
+ err_t ugh = NULL;
+ ca_info_t *issuer;
+ x509_t *issuer_cert;
+ rsa_public_key_t *issuer_public_key;
+ bool valid_signature;
+
+ DBG1(DBG_CFG, "subject: '%D'", cert->get_subject(cert));
+ DBG1(DBG_CFG, "issuer: '%D'", cert->get_issuer(cert));
+
+ ugh = cert->is_valid(cert, &until);
+ if (ugh != NULL)
+ {
+ DBG1(DBG_CFG, "certificate %s", ugh);
+ return FALSE;
+ }
+ DBG2(DBG_CFG, "certificate is valid");
+
+ issuer = get_issuer(this, cert);
+ if (issuer == NULL)
+ {
+ DBG1(DBG_CFG, "issuer not found");
+ return FALSE;
+ }
+ DBG2(DBG_CFG, "issuer found");
+
+ issuer_cert = issuer->get_certificate(issuer);
+ issuer_public_key = issuer_cert->get_public_key(issuer_cert);
+ valid_signature = cert->verify(cert, issuer_public_key);
+
+ if (!valid_signature)
+ {
+ DBG1(DBG_CFG, "certificate signature is invalid");
+ return FALSE;
+ }
+ DBG2(DBG_CFG, "certificate signature is valid");
+
+ /* check if cert is a self-signed root ca */
+ if (pathlen > 0 && cert->is_self_signed(cert))
+ {
+ DBG1(DBG_CFG, "reached self-signed root ca");
+
+ /* set the definite status and trust interval of the end entity certificate */
+ end_cert->set_until(end_cert, until);
+ if (cert_copy)
+ {
+ cert_copy->set_status(cert_copy, end_cert->get_status(end_cert));
+ cert_copy->set_until(cert_copy, until);
+ }
+ return TRUE;
+ }
+ else
+ {
+ time_t nextUpdate;
+ cert_status_t status;
+ certinfo_t *certinfo = certinfo_create(cert->get_serialNumber(cert));
+
+ certinfo->set_nextUpdate(certinfo, until);
+
+ if (pathlen == 0)
+ {
+ /* add any crl and ocsp uris contained in the certificate under test */
+ add_uris(issuer, cert);
+ }
+
+ /* first check certificate revocation using ocsp */
+ status = issuer->verify_by_ocsp(issuer, certinfo, &this->public.credential_store);
+
+ /* if ocsp service is not available then fall back to crl */
+ if ((status == CERT_UNDEFINED) || (status == CERT_UNKNOWN && this->strict))
+ {
+ status = issuer->verify_by_crl(issuer, certinfo, CRL_DIR);
+ }
+
+ nextUpdate = certinfo->get_nextUpdate(certinfo);
+ cert->set_status(cert, status);
+
+ switch (status)
+ {
+ case CERT_GOOD:
+ /* set nextUpdate */
+ cert->set_until(cert, nextUpdate);
+
+ /* if status information is stale */
+ if (this->strict && nextUpdate < time(NULL))
+ {
+ DBG2(DBG_CFG, "certificate is good but status is stale");
+ certinfo->destroy(certinfo);
+ return FALSE;
+ }
+ DBG1(DBG_CFG, "certificate is good");
+
+ /* with strict crl policy the public key must have the same
+ * lifetime as the validity of the ocsp status or crl lifetime
+ */
+ if (this->strict && nextUpdate < until)
+ until = nextUpdate;
+ break;
+ case CERT_REVOKED:
+ {
+ time_t revocationTime = certinfo->get_revocationTime(certinfo);
+ DBG1(DBG_CFG,
+ "certificate was revoked on %T, reason: %N",
+ &revocationTime, crl_reason_names,
+ certinfo->get_revocationReason(certinfo));
+
+ /* set revocationTime */
+ cert->set_until(cert, revocationTime);
+
+ /* update status of end certificate in the credential store */
+ if (cert_copy)
+ {
+ if (pathlen > 0)
+ {
+ cert_copy->set_status(cert_copy, CERT_UNTRUSTED);
+ }
+ else
+ {
+ cert_copy->set_status(cert_copy, CERT_REVOKED);
+ cert_copy->set_until(cert_copy,
+ certinfo->get_revocationTime(certinfo));
+ }
+ }
+ certinfo->destroy(certinfo);
+ return FALSE;
+ }
+ case CERT_UNKNOWN:
+ case CERT_UNDEFINED:
+ default:
+ DBG1(DBG_CFG, "certificate status unknown");
+ if (this->strict)
+ {
+ /* update status of end certificate in the credential store */
+ if (cert_copy)
+ {
+ cert_copy->set_status(cert_copy, CERT_UNTRUSTED);
+ }
+ certinfo->destroy(certinfo);
+ return FALSE;
+ }
+ break;
+ }
+ certinfo->destroy(certinfo);
+ }
+ /* go up one step in the trust chain */
+ cert = issuer_cert;
+ }
+ DBG1(DBG_CFG, "maximum ca path length of %d levels exceeded", MAX_CA_PATH_LEN);
+ return FALSE;
+}
+
+/**
+ * Add a unique certificate to a linked list
+ */
+static x509_t* add_certificate(linked_list_t *certs, x509_t *cert)
+{
+ x509_t *found_cert = find_certificate(certs, cert);
+
+ if (found_cert)
+ {
+ /* add the authority flags */
+ found_cert->add_authority_flags(found_cert, cert->get_authority_flags(cert));
+
+ cert->destroy(cert);
+ return found_cert;
+ }
+ else
+ {
+ certs->insert_last(certs, (void*)cert);
+ return cert;
+ }
+}
+
+/**
+ * Add a unique ca info record to a linked list
+ */
+static void add_ca_info(private_local_credential_store_t *this, ca_info_t *ca_info)
+{
+ ca_info_t *current_ca_info;
+ ca_info_t *found_ca_info = NULL;
+
+ iterator_t *iterator = this->ca_infos->create_iterator(this->ca_infos, TRUE);
+
+ while (iterator->iterate(iterator, (void**)&current_ca_info))
+ {
+ if (current_ca_info->equals(current_ca_info, ca_info))
+ {
+ found_ca_info = current_ca_info;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+
+ if (found_ca_info)
+ {
+ current_ca_info->add_info(current_ca_info, ca_info);
+ ca_info->destroy(ca_info);
+ }
+ else
+ {
+ this->ca_infos->insert_last(this->ca_infos, (void*)ca_info);
+ }
+}
+
+/**
+ * Release ca info record of a given name
+ */
+static status_t release_ca_info(private_local_credential_store_t *this, const char *name)
+{
+ status_t status = NOT_FOUND;
+ ca_info_t *ca_info;
+
+ iterator_t *iterator = this->ca_infos->create_iterator(this->ca_infos, TRUE);
+
+ while (iterator->iterate(iterator, (void**)&ca_info))
+ {
+ if (ca_info->equals_name_release_info(ca_info, name))
+ {
+ status = SUCCESS;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+
+ return status;
+}
+
+/**
+ * Implements local_credential_store_t.add_end_certificate
+ */
+static x509_t* add_end_certificate(private_local_credential_store_t *this, x509_t *cert)
+{
+ x509_t *ret_cert = add_certificate(this->certs, cert);
+
+ /* add crl and ocsp uris the first time the certificate is added */
+ if (ret_cert == cert)
+ {
+ ca_info_t *issuer = get_issuer(this, cert);
+
+ if (issuer)
+ {
+ add_uris(issuer, cert);
+ }
+ }
+ return ret_cert;
+}
+
+/**
+ * Implements local_credential_store_t.add_auth_certificate
+ */
+static x509_t* add_auth_certificate(private_local_credential_store_t *this, x509_t *cert, u_int auth_flags)
+{
+ cert->add_authority_flags(cert, auth_flags);
+ return add_certificate(this->auth_certs, cert);
+}
+
+/**
+ * Implements local_credential_store_t.create_cert_iterator
+ */
+static iterator_t* create_cert_iterator(private_local_credential_store_t *this)
+{
+ return this->certs->create_iterator(this->certs, TRUE);
+}
+
+/**
+ * Implements local_credential_store_t.create_cacert_iterator
+ */
+static iterator_t* create_auth_cert_iterator(private_local_credential_store_t *this)
+{
+ return this->auth_certs->create_iterator(this->auth_certs, TRUE);
+}
+
+/**
+ * Implements local_credential_store_t.create_cainfo_iterator
+ */
+static iterator_t* create_cainfo_iterator(private_local_credential_store_t *this)
+{
+ return this->ca_infos->create_iterator(this->ca_infos, TRUE);
+}
+
+/**
+ * Implements local_credential_store_t.load_auth_certificates
+ */
+static void load_auth_certificates(private_local_credential_store_t *this,
+ u_int auth_flag,
+ const char* label,
+ const char* path)
+{
+ struct dirent* entry;
+ struct stat stb;
+ DIR* dir;
+
+ DBG1(DBG_CFG, "loading %s certificates from '%s/'", label, path);
+
+ dir = opendir(path);
+ if (dir == NULL)
+ {
+ DBG1(DBG_CFG, "error opening %s certs directory %s'", label, path);
+ return;
+ }
+
+ while ((entry = readdir(dir)) != NULL)
+ {
+ char file[PATH_BUF];
+
+ snprintf(file, sizeof(file), "%s/%s", path, entry->d_name);
+
+ if (stat(file, &stb) == -1)
+ {
+ continue;
+ }
+ /* try to parse all regular files */
+ if (stb.st_mode & S_IFREG)
+ {
+ x509_t *cert = x509_create_from_file(file, label);
+
+ if (cert)
+ {
+ err_t ugh = cert->is_valid(cert, NULL);
+
+ if (ugh != NULL)
+ {
+ DBG1(DBG_CFG, "warning: %s certificate %s", label, ugh);
+ }
+
+ if (auth_flag == AUTH_CA && !cert->is_ca(cert))
+ {
+ DBG1(DBG_CFG, " CA basic constraints flag not set, cert discarded");
+ cert->destroy(cert);
+ }
+ else
+ {
+ x509_t *ret_cert;
+
+ cert->add_authority_flags(cert, auth_flag);
+
+ ret_cert = add_certificate(this->auth_certs, cert);
+
+ if (auth_flag == AUTH_CA && ret_cert == cert)
+ {
+ ca_info_t *ca_info = ca_info_create(NULL, cert);
+
+ add_ca_info(this, ca_info);
+ }
+ }
+ }
+ }
+ }
+ closedir(dir);
+}
+
+/**
+ * Implements local_credential_store_t.load_ca_certificates
+ */
+static void load_ca_certificates(private_local_credential_store_t *this)
+{
+ load_auth_certificates(this, AUTH_CA, "ca", CA_CERTIFICATE_DIR);
+
+ /* add any crl and ocsp uris found in the ca certificates to the
+ * corresponding issuer info record. We can do this only after all
+ * ca certificates have been loaded and the ca hierarchy is known.
+ */
+ {
+ iterator_t *iterator = this->ca_infos->create_iterator(this->ca_infos, TRUE);
+ ca_info_t *ca_info;
+
+ while (iterator->iterate(iterator, (void **)&ca_info))
+ {
+ x509_t *cacert = ca_info->get_certificate(ca_info);
+ ca_info_t *issuer = get_issuer(this, cacert);
+
+ if (issuer)
+ {
+ add_uris(issuer, cacert);
+ }
+ }
+ iterator->destroy(iterator);
+ }
+}
+
+/**
+ * Implements local_credential_store_t.load_ocsp_certificates
+ */
+static void load_ocsp_certificates(private_local_credential_store_t *this)
+{
+ load_auth_certificates(this, AUTH_OCSP, "ocsp", OCSP_CERTIFICATE_DIR);
+}
+
+/**
+ * Add the latest crl to the issuing ca
+ */
+static void add_crl(private_local_credential_store_t *this, crl_t *crl, const char *path)
+{
+ iterator_t *iterator = this->ca_infos->create_iterator(this->ca_infos, TRUE);
+ ca_info_t *ca_info;
+ bool found = FALSE;
+
+ while (iterator->iterate(iterator, (void**)&ca_info))
+ {
+ if (ca_info->is_crl_issuer(ca_info, crl))
+ {
+ char buffer[BUF_LEN];
+ chunk_t uri = { buffer, 7 + strlen(path) };
+
+ ca_info->add_crl(ca_info, crl);
+ if (uri.len < BUF_LEN)
+ {
+ snprintf(buffer, BUF_LEN, "file://%s", path);
+ ca_info->add_crluri(ca_info, uri);
+ }
+ found = TRUE;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+
+ if (!found)
+ {
+ crl->destroy(crl);
+ DBG2(DBG_CFG, " no issuing ca found for this crl - discarded");
+ }
+}
+
+/**
+ * Implements local_credential_store_t.load_crls
+ */
+static void load_crls(private_local_credential_store_t *this)
+{
+ struct dirent* entry;
+ struct stat stb;
+ DIR* dir;
+ crl_t *crl;
+
+ DBG1(DBG_CFG, "loading crls from '%s/'", CRL_DIR);
+
+ dir = opendir(CRL_DIR);
+ if (dir == NULL)
+ {
+ DBG1(DBG_CFG, "error opening crl directory %s'", CRL_DIR);
+ return;
+ }
+
+ while ((entry = readdir(dir)) != NULL)
+ {
+ char file[PATH_BUF];
+
+ snprintf(file, sizeof(file), "%s/%s", CRL_DIR, entry->d_name);
+
+ if (stat(file, &stb) == -1)
+ {
+ continue;
+ }
+ /* try to parse all regular files */
+ if (stb.st_mode & S_IFREG)
+ {
+ crl = crl_create_from_file(file);
+ if (crl)
+ {
+ DBG1(DBG_CFG, " crl is %s", crl->is_valid(crl)? "valid":"stale");
+ add_crl(this, crl, file);
+ }
+ }
+ }
+ closedir(dir);
+}
+
+/**
+ * Convert a string of characters into a binary secret
+ * A string between single or double quotes is treated as ASCII characters
+ * A string prepended by 0x is treated as HEX and prepended by 0s as Base64
+ */
+static err_t extract_secret(chunk_t *secret, chunk_t *line)
+{
+ chunk_t raw_secret;
+ char delimiter = ' ';
+ bool quotes = FALSE;
+
+ if (!eat_whitespace(line))
+ {
+ return "missing secret";
+ }
+
+ if (*line->ptr == '\'' || *line->ptr == '"')
+ {
+ quotes = TRUE;
+ delimiter = *line->ptr;
+ line->ptr++; line->len--;
+ }
+
+ if (!extract_token(&raw_secret, delimiter, line))
+ {
+ if (delimiter == ' ')
+ {
+ raw_secret = *line;
+ }
+ else
+ {
+ return "missing second delimiter";
+ }
+ }
+
+ if (quotes)
+ { /* treat as an ASCII string */
+ if (raw_secret.len > secret->len)
+ return "secret larger than buffer";
+ memcpy(secret->ptr, raw_secret.ptr, raw_secret.len);
+ secret->len = raw_secret.len;
+ }
+ else
+ { /* convert from HEX or Base64 to binary */
+ size_t len;
+ err_t ugh = ttodata(raw_secret.ptr, raw_secret.len, 0, secret->ptr, secret->len, &len);
+
+ if (ugh != NULL)
+ return ugh;
+ if (len > secret->len)
+ return "secret larger than buffer";
+ secret->len = len;
+ }
+ return NULL;
+}
+
+/**
+ * Implements local_credential_store_t.load_secrets
+ */
+static void load_secrets(private_local_credential_store_t *this)
+{
+ FILE *fd = fopen(SECRETS_FILE, "r");
+
+ if (fd)
+ {
+ int bytes;
+ int line_nr = 0;
+ chunk_t chunk, src, line;
+
+ DBG1(DBG_CFG, "loading secrets from \"%s\"", SECRETS_FILE);
+
+ fseek(fd, 0, SEEK_END);
+ chunk.len = ftell(fd);
+ rewind(fd);
+ chunk.ptr = malloc(chunk.len);
+ bytes = fread(chunk.ptr, 1, chunk.len, fd);
+ fclose(fd);
+
+ src = chunk;
+
+ while (fetchline(&src, &line))
+ {
+ chunk_t ids, token;
+ bool is_eap = FALSE;
+
+ line_nr++;
+
+ if (!eat_whitespace(&line))
+ {
+ continue;
+ }
+ if (!extract_token(&ids, ':', &line))
+ {
+ DBG1(DBG_CFG, "line %d: missing ':' separator", line_nr);
+ goto error;
+ }
+ /* NULL terminate the ids string by replacing the : separator */
+ *(ids.ptr + ids.len) = '\0';
+
+ if (!eat_whitespace(&line) || !extract_token(&token, ' ', &line))
+ {
+ DBG1(DBG_CFG, "line %d: missing token", line_nr);
+ goto error;
+ }
+ if (match("RSA", &token))
+ {
+ char path[PATH_BUF];
+ chunk_t filename;
+
+ char buf[BUF_LEN];
+ chunk_t secret = { buf, BUF_LEN };
+ chunk_t *passphrase = NULL;
+
+ rsa_private_key_t *key;
+
+ err_t ugh = extract_value(&filename, &line);
+
+ if (ugh != NULL)
+ {
+ DBG1(DBG_CFG, "line %d: %s", line_nr, ugh);
+ goto error;
+ }
+ if (filename.len == 0)
+ {
+ DBG1(DBG_CFG, "line %d: empty filename", line_nr);
+ goto error;
+ }
+ if (*filename.ptr == '/')
+ {
+ /* absolute path name */
+ snprintf(path, sizeof(path), "%.*s", filename.len, filename.ptr);
+ }
+ else
+ {
+ /* relative path name */
+ snprintf(path, sizeof(path), "%s/%.*s", PRIVATE_KEY_DIR,
+ filename.len, filename.ptr);
+ }
+
+ /* check for optional passphrase */
+ if (eat_whitespace(&line))
+ {
+ ugh = extract_secret(&secret, &line);
+ if (ugh != NULL)
+ {
+ DBG1(DBG_CFG, "line %d: malformed passphrase: %s", line_nr, ugh);
+ goto error;
+ }
+ if (secret.len > 0)
+ passphrase = &secret;
+ }
+ key = rsa_private_key_create_from_file(path, passphrase);
+ if (key)
+ {
+ this->private_keys->insert_last(this->private_keys, (void*)key);
+ }
+ }
+ else if ( match("PSK", &token) ||
+ ((match("EAP", &token) || match("XAUTH", &token)) && (is_eap = TRUE)))
+ {
+ shared_key_t *shared_key;
+
+ char buf[BUF_LEN];
+ chunk_t secret = { buf, BUF_LEN };
+
+ err_t ugh = extract_secret(&secret, &line);
+ if (ugh != NULL)
+ {
+ DBG1(DBG_CFG, "line %d: malformed secret: %s", line_nr, ugh);
+ goto error;
+ }
+
+ DBG1(DBG_CFG, " loading %s key for %s",
+ is_eap ? "EAP" : "shared",
+ ids.len > 0 ? (char*)ids.ptr : "%any");
+
+ DBG4(DBG_CFG, " secret:", secret);
+
+ shared_key = shared_key_create(secret);
+ if (shared_key)
+ {
+ if (is_eap)
+ {
+ this->eap_keys->insert_last(this->eap_keys, (void*)shared_key);
+ }
+ else
+ {
+ this->shared_keys->insert_last(this->shared_keys, (void*)shared_key);
+ }
+ }
+ while (ids.len > 0)
+ {
+ chunk_t id;
+ identification_t *peer_id;
+
+ ugh = extract_value(&id, &ids);
+ if (ugh != NULL)
+ {
+ DBG1(DBG_CFG, "line %d: %s", line_nr, ugh);
+ goto error;
+ }
+ if (id.len == 0)
+ {
+ continue;
+ }
+
+ /* NULL terminate the ID string */
+ *(id.ptr + id.len) = '\0';
+
+ peer_id = identification_create_from_string(id.ptr);
+ if (peer_id == NULL)
+ {
+ DBG1(DBG_CFG, "line %d: malformed ID: %s", line_nr, id.ptr);
+ goto error;
+ }
+
+ if (peer_id->get_type(peer_id) == ID_ANY)
+ {
+ peer_id->destroy(peer_id);
+ continue;
+ }
+ shared_key->peers->insert_last(shared_key->peers, (void*)peer_id);
+ }
+ }
+ else if (match("PIN", &token))
+ {
+
+ }
+ else
+ {
+ DBG1(DBG_CFG, "line %d: token must be either "
+ "RSA, PSK, EAP, or PIN", line_nr, token.len);
+ goto error;
+ }
+ }
+error:
+ free(chunk.ptr);
+ }
+ else
+ {
+ DBG1(DBG_CFG, "could not open file '%s'", SECRETS_FILE);
+ }
+}
+
+/**
+ * Implementation of local_credential_store_t.destroy.
+ */
+static void destroy(private_local_credential_store_t *this)
+{
+ this->certs->destroy_offset(this->certs, offsetof(x509_t, destroy));
+ this->auth_certs->destroy_offset(this->auth_certs, offsetof(x509_t, destroy));
+ this->ca_infos->destroy_offset(this->ca_infos, offsetof(ca_info_t, destroy));
+ this->private_keys->destroy_offset(this->private_keys, offsetof(rsa_private_key_t, destroy));
+ this->shared_keys->destroy_function(this->shared_keys, (void*)shared_key_destroy);
+ this->eap_keys->destroy_function(this->eap_keys, (void*)shared_key_destroy);
+ free(this);
+}
+
+/**
+ * Described in header.
+ */
+local_credential_store_t * local_credential_store_create(bool strict)
+{
+ private_local_credential_store_t *this = malloc_thing(private_local_credential_store_t);
+
+ this->public.credential_store.get_shared_key = (status_t (*) (credential_store_t*,identification_t*,identification_t*,chunk_t*))get_shared_key;
+ this->public.credential_store.get_eap_key = (status_t (*) (credential_store_t*,identification_t*,identification_t*,chunk_t*))get_eap_key;
+ this->public.credential_store.get_rsa_public_key = (rsa_public_key_t*(*)(credential_store_t*,identification_t*))get_rsa_public_key;
+ this->public.credential_store.get_rsa_private_key = (rsa_private_key_t* (*) (credential_store_t*,rsa_public_key_t*))get_rsa_private_key;
+ this->public.credential_store.has_rsa_private_key = (bool (*) (credential_store_t*,rsa_public_key_t*))has_rsa_private_key;
+ this->public.credential_store.get_trusted_public_key = (rsa_public_key_t*(*)(credential_store_t*,identification_t*))get_trusted_public_key;
+ this->public.credential_store.get_certificate = (x509_t* (*) (credential_store_t*,identification_t*))get_certificate;
+ this->public.credential_store.get_auth_certificate = (x509_t* (*) (credential_store_t*,u_int,identification_t*))get_auth_certificate;
+ this->public.credential_store.get_ca_certificate_by_keyid = (x509_t* (*) (credential_store_t*,chunk_t))get_ca_certificate_by_keyid;
+ this->public.credential_store.get_issuer = (ca_info_t* (*) (credential_store_t*,const x509_t*))get_issuer;
+ this->public.credential_store.is_trusted = (bool (*) (credential_store_t*,x509_t*))is_trusted;
+ this->public.credential_store.verify = (bool (*) (credential_store_t*,x509_t*,bool*))verify;
+ this->public.credential_store.add_end_certificate = (x509_t* (*) (credential_store_t*,x509_t*))add_end_certificate;
+ this->public.credential_store.add_auth_certificate = (x509_t* (*) (credential_store_t*,x509_t*,u_int))add_auth_certificate;
+ this->public.credential_store.add_ca_info = (void (*) (credential_store_t*,ca_info_t*))add_ca_info;
+ this->public.credential_store.release_ca_info = (status_t (*) (credential_store_t*,const char*))release_ca_info;
+ this->public.credential_store.create_cert_iterator = (iterator_t* (*) (credential_store_t*))create_cert_iterator;
+ this->public.credential_store.create_auth_cert_iterator = (iterator_t* (*) (credential_store_t*))create_auth_cert_iterator;
+ this->public.credential_store.create_cainfo_iterator = (iterator_t* (*) (credential_store_t*))create_cainfo_iterator;
+ this->public.credential_store.load_ca_certificates = (void (*) (credential_store_t*))load_ca_certificates;
+ this->public.credential_store.load_ocsp_certificates = (void (*) (credential_store_t*))load_ocsp_certificates;
+ this->public.credential_store.load_crls = (void (*) (credential_store_t*))load_crls;
+ this->public.credential_store.load_secrets = (void (*) (credential_store_t*))load_secrets;
+ this->public.credential_store.destroy = (void (*) (credential_store_t*))destroy;
+
+ /* private variables */
+ this->shared_keys = linked_list_create();
+ this->eap_keys = linked_list_create();
+ this->private_keys = linked_list_create();
+ this->certs = linked_list_create();
+ this->auth_certs = linked_list_create();
+ this->ca_infos = linked_list_create();
+ this->strict = strict;
+
+ return (&this->public);
+}
diff --git a/src/charon/config/credentials/local_credential_store.h b/src/charon/config/credentials/local_credential_store.h
new file mode 100644
index 000000000..88a94d6f9
--- /dev/null
+++ b/src/charon/config/credentials/local_credential_store.h
@@ -0,0 +1,64 @@
+/**
+ * @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_
+
+typedef struct local_credential_store_t local_credential_store_t;
+
+#include <library.h>
+#include <credential_store.h>
+#include <daemon.h>
+
+
+/**
+ * @brief A credential_store_t implementation using simple credentail lists.
+ *
+ * The local_credential_store_t class implements the credential_store_t interface
+ * as simple as possible. The credentials are stored in lists, and are loaded from
+ * files on the disk.
+ * Shared secret are not handled yet, so get_shared_secret always returns NOT_FOUND.
+ *
+ * @b Constructors:
+ * - local_credential_store_create(bool strict)
+ *
+ * @ingroup config
+ */
+struct local_credential_store_t {
+
+ /**
+ * Implements credential_store_t interface
+ */
+ credential_store_t credential_store;
+};
+
+/**
+ * @brief Creates a local_credential_store_t instance.
+ *
+ * @param strict enforce a strict crl policy
+ * @return credential store instance.
+ *
+ * @ingroup config
+ */
+local_credential_store_t *local_credential_store_create(bool strict);
+
+#endif /* LOCAL_CREDENTIAL_H_ */
diff --git a/src/charon/config/policies/local_policy_store.c b/src/charon/config/policies/local_policy_store.c
new file mode 100644
index 000000000..dd22b43a0
--- /dev/null
+++ b/src/charon/config/policies/local_policy_store.c
@@ -0,0 +1,282 @@
+/**
+ * @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 <string.h>
+
+#include "local_policy_store.h"
+
+#include <daemon.h>
+#include <utils/linked_list.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;
+
+ /**
+ * Mutex to exclusivly access list
+ */
+ pthread_mutex_t mutex;
+};
+
+/**
+ * Implementation of policy_store_t.add_policy.
+ */
+static void add_policy(private_local_policy_store_t *this, policy_t *policy)
+{
+ pthread_mutex_lock(&(this->mutex));
+ this->policies->insert_last(this->policies, (void*)policy);
+ pthread_mutex_unlock(&(this->mutex));
+}
+
+/**
+ * Check if a policy contains traffic selectors
+ */
+static bool contains_traffic_selectors(policy_t *policy, bool mine,
+ linked_list_t *ts, host_t *host)
+{
+ linked_list_t *selected;
+ bool contains = FALSE;
+
+ if (mine)
+ {
+ selected = policy->select_my_traffic_selectors(policy, ts, host);
+ }
+ else
+ {
+ selected = policy->select_other_traffic_selectors(policy, ts, host);
+ }
+ if (selected->get_count(selected))
+ {
+ contains = TRUE;
+ }
+ selected->destroy_offset(selected, offsetof(traffic_selector_t, destroy));
+ return contains;
+}
+
+/**
+ * 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,
+ linked_list_t *my_ts, linked_list_t *other_ts,
+ host_t *my_host, host_t *other_host)
+{
+ typedef enum {
+ PRIO_UNDEFINED = 0x00,
+ PRIO_TS_MISMATCH = 0x01,
+ PRIO_ID_ANY = 0x02,
+ PRIO_ID_MATCH = PRIO_ID_ANY + MAX_WILDCARDS,
+ } prio_t;
+
+ prio_t best_prio = PRIO_UNDEFINED;
+
+ iterator_t *iterator;
+ policy_t *candidate;
+ policy_t *found = NULL;
+ traffic_selector_t *ts;
+
+ DBG1(DBG_CFG, "searching policy for '%D'...'%D'", my_id, other_id);
+ iterator = my_ts->create_iterator(my_ts, TRUE);
+ while (iterator->iterate(iterator, (void**)&ts))
+ {
+ DBG1(DBG_CFG, " local TS: %R", ts);
+ }
+ iterator->destroy(iterator);
+ iterator = other_ts->create_iterator(other_ts, TRUE);
+ while (iterator->iterate(iterator, (void**)&ts))
+ {
+ DBG1(DBG_CFG, " remote TS: %R", ts);
+ }
+ iterator->destroy(iterator);
+
+ pthread_mutex_lock(&(this->mutex));
+ iterator = this->policies->create_iterator(this->policies, TRUE);
+
+ /* determine closest matching policy */
+ while (iterator->iterate(iterator, (void**)&candidate))
+ {
+ identification_t *candidate_my_id;
+ identification_t *candidate_other_id;
+ int wildcards;
+
+ candidate_my_id = candidate->get_my_id(candidate);
+ candidate_other_id = candidate->get_other_id(candidate);
+
+ /* my_id is either %any or if set must match exactly */
+ if (candidate_my_id->matches(candidate_my_id, my_id, &wildcards))
+ {
+ prio_t prio = PRIO_UNDEFINED;
+
+ /* wildcard match for other_id */
+ if (!other_id->matches(other_id, candidate_other_id, &wildcards))
+ {
+ continue;
+ }
+ prio = PRIO_ID_MATCH - wildcards;
+
+ /* only accept if traffic selectors match */
+ if (!contains_traffic_selectors(candidate, TRUE, my_ts, my_host) ||
+ !contains_traffic_selectors(candidate, FALSE, other_ts, other_host))
+ {
+ DBG2(DBG_CFG, "candidate '%s' inacceptable due traffic "
+ "selector mismatch", candidate->get_name(candidate));
+ prio = PRIO_TS_MISMATCH;
+ }
+
+ DBG2(DBG_CFG, "candidate policy '%s': '%D'...'%D' (prio=%d)",
+ candidate->get_name(candidate),
+ candidate_my_id, candidate_other_id, prio);
+
+ if (prio > best_prio)
+ {
+ found = candidate;
+ best_prio = prio;
+ }
+ }
+ }
+ iterator->destroy(iterator);
+
+ if (found)
+ {
+ DBG1(DBG_CFG, "found matching policy '%s': '%D'...'%D' (prio=%d)",
+ found->get_name(found), found->get_my_id(found),
+ found->get_other_id(found), best_prio);
+ /* give out a new reference to it */
+ found->get_ref(found);
+ }
+ pthread_mutex_unlock(&(this->mutex));
+ return found;
+}
+
+/**
+ * Implementation of policy_store_t.get_policy_by_name.
+ */
+static policy_t *get_policy_by_name(private_local_policy_store_t *this, char *name)
+{
+ iterator_t *iterator;
+ policy_t *current, *found = NULL;
+
+ DBG2(DBG_CFG, "looking for policy '%s'", name);
+
+ pthread_mutex_lock(&(this->mutex));
+ iterator = this->policies->create_iterator(this->policies, TRUE);
+ while (iterator->iterate(iterator, (void **)&current))
+ {
+ if (strcmp(current->get_name(current), name) == 0)
+ {
+ found = current;
+ }
+ }
+ iterator->destroy(iterator);
+ pthread_mutex_unlock(&(this->mutex));
+
+ /* give out a new reference */
+ found->get_ref(found);
+ return found;
+}
+
+/**
+ * Implementation of policy_store_t.delete_policy.
+ */
+static status_t delete_policy(private_local_policy_store_t *this, char *name)
+{
+ iterator_t *iterator;
+ policy_t *current;
+ bool found = FALSE;
+
+ pthread_mutex_lock(&(this->mutex));
+ iterator = this->policies->create_iterator(this->policies, TRUE);
+ while (iterator->iterate(iterator, (void **)&current))
+ {
+ if (strcmp(current->get_name(current), name) == 0)
+ {
+ /* remove policy from list, and destroy it */
+ iterator->remove(iterator);
+ current->destroy(current);
+ found = TRUE;
+ /* we do not break here, as there may be multipe policies */
+ }
+ }
+ iterator->destroy(iterator);
+ pthread_mutex_unlock(&(this->mutex));
+ if (found)
+ {
+ return SUCCESS;
+ }
+ return NOT_FOUND;
+}
+
+/**
+ * Implementation of policy_store_t.create_iterator.
+ */
+static iterator_t* create_iterator(private_local_policy_store_t *this)
+{
+ return this->policies->create_iterator_locked(this->policies,
+ &this->mutex);
+}
+
+/**
+ * Implementation of policy_store_t.destroy.
+ */
+static void destroy(private_local_policy_store_t *this)
+{
+ pthread_mutex_lock(&(this->mutex));
+ this->policies->destroy_offset(this->policies, offsetof(policy_t, destroy));
+ pthread_mutex_unlock(&(this->mutex));
+ free(this);
+}
+
+/**
+ * Described in header.
+ */
+local_policy_store_t *local_policy_store_create(void)
+{
+ 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*,
+ linked_list_t*,linked_list_t*,host_t*,host_t*))get_policy;
+ this->public.policy_store.get_policy_by_name = (policy_t* (*) (policy_store_t*,char*))get_policy_by_name;
+ this->public.policy_store.delete_policy = (status_t (*) (policy_store_t*,char*))delete_policy;
+ this->public.policy_store.create_iterator = (iterator_t* (*) (policy_store_t*))create_iterator;
+ this->public.policy_store.destroy = (void (*) (policy_store_t*))destroy;
+
+ /* private variables */
+ this->policies = linked_list_create();
+ pthread_mutex_init(&(this->mutex), NULL);
+
+ return (&this->public);
+}
diff --git a/src/charon/config/policies/local_policy_store.h b/src/charon/config/policies/local_policy_store.h
new file mode 100644
index 000000000..01d5d2d60
--- /dev/null
+++ b/src/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_
+
+typedef struct local_policy_store_t local_policy_store_t;
+
+#include <library.h>
+#include <config/policies/policy_store.h>
+
+
+/**
+ * @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(void);
+
+#endif /* LOCAL_POLICY_STORE_H_ */
diff --git a/src/charon/config/policies/policy.c b/src/charon/config/policies/policy.c
new file mode 100644
index 000000000..363d1609f
--- /dev/null
+++ b/src/charon/config/policies/policy.c
@@ -0,0 +1,635 @@
+/**
+ * @file policy.c
+ *
+ * @brief Implementation of policy_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <time.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "policy.h"
+
+#include <daemon.h>
+#include <utils/linked_list.h>
+#include <utils/identification.h>
+
+ENUM(dpd_action_names, DPD_NONE, DPD_RESTART,
+ "DPD_NONE",
+ "DPD_CLEAR",
+ "DPD_ROUTE",
+ "DPD_RESTART"
+);
+
+ENUM(mode_names, MODE_TRANSPORT, MODE_BEET,
+ "TRANSPORT",
+ "TUNNEL",
+ "2",
+ "3",
+ "BEET"
+);
+
+typedef struct private_policy_t private_policy_t;
+
+/**
+ * Private data of an policy_t object
+ */
+struct private_policy_t {
+
+ /**
+ * Public part
+ */
+ policy_t public;
+
+ /**
+ * Number of references hold by others to this policy
+ */
+ refcount_t refcount;
+
+ /**
+ * Name of the policy, used to query it
+ */
+ char *name;
+
+ /**
+ * id to use to identify us
+ */
+ identification_t *my_id;
+
+ /**
+ * allowed id for other
+ */
+ identification_t *other_id;
+
+ /**
+ * virtual IP to use locally
+ */
+ host_t *my_virtual_ip;
+
+ /**
+ * virtual IP to use remotly
+ */
+ host_t *other_virtual_ip;
+
+ /**
+ * Method to use for own authentication data
+ */
+ auth_method_t auth_method;
+
+ /**
+ * EAP type to use for peer authentication
+ */
+ eap_type_t eap_type;
+
+ /**
+ * we have a cert issued by this CA
+ */
+ identification_t *my_ca;
+
+ /**
+ * we require the other end to have a cert issued by this CA
+ */
+ identification_t *other_ca;
+
+ /**
+ * updown script
+ */
+ char *updown;
+
+ /**
+ * allow host access
+ */
+ bool hostaccess;
+
+ /**
+ * 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;
+
+ /**
+ * Time before an SA gets invalid
+ */
+ u_int32_t soft_lifetime;
+
+ /**
+ * Time before an SA gets rekeyed
+ */
+ u_int32_t hard_lifetime;
+
+ /**
+ * Time, which specifies the range of a random value
+ * substracted from soft_lifetime.
+ */
+ u_int32_t jitter;
+
+ /**
+ * What to do with an SA when other peer seams to be dead?
+ */
+ bool dpd_action;
+
+ /**
+ * Mode to propose for a initiated CHILD: tunnel/transport
+ */
+ mode_t mode;
+};
+
+/**
+ * Implementation of policy_t.get_name
+ */
+static char *get_name(private_policy_t *this)
+{
+ return this->name;
+}
+
+/**
+ * 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.get_my_ca
+ */
+static identification_t *get_my_ca(private_policy_t *this)
+{
+ return this->my_ca;
+}
+
+/**
+ * Implementation of policy_t.get_other_ca
+ */
+static identification_t *get_other_ca(private_policy_t *this)
+{
+ return this->other_ca;
+}
+
+/**
+ * Implementation of connection_t.auth_method_t.
+ */
+static auth_method_t get_auth_method(private_policy_t *this)
+{
+ return this->auth_method;
+}
+
+/**
+ * Implementation of connection_t.get_eap_type.
+ */
+static eap_type_t get_eap_type(private_policy_t *this)
+{
+ return this->eap_type;
+}
+
+/**
+ * Get traffic selectors, with wildcard-address update
+ */
+static linked_list_t *get_traffic_selectors(private_policy_t *this,
+ linked_list_t *list, host_t *host)
+{
+ iterator_t *iterator;
+ traffic_selector_t *current;
+ linked_list_t *result = linked_list_create();
+
+ iterator = list->create_iterator(list, TRUE);
+
+ while (iterator->iterate(iterator, (void**)&current))
+ {
+ /* we make a copy of the TS, this allows us to update wildcard
+ * addresses in it. We won't pollute the shared policy. */
+ current = current->clone(current);
+ if (host)
+ {
+ current->set_address(current, host);
+ }
+
+ result->insert_last(result, (void*)current);
+ }
+ iterator->destroy(iterator);
+ return result;
+}
+
+/**
+ * Implementation of policy_t.get_my_traffic_selectors
+ */
+static linked_list_t *get_my_traffic_selectors(private_policy_t *this, host_t *me)
+{
+ return get_traffic_selectors(this, this->my_ts, me);
+}
+
+/**
+ * Implementation of policy_t.get_other_traffic_selectors
+ */
+static linked_list_t *get_other_traffic_selectors(private_policy_t *this, host_t *other)
+{
+ return get_traffic_selectors(this, this->other_ts, other);
+}
+
+/**
+ * Narrow traffic selectors, with wildcard-address update in "stored".
+ */
+static linked_list_t *select_traffic_selectors(private_policy_t *this,
+ linked_list_t *stored,
+ linked_list_t *supplied,
+ host_t *host)
+{
+ iterator_t *supplied_iter, *stored_iter, *i1, *i2;
+ traffic_selector_t *supplied_ts, *stored_ts, *selected_ts, *ts1, *ts2;
+ linked_list_t *selected = linked_list_create();
+
+ DBG2(DBG_CFG, "selecting traffic selectors");
+
+ stored_iter = stored->create_iterator(stored, TRUE);
+ supplied_iter = supplied->create_iterator(supplied, TRUE);
+
+ /* iterate over all stored selectors */
+ while (stored_iter->iterate(stored_iter, (void**)&stored_ts))
+ {
+ /* we make a copy of the TS, this allows us to update wildcard
+ * addresses in it. We won't pollute the shared policy. */
+ stored_ts = stored_ts->clone(stored_ts);
+ if (host)
+ {
+ stored_ts->set_address(stored_ts, host);
+ }
+
+ supplied_iter->reset(supplied_iter);
+ /* iterate over all supplied traffic selectors */
+ while (supplied_iter->iterate(supplied_iter, (void**)&supplied_ts))
+ {
+ DBG2(DBG_CFG, "stored %R <=> %R received",
+ stored_ts, 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);
+
+ DBG2(DBG_CFG, "found traffic selector for %s: %R",
+ stored == this->my_ts ? "us" : "other", selected_ts);
+ }
+ }
+ stored_ts->destroy(stored_ts);
+ }
+ stored_iter->destroy(stored_iter);
+ supplied_iter->destroy(supplied_iter);
+
+ /* remove any redundant traffic selectors in the list */
+ i1 = selected->create_iterator(selected, TRUE);
+ i2 = selected->create_iterator(selected, TRUE);
+ while (i1->iterate(i1, (void**)&ts1))
+ {
+ while (i2->iterate(i2, (void**)&ts2))
+ {
+ if (ts1 != ts2)
+ {
+ if (ts2->is_contained_in(ts2, ts1))
+ {
+ i2->remove(i2);
+ ts2->destroy(ts2);
+ i1->reset(i1);
+ break;
+ }
+ if (ts1->is_contained_in(ts1, ts2))
+ {
+ i1->remove(i1);
+ ts1->destroy(ts1);
+ i2->reset(i2);
+ break;
+ }
+ }
+ }
+ }
+ i1->destroy(i1);
+ i2->destroy(i2);
+
+ return selected;
+}
+
+/**
+ * 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,
+ host_t *me)
+{
+ return select_traffic_selectors(this, this->my_ts, supplied, me);
+}
+
+/**
+ * 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,
+ host_t* other)
+{
+ return select_traffic_selectors(this, this->other_ts, supplied, other);
+}
+
+/**
+ * Implementation of policy_t.get_proposal_iterator
+ */
+static linked_list_t *get_proposals(private_policy_t *this)
+{
+ iterator_t *iterator;
+ proposal_t *current;
+ linked_list_t *proposals = linked_list_create();
+
+ iterator = this->proposals->create_iterator(this->proposals, TRUE);
+ while (iterator->iterate(iterator, (void**)&current))
+ {
+ current = current->clone(current);
+ proposals->insert_last(proposals, (void*)current);
+ }
+ iterator->destroy(iterator);
+
+ return 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->iterate(stored_iter, (void**)&stored))
+ {
+ supplied_iter->reset(supplied_iter);
+ while (supplied_iter->iterate(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_authorities
+ */
+static void add_authorities(private_policy_t *this, identification_t *my_ca, identification_t *other_ca)
+{
+ this->my_ca = my_ca;
+ this->other_ca = other_ca;
+}
+
+/**
+ * Implementation of policy_t.get_updown
+ */
+static char* get_updown(private_policy_t *this)
+{
+ return this->updown;
+}
+
+/**
+ * Implementation of policy_t.get_hostaccess
+ */
+static bool get_hostaccess(private_policy_t *this)
+{
+ return this->hostaccess;
+}
+
+/**
+ * Implements policy_t.get_dpd_action
+ */
+static dpd_action_t get_dpd_action(private_policy_t *this)
+{
+ return this->dpd_action;
+}
+
+/**
+ * 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);
+}
+
+/**
+ * Implementation of policy_t.get_soft_lifetime
+ */
+static u_int32_t get_soft_lifetime(private_policy_t *this)
+{
+ if (this->jitter == 0)
+ {
+ return this->soft_lifetime ;
+ }
+ return this->soft_lifetime - (random() % this->jitter);
+}
+
+/**
+ * Implementation of policy_t.get_hard_lifetime
+ */
+static u_int32_t get_hard_lifetime(private_policy_t *this)
+{
+ return this->hard_lifetime;
+}
+
+/**
+ * Implementation of policy_t.get_mode.
+ */
+static mode_t get_mode(private_policy_t *this)
+{
+ return this->mode;
+}
+
+/**
+ * Implementation of policy_t.get_virtual_ip.
+ */
+static host_t* get_virtual_ip(private_policy_t *this, host_t *suggestion)
+{
+ if (suggestion == NULL)
+ {
+ if (this->my_virtual_ip)
+ {
+ return this->my_virtual_ip->clone(this->my_virtual_ip);
+ }
+ return NULL;
+ }
+ if (this->other_virtual_ip)
+ {
+ return this->other_virtual_ip->clone(this->other_virtual_ip);
+ }
+ if (suggestion->is_anyaddr(suggestion))
+ {
+ return NULL;
+ }
+ return suggestion->clone(suggestion);
+}
+
+/**
+ * Implements policy_t.get_ref.
+ */
+static void get_ref(private_policy_t *this)
+{
+ ref_get(&this->refcount);
+}
+
+/**
+ * Implements policy_t.destroy.
+ */
+static void destroy(private_policy_t *this)
+{
+ if (ref_put(&this->refcount))
+ {
+
+ this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
+ this->my_ts->destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy));
+ this->other_ts->destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy));
+
+ /* delete certification authorities */
+ DESTROY_IF(this->my_ca);
+ DESTROY_IF(this->other_ca);
+
+ /* delete updown script */
+ if (this->updown)
+ {
+ free(this->updown);
+ }
+
+ /* delete ids */
+ this->my_id->destroy(this->my_id);
+ this->other_id->destroy(this->other_id);
+ DESTROY_IF(this->my_virtual_ip);
+ DESTROY_IF(this->other_virtual_ip);
+
+ free(this->name);
+ free(this);
+ }
+}
+
+/*
+ * Described in header-file
+ */
+policy_t *policy_create(char *name, identification_t *my_id, identification_t *other_id,
+ host_t *my_virtual_ip, host_t *other_virtual_ip,
+ auth_method_t auth_method, eap_type_t eap_type,
+ u_int32_t hard_lifetime, u_int32_t soft_lifetime,
+ u_int32_t jitter, char *updown, bool hostaccess,
+ mode_t mode, dpd_action_t dpd_action)
+{
+ private_policy_t *this = malloc_thing(private_policy_t);
+
+ /* public functions */
+ this->public.get_name = (char* (*) (policy_t*))get_name;
+ 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.get_my_ca = (identification_t* (*) (policy_t*))get_my_ca;
+ this->public.get_other_ca = (identification_t* (*) (policy_t*))get_other_ca;
+ this->public.get_auth_method = (auth_method_t (*) (policy_t*)) get_auth_method;
+ this->public.get_eap_type = (eap_type_t (*) (policy_t*)) get_eap_type;
+ this->public.get_my_traffic_selectors = (linked_list_t* (*) (policy_t*,host_t*))get_my_traffic_selectors;
+ this->public.get_other_traffic_selectors = (linked_list_t* (*) (policy_t*,host_t*))get_other_traffic_selectors;
+ this->public.select_my_traffic_selectors = (linked_list_t* (*) (policy_t*,linked_list_t*,host_t*))select_my_traffic_selectors;
+ this->public.select_other_traffic_selectors = (linked_list_t* (*) (policy_t*,linked_list_t*,host_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.add_authorities = (void (*) (policy_t*,identification_t*,identification_t*))add_authorities;
+ this->public.get_updown = (char* (*) (policy_t*))get_updown;
+ this->public.get_hostaccess = (bool (*) (policy_t*))get_hostaccess;
+ this->public.get_dpd_action = (dpd_action_t (*) (policy_t*))get_dpd_action;
+ this->public.get_soft_lifetime = (u_int32_t (*) (policy_t *))get_soft_lifetime;
+ this->public.get_hard_lifetime = (u_int32_t (*) (policy_t *))get_hard_lifetime;
+ this->public.get_mode = (mode_t (*) (policy_t *))get_mode;
+ this->public.get_virtual_ip = (host_t* (*)(policy_t*,host_t*))get_virtual_ip;
+ this->public.get_ref = (void (*) (policy_t*))get_ref;
+ this->public.destroy = (void (*) (policy_t*))destroy;
+
+ /* apply init values */
+ this->name = strdup(name);
+ this->my_id = my_id;
+ this->other_id = other_id;
+ this->my_virtual_ip = my_virtual_ip;
+ this->other_virtual_ip = other_virtual_ip;
+ this->auth_method = auth_method;
+ this->eap_type = eap_type;
+ this->hard_lifetime = hard_lifetime;
+ this->soft_lifetime = soft_lifetime;
+ this->jitter = jitter;
+ this->updown = (updown == NULL) ? NULL : strdup(updown);
+ this->hostaccess = hostaccess;
+ this->dpd_action = dpd_action;
+ this->mode = mode;
+
+ /* initialize private members*/
+ this->refcount = 1;
+ this->my_ca = NULL;
+ this->other_ca = NULL;
+ this->proposals = linked_list_create();
+ this->my_ts = linked_list_create();
+ this->other_ts = linked_list_create();
+
+ return &this->public;
+}
diff --git a/src/charon/config/policies/policy.h b/src/charon/config/policies/policy.h
new file mode 100644
index 000000000..d8916b29e
--- /dev/null
+++ b/src/charon/config/policies/policy.h
@@ -0,0 +1,413 @@
+/**
+ * @file policy.h
+ *
+ * @brief Interface of policy_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef enum dpd_action_t dpd_action_t;
+typedef struct policy_t policy_t;
+
+#include <library.h>
+#include <utils/identification.h>
+#include <config/traffic_selector.h>
+#include <config/proposal.h>
+#include <sa/authenticators/authenticator.h>
+#include <sa/authenticators/eap/eap_method.h>
+
+
+/**
+ * @brief Actions to take when a peer does not respond (dead peer detected).
+ *
+ * These values are the same as in pluto/starter, so do not modify them!
+ *
+ * @ingroup config
+ */
+enum dpd_action_t {
+ /** DPD disabled */
+ DPD_NONE,
+ /** remove CHILD_SA without replacement */
+ DPD_CLEAR,
+ /** route the CHILD_SA to resetup when needed */
+ DPD_ROUTE,
+ /** restart CHILD_SA in a new IKE_SA, immediately */
+ DPD_RESTART,
+};
+
+/**
+ * enum names for dpd_action_t.
+ */
+extern enum_name_t *dpd_action_names;
+
+/**
+ * @brief Mode of an IPsec SA.
+ *
+ * These are equal to those defined in XFRM, so don't change.
+ *
+ * @ingroup config
+ */
+enum mode_t {
+ /** transport mode, no inner address */
+ MODE_TRANSPORT = 0,
+ /** tunnel mode, inner and outer addresses */
+ MODE_TUNNEL = 1,
+ /** BEET mode, tunnel mode but fixed, bound inner addresses */
+ MODE_BEET = 4,
+};
+
+/**
+ * enum names for mode_t.
+ */
+extern enum_name_t *mode_names;
+
+/**
+ * @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 the name of the policy.
+ *
+ * Returned object is not getting cloned.
+ *
+ * @param this calling object
+ * @return policy's name
+ */
+ char *(*get_name) (policy_t *this);
+
+ /**
+ * @brief Get own id.
+ *
+ * Returned object is not getting cloned.
+ *
+ * @param this calling object
+ * @return own id
+ */
+ identification_t *(*get_my_id) (policy_t *this);
+
+ /**
+ * @brief Get peer id.
+ *
+ * Returned object is not getting cloned.
+ *
+ * @param this calling object
+ * @return other id
+ */
+ identification_t *(*get_other_id) (policy_t *this);
+
+ /**
+ * @brief Get own ca.
+ *
+ * Returned object is not getting cloned.
+ *
+ * @param this calling object
+ * @return own ca
+ */
+ identification_t *(*get_my_ca) (policy_t *this);
+
+ /**
+ * @brief Get peer ca.
+ *
+ * Returned object is not getting cloned.
+ *
+ * @param this calling object
+ * @return other ca
+ */
+ identification_t *(*get_other_ca) (policy_t *this);
+
+ /**
+ * @brief Get the authentication method to use.
+ *
+ * @param this calling object
+ * @return authentication method
+ */
+ auth_method_t (*get_auth_method) (policy_t *this);
+
+ /**
+ * @brief Get the EAP type to use for peer authentication.
+ *
+ * @param this calling object
+ * @return authentication method
+ */
+ eap_type_t (*get_eap_type) (policy_t *this);
+
+ /**
+ * @brief Get configured traffic selectors for our site.
+ *
+ * Returns a list with all traffic selectors for the local
+ * site. List and items must be destroyed after usage.
+ *
+ * @param this calling object
+ * @return list with traffic selectors
+ */
+ linked_list_t *(*get_my_traffic_selectors) (policy_t *this, host_t *me);
+
+ /**
+ * @brief Get configured traffic selectors for others site.
+ *
+ * Returns a list with all traffic selectors for the remote
+ * site. List and items must be destroyed after usage.
+ *
+ * @param this calling object
+ * @return list with traffic selectors
+ */
+ linked_list_t *(*get_other_traffic_selectors) (policy_t *this, host_t* other);
+
+ /**
+ * @brief Select traffic selectors from a supplied list for local site.
+ *
+ * Resulted list and traffic selectors must be destroyed after usage.
+ * As the traffic selectors may contain a wildcard address (0.0.0.0) for
+ * addresses we don't know in previous, an address may be supplied to
+ * replace these 0.0.0.0 addresses on-the-fly.
+ *
+ * @param this calling object
+ * @param supplied linked list with traffic selectors
+ * @param me host address used by us
+ * @return list containing the selected traffic selectors
+ */
+ linked_list_t *(*select_my_traffic_selectors) (policy_t *this,
+ linked_list_t *supplied,
+ host_t *me);
+
+ /**
+ * @brief Select traffic selectors from a supplied list for remote site.
+ *
+ * Resulted list and traffic selectors must be destroyed after usage.
+ * As the traffic selectors may contain a wildcard address (0.0.0.0) for
+ * addresses we don't know in previous, an address may be supplied to
+ * replace these 0.0.0.0 addresses on-the-fly.
+ *
+ * @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,
+ host_t *other);
+
+ /**
+ * @brief Get the list of internally stored proposals.
+ *
+ * policy_t does store proposals for AH/ESP, IKE proposals are in
+ * the connection_t.
+ * Resulting list and all of its proposals must be freed after usage.
+ *
+ * @param this calling object
+ * @return lists with proposals
+ */
+ linked_list_t *(*get_proposals) (policy_t *this);
+
+ /**
+ * @brief Select a proposal from a supplied list.
+ *
+ * Returned propsal is newly created and must be destroyed after usage.
+ *
+ * @param this calling object
+ * @param proposals list from from wich proposals are selected
+ * @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, traffic selector is owned by policy.
+ *
+ * @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, traffic selector is owned by policy.
+ *
+ * @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.
+ * After add, proposal is owned by policy.
+ *
+ * @param this calling object
+ * @param proposal proposal to add
+ */
+ void (*add_proposal) (policy_t *this, proposal_t *proposal);
+
+ /**
+ * @brief Add certification authorities.
+ *
+ * @param this calling object
+ * @param my_ca issuer of my certificate
+ * @param other_ca required issuer of the peer's certificate
+ */
+ void (*add_authorities) (policy_t *this, identification_t *my_ca, identification_t *other_ca);
+
+ /**
+ * @brief Get updown script
+ *
+ * @param this calling object
+ * @return path to updown script
+ */
+ char* (*get_updown) (policy_t *this);
+
+ /**
+ * @brief Get hostaccess flag
+ *
+ * @param this calling object
+ * @return value of hostaccess flag
+ */
+ bool (*get_hostaccess) (policy_t *this);
+
+ /**
+ * @brief What should be done with a CHILD_SA, when other peer does not respond.
+ *
+ * @param this calling object
+ * @return dpd action
+ */
+ dpd_action_t (*get_dpd_action) (policy_t *this);
+
+ /**
+ * @brief Get the lifetime of a policy, before rekeying starts.
+ *
+ * A call to this function automatically adds a jitter to
+ * avoid simultanous rekeying.
+ *
+ * @param this policy
+ * @return lifetime in seconds
+ */
+ u_int32_t (*get_soft_lifetime) (policy_t *this);
+
+ /**
+ * @brief Get the lifetime of a policy, before SA gets deleted.
+ *
+ * @param this policy
+ * @return lifetime in seconds
+ */
+ u_int32_t (*get_hard_lifetime) (policy_t *this);
+
+ /**
+ * @brief Get the mode to use for the CHILD_SA, tunnel, transport or BEET.
+ *
+ * @param this policy
+ * @return lifetime in seconds
+ */
+ mode_t (*get_mode) (policy_t *this);
+
+ /**
+ * @brief Get a virtual IP for the local or the remote host.
+ *
+ * By supplying NULL as IP, an IP for the local host is requested. It
+ * may be %any or specific.
+ * By supplying %any as host, an IP from the pool is selected to be
+ * served to the peer.
+ * If a specified host is supplied, it is checked if this address
+ * is acceptable to serve to the peer. If so, it is returned. Otherwise,
+ * an alternative IP is returned.
+ * In any mode, this call may return NULL indicating virtual IP should
+ * not be used.
+ *
+ * @param this policy
+ * @param suggestion NULL, %any or specific, see description
+ * @return clone of an IP to use, or NULL
+ */
+ host_t* (*get_virtual_ip) (policy_t *this, host_t *suggestion);
+
+ /**
+ * @brief Get a new reference.
+ *
+ * Get a new reference to this policy by increasing
+ * it's internal reference counter.
+ * Do not call get_ref or any other function until you
+ * already have a reference. Otherwise the object may get
+ * destroyed while calling get_ref(),
+ *
+ * @param this calling object
+ */
+ void (*get_ref) (policy_t *this);
+
+ /**
+ * @brief Destroys the policy object.
+ *
+ * Decrements the internal reference counter and
+ * destroys the policy when it reaches zero.
+ *
+ * @param this calling object
+ */
+ void (*destroy) (policy_t *this);
+};
+
+/**
+ * @brief Create a configuration object for IKE_AUTH and later.
+ *
+ * name-string gets cloned, ID's not.
+ * Virtual IPs are used if they are != NULL. A %any host means the virtual
+ * IP should be obtained from the other peer.
+ * Lifetimes are in seconds. To prevent to peers to start rekeying at the
+ * same time, a jitter may be specified. Rekeying of an SA starts at
+ * (soft_lifetime - random(0, jitter)). After a successful rekeying,
+ * the hard_lifetime limit counter is reset. You should specify
+ * hard_lifetime > soft_lifetime > jitter.
+ * After a call to create, a reference is obtained (refcount = 1).
+ *
+ * @param name name of the policy
+ * @param my_id identification_t for ourselves
+ * @param other_id identification_t for the remote guy
+ * @param my_virtual_ip virtual IP for local host, or NULL
+ * @param other_virtual_ip virtual IP for remote host, or NULL
+ * @param auth_method Authentication method to use for our(!) auth data
+ * @param eap_type EAP type to use for peer authentication
+ * @param hard_lifetime lifetime before deleting an SA
+ * @param soft_lifetime lifetime before rekeying an SA
+ * @param jitter range of randomization time
+ * @param updown updown script to execute on up/down event
+ * @param hostaccess allow access to the host itself (used by the updown script)
+ * @param mode mode to propose for CHILD_SA, transport, tunnel or BEET
+ * @param dpd_action what to to with a CHILD_SA when other peer does not respond
+ * @return policy_t object
+ *
+ * @ingroup config
+ */
+policy_t *policy_create(char *name,
+ identification_t *my_id, identification_t *other_id,
+ host_t *my_virtual_ip, host_t *other_virtual_ip,
+ auth_method_t auth_method, eap_type_t eap_type,
+ u_int32_t hard_lifetime, u_int32_t soft_lifetime,
+ u_int32_t jitter, char *updown, bool hostaccess,
+ mode_t mode, dpd_action_t dpd_action);
+
+#endif /* POLICY_H_ */
diff --git a/src/charon/config/policies/policy_store.h b/src/charon/config/policies/policy_store.h
new file mode 100755
index 000000000..cd8870953
--- /dev/null
+++ b/src/charon/config/policies/policy_store.h
@@ -0,0 +1,119 @@
+/**
+ * @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_
+
+typedef struct policy_store_t policy_store_t;
+
+#include <library.h>
+#include <config/policies/policy.h>
+#include <utils/linked_list.h>
+
+
+/**
+ * @brief The interface for a store of policy_t's.
+ *
+ * The store uses reference counting to manage their lifetime. Call
+ * destroy() for a policy which is returned from the store after usage.
+ *
+ * @b Constructors:
+ * - stroke_create()
+ *
+ * @ingroup config
+ */
+struct policy_store_t {
+
+ /**
+ * @brief Returns a policy identified by two IDs and a set of traffic selectors.
+ *
+ * other_id must be fully qualified. my_id may be %any, as the
+ * other peer may not include an IDr Request.
+ *
+ * @param this calling object
+ * @param my_id own ID of the policy
+ * @param other_id others ID of the policy
+ * @param my_ts traffic selectors requested for local host
+ * @param other_ts traffic selectors requested for remote host
+ * @param my_host host to use for wilcards in TS compare
+ * @param other_host host to use for wildcards in TS compare
+ * @return
+ * - matching policy_t, if found
+ * - NULL otherwise
+ */
+ policy_t *(*get_policy) (policy_store_t *this,
+ identification_t *my_id, identification_t *other_id,
+ linked_list_t *my_ts, linked_list_t *other_ts,
+ host_t *my_host, host_t* other_host);
+
+ /**
+ * @brief Returns a policy identified by a connection name.
+ *
+ * @param this calling object
+ * @param name name of the policy
+ * @return
+ * - matching policy_t, if found
+ * - NULL otherwise
+ */
+ policy_t *(*get_policy_by_name) (policy_store_t *this, char *name);
+
+ /**
+ * @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 Delete a policy from the store.
+ *
+ * Remove a policy from the store identified by its name.
+ *
+ * @param this calling object
+ * @param policy policy to add
+ * @return
+ * - SUCCESS, or
+ * - NOT_FOUND
+ */
+ status_t (*delete_policy) (policy_store_t *this, char *name);
+
+ /**
+ * @brief Get an iterator for the stored policies.
+ *
+ * @param this calling object
+ * @return iterator over all stored policies
+ */
+ iterator_t* (*create_iterator) (policy_store_t *this);
+
+ /**
+ * @brief Destroys a policy_store_t object.
+ *
+ * @param this calling object
+ */
+ void (*destroy) (policy_store_t *this);
+};
+
+#endif /*POLICY_STORE_H_*/
diff --git a/src/charon/config/proposal.c b/src/charon/config/proposal.c
new file mode 100644
index 000000000..dcab8cbdd
--- /dev/null
+++ b/src/charon/config/proposal.c
@@ -0,0 +1,641 @@
+/**
+ * @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 <daemon.h>
+#include <utils/linked_list.h>
+#include <utils/identification.h>
+#include <utils/lexparser.h>
+#include <crypto/prfs/prf.h>
+#include <crypto/crypters/crypter.h>
+#include <crypto/signers/signer.h>
+
+
+ENUM(protocol_id_names, PROTO_NONE, PROTO_ESP,
+ "PROTO_NONE",
+ "IKE",
+ "AH",
+ "ESP",
+);
+
+ENUM_BEGIN(transform_type_names, UNDEFINED_TRANSFORM_TYPE, UNDEFINED_TRANSFORM_TYPE,
+ "UNDEFINED_TRANSFORM_TYPE");
+ENUM_NEXT(transform_type_names, ENCRYPTION_ALGORITHM, EXTENDED_SEQUENCE_NUMBERS, UNDEFINED_TRANSFORM_TYPE,
+ "ENCRYPTION_ALGORITHM",
+ "PSEUDO_RANDOM_FUNCTION",
+ "INTEGRITY_ALGORITHM",
+ "DIFFIE_HELLMAN_GROUP",
+ "EXTENDED_SEQUENCE_NUMBERS");
+ENUM_END(transform_type_names, EXTENDED_SEQUENCE_NUMBERS);
+
+ENUM(extended_sequence_numbers_names, NO_EXT_SEQ_NUMBERS, EXT_SEQ_NUMBERS,
+ "NO_EXT_SEQ_NUMBERS",
+ "EXT_SEQ_NUMBERS",
+);
+
+typedef struct private_proposal_t private_proposal_t;
+
+/**
+ * Private data of an proposal_t object
+ */
+struct private_proposal_t {
+
+ /**
+ * Public part
+ */
+ proposal_t public;
+
+ /**
+ * 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
+ */
+ u_int64_t spi;
+};
+
+/**
+ * Add algorithm/keysize to a algorithm list
+ */
+static void add_algo(linked_list_t *list, u_int16_t algo, size_t key_size)
+{
+ algorithm_t *algo_key;
+
+ 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, transform_type_t type, u_int16_t algo, size_t key_size)
+{
+ switch (type)
+ {
+ case ENCRYPTION_ALGORITHM:
+ add_algo(this->encryption_algos, algo, key_size);
+ break;
+ case INTEGRITY_ALGORITHM:
+ add_algo(this->integrity_algos, algo, key_size);
+ break;
+ case PSEUDO_RANDOM_FUNCTION:
+ add_algo(this->prf_algos, algo, key_size);
+ break;
+ case DIFFIE_HELLMAN_GROUP:
+ add_algo(this->dh_groups, algo, 0);
+ break;
+ case EXTENDED_SEQUENCE_NUMBERS:
+ add_algo(this->esns, algo, 0);
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * Implements proposal_t.get_algorithm.
+ */
+static bool get_algorithm(private_proposal_t *this, transform_type_t type, algorithm_t** algo)
+{
+ linked_list_t *list;
+ switch (type)
+ {
+ case ENCRYPTION_ALGORITHM:
+ list = this->encryption_algos;
+ break;
+ case INTEGRITY_ALGORITHM:
+ list = this->integrity_algos;
+ break;
+ case PSEUDO_RANDOM_FUNCTION:
+ list = this->prf_algos;
+ break;
+ case DIFFIE_HELLMAN_GROUP:
+ list = this->dh_groups;
+ break;
+ case EXTENDED_SEQUENCE_NUMBERS:
+ list = this->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, transform_type_t type)
+{
+ switch (type)
+ {
+ case ENCRYPTION_ALGORITHM:
+ return this->encryption_algos->create_iterator(this->encryption_algos, TRUE);
+ case INTEGRITY_ALGORITHM:
+ return this->integrity_algos->create_iterator(this->integrity_algos, TRUE);
+ case PSEUDO_RANDOM_FUNCTION:
+ return this->prf_algos->create_iterator(this->prf_algos, TRUE);
+ case DIFFIE_HELLMAN_GROUP:
+ return this->dh_groups->create_iterator(this->dh_groups, TRUE);
+ case EXTENDED_SEQUENCE_NUMBERS:
+ return this->esns->create_iterator(this->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->iterate(first_iter, (void**)&first_alg))
+ {
+ second_iter->reset(second_iter);
+ while (second_iter->iterate(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;
+ bool add;
+
+ DBG2(DBG_CFG, "selecting proposal:");
+
+ /* check protocol */
+ if (this->protocol != other->protocol)
+ {
+ DBG2(DBG_CFG, " protocol mismatch, skipping");
+ return NULL;
+ }
+
+ selected = proposal_create(this->protocol);
+
+ /* select encryption algorithm */
+ if (select_algo(this->encryption_algos, other->encryption_algos, &add, &algo, &key_size))
+ {
+ if (add)
+ {
+ selected->add_algorithm(selected, ENCRYPTION_ALGORITHM, algo, key_size);
+ }
+ }
+ else
+ {
+ selected->destroy(selected);
+ DBG2(DBG_CFG, " no acceptable ENCRYPTION_ALGORITHM found, skipping");
+ return NULL;
+ }
+ /* select integrity algorithm */
+ if (select_algo(this->integrity_algos, other->integrity_algos, &add, &algo, &key_size))
+ {
+ if (add)
+ {
+ selected->add_algorithm(selected, INTEGRITY_ALGORITHM, algo, key_size);
+ }
+ }
+ else
+ {
+ selected->destroy(selected);
+ DBG2(DBG_CFG, " no acceptable INTEGRITY_ALGORITHM found, skipping");
+ return NULL;
+ }
+ /* select prf algorithm */
+ if (select_algo(this->prf_algos, other->prf_algos, &add, &algo, &key_size))
+ {
+ if (add)
+ {
+ selected->add_algorithm(selected, PSEUDO_RANDOM_FUNCTION, algo, key_size);
+ }
+ }
+ else
+ {
+ selected->destroy(selected);
+ DBG2(DBG_CFG, " no acceptable PSEUDO_RANDOM_FUNCTION found, skipping");
+ return NULL;
+ }
+ /* select a DH-group */
+ if (select_algo(this->dh_groups, other->dh_groups, &add, &algo, &key_size))
+ {
+ if (add)
+ {
+ selected->add_algorithm(selected, DIFFIE_HELLMAN_GROUP, algo, 0);
+ }
+ }
+ else
+ {
+ selected->destroy(selected);
+ DBG2(DBG_CFG, " no acceptable DIFFIE_HELLMAN_GROUP found, skipping");
+ return NULL;
+ }
+ /* select if we use ESNs */
+ if (select_algo(this->esns, other->esns, &add, &algo, &key_size))
+ {
+ if (add)
+ {
+ selected->add_algorithm(selected, EXTENDED_SEQUENCE_NUMBERS, algo, 0);
+ }
+ }
+ else
+ {
+ selected->destroy(selected);
+ DBG2(DBG_CFG, " no acceptable EXTENDED_SEQUENCE_NUMBERS found, skipping");
+ return NULL;
+ }
+ DBG2(DBG_CFG, " proposal matches");
+
+ /* apply SPI from "other" */
+ selected->set_spi(selected, other->spi);
+
+ /* everything matched, return new proposal */
+ return selected;
+}
+
+/**
+ * Implements proposal_t.get_protocols.
+ */
+static protocol_id_t get_protocol(private_proposal_t *this)
+{
+ return this->protocol;
+}
+
+/**
+ * Implements proposal_t.set_spi.
+ */
+static void set_spi(private_proposal_t *this, u_int64_t spi)
+{
+ this->spi = spi;
+}
+
+/**
+ * Implements proposal_t.get_spi.
+ */
+static u_int64_t get_spi(private_proposal_t *this)
+{
+ return this->spi;
+}
+
+/**
+ * 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->iterate(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->protocol);
+
+ clone_algo_list(this->encryption_algos, clone->encryption_algos);
+ clone_algo_list(this->integrity_algos, clone->integrity_algos);
+ clone_algo_list(this->prf_algos, clone->prf_algos);
+ clone_algo_list(this->dh_groups, clone->dh_groups);
+ clone_algo_list(this->esns, clone->esns);
+
+ clone->spi = this->spi;
+
+ return &clone->public;
+}
+
+static status_t add_string_algo(private_proposal_t *this, chunk_t alg)
+{
+ if (strncmp(alg.ptr, "null", alg.len) == 0)
+ {
+ add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_NULL, 0);
+ }
+ else if (strncmp(alg.ptr, "aes128", alg.len) == 0)
+ {
+ add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128);
+ }
+ else if (strncmp(alg.ptr, "aes192", alg.len) == 0)
+ {
+ add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 192);
+ }
+ else if (strncmp(alg.ptr, "aes256", alg.len) == 0)
+ {
+ add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 256);
+ }
+ else if (strncmp(alg.ptr, "3des", alg.len) == 0)
+ {
+ add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_3DES, 0);
+ }
+ /* blowfish only uses some predefined key sizes yet */
+ else if (strncmp(alg.ptr, "blowfish128", alg.len) == 0)
+ {
+ add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 128);
+ }
+ else if (strncmp(alg.ptr, "blowfish192", alg.len) == 0)
+ {
+ add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 192);
+ }
+ else if (strncmp(alg.ptr, "blowfish256", alg.len) == 0)
+ {
+ add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 256);
+ }
+ else if (strncmp(alg.ptr, "sha", alg.len) == 0 ||
+ strncmp(alg.ptr, "sha1", alg.len) == 0)
+ {
+ /* sha means we use SHA for both, PRF and AUTH */
+ add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
+ if (this->protocol == PROTO_IKE)
+ {
+ add_algorithm(this, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA1, 0);
+ }
+ }
+ else if (strncmp(alg.ptr, "sha256", alg.len) == 0)
+ {
+ add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_128, 0);
+ if (this->protocol == PROTO_IKE)
+ {
+ add_algorithm(this, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA2_256, 0);
+ }
+ }
+ else if (strncmp(alg.ptr, "sha384", alg.len) == 0)
+ {
+ add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_384_192, 0);
+ if (this->protocol == PROTO_IKE)
+ {
+ add_algorithm(this, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA2_384, 0);
+ }
+ }
+ else if (strncmp(alg.ptr, "sha512", alg.len) == 0)
+ {
+ add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_512_256, 0);
+ if (this->protocol == PROTO_IKE)
+ {
+ add_algorithm(this, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA2_512, 0);
+ }
+ }
+ else if (strncmp(alg.ptr, "md5", alg.len) == 0)
+ {
+ add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
+ if (this->protocol == PROTO_IKE)
+ {
+ add_algorithm(this, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_MD5, 0);
+ }
+ }
+ else if (strncmp(alg.ptr, "modp768", alg.len) == 0)
+ {
+ add_algorithm(this, DIFFIE_HELLMAN_GROUP, MODP_768_BIT, 0);
+ }
+ else if (strncmp(alg.ptr, "modp1024", alg.len) == 0)
+ {
+ add_algorithm(this, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0);
+ }
+ else if (strncmp(alg.ptr, "modp1536", alg.len) == 0)
+ {
+ add_algorithm(this, DIFFIE_HELLMAN_GROUP, MODP_1536_BIT, 0);
+ }
+ else if (strncmp(alg.ptr, "modp2048", alg.len) == 0)
+ {
+ add_algorithm(this, DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0);
+ }
+ else if (strncmp(alg.ptr, "modp4096", alg.len) == 0)
+ {
+ add_algorithm(this, DIFFIE_HELLMAN_GROUP, MODP_4096_BIT, 0);
+ }
+ else if (strncmp(alg.ptr, "modp8192", alg.len) == 0)
+ {
+ add_algorithm(this, DIFFIE_HELLMAN_GROUP, MODP_8192_BIT, 0);
+ }
+ else
+ {
+ return FAILED;
+ }
+ return SUCCESS;
+}
+
+/**
+ * Implements proposal_t.destroy.
+ */
+static void destroy(private_proposal_t *this)
+{
+ this->encryption_algos->destroy_function(this->encryption_algos, free);
+ this->integrity_algos->destroy_function(this->integrity_algos, free);
+ this->prf_algos->destroy_function(this->prf_algos, free);
+ this->dh_groups->destroy_function(this->dh_groups, free);
+ this->esns->destroy_function(this->esns, free);
+ free(this);
+}
+
+/*
+ * Describtion in header-file
+ */
+proposal_t *proposal_create(protocol_id_t protocol)
+{
+ private_proposal_t *this = malloc_thing(private_proposal_t);
+
+ this->public.add_algorithm = (void (*)(proposal_t*,transform_type_t,u_int16_t,size_t))add_algorithm;
+ this->public.create_algorithm_iterator = (iterator_t* (*)(proposal_t*,transform_type_t))create_algorithm_iterator;
+ this->public.get_algorithm = (bool (*)(proposal_t*,transform_type_t,algorithm_t**))get_algorithm;
+ this->public.select = (proposal_t* (*)(proposal_t*,proposal_t*))select_proposal;
+ this->public.get_protocol = (protocol_id_t(*)(proposal_t*))get_protocol;
+ this->public.set_spi = (void(*)(proposal_t*,u_int64_t))set_spi;
+ this->public.get_spi = (u_int64_t(*)(proposal_t*))get_spi;
+ this->public.clone = (proposal_t*(*)(proposal_t*))clone_;
+ this->public.destroy = (void(*)(proposal_t*))destroy;
+
+ this->spi = 0;
+ this->protocol = protocol;
+
+ this->encryption_algos = linked_list_create();
+ this->integrity_algos = linked_list_create();
+ this->prf_algos = linked_list_create();
+ this->dh_groups = linked_list_create();
+ this->esns = linked_list_create();
+
+ return &this->public;
+}
+
+/*
+ * Describtion in header-file
+ */
+proposal_t *proposal_create_default(protocol_id_t protocol)
+{
+ private_proposal_t *this = (private_proposal_t*)proposal_create(protocol);
+
+ switch (protocol)
+ {
+ case PROTO_IKE:
+ add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128);
+ add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 192);
+ add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 256);
+ add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_3DES, 0);
+ add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_128, 0);
+ add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
+ add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
+ add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_384_192, 0);
+ add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_512_256, 0);
+ add_algorithm(this, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA2_256, 0);
+ add_algorithm(this, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA1, 0);
+ add_algorithm(this, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_MD5, 0);
+ add_algorithm(this, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA2_384, 0);
+ add_algorithm(this, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA2_512, 0);
+ add_algorithm(this, DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0);
+ add_algorithm(this, DIFFIE_HELLMAN_GROUP, MODP_1536_BIT, 0);
+ add_algorithm(this, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0);
+ add_algorithm(this, DIFFIE_HELLMAN_GROUP, MODP_4096_BIT, 0);
+ add_algorithm(this, DIFFIE_HELLMAN_GROUP, MODP_8192_BIT, 0);
+ break;
+ case PROTO_ESP:
+ add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128);
+ add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 192);
+ add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 256);
+ add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_3DES, 0);
+ add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 256);
+ add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
+ add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
+ add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
+ break;
+ case PROTO_AH:
+ add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
+ add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
+ add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
+ break;
+ default:
+ break;
+ }
+
+ return &this->public;
+}
+
+/*
+ * Describtion in header-file
+ */
+proposal_t *proposal_create_from_string(protocol_id_t protocol, const char *algs)
+{
+ private_proposal_t *this = (private_proposal_t*)proposal_create(protocol);
+ chunk_t string = {(void*)algs, strlen(algs)};
+ chunk_t alg;
+ status_t status = SUCCESS;
+
+ eat_whitespace(&string);
+ if (string.len < 1)
+ {
+ destroy(this);
+ return NULL;
+ }
+
+ /* get all tokens, separated by '-' */
+ while (extract_token(&alg, '-', &string))
+ {
+ status |= add_string_algo(this, alg);
+ }
+ if (string.len)
+ {
+ status |= add_string_algo(this, string);
+ }
+ if (status != SUCCESS)
+ {
+ destroy(this);
+ return NULL;
+ }
+
+ if (protocol == PROTO_AH || protocol == PROTO_ESP)
+ {
+ add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
+ }
+ return &this->public;
+}
diff --git a/src/charon/config/proposal.h b/src/charon/config/proposal.h
new file mode 100644
index 000000000..abcb40999
--- /dev/null
+++ b/src/charon/config/proposal.h
@@ -0,0 +1,266 @@
+/**
+ * @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_
+
+typedef enum protocol_id_t protocol_id_t;
+typedef enum transform_type_t transform_type_t;
+typedef enum extended_sequence_numbers_t extended_sequence_numbers_t;
+typedef struct algorithm_t algorithm_t;
+typedef struct proposal_t proposal_t;
+
+#include <library.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>
+
+/**
+ * Protocol ID of a proposal.
+ *
+ * @ingroup config
+ */
+enum protocol_id_t {
+ PROTO_NONE = 0,
+ PROTO_IKE = 1,
+ PROTO_AH = 2,
+ PROTO_ESP = 3,
+};
+
+/**
+ * enum names for protocol_id_t
+ *
+ * @ingroup config
+ */
+extern enum_name_t *protocol_id_names;
+
+
+/**
+ * Type of a transform, as in IKEv2 RFC 3.3.2.
+ *
+ * @ingroup config
+ */
+enum transform_type_t {
+ UNDEFINED_TRANSFORM_TYPE = 241,
+ ENCRYPTION_ALGORITHM = 1,
+ PSEUDO_RANDOM_FUNCTION = 2,
+ INTEGRITY_ALGORITHM = 3,
+ DIFFIE_HELLMAN_GROUP = 4,
+ EXTENDED_SEQUENCE_NUMBERS = 5
+};
+
+/**
+ * enum names for transform_type_t.
+ *
+ * @ingroup config
+ */
+extern enum_name_t *transform_type_names;
+
+
+/**
+ * Extended sequence numbers, as in IKEv2 RFC 3.3.2.
+ *
+ * @ingroup config
+ */
+enum extended_sequence_numbers_t {
+ NO_EXT_SEQ_NUMBERS = 0,
+ EXT_SEQ_NUMBERS = 1
+};
+
+/**
+ * enum strings for extended_sequence_numbers_t.
+ *
+ * @ingroup config
+ */
+extern enum_name_t *extended_sequence_numbers_names;
+
+
+
+/**
+ * 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 in bits, or zero if not needed
+ */
+ u_int16_t key_size;
+};
+
+/**
+ * @brief Stores a set of algorithms used for an SA.
+ *
+ * A proposal stores algorithms for a specific
+ * protocol. It can store algorithms for one protocol.
+ * Proposals with multiple protocols are not supported,
+ * as it's not specified in RFC4301 anymore.
+ *
+ * @b Constructors:
+ * - proposal_create()
+ *
+ * @ingroup config
+ */
+struct proposal_t {
+
+ /**
+ * @brief Add an algorithm to the proposal.
+ *
+ * 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.
+ *
+ * @param this calling object
+ * @param type kind of algorithm
+ * @param alg identifier for algorithm
+ * @param key_size key size to use
+ */
+ void (*add_algorithm) (proposal_t *this, transform_type_t type, u_int16_t alg, size_t key_size);
+
+ /**
+ * @brief Get an iterator over algorithms for a specifc algo type.
+ *
+ * @param this calling object
+ * @param type kind of algorithm
+ * @return iterator over algorithm_t's
+ */
+ iterator_t *(*create_algorithm_iterator) (proposal_t *this, transform_type_t type);
+
+ /**
+ * @brief Get the algorithm for a type to use.
+ *
+ * If there are multiple algorithms, only the first is returned.
+ * Result is still owned by proposal, do not modify!
+ *
+ * @param this calling object
+ * @param type kind of algorithm
+ * @param[out] algo pointer which receives algorithm and key size
+ * @return TRUE if algorithm of this kind available
+ */
+ bool (*get_algorithm) (proposal_t *this, 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 protocol ID of the proposal.
+ *
+ * @param this calling object
+ * @return protocol of the proposal
+ */
+ protocol_id_t (*get_protocol) (proposal_t *this);
+
+ /**
+ * @brief Get the SPI of the proposal.
+ *
+ * @param this calling object
+ * @return spi for proto
+ */
+ u_int64_t (*get_spi) (proposal_t *this);
+
+ /**
+ * @brief Set the SPI of the proposal.
+ *
+ * @param this calling object
+ * @param spi spi to set for proto
+ */
+ void (*set_spi) (proposal_t *this, 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, ESP or IKE.
+ *
+ * @param protocol protocol, such as PROTO_ESP
+ * @return proposal_t object
+ *
+ * @ingroup config
+ */
+proposal_t *proposal_create(protocol_id_t protocol);
+
+/**
+ * @brief Create a default proposal if nothing further specified.
+ *
+ * @param protocol protocol, such as PROTO_ESP
+ * @return proposal_t object
+ *
+ * @ingroup config
+ */
+proposal_t *proposal_create_default(protocol_id_t protocol);
+
+/**
+ * @brief Create a proposal from a string identifying the algorithms.
+ *
+ * The string is in the same form as a in the ipsec.conf file.
+ * E.g.: aes128-sha2_256-modp2048
+ * 3des-md5
+ * An additional '!' at the end of the string forces this proposal,
+ * without it the peer may choose another algorithm we support.
+ *
+ * @param protocol protocol, such as PROTO_ESP
+ * @param algs algorithms as string
+ * @return proposal_t object
+ *
+ * @ingroup config
+ */
+proposal_t *proposal_create_from_string(protocol_id_t protocol, const char *algs);
+
+#endif /* PROPOSAL_H_ */
diff --git a/src/charon/config/traffic_selector.c b/src/charon/config/traffic_selector.c
new file mode 100644
index 000000000..2fb012e16
--- /dev/null
+++ b/src/charon/config/traffic_selector.c
@@ -0,0 +1,795 @@
+/**
+ * @file traffic_selector.c
+ *
+ * @brief Implementation of traffic_selector_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Tobias Brunner
+ * Copyright (C) 2005-2007 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <arpa/inet.h>
+#include <string.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <printf.h>
+
+#include "traffic_selector.h"
+
+#include <daemon.h>
+#include <utils/linked_list.h>
+#include <utils/identification.h>
+
+ENUM(ts_type_name, TS_IPV4_ADDR_RANGE, TS_IPV6_ADDR_RANGE,
+ "TS_IPV4_ADDR_RANGE",
+ "TS_IPV6_ADDR_RANGE",
+);
+
+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;
+
+ /**
+ * narrow this traffic selector to hosts external ip
+ * if set, from and to have no meaning until set_address() is called
+ */
+ bool dynamic;
+
+ /**
+ * begin of address range, network order
+ */
+ union {
+ /** dummy char for common address manipulation */
+ char from[0];
+ /** IPv4 address */
+ u_int32_t from4[1];
+ /** IPv6 address */
+ u_int32_t from6[4];
+ };
+
+ /**
+ * end of address range, network order
+ */
+ union {
+ /** dummy char for common address manipulation */
+ char to[0];
+ /** IPv4 address */
+ u_int32_t to4[1];
+ /** IPv6 address */
+ u_int32_t to6[4];
+ };
+
+ /**
+ * begin of port range
+ */
+ u_int16_t from_port;
+
+ /**
+ * end of port range
+ */
+ u_int16_t to_port;
+};
+
+/**
+ * calculate to "to"-address for the "from" address and a subnet size
+ */
+static void calc_range(private_traffic_selector_t *this, u_int8_t netbits)
+{
+ int byte;
+ size_t size = (this->type == TS_IPV4_ADDR_RANGE) ? 4 : 16;
+
+ /* go through the from address, starting at the tail. While we
+ * have not processed the bits belonging to the host, set them to 1 on
+ * the to address. If we reach the bits for the net, copy them from "from". */
+ for (byte = size - 1; byte >=0; byte--)
+ {
+ u_char mask = 0x00;
+ int shift;
+
+ shift = (byte+1) * 8 - netbits;
+ if (shift > 0)
+ {
+ mask = 1 << shift;
+ if (mask != 0xFF)
+ {
+ mask--;
+ }
+ }
+ this->to[byte] = this->from[byte] | mask;
+ }
+}
+
+/**
+ * calculate to subnet size from "to"- and "from"-address
+ */
+static u_int8_t calc_netbits(private_traffic_selector_t *this)
+{
+ int byte, bit;
+ size_t size = (this->type == TS_IPV4_ADDR_RANGE) ? 4 : 16;
+
+ /* go trough all bits of the addresses, begging in the front.
+ * As longer as they equal, the subnet gets larger */
+ for (byte = 0; byte < size; byte++)
+ {
+ for (bit = 7; bit >= 0; bit--)
+ {
+ if ((1<<bit & this->from[byte]) != (1<<bit & this->to[byte]))
+ {
+ return ((7 - bit) + (byte * 8));
+ }
+ }
+ }
+ /* single host, netmask is 32/128 */
+ return (size * 8);
+}
+
+/**
+ * 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);
+
+/**
+ * output handler in printf()
+ */
+static int print(FILE *stream, const struct printf_info *info,
+ const void *const *args)
+{
+ private_traffic_selector_t *this = *((private_traffic_selector_t**)(args[0]));
+ char addr_str[INET6_ADDRSTRLEN] = "";
+ char *serv_proto = NULL;
+ u_int8_t mask;
+ bool has_proto;
+ bool has_ports;
+ size_t written = 0;
+
+ if (this == NULL)
+ {
+ return fprintf(stream, "(null)");
+ }
+
+ if (this->type == TS_IPV4_ADDR_RANGE)
+ {
+ inet_ntop(AF_INET, &this->from4, addr_str, sizeof(addr_str));
+ }
+ else
+ {
+ inet_ntop(AF_INET6, &this->from6, addr_str, sizeof(addr_str));
+ }
+ mask = calc_netbits(this);
+
+ written += fprintf(stream, "%s/%d", addr_str, mask);
+
+ /* check if we have protocol and/or port selectors */
+ has_proto = this->protocol != 0;
+ has_ports = !(this->from_port == 0 && this->to_port == 0xFFFF);
+
+ if (!has_proto && !has_ports)
+ {
+ return written;
+ }
+
+ written += fprintf(stream, "[");
+
+ /* build protocol string */
+ if (has_proto)
+ {
+ struct protoent *proto = getprotobynumber(this->protocol);
+
+ if (proto)
+ {
+ written += fprintf(stream, "%s", proto->p_name);
+ serv_proto = proto->p_name;
+ }
+ else
+ {
+ written += fprintf(stream, "%d", this->protocol);
+ }
+ }
+
+ if (has_proto && has_ports)
+ {
+ written += fprintf(stream, "/");
+ }
+
+ /* build port string */
+ if (has_ports)
+ {
+ if (this->from_port == this->to_port)
+ {
+ struct servent *serv = getservbyport(htons(this->from_port), serv_proto);
+
+ if (serv)
+ {
+ written += fprintf(stream, "%s", serv->s_name);
+ }
+ else
+ {
+ written += fprintf(stream, "%d", this->from_port);
+ }
+ }
+ else
+ {
+ written += fprintf(stream, "%d-%d", this->from_port, this->to_port);
+ }
+ }
+
+ written += fprintf(stream, "]");
+
+ return written;
+}
+
+/**
+ * register printf() handlers
+ */
+static void __attribute__ ((constructor))print_register()
+{
+ register_printf_function(PRINTF_TRAFFIC_SELECTOR, print, arginfo_ptr);
+}
+
+/**
+ * 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 == other->type && (this->protocol == other->protocol ||
+ this->protocol == 0 || other->protocol == 0))
+ {
+ u_int16_t from_port, to_port;
+ u_char *from, *to;
+ u_int8_t protocol;
+ size_t size;
+ private_traffic_selector_t *new_ts;
+
+ /* 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)
+ {
+ return NULL;
+ }
+ /* select protocol, which is not zero */
+ protocol = max(this->protocol, other->protocol);
+
+ switch (this->type)
+ {
+ case TS_IPV4_ADDR_RANGE:
+ size = sizeof(this->from4);
+ break;
+ case TS_IPV6_ADDR_RANGE:
+ size = sizeof(this->from6);
+ break;
+ default:
+ return NULL;
+ }
+
+ /* get higher from-address */
+ if (memcmp(this->from, other->from, size) > 0)
+ {
+ from = this->from;
+ }
+ else
+ {
+ from = other->from;
+ }
+ /* get lower to-address */
+ if (memcmp(this->to, other->to, size) > 0)
+ {
+ to = other->to;
+ }
+ else
+ {
+ to = this->to;
+ }
+ /* if "from" > "to", we don't have a match */
+ if (memcmp(from, to, size) > 0)
+ {
+ return NULL;
+ }
+
+ /* we have a match in protocol, port, and address: return it... */
+ new_ts = traffic_selector_create(protocol, this->type, from_port, to_port);
+ new_ts->type = this->type;
+ memcpy(new_ts->from, from, size);
+ memcpy(new_ts->to, to, size);
+
+ return &new_ts->public;
+ }
+ return NULL;
+}
+
+/**
+ * implements traffic_selector_t.equals
+ */
+static bool equals(private_traffic_selector_t *this, private_traffic_selector_t *other)
+{
+ if (this->type != other->type)
+ {
+ return FALSE;
+ }
+ if (!(this->from_port == other->from_port &&
+ this->to_port == other->to_port &&
+ this->protocol == other->protocol))
+ {
+ return FALSE;
+ }
+ switch (this->type)
+ {
+ case TS_IPV4_ADDR_RANGE:
+ if (memeq(this->from4, other->from4, sizeof(this->from4)))
+ {
+ return TRUE;
+ }
+ break;
+ case TS_IPV6_ADDR_RANGE:
+ if (memeq(this->from6, other->from6, sizeof(this->from6)))
+ {
+ return TRUE;
+ }
+ break;
+ default:
+ break;
+ }
+ return FALSE;
+}
+
+/**
+ * Implements traffic_selector_t.get_from_address.
+ */
+static chunk_t get_from_address(private_traffic_selector_t *this)
+{
+ chunk_t from = chunk_empty;
+
+ switch (this->type)
+ {
+ case TS_IPV4_ADDR_RANGE:
+ {
+ from.len = sizeof(this->from4);
+ from.ptr = malloc(from.len);
+ memcpy(from.ptr, this->from4, from.len);
+ break;
+ }
+ case TS_IPV6_ADDR_RANGE:
+ {
+ from.len = sizeof(this->from6);
+ from.ptr = malloc(from.len);
+ memcpy(from.ptr, this->from6, from.len);
+ break;
+ }
+ }
+ return from;
+}
+
+/**
+ * Implements traffic_selector_t.get_to_address.
+ */
+static chunk_t get_to_address(private_traffic_selector_t *this)
+{
+ chunk_t to = chunk_empty;
+
+ switch (this->type)
+ {
+ case TS_IPV4_ADDR_RANGE:
+ {
+ to.len = sizeof(this->to4);
+ to.ptr = malloc(to.len);
+ memcpy(to.ptr, this->to4, to.len);
+ break;
+ }
+ case TS_IPV6_ADDR_RANGE:
+ {
+ to.len = sizeof(this->to6);
+ to.ptr = malloc(to.len);
+ memcpy(to.ptr, this->to6, to.len);
+ break;
+ }
+ }
+ return to;
+}
+
+/**
+ * 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.is_host.
+ */
+static bool is_host(private_traffic_selector_t *this, host_t *host)
+{
+ if (this->dynamic)
+ {
+ return TRUE;
+ }
+
+ if (host)
+ {
+ chunk_t addr;
+ int family = host->get_family(host);
+
+ if ((family == AF_INET && this->type == TS_IPV4_ADDR_RANGE) ||
+ (family == AF_INET6 && this->type == TS_IPV6_ADDR_RANGE))
+ {
+ addr = host->get_address(host);
+ if (memeq(addr.ptr, this->from, addr.len) &&
+ memeq(addr.ptr, this->to, addr.len))
+ {
+ return TRUE;
+ }
+ }
+ }
+ else
+ {
+ size_t length = (this->type == TS_IPV4_ADDR_RANGE) ? 4 : 16;
+
+ if (memeq(this->from, this->to, length))
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ * Implements traffic_selector_t.set_address.
+ */
+static void set_address(private_traffic_selector_t *this, host_t *host)
+{
+ if (this->dynamic)
+ {
+ this->type = host->get_family(host) == AF_INET ?
+ TS_IPV4_ADDR_RANGE : TS_IPV6_ADDR_RANGE;
+
+ chunk_t from = host->get_address(host);
+ memcpy(this->from, from.ptr, from.len);
+ memcpy(this->to, from.ptr, from.len);
+ }
+}
+
+/**
+ * Implements traffic_selector_t.is_contained_in.
+ */
+static bool is_contained_in(private_traffic_selector_t *this,
+ private_traffic_selector_t *other)
+{
+ private_traffic_selector_t *subset;
+ bool contained_in = FALSE;
+
+ subset = (private_traffic_selector_t*)get_subset(this, other);
+
+ if (subset)
+ {
+ if (equals(subset, this))
+ {
+ contained_in = TRUE;
+ }
+ free(subset);
+ }
+ return contained_in;
+}
+
+/**
+ * Implements traffic_selector_t.includes.
+ */
+static bool includes(private_traffic_selector_t *this, host_t *host)
+{
+ chunk_t addr;
+ int family = host->get_family(host);
+
+ if ((family == AF_INET && this->type == TS_IPV4_ADDR_RANGE) ||
+ (family == AF_INET6 && this->type == TS_IPV6_ADDR_RANGE))
+ {
+ addr = host->get_address(host);
+
+ return memcmp(this->from, addr.ptr, addr.len) <= 0 &&
+ memcmp(this->to, addr.ptr, addr.len) >= 0;
+ }
+
+ return FALSE;
+}
+
+/**
+ * Implements traffic_selector_t.clone.
+ */
+static traffic_selector_t *clone_(private_traffic_selector_t *this)
+{
+ private_traffic_selector_t *clone;
+
+ clone = traffic_selector_create(this->protocol, this->type,
+ this->from_port, this->to_port);
+
+ clone->dynamic = this->dynamic;
+ switch (clone->type)
+ {
+ case TS_IPV4_ADDR_RANGE:
+ {
+ memcpy(clone->from4, this->from4, sizeof(this->from4));
+ memcpy(clone->to4, this->to4, sizeof(this->to4));
+ return &clone->public;
+ }
+ case TS_IPV6_ADDR_RANGE:
+ {
+ memcpy(clone->from6, this->from6, sizeof(this->from6));
+ memcpy(clone->to6, this->to6, sizeof(this->to6));
+ return &clone->public;
+ }
+ default:
+ {
+ /* unreachable */
+ return &clone->public;
+ }
+ }
+}
+
+/**
+ * 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, u_int16_t from_port,
+ chunk_t to, u_int16_t to_port)
+{
+ private_traffic_selector_t *this = traffic_selector_create(protocol, type,
+ from_port, to_port);
+
+ switch (type)
+ {
+ case TS_IPV4_ADDR_RANGE:
+ {
+ if (from.len != 4 || to.len != 4)
+ {
+ free(this);
+ return NULL;
+ }
+ memcpy(this->from4, from.ptr, from.len);
+ memcpy(this->to4, to.ptr, to.len);
+ break;
+ }
+ case TS_IPV6_ADDR_RANGE:
+ {
+ if (from.len != 16 || to.len != 16)
+ {
+ free(this);
+ return NULL;
+ }
+ memcpy(this->from6, from.ptr, from.len);
+ memcpy(this->to6, to.ptr, to.len);
+ break;
+ }
+ 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, u_int8_t protocol, u_int16_t port)
+{
+ private_traffic_selector_t *this = traffic_selector_create(protocol, 0, 0, 65535);
+
+ switch (net->get_family(net))
+ {
+ case AF_INET:
+ {
+ chunk_t from;
+
+ this->type = TS_IPV4_ADDR_RANGE;
+ from = net->get_address(net);
+ memcpy(this->from4, from.ptr, from.len);
+ if (this->from4[0] == 0)
+ {
+ /* use /0 for 0.0.0.0 */
+ this->to4[0] = ~0;
+ }
+ else
+ {
+ calc_range(this, netbits);
+ }
+ break;
+ }
+ case AF_INET6:
+ {
+ chunk_t from;
+
+ this->type = TS_IPV6_ADDR_RANGE;
+ from = net->get_address(net);
+ memcpy(this->from6, from.ptr, from.len);
+ if (this->from6[0] == 0 && this->from6[1] == 0 &&
+ this->from6[2] == 0 && this->from6[3] == 0)
+ {
+ /* use /0 for ::0 */
+ this->to6[0] = ~0;
+ this->to6[1] = ~0;
+ this->to6[2] = ~0;
+ this->to6[3] = ~0;
+ }
+ else
+ {
+ calc_range(this, netbits);
+ }
+ break;
+ }
+ default:
+ {
+ free(this);
+ return NULL;
+ }
+ }
+ if (port)
+ {
+ this->from_port = port;
+ this->to_port = port;
+ }
+ 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);
+
+ this->type = type;
+ switch (type)
+ {
+ case TS_IPV4_ADDR_RANGE:
+ {
+ if (inet_pton(AF_INET, from_addr, (struct in_addr*)this->from4) < 0)
+ {
+ free(this);
+ return NULL;
+ }
+ if (inet_pton(AF_INET, to_addr, (struct in_addr*)this->to4) < 0)
+ {
+ free(this);
+ return NULL;
+ }
+ break;
+ }
+ case TS_IPV6_ADDR_RANGE:
+ {
+ if (inet_pton(AF_INET6, from_addr, (struct in6_addr*)this->from6) < 0)
+ {
+ free(this);
+ return NULL;
+ }
+ if (inet_pton(AF_INET6, to_addr, (struct in6_addr*)this->to6) < 0)
+ {
+ free(this);
+ return NULL;
+ }
+ break;
+ }
+ }
+ return (&this->public);
+}
+
+/*
+ * see header
+ */
+traffic_selector_t *traffic_selector_create_dynamic(
+ u_int8_t protocol, ts_type_t type,
+ u_int16_t from_port, u_int16_t to_port)
+{
+ private_traffic_selector_t *this = traffic_selector_create(protocol, type,
+ from_port, to_port);
+
+ memset(this->from6, 0, sizeof(this->from6));
+ memset(this->to6, 0xFF, sizeof(this->to6));
+
+ this->dynamic = TRUE;
+
+ 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.equals = (bool(*)(traffic_selector_t*,traffic_selector_t*))equals;
+ 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.is_host = (bool(*)(traffic_selector_t*,host_t*))is_host;
+ this->public.is_contained_in = (bool(*)(traffic_selector_t*,traffic_selector_t*))is_contained_in;
+ this->public.includes = (bool(*)(traffic_selector_t*,host_t*))includes;
+ this->public.set_address = (void(*)(traffic_selector_t*,host_t*))set_address;
+ 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;
+ this->dynamic = FALSE;
+
+ return this;
+}
+
+/* vim: set ts=4 sw=4 noet: */
diff --git a/src/charon/config/traffic_selector.h b/src/charon/config/traffic_selector.h
new file mode 100644
index 000000000..0e798fc6a
--- /dev/null
+++ b/src/charon/config/traffic_selector.h
@@ -0,0 +1,312 @@
+/**
+ * @file traffic_selector.h
+ *
+ * @brief Interface of traffic_selector_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Tobias Brunner
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef enum ts_type_t ts_type_t;
+typedef struct traffic_selector_t traffic_selector_t;
+
+#include <library.h>
+#include <utils/host.h>
+
+/**
+ * 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
+};
+
+/**
+ * enum names for ts_type_t
+ */
+extern enum_name_t *ts_type_name;
+
+/**
+ * @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.
+ *
+ * Chunk is in network order gets allocated.
+ *
+ * @param this called object
+ * @return chunk containing the address
+ */
+ chunk_t (*get_from_address) (traffic_selector_t *this);
+
+ /**
+ * @brief Get ending address of this ts as a chunk.
+ *
+ * Chunk is in network order gets allocated.
+ *
+ * @param this called object
+ * @return chunk containing the address
+ */
+ chunk_t (*get_to_address) (traffic_selector_t *this);
+
+ /**
+ * @brief Get starting port of this ts.
+ *
+ * Port is in host order, since the parser converts it.
+ * Size depends on protocol.
+ *
+ * @param this called object
+ * @return port
+ */
+ u_int16_t (*get_from_port) (traffic_selector_t *this);
+
+ /**
+ * @brief Get ending port of this ts.
+ *
+ * Port is in host order, since the parser converts it.
+ * Size depends on protocol.
+ *
+ * @param this called object
+ * @return port
+ */
+ u_int16_t (*get_to_port) (traffic_selector_t *this);
+
+ /**
+ * @brief Get the type of the traffic selector.
+ *
+ * @param this called object
+ * @return ts_type_t specifying the type
+ */
+ ts_type_t (*get_type) (traffic_selector_t *this);
+
+ /**
+ * @brief Get the protocol id of this ts.
+ *
+ * @param this called object
+ * @return protocol id
+ */
+ u_int8_t (*get_protocol) (traffic_selector_t *this);
+
+ /**
+ * @brief Check if the traffic selector is for a single host.
+ *
+ * Traffic selector may describe the end of *-to-host tunnel. In this
+ * case, the address range is a single address equal to the hosts
+ * peer address.
+ * If host is NULL, the traffic selector is checked if it is a single host,
+ * but not a specific one.
+ *
+ * @param this called object
+ * @param host host_t specifying the address range
+ */
+ bool (*is_host) (traffic_selector_t *this, host_t* host);
+
+ /**
+ * @brief Update the address of a traffic selector.
+ *
+ * Update the address range of a traffic selector, if it is
+ * constructed with the traffic_selector_create_dynamic().
+ *
+ * @param this called object
+ * @param host host_t specifying the address
+ */
+ void (*set_address) (traffic_selector_t *this, host_t* host);
+
+ /**
+ * @brief Compare two traffic selectors for equality.
+ *
+ * @param this first to compare
+ * @param other second to compare with first
+ * @return pointer to a string.
+ */
+ bool (*equals) (traffic_selector_t *this, traffic_selector_t *other);
+
+ /**
+ * @brief Check if a traffic selector is contained completly in another.
+ *
+ * contains() allows to check if multiple traffic selectors are redundant.
+ *
+ * @param this ts that is contained in another
+ * @param other ts that contains this
+ * @return TRUE if other contains this completly, FALSE otherwise
+ */
+ bool (*is_contained_in) (traffic_selector_t *this, traffic_selector_t *other);
+
+ /**
+ * @brief Check if a specific host is included in the address range of
+ * this traffic selector.
+ *
+ * @param this called object
+ * @param host the host to check
+ */
+ bool (*includes) (traffic_selector_t *this, host_t *host);
+
+ /**
+ * @brief Destroys the ts object
+ *
+ * @param this called object
+ */
+ 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
+ *
+ * @ingroup config
+ */
+traffic_selector_t *traffic_selector_create_from_bytes(
+ u_int8_t protocol, ts_type_t type,
+ chunk_t from_address, u_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.
+ * Additionally, a protocol and a port may be specified. Port ranges
+ * are not supported via this constructor.
+ *
+ * @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,
+ u_int8_t protocol, u_int16_t port);
+
+/**
+ * @brief Create a traffic selector for host-to-host cases.
+ *
+ * For host2host or virtual IP setups, the traffic selectors gets
+ * created at runtime using the external/virtual IP. Using this constructor,
+ * a call to set_address() sets this traffic selector to the supplied host.
+ *
+ *
+ * @param protocol upper layer protocl to allow
+ * @param type family type
+ * @param from_port start of allowed port range
+ * @param to_port end of range
+ * @return
+ * - traffic_selector_t object
+ * - NULL if type not supported
+ *
+ * @ingroup config
+ */
+traffic_selector_t *traffic_selector_create_dynamic(
+ u_int8_t protocol, ts_type_t type,
+ u_int16_t from_port, u_int16_t to_port);
+
+#endif /* TRAFFIC_SELECTOR_H_ */
+
+/* vim: set ts=4 sw=4 noet: */
diff --git a/src/charon/daemon.c b/src/charon/daemon.c
new file mode 100644
index 000000000..7671aea86
--- /dev/null
+++ b/src/charon/daemon.c
@@ -0,0 +1,529 @@
+/**
+ * @file daemon.c
+ *
+ * @brief Implementation of daemon_t and main of IKEv2-Daemon.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <time.h>
+#include <string.h>
+#include <getopt.h>
+#include <errno.h>
+#ifdef HAVE_BACKTRACE
+# include <execinfo.h>
+#endif /* HAVE_BACKTRACE */
+
+#include "daemon.h"
+
+#include <library.h>
+#include <crypto/ca.h>
+#include <utils/fetcher.h>
+#include <config/credentials/local_credential_store.h>
+#include <config/connections/local_connection_store.h>
+#include <config/policies/local_policy_store.h>
+#include <sa/authenticators/eap/eap_method.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;
+
+ /**
+ * Signal set used for signal handling.
+ */
+ sigset_t signal_set;
+
+ /**
+ * The thread_id of main-thread.
+ */
+ pthread_t main_thread_id;
+};
+
+/**
+ * One and only instance of the daemon.
+ */
+daemon_t *charon;
+
+/**
+ * hook in library for debugging messages
+ */
+extern void (*dbg) (int level, char *fmt, ...);
+
+/**
+ * Logging hook for library logs, spreads debug message over bus
+ */
+static void dbg_bus(int level, char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ charon->bus->vsignal(charon->bus, DBG_LIB, level, fmt, args);
+ va_end(args);
+}
+
+/**
+ * Logging hook for library logs, using stderr output
+ */
+static void dbg_stderr(int level, char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ fprintf(stderr, "00[LIB] ");
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n");
+ va_end(args);
+}
+
+/**
+ * Run the daemon and handle unix signals
+ */
+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)
+ {
+ DBG1(DBG_DMN, "error %d while waiting for a signal", error);
+ return;
+ }
+ switch (signal_number)
+ {
+ case SIGHUP:
+ {
+ DBG1(DBG_DMN, "signal of type SIGHUP received. Ignored");
+ break;
+ }
+ case SIGINT:
+ {
+ DBG1(DBG_DMN, "signal of type SIGINT received. Shutting down");
+ return;
+ }
+ case SIGTERM:
+ DBG1(DBG_DMN, "signal of type SIGTERM received. Shutting down");
+ return;
+ default:
+ {
+ DBG1(DBG_DMN, "unknown signal %d received. Ignored", signal_number);
+ break;
+ }
+ }
+ }
+}
+
+/**
+ * Clean up all daemon resources
+ */
+static void destroy(private_daemon_t *this)
+{
+ /* destruction is a non trivial task, we need to follow
+ * a strict order to prevent threading issues!
+ * Kill active threads first, except the sender, as
+ * the killed IKE_SA want to send delete messages.
+ */
+ /* we don't want to receive anything anymore... */
+ DESTROY_IF(this->public.receiver);
+ /* ignore all incoming user requests */
+ DESTROY_IF(this->public.stroke);
+ /* stop scheduing jobs */
+ DESTROY_IF(this->public.scheduler);
+ /* stop processing jobs */
+ DESTROY_IF(this->public.thread_pool);
+ /* shut down manager with all IKE SAs */
+ DESTROY_IF(this->public.ike_sa_manager);
+ /* all child SAs should be down now, so kill kernel interface */
+ DESTROY_IF(this->public.kernel_interface);
+ /* destroy other infrastructure */
+ DESTROY_IF(this->public.job_queue);
+ DESTROY_IF(this->public.event_queue);
+ DESTROY_IF(this->public.configuration);
+ DESTROY_IF(this->public.credentials);
+ DESTROY_IF(this->public.connections);
+ DESTROY_IF(this->public.policies);
+ sched_yield();
+ /* we hope the sender could send the outstanding deletes, but
+ * we shut down here at any cost */
+ DESTROY_IF(this->public.sender);
+ DESTROY_IF(this->public.socket);
+ /* before destroying bus with its listeners, rehook library logs */
+ dbg = dbg_stderr;
+ DESTROY_IF(this->public.bus);
+ DESTROY_IF(this->public.outlog);
+ DESTROY_IF(this->public.syslog);
+ DESTROY_IF(this->public.authlog);
+ free(this);
+}
+
+/**
+ * Enforce daemon shutdown, with a given reason to do so.
+ */
+static void kill_daemon(private_daemon_t *this, char *reason)
+{
+ /* we send SIGTERM, so the daemon can cleanly shut down */
+ DBG1(DBG_DMN, "killing daemon: %s", reason);
+ if (this->main_thread_id == pthread_self())
+ {
+ /* initialization failed, terminate daemon */
+ destroy(this);
+ unlink(PID_FILE);
+ exit(-1);
+ }
+ else
+ {
+ DBG1(DBG_DMN, "sending SIGTERM to ourself");
+ raise(SIGTERM);
+ /* thread must die, since he produced a ciritcal failure and can't continue */
+ pthread_exit(NULL);
+ }
+}
+
+/**
+ * Initialize the daemon, optional with a strict crl policy
+ */
+static void initialize(private_daemon_t *this, bool strict, bool syslog,
+ level_t levels[])
+{
+ credential_store_t* credentials;
+ signal_t signal;
+
+ /* for uncritical pseudo random numbers */
+ srandom(time(NULL) + getpid());
+
+ /* setup bus and it's listeners first to enable log output */
+ this->public.bus = bus_create();
+ this->public.outlog = file_logger_create(stdout);
+ this->public.syslog = sys_logger_create(LOG_DAEMON);
+ this->public.authlog = sys_logger_create(LOG_AUTHPRIV);
+ this->public.bus->add_listener(this->public.bus, &this->public.syslog->listener);
+ this->public.bus->add_listener(this->public.bus, &this->public.outlog->listener);
+ this->public.bus->add_listener(this->public.bus, &this->public.authlog->listener);
+ this->public.authlog->set_level(this->public.authlog, SIG_ANY, LEVEL_AUDIT);
+ /* set up hook to log dbg message in library via charons message bus */
+ dbg = dbg_bus;
+
+ /* apply loglevels */
+ for (signal = 0; signal < DBG_MAX; signal++)
+ {
+ if (syslog)
+ {
+ this->public.syslog->set_level(this->public.syslog,
+ signal, levels[signal]);
+ }
+ else
+ {
+ this->public.outlog->set_level(this->public.outlog,
+ signal, levels[signal]);
+ }
+ }
+
+ DBG1(DBG_DMN, "starting charon (strongSwan Version %s)", VERSION);
+
+ this->public.configuration = configuration_create();
+ this->public.socket = socket_create(IKEV2_UDP_PORT, IKEV2_NATT_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.connections = (connection_store_t*)local_connection_store_create();
+ this->public.policies = (policy_store_t*)local_policy_store_create();
+ this->public.credentials = (credential_store_t*)local_credential_store_create(strict);
+
+ /* initialize fetcher_t class */
+ fetcher_initialize();
+
+ /* load secrets, ca certificates and crls */
+ credentials = this->public.credentials;
+ credentials->load_ca_certificates(credentials);
+ credentials->load_ocsp_certificates(credentials);
+ credentials->load_crls(credentials);
+ credentials->load_secrets(credentials);
+
+ /* 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);
+}
+
+/**
+ * Handle SIGSEGV/SIGILL signals raised by threads
+ */
+void signal_handler(int signal)
+{
+#ifdef HAVE_BACKTRACE
+ void *array[20];
+ size_t size;
+ char **strings;
+ size_t i;
+
+ size = backtrace(array, 20);
+ strings = backtrace_symbols(array, size);
+
+ DBG1(DBG_DMN, "thread %u received %s. Dumping %d frames from stack:",
+ pthread_self(), signal == SIGSEGV ? "SIGSEGV" : "SIGILL", size);
+
+ for (i = 0; i < size; i++)
+ {
+ DBG1(DBG_DMN, " %s", strings[i]);
+ }
+ free (strings);
+#else /* !HAVE_BACKTRACE */
+ DBG1(DBG_DMN, "thread %u received %s",
+ pthread_self(), signal == SIGSEGV ? "SIGSEGV" : "SIGILL");
+#endif /* HAVE_BACKTRACE */
+ DBG1(DBG_DMN, "killing ourself hard after SIGSEGV");
+ raise(SIGKILL);
+}
+
+/**
+ * Create the daemon.
+ */
+private_daemon_t *daemon_create(void)
+{
+ private_daemon_t *this = malloc_thing(private_daemon_t);
+ struct sigaction action;
+
+ /* assign methods */
+ 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.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->public.bus = NULL;
+ this->public.outlog = NULL;
+ this->public.syslog = NULL;
+ this->public.authlog = 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;
+ sigaction(SIGSEGV, &action, NULL);
+ sigaction(SIGILL, &action, NULL);
+ return this;
+}
+
+/**
+ * print command line usage and exit
+ */
+static void usage(const char *msg)
+{
+ if (msg != NULL && *msg != '\0')
+ {
+ fprintf(stderr, "%s\n", msg);
+ }
+ fprintf(stderr, "Usage: charon\n"
+ " [--help]\n"
+ " [--version]\n"
+ " [--strictcrlpolicy]\n"
+ " [--cachecrls]\n"
+ " [--crlcheckinterval <interval>]\n"
+ " [--eapdir <dir>]\n"
+ " [--use-syslog]\n"
+ " [--debug-<type> <level>]\n"
+ " <type>: log context type (dmn|mgr|ike|chd|job|cfg|knl|net|enc|lib)\n"
+ " <level>: log verbosity (-1 = silent, 0 = audit, 1 = control,\n"
+ " 2 = controlmore, 3 = raw, 4 = private)\n"
+ "\n"
+ );
+ exit(msg == NULL? 0 : 1);
+}
+
+/**
+ * Main function, manages the daemon.
+ */
+int main(int argc, char *argv[])
+{
+ u_int crl_check_interval = 0;
+ bool strict_crl_policy = FALSE;
+ bool cache_crls = FALSE;
+ bool use_syslog = FALSE;
+ char *eapdir = IPSEC_EAPDIR;
+
+ private_daemon_t *private_charon;
+ FILE *pid_file;
+ struct stat stb;
+ linked_list_t *list;
+ host_t *host;
+ level_t levels[DBG_MAX];
+ int signal;
+
+ /* use CTRL loglevel for default */
+ for (signal = 0; signal < DBG_MAX; signal++)
+ {
+ levels[signal] = LEVEL_CTRL;
+ }
+
+ /* handle arguments */
+ for (;;)
+ {
+ struct option long_opts[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'v' },
+ { "use-syslog", no_argument, NULL, 'l' },
+ { "strictcrlpolicy", no_argument, NULL, 'r' },
+ { "cachecrls", no_argument, NULL, 'C' },
+ { "crlcheckinterval", required_argument, NULL, 'x' },
+ { "eapdir", required_argument, NULL, 'e' },
+ /* TODO: handle "debug-all" */
+ { "debug-dmn", required_argument, &signal, DBG_DMN },
+ { "debug-mgr", required_argument, &signal, DBG_MGR },
+ { "debug-ike", required_argument, &signal, DBG_IKE },
+ { "debug-chd", required_argument, &signal, DBG_CHD },
+ { "debug-job", required_argument, &signal, DBG_JOB },
+ { "debug-cfg", required_argument, &signal, DBG_CFG },
+ { "debug-knl", required_argument, &signal, DBG_KNL },
+ { "debug-net", required_argument, &signal, DBG_NET },
+ { "debug-enc", required_argument, &signal, DBG_ENC },
+ { "debug-lib", required_argument, &signal, DBG_LIB },
+ { 0,0,0,0 }
+ };
+
+ int c = getopt_long(argc, argv, "", long_opts, NULL);
+ switch (c)
+ {
+ case EOF:
+ break;
+ case 'h':
+ usage(NULL);
+ break;
+ case 'v':
+ printf("Linux strongSwan %s\n", VERSION);
+ exit(0);
+ case 'l':
+ use_syslog = TRUE;
+ continue;
+ case 'r':
+ strict_crl_policy = TRUE;
+ continue;
+ case 'C':
+ cache_crls = TRUE;
+ continue;
+ case 'x':
+ crl_check_interval = atoi(optarg);
+ continue;
+ case 'e':
+ eapdir = optarg;
+ continue;
+ case 0:
+ /* option is in signal */
+ levels[signal] = atoi(optarg);
+ continue;
+ default:
+ usage("");
+ break;
+ }
+ break;
+ }
+
+ private_charon = daemon_create();
+ charon = (daemon_t*)private_charon;
+
+ /* initialize daemon */
+ initialize(private_charon, strict_crl_policy, use_syslog, levels);
+
+ /* load pluggable EAP modules */
+ eap_method_load(eapdir);
+
+ /* set cache_crls and crl_check_interval options */
+ ca_info_set_options(cache_crls, crl_check_interval);
+
+ /* check/setup PID file */
+ if (stat(PID_FILE, &stb) == 0)
+ {
+ DBG1(DBG_DMN, "charon already running (\""PID_FILE"\" exists)");
+ destroy(private_charon);
+ exit(-1);
+ }
+ pid_file = fopen(PID_FILE, "w");
+ if (pid_file)
+ {
+ fprintf(pid_file, "%d\n", getpid());
+ fclose(pid_file);
+ }
+
+ /* log socket info */
+ list = charon->kernel_interface->create_address_list(charon->kernel_interface);
+ DBG1(DBG_NET, "listening on %d addresses:", list->get_count(list));
+ while (list->remove_first(list, (void**)&host) == SUCCESS)
+ {
+ DBG1(DBG_NET, " %H", host);
+ host->destroy(host);
+ }
+ list->destroy(list);
+
+ /* run daemon */
+ run(private_charon);
+
+ eap_method_unload();
+ fetcher_finalize();
+ /* normal termination, cleanup and exit */
+ destroy(private_charon);
+ unlink(PID_FILE);
+
+ return 0;
+}
diff --git a/src/charon/daemon.h b/src/charon/daemon.h
new file mode 100644
index 000000000..420262474
--- /dev/null
+++ b/src/charon/daemon.h
@@ -0,0 +1,403 @@
+/**
+ * @file daemon.h
+ *
+ * @brief Interface of daemon_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct daemon_t daemon_t;
+
+#include <credential_store.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 <bus/bus.h>
+#include <bus/listeners/file_logger.h>
+#include <bus/listeners/sys_logger.h>
+#include <sa/ike_sa_manager.h>
+#include <queues/job_queue.h>
+#include <queues/event_queue.h>
+#include <config/configuration.h>
+#include <config/connections/connection_store.h>
+#include <config/policies/policy_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 | +------+ +------------+ +------+
+ +------------+
+
+ @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 sender. 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 tasks tasks
+ *
+ * Tasks process and build message payloads. They are used to create
+ * and process multiple exchanges.
+ *
+ * @ingroup sa
+ */
+
+/**
+ * @defgroup authenticators authenticators
+ *
+ * Authenticator classes to prove identity of peer.
+ *
+ * @ingroup sa
+ */
+
+/**
+ * @defgroup eap eap
+ *
+ * EAP authentication module interface and it's implementations.
+ *
+ * @ingroup authenticators
+ */
+
+/**
+ * @defgroup threads threads
+ *
+ * Threaded classes, which will do their job alone.
+ *
+ * @ingroup charon
+ */
+
+/**
+ * @defgroup bus bus
+ *
+ * Signaling bus and its listeners.
+ *
+ * @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
+
+/**
+ * UDP Port to which the daemon will float to if NAT is detected.
+ *
+ * @ingroup charon
+ */
+#define IKEV2_NATT_PORT 4500
+
+/**
+ * PID file, in which charon stores its process id
+ *
+ * @ingroup charon
+ */
+#define PID_FILE IPSEC_PIDDIR "/charon.pid"
+
+/**
+ * Configuration directory
+ *
+ * @ingroup charon
+ */
+#define CONFIG_DIR IPSEC_CONFDIR
+
+/**
+ * Directory of IPsec relevant files
+ *
+ * @ingroup charon
+ */
+#define IPSEC_D_DIR CONFIG_DIR "/ipsec.d"
+
+/**
+ * Default directory for private keys
+ *
+ * @ingroup charon
+ */
+#define PRIVATE_KEY_DIR IPSEC_D_DIR "/private"
+
+/**
+ * Default directory for end entity certificates
+ *
+ * @ingroup charon
+ */
+#define CERTIFICATE_DIR IPSEC_D_DIR "/certs"
+
+/**
+ * Default directory for trusted CA certificates
+ *
+ * @ingroup charon
+ */
+#define CA_CERTIFICATE_DIR IPSEC_D_DIR "/cacerts"
+
+/**
+ * Default directory for OCSP signing certificates
+ *
+ * @ingroup charon
+ */
+#define OCSP_CERTIFICATE_DIR IPSEC_D_DIR "/ocspcerts"
+
+/**
+ * Default directory for CRLs
+ *
+ * @ingroup charon
+ */
+#define CRL_DIR IPSEC_D_DIR "/crls"
+
+/**
+ * Secrets files
+ *
+ * @ingroup charon
+ */
+#define SECRETS_FILE CONFIG_DIR "/ipsec.secrets"
+
+/**
+ * @brief Main class of daemon, contains some globals.
+ *
+ * @ingroup charon
+ */
+struct daemon_t {
+ /**
+ * A socket_t instance.
+ */
+ socket_t *socket;
+
+ /**
+ * 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;
+
+ /**
+ * The signaling bus.
+ */
+ bus_t *bus;
+
+ /**
+ * A bus listener logging to stdout
+ */
+ file_logger_t *outlog;
+
+ /**
+ * A bus listener logging to syslog
+ */
+ sys_logger_t *syslog;
+
+ /**
+ * A bus listener logging most important events
+ */
+ sys_logger_t *authlog;
+
+ /**
+ * 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/src/charon/encoding/generator.c b/src/charon/encoding/generator.c
new file mode 100644
index 000000000..efa845bb3
--- /dev/null
+++ b/src/charon/encoding/generator.c
@@ -0,0 +1,1063 @@
+/**
+ * @file generator.c
+ *
+ * @brief Implementation of generator_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <library.h>
+#include <daemon.h>
+#include <utils/linked_list.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;
+};
+
+/**
+ * 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:
+ DBG1(DBG_ENC, "U_INT Type %N is not supported",
+ encoding_type_names, int_type);
+
+ return;
+ }
+ /* U_INT Types of multiple then 8 bits must be aligned */
+ if (((number_of_bits % 8) == 0) && (this->current_bit != 0))
+ {
+ DBG1(DBG_ENC, "U_INT Type %N is not 8 Bit aligned",
+ encoding_type_names, 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;
+ DBG3(DBG_ENC, " => %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;
+ DBG3(DBG_ENC, " => %d", *(this->out_position));
+ this->out_position++;
+ this->current_bit = 0;
+
+ }
+ else
+ {
+ DBG1(DBG_ENC, "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));
+ DBG3(DBG_ENC, " => %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)
+ {
+ DBG1(DBG_ENC, "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 = *((u_int16_t*)(this->data_struct + offset));
+ /* unset most significant bit */
+ int16_val &= 0x7FFF;
+ if (attribute_format_flag)
+ {
+ int16_val |= 0x8000;
+ }
+ int16_val = htons(int16_val);
+ DBG3(DBG_ENC, " => %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)));
+ DBG3(DBG_ENC, " => %b", (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)));
+ DBG3(DBG_ENC, " => %b", (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));
+ DBG3(DBG_ENC, " => %b %b",
+ (void*)&int32_val_low, sizeof(int32_val_low),
+ (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));
+ DBG3(DBG_ENC, " => %b", (void*)(this->data_struct + offset), sizeof(u_int64_t));
+ break;
+ }
+ default:
+ {
+ DBG1(DBG_ENC, "U_INT Type %N is not supported",
+ encoding_type_names, 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))
+ {
+ DBG1(DBG_ENC, "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)
+ {
+ DBG1(DBG_ENC, "reserved field cannot be written cause "
+ "alignement 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;
+
+
+ DBG3(DBG_ENC, " => %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)
+ {
+ DBG1(DBG_ENC, "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);
+
+ DBG3(DBG_ENC, " => %B", 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));
+
+ DBG2(DBG_ENC, "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;
+
+ DBG3(DBG_ENC, "generated data of this generator %B", 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;
+
+ DBG2(DBG_ENC, "generating payload of type %N",
+ payload_type_names, payload_type);
+
+ /* each payload has its own encoding rules */
+ payload->get_encoding_rules(payload,&rules,&rule_count);
+
+ for (i = 0; i < rule_count;i++)
+ {
+ DBG2(DBG_ENC, " generating rule %d %N",
+ i, encoding_type_names, 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_DATA:
+ {
+ 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_DATA:
+ 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;
+ payload_t *current_proposal;
+
+ /* create forward iterator */
+ iterator = proposals->create_iterator(proposals,TRUE);
+ /* every proposal is processed (iterative call )*/
+ while (iterator->iterate(iterator, (void**)&current_proposal))
+ {
+ u_int32_t before_generate_position_offset;
+ u_int32_t after_generate_position_offset;
+
+ 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;
+ payload_t *current_transform;
+
+ /* create forward iterator */
+ iterator = transforms->create_iterator(transforms,TRUE);
+ while (iterator->iterate(iterator, (void**)&current_transform))
+ {
+ u_int32_t before_generate_position_offset;
+ u_int32_t after_generate_position_offset;
+
+ 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;
+ payload_t *current_attribute;
+
+ /* create forward iterator */
+ iterator = transform_attributes->create_iterator(transform_attributes,TRUE);
+ while (iterator->iterate(iterator, (void**)&current_attribute))
+ {
+ u_int32_t before_generate_position_offset;
+ u_int32_t after_generate_position_offset;
+
+ 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;
+ payload_t *current_attribute;
+
+ /* create forward iterator */
+ iterator = configuration_attributes->create_iterator(configuration_attributes,TRUE);
+ while (iterator->iterate(iterator, (void**)&current_attribute))
+ {
+ u_int32_t before_generate_position_offset;
+ u_int32_t after_generate_position_offset;
+
+ 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)
+ {
+ DBG2(DBG_ENC, "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;
+ payload_t *current_traffic_selector_substructure;
+
+ /* create forward iterator */
+ iterator = traffic_selectors->create_iterator(traffic_selectors,TRUE);
+ /* every proposal is processed (iterative call )*/
+ while (iterator->iterate(iterator, (void **)&current_traffic_selector_substructure))
+ {
+ u_int32_t before_generate_position_offset;
+ u_int32_t after_generate_position_offset;
+
+ 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:
+ DBG1(DBG_ENC, "field type %N is not supported",
+ encoding_type_names, rules[i].type);
+ return;
+ }
+ }
+ DBG2(DBG_ENC, "generating %N payload finished",
+ payload_type_names, payload_type);
+ DBG3(DBG_ENC, "generated data for this payload %b",
+ 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;
+
+ return &(this->public);
+}
diff --git a/src/charon/encoding/generator.h b/src/charon/encoding/generator.h
new file mode 100644
index 000000000..8eff957cc
--- /dev/null
+++ b/src/charon/encoding/generator.h
@@ -0,0 +1,102 @@
+/**
+ * @file generator.h
+ *
+ * @brief Interface of generator_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct generator_t generator_t;
+
+#include <library.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
+
+
+/**
+ * @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(void);
+
+#endif /*GENERATOR_H_*/
diff --git a/src/charon/encoding/message.c b/src/charon/encoding/message.c
new file mode 100644
index 000000000..5f3f91f8b
--- /dev/null
+++ b/src/charon/encoding/message.c
@@ -0,0 +1,1316 @@
+/**
+ * @file message.c
+ *
+ * @brief Implementation of message_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <printf.h>
+
+#include "message.h"
+
+#include <library.h>
+#include <daemon.h>
+#include <sa/ike_sa_id.h>
+#include <encoding/generator.h>
+#include <encoding/parser.h>
+#include <utils/linked_list.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 20
+
+
+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},
+ {VENDOR_ID,0,10,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},
+ {VENDOR_ID,0,10,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},
+ {EXTENSIBLE_AUTHENTICATION,0,1,TRUE,TRUE},
+ {AUTHENTICATION,0,1,TRUE,TRUE},
+ {ID_INITIATOR,1,1,TRUE,FALSE},
+ {CERTIFICATE,0,1,TRUE,FALSE},
+ {CERTIFICATE_REQUEST,0,1,TRUE,FALSE},
+ {ID_RESPONDER,0,1,TRUE,FALSE},
+ {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},
+ {VENDOR_ID,0,10,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},
+ {EXTENSIBLE_AUTHENTICATION,0,1,TRUE,TRUE},
+ {CERTIFICATE,0,1,TRUE,FALSE},
+ {ID_RESPONDER,0,1,TRUE,FALSE},
+ {AUTHENTICATION,0,1,TRUE,FALSE},
+ {SECURITY_ASSOCIATION,0,1,TRUE,FALSE},
+ {TRAFFIC_SELECTOR_INITIATOR,0,1,TRUE,FALSE},
+ {TRAFFIC_SELECTOR_RESPONDER,0,1,TRUE,FALSE},
+ {CONFIGURATION,0,1,TRUE,FALSE},
+ {VENDOR_ID,0,10,TRUE,FALSE},
+};
+
+
+/**
+ * Message rule for INFORMATIONAL from initiator.
+ */
+static payload_rule_t informational_i_payload_rules[] = {
+ {NOTIFY,0,MAX_NOTIFY_PAYLOADS,TRUE,FALSE},
+ {CONFIGURATION,0,1,TRUE,FALSE},
+ {DELETE,0,1,TRUE,FALSE},
+ {VENDOR_ID,0,10,TRUE,FALSE},
+
+};
+
+/**
+ * Message rule for INFORMATIONAL from responder.
+ */
+static payload_rule_t informational_r_payload_rules[] = {
+ {NOTIFY,0,MAX_NOTIFY_PAYLOADS,TRUE,FALSE},
+ {CONFIGURATION,0,1,TRUE,FALSE},
+ {DELETE,0,1,TRUE,FALSE},
+ {VENDOR_ID,0,10,TRUE,FALSE},
+};
+
+/**
+ * Message rule for CREATE_CHILD_SA from initiator.
+ */
+static payload_rule_t create_child_sa_i_payload_rules[] = {
+ {NOTIFY,0,MAX_NOTIFY_PAYLOADS,TRUE,FALSE},
+ {SECURITY_ASSOCIATION,1,1,TRUE,FALSE},
+ {NONCE,1,1,TRUE,FALSE},
+ {KEY_EXCHANGE,0,1,TRUE,FALSE},
+ {TRAFFIC_SELECTOR_INITIATOR,0,1,TRUE,FALSE},
+ {TRAFFIC_SELECTOR_RESPONDER,0,1,TRUE,FALSE},
+ {CONFIGURATION,0,1,TRUE,FALSE},
+ {VENDOR_ID,0,10,TRUE,FALSE},
+};
+
+/**
+ * Message rule for CREATE_CHILD_SA from responder.
+ */
+static payload_rule_t create_child_sa_r_payload_rules[] = {
+ {NOTIFY,0,MAX_NOTIFY_PAYLOADS,TRUE,TRUE},
+ {SECURITY_ASSOCIATION,1,1,TRUE,FALSE},
+ {NONCE,1,1,TRUE,FALSE},
+ {KEY_EXCHANGE,0,1,TRUE,FALSE},
+ {TRAFFIC_SELECTOR_INITIATOR,0,1,TRUE,FALSE},
+ {TRAFFIC_SELECTOR_RESPONDER,0,1,TRUE,FALSE},
+ {CONFIGURATION,0,1,TRUE,FALSE},
+ {VENDOR_ID,0,10,TRUE,FALSE},
+};
+
+
+/**
+ * Message rules, defines allowed payloads.
+ */
+static message_rule_t message_rules[] = {
+ {IKE_SA_INIT,TRUE,FALSE,(sizeof(ike_sa_init_i_payload_rules)/sizeof(payload_rule_t)),ike_sa_init_i_payload_rules},
+ {IKE_SA_INIT,FALSE,FALSE,(sizeof(ike_sa_init_r_payload_rules)/sizeof(payload_rule_t)),ike_sa_init_r_payload_rules},
+ {IKE_AUTH,TRUE,TRUE,(sizeof(ike_auth_i_payload_rules)/sizeof(payload_rule_t)),ike_auth_i_payload_rules},
+ {IKE_AUTH,FALSE,TRUE,(sizeof(ike_auth_r_payload_rules)/sizeof(payload_rule_t)),ike_auth_r_payload_rules},
+ {INFORMATIONAL,TRUE,TRUE,(sizeof(informational_i_payload_rules)/sizeof(payload_rule_t)),informational_i_payload_rules},
+ {INFORMATIONAL,FALSE,TRUE,(sizeof(informational_r_payload_rules)/sizeof(payload_rule_t)),informational_r_payload_rules},
+ {CREATE_CHILD_SA,TRUE,TRUE,(sizeof(create_child_sa_i_payload_rules)/sizeof(payload_rule_t)),create_child_sa_i_payload_rules},
+ {CREATE_CHILD_SA,FALSE,TRUE,(sizeof(create_child_sa_r_payload_rules)/sizeof(payload_rule_t)),create_child_sa_r_payload_rules},
+};
+
+
+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;
+};
+
+/**
+ * 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)
+{
+ DESTROY_IF(this->ike_sa_id);
+ this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
+}
+
+/**
+ * Implementation of message_t.get_ike_sa_id.
+ */
+static ike_sa_id_t* get_ike_sa_id (private_message_t *this)
+{
+ return this->ike_sa_id;
+}
+
+/**
+ * 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_initiator_spi.
+ */
+static u_int64_t get_initiator_spi (private_message_t *this)
+{
+ return (this->ike_sa_id->get_initiator_spi(this->ike_sa_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;
+}
+
+/**
+ * Is this message in an encoded form?
+ */
+static bool is_encoded(private_message_t *this)
+{
+ chunk_t data = this->packet->get_data(this->packet);
+
+ if (data.ptr == NULL)
+ {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * Implementation of message_t.add_payload.
+ */
+static void add_payload(private_message_t *this, payload_t *payload)
+{
+ payload_t *last_payload, *first_payload;
+
+ if ((this->is_request && payload->get_type(payload) == ID_INITIATOR) ||
+ (!this->is_request && payload->get_type(payload) == ID_RESPONDER))
+ {
+ /* HOTD: insert ID payload in the beginning to respect RFC */
+ if (this->payloads->get_first(this->payloads,
+ (void **)&first_payload) == SUCCESS)
+ {
+ payload->set_next_type(payload, first_payload->get_type(first_payload));
+ }
+ else
+ {
+ payload->set_next_type(payload, NO_PAYLOAD);
+ }
+ this->first_payload = payload->get_type(payload);
+ this->payloads->insert_first(this->payloads, payload);
+ }
+ else
+ {
+ if (this->payloads->get_count(this->payloads) > 0)
+ {
+ this->payloads->get_last(this->payloads,(void **) &last_payload);
+ last_payload->set_next_type(last_payload, payload->get_type(payload));
+ }
+ else
+ {
+ this->first_payload = payload->get_type(payload);
+ }
+ payload->set_next_type(payload, NO_PAYLOAD);
+ this->payloads->insert_last(this->payloads, payload);
+ }
+
+ DBG2(DBG_ENC ,"added payload of type %N to message",
+ payload_type_names, payload->get_type(payload));
+}
+
+/**
+ * Implementation of message_t.add_notify.
+ */
+static void add_notify(private_message_t *this, bool flush, notify_type_t type,
+ chunk_t data)
+{
+ notify_payload_t *notify;
+ payload_t *payload;
+
+ if (flush)
+ {
+ while (this->payloads->remove_last(this->payloads,
+ (void**)&payload) == SUCCESS)
+ {
+ payload->destroy(payload);
+ }
+ }
+ notify = notify_payload_create();
+ notify->set_notify_type(notify, type);
+ notify->set_notification_data(notify, data);
+ add_payload(this, (payload_t*)notify);
+}
+
+/**
+ * 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_payload_iterator.
+ */
+static iterator_t *get_payload_iterator(private_message_t *this)
+{
+ return this->payloads->create_iterator(this->payloads, TRUE);
+}
+
+/**
+ * Implementation of message_t.get_payload.
+ */
+static payload_t *get_payload(private_message_t *this, payload_type_t type)
+{
+ payload_t *current, *found = NULL;
+ iterator_t *iterator;
+
+ iterator = this->payloads->create_iterator(this->payloads, TRUE);
+ while (iterator->iterate(iterator, (void**)&current))
+ {
+ if (current->get_type(current) == type)
+ {
+ found = current;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ return found;
+}
+
+/**
+ * output handler in printf()
+ */
+static int print(FILE *stream, const struct printf_info *info,
+ const void *const *args)
+{
+ private_message_t *this = *((private_message_t**)(args[0]));
+ iterator_t *iterator;
+ payload_t *payload;
+ bool first = TRUE;
+ size_t total_written = 0;
+ size_t written;
+
+ if (this == NULL)
+ {
+ return fprintf(stream, "(null)");
+ }
+
+ written = fprintf(stream, "%N %s [",
+ exchange_type_names, this->exchange_type,
+ this->is_request ? "request" : "response");
+ if (written < 0)
+ {
+ return written;
+ }
+ total_written += written;
+
+ iterator = this->payloads->create_iterator(this->payloads, TRUE);
+ while (iterator->iterate(iterator, (void**)&payload))
+ {
+ if (!first)
+ {
+ written = fprintf(stream, " ");
+ if (written < 0)
+ {
+ return written;
+ }
+ total_written += written;
+ }
+ else
+ {
+ first = FALSE;
+ }
+ written = fprintf(stream, "%N", payload_type_short_names,
+ payload->get_type(payload));
+ if (written < 0)
+ {
+ return written;
+ }
+ total_written += written;
+ }
+ iterator->destroy(iterator);
+ written = fprintf(stream, "]");
+ if (written < 0)
+ {
+ return written;
+ }
+ total_written += written;
+ return total_written;
+}
+
+/**
+ * register printf() handlers
+ */
+static void __attribute__ ((constructor))print_register()
+{
+ register_printf_function(PRINTF_MESSAGE, print, arginfo_ptr);
+}
+
+/**
+ * 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)
+ {
+ DBG2(DBG_ENC, "message doesn't have to be encrypted");
+ /* message contains no content to encrypt */
+ return SUCCESS;
+ }
+
+ DBG2(DBG_ENC, "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();
+
+ DBG2(DBG_ENC, "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);
+
+ status = 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))
+ {
+ DBG2(DBG_ENC, "payload %N gets encrypted",
+ payload_type_names, current_payload->get_type(current_payload));
+ to_encrypt = TRUE;
+ }
+
+ if (to_encrypt)
+ {
+ DBG2(DBG_ENC, "insert payload %N to encryption payload",
+ payload_type_names, current_payload->get_type(current_payload));
+ encryption_payload->add_payload(encryption_payload,current_payload);
+ }
+ else
+ {
+ DBG2(DBG_ENC, "insert payload %N unencrypted",
+ payload_type_names ,current_payload->get_type(current_payload));
+ add_payload(this, (payload_t*)encryption_payload);
+ }
+ }
+
+ status = SUCCESS;
+ DBG2(DBG_ENC, "encrypting encryption payload");
+ encryption_payload->set_transforms(encryption_payload, crypter,signer);
+ status = encryption_payload->encrypt(encryption_payload);
+ DBG2(DBG_ENC, "add encrypted payload to payload list");
+ add_payload(this, (payload_t*)encryption_payload);
+
+ all_payloads->destroy(all_payloads);
+
+ return status;
+}
+
+/**
+ * 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;
+
+ if (is_encoded(this))
+ {
+ /* already generated, return a new packet clone */
+ *packet = this->packet->clone(this->packet);
+ return SUCCESS;
+ }
+
+ DBG1(DBG_ENC, "generating %M", this);
+
+ if (this->exchange_type == EXCHANGE_TYPE_UNDEFINED)
+ {
+ DBG1(DBG_ENC, "exchange type is not defined");
+ return INVALID_STATE;
+ }
+
+ if (this->packet->get_source(this->packet) == NULL ||
+ this->packet->get_destination(this->packet) == NULL)
+ {
+ DBG1(DBG_ENC, "%s not defined",
+ !this->packet->get_source(this->packet) ? "source" : "destination");
+ return INVALID_STATE;
+ }
+
+ /* set the rules for this messge */
+ status = set_message_rule(this);
+ if (status != SUCCESS)
+ {
+ DBG1(DBG_ENC, "no message rules specified for this message type");
+ return NOT_SUPPORTED;
+ }
+
+ /* going to encrypt all content which have to be encrypted */
+ status = encrypt_payloads(this, crypter, signer);
+ if (status != SUCCESS)
+ {
+ DBG1(DBG_ENC, "payload encryption failed");
+ 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->iterate(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)
+ {
+ DBG2(DBG_ENC, "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);
+
+ DBG2(DBG_ENC, "message generated successfully");
+ return SUCCESS;
+}
+
+/**
+ * Implementation of message_t.get_packet.
+ */
+static packet_t *get_packet (private_message_t *this)
+{
+ if (this->packet == NULL)
+ {
+ return NULL;
+ }
+ return this->packet->clone(this->packet);
+}
+
+/**
+ * Implementation of message_t.get_packet_data.
+ */
+static chunk_t get_packet_data (private_message_t *this)
+{
+ if (this->packet == NULL)
+ {
+ return chunk_empty;
+ }
+ 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;
+
+ DBG2(DBG_ENC, "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)
+ {
+ DBG1(DBG_ENC, "header could not be parsed");
+ return status;
+
+ }
+
+ /* verify payload */
+ status = ike_header->payload_interface.verify(&(ike_header->payload_interface));
+ if (status != SUCCESS)
+ {
+ DBG1(DBG_ENC, "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));
+
+ DBG2(DBG_ENC, "parsed a %N %s", exchange_type_names, this->exchange_type,
+ this->is_request ? "request" : "response");
+
+ ike_header->destroy(ike_header);
+
+ /* get the rules for this messge */
+ status = set_message_rule(this);
+ if (status != SUCCESS)
+ {
+ DBG1(DBG_ENC, "no message rules specified for a %N %s",
+ exchange_type_names, this->exchange_type,
+ this->is_request ? "request" : "response");
+ }
+
+ return status;
+}
+
+/**
+ * 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;
+ payload_t *current_payload;
+ status_t status;
+
+ iterator = this->payloads->create_iterator(this->payloads,TRUE);
+
+ /* process each payload and decrypt a encryption payload */
+ while(iterator->iterate(iterator, (void**)&current_payload))
+ {
+ payload_rule_t *payload_rule;
+ payload_type_t current_payload_type;
+
+ /* needed to check */
+ current_payload_type = current_payload->get_type(current_payload);
+
+ DBG2(DBG_ENC, "process payload of type %N",
+ payload_type_names, 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;
+
+ DBG2(DBG_ENC, "found an encryption payload");
+
+ if (payload_number != this->payloads->get_count(this->payloads))
+ {
+ /* encrypted payload is not last one */
+ DBG1(DBG_ENC, "encrypted payload is not last payload");
+ iterator->destroy(iterator);
+ return VERIFY_ERROR;
+ }
+ /* decrypt */
+ encryption_payload->set_transforms(encryption_payload, crypter, signer);
+ DBG2(DBG_ENC, "verify signature of encryption payload");
+ status = encryption_payload->verify_signature(encryption_payload,
+ this->packet->get_data(this->packet));
+ if (status != SUCCESS)
+ {
+ DBG1(DBG_ENC, "encryption payload signature invalid");
+ iterator->destroy(iterator);
+ return FAILED;
+ }
+ DBG2(DBG_ENC, "decrypting content of encryption payload");
+ status = encryption_payload->decrypt(encryption_payload);
+ if (status != SUCCESS)
+ {
+ DBG1(DBG_ENC, "encrypted payload could not be decrypted and parsed");
+ iterator->destroy(iterator);
+ return PARSE_ERROR;
+ }
+
+ /* 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)
+ {
+ DBG2(DBG_ENC, "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);
+ DBG2(DBG_ENC, "insert unencrypted payload of type %N at end of list",
+ payload_type_names, 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 && current_payload_type != NO_PAYLOAD)
+ {
+ /* get the ruleset for found payload */
+ status = get_payload_rule(this, current_payload_type, &payload_rule);
+ if (status != SUCCESS)
+ {
+ /* payload is not allowed */
+ DBG1(DBG_ENC, "payload type %N not allowed",
+ payload_type_names, current_payload_type);
+ iterator->destroy(iterator);
+ return VERIFY_ERROR;
+ }
+
+ /* 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 */
+ DBG1(DBG_ENC, "payload type %N should be %s!",
+ payload_type_names, current_payload_type,
+ (payload_rule->encrypted) ? "encrypted" : "not encrypted");
+ iterator->destroy(iterator);
+ return VERIFY_ERROR;
+ }
+ }
+ /* 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.verify.
+ */
+static status_t verify(private_message_t *this)
+{
+ int i;
+ iterator_t *iterator;
+ payload_t *current_payload;
+ size_t total_found_payloads = 0;
+
+ DBG2(DBG_ENC, "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->iterate(iterator,(void **)&current_payload))
+ {
+ payload_type_t current_payload_type;
+
+ 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))
+ {
+ DBG1(DBG_ENC, "%N is not supported, but its critical!",
+ payload_type_names, 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++;
+ DBG2(DBG_ENC, "found payload of type %N",
+ payload_type_names, 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)
+ {
+ DBG1(DBG_ENC, "payload of type %N more than %d times (%d) occured in current message",
+ payload_type_names, current_payload_type,
+ this->message_rule->payload_rules[i].max_occurence, found_payloads);
+ iterator->destroy(iterator);
+ return VERIFY_ERROR;
+ }
+ }
+ }
+
+ if (found_payloads < this->message_rule->payload_rules[i].min_occurence)
+ {
+ DBG1(DBG_ENC, "payload of type %N not occured %d times (%d)",
+ payload_type_names, this->message_rule->payload_rules[i].payload_type,
+ this->message_rule->payload_rules[i].min_occurence, found_payloads);
+ iterator->destroy(iterator);
+ return VERIFY_ERROR;
+ }
+ 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 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;
+
+ DBG2(DBG_ENC, "parsing body of message, first payload is %N",
+ payload_type_names, current_payload_type);
+
+ /* parse payload for payload, while there are more available */
+ while ((current_payload_type != NO_PAYLOAD))
+ {
+ payload_t *current_payload;
+
+ DBG2(DBG_ENC, "starting parsing a %N payload",
+ payload_type_names, current_payload_type);
+
+ /* parse current payload */
+ status = this->parser->parse_payload(this->parser,current_payload_type,(payload_t **) &current_payload);
+
+ if (status != SUCCESS)
+ {
+ DBG1(DBG_ENC, "payload type %N could not be parsed",
+ payload_type_names, current_payload_type);
+ return PARSE_ERROR;
+ }
+
+ DBG2(DBG_ENC, "verifying payload of type %N",
+ payload_type_names, current_payload_type);
+
+ /* verify it, stop parsig if its invalid */
+ status = current_payload->verify(current_payload);
+ if (status != SUCCESS)
+ {
+ DBG1(DBG_ENC, "%N payload verification failed",
+ payload_type_names, current_payload_type);
+ current_payload->destroy(current_payload);
+ return VERIFY_ERROR;
+ }
+
+ DBG2(DBG_ENC, "%N payload verified. Adding to payload list",
+ payload_type_names, 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)
+ {
+ DBG2(DBG_ENC, "%N payload found. Stop parsing",
+ payload_type_names, current_payload_type);
+ break;
+ }
+
+ /* get next payload type */
+ current_payload_type = current_payload->get_next_type(current_payload);
+ }
+
+ if (current_payload_type == ENCRYPTED)
+ {
+ status = decrypt_payloads(this,crypter,signer);
+ if (status != SUCCESS)
+ {
+ DBG1(DBG_ENC, "could not decrypt payloads");
+ return status;
+ }
+ }
+
+ status = verify(this);
+ if (status != SUCCESS)
+ {
+ return status;
+ }
+
+ DBG1(DBG_ENC, "parsed %M", this);
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of message_t.destroy.
+ */
+static void destroy (private_message_t *this)
+{
+ DESTROY_IF(this->ike_sa_id);
+ this->payloads->destroy_offset(this->payloads, offsetof(payload_t, destroy));
+ this->packet->destroy(this->packet);
+ 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_initiator_spi = (u_int64_t(*)(message_t*))get_initiator_spi;
+ 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 = (ike_sa_id_t*(*)(message_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.add_notify = (void(*)(message_t*,bool,notify_type_t,chunk_t))add_notify;
+ 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.get_payload = (payload_t * (*) (message_t *, payload_type_t)) get_payload;
+ 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 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));
+
+ return (&this->public);
+}
+
+/*
+ * Described in Header.
+ */
+message_t *message_create()
+{
+ return message_create_from_packet(NULL);
+}
diff --git a/src/charon/encoding/message.h b/src/charon/encoding/message.h
new file mode 100644
index 000000000..73c2e05c6
--- /dev/null
+++ b/src/charon/encoding/message.h
@@ -0,0 +1,390 @@
+/**
+ * @file message.h
+ *
+ * @brief Interface of message_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct message_t message_t;
+
+#include <library.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>
+
+/**
+ * @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 initiator SPI of the message.
+ *
+ * @param this message_t object
+ * @return initiator spi of the message
+ */
+ u_int64_t (*get_initiator_spi) (message_t *this);
+
+ /**
+ * @brief Gets the responder SPI of the message.
+ *
+ * @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.
+ *
+ * ike_sa_id gets cloned.
+ *
+ * @param this message_t object
+ * @param ike_sa_id ike_sa_id to set
+ */
+ void (*set_ike_sa_id) (message_t *this, ike_sa_id_t * ike_sa_id);
+
+ /**
+ * @brief Gets the IKE_SA ID of the message.
+ *
+ * The ike_sa_id points to the message internal id, do not modify.
+ *
+ * @param this message_t object
+ * @return ike_sa_id of message
+ */
+ ike_sa_id_t *(*get_ike_sa_id) (message_t *this);
+
+ /**
+ * @brief Sets the exchange type of the message.
+ *
+ * @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 Build a notify payload and add it to the message.
+ *
+ * This is a helper method to create notify messages or add
+ * notify payload to messages. The flush parameter specifies if existing
+ * payloads should get removed before appending the notify.
+ *
+ * @param this message_t object
+ * @param flush TRUE to remove existing payloads
+ * @param type type of the notify
+ * @param data a chunk of data to add to the notify, gets cloned
+ */
+ void (*add_notify) (message_t *this, bool flush, notify_type_t type,
+ chunk_t data);
+
+ /**
+ * @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 parsing successful
+ * - NOT_SUPPORTED if ciritcal unknown payloads found
+ * - NOT_SUPPORTED if message type is not supported!
+ * - PARSE_ERROR if message parsing failed
+ * - VERIFY_ERROR if message verification failed (bad syntax)
+ * - FAILED if integrity check 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.
+ * Generation is only done once, multiple calls will just return a packet copy.
+ *
+ * @param this message_t object
+ * @param crypter crypter to use when a payload must be encrypted
+ * @param signer signer to build a mac
+ * @param packet copy of generated packet
+ * @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);
+
+ /**
+ * @brief Find a payload of a spicific type.
+ *
+ * Returns the first occurance.
+ *
+ * @param this message_t object
+ * @param type type of the payload to find
+ * @return payload, or NULL if no such payload found
+ */
+ payload_t* (*get_payload) (message_t *this, payload_type_t type);
+
+ /**
+ * @brief Returns a clone of the internal stored packet_t object.
+ *
+ * @param this message_t object
+ * @return packet_t object as clone of internal one
+ */
+ packet_t * (*get_packet) (message_t *this);
+
+ /**
+ * @brief Returns a clone of the internal stored packet_t data.
+ *
+ * @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(void);
+
+#endif /*MESSAGE_H_*/
diff --git a/src/charon/encoding/parser.c b/src/charon/encoding/parser.c
new file mode 100644
index 000000000..d7caf7099
--- /dev/null
+++ b/src/charon/encoding/parser.c
@@ -0,0 +1,1048 @@
+/**
+ * @file parser.c
+ *
+ * @brief Implementation of parser_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <library.h>
+#include <daemon.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 recursively 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;
+};
+
+/**
+ * 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)
+ {
+ DBG1(DBG_ENC, " not enough input to parse rule %d %N",
+ rule_number, encoding_type_names, 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:
+ DBG2(DBG_ENC, " found rule %d %N on bitpos %d",
+ rule_number, encoding_type_names,
+ this->rules[rule_number].type, this->bit_pos);
+ return PARSE_ERROR;
+ }
+
+ if (output_pos != NULL)
+ {
+ DBG3(DBG_ENC, " => %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)
+ {
+ DBG1(DBG_ENC, " not enough input to parse rule %d %N",
+ rule_number, encoding_type_names, this->rules[rule_number].type);
+ return PARSE_ERROR;
+ }
+ if (this->bit_pos)
+ {
+ DBG1(DBG_ENC, " found rule %d %N on bitpos %d",
+ rule_number, encoding_type_names,
+ this->rules[rule_number].type, this->bit_pos);
+ return PARSE_ERROR;
+ }
+
+ /* caller interested in result ? */
+ if (output_pos != NULL)
+ {
+ *output_pos = *(this->byte_pos);
+ DBG3(DBG_ENC, " => %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)
+ {
+ DBG1(DBG_ENC, " not enough input to parse rule %d %N",
+ rule_number, encoding_type_names, this->rules[rule_number].type);
+ return PARSE_ERROR;
+ }
+ if (this->bit_pos != 1)
+ {
+ DBG2(DBG_ENC, " found rule %d %N on bitpos %d", rule_number,
+ encoding_type_names, 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;
+ DBG3(DBG_ENC, " => %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)
+ {
+ DBG1(DBG_ENC, " not enough input to parse rule %d %N",
+ rule_number, encoding_type_names, this->rules[rule_number].type);
+ return PARSE_ERROR;
+ }
+ if (this->bit_pos)
+ {
+ DBG1(DBG_ENC, " found rule %d %N on bitpos %d", rule_number,
+ encoding_type_names, 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));
+
+ DBG3(DBG_ENC, " => %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)
+ {
+ DBG1(DBG_ENC, " not enough input to parse rule %d %N",
+ rule_number, encoding_type_names, this->rules[rule_number].type);
+ return PARSE_ERROR;
+ }
+ if (this->bit_pos)
+ {
+ DBG1(DBG_ENC, " found rule %d %N on bitpos %d", rule_number,
+ encoding_type_names, 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));
+
+ DBG3(DBG_ENC, " => %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)
+ {
+ DBG1(DBG_ENC, " not enough input to parse rule %d %N",
+ rule_number, encoding_type_names, this->rules[rule_number].type);
+ return PARSE_ERROR;
+ }
+ if (this->bit_pos)
+ {
+ DBG1(DBG_ENC, " found rule %d %N on bitpos %d", rule_number,
+ encoding_type_names, 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));
+
+ DBG3(DBG_ENC, " => %b", (void*)output_pos, sizeof(u_int64_t));
+ }
+ 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)
+ {
+ DBG1(DBG_ENC, " not enough input to parse rule %d %N",
+ rule_number, encoding_type_names, this->rules[rule_number].type);
+ return PARSE_ERROR;
+ }
+ if (this->bit_pos)
+ {
+ DBG1(DBG_ENC, " found rule %d %N on bitpos %d", rule_number,
+ encoding_type_names, 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);
+
+ DBG3(DBG_ENC, " => %b", (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)
+ {
+ DBG1(DBG_ENC, " not enough input to parse rule %d %N",
+ rule_number, encoding_type_names, 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;
+ }
+
+ DBG3(DBG_ENC, " => %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)
+ {
+ DBG1(DBG_ENC, " invalid length for rule %d %N",
+ rule_number, encoding_type_names, this->rules[rule_number].type);
+ return PARSE_ERROR;
+ }
+
+ if (this->bit_pos)
+ {
+ DBG1(DBG_ENC, " found rule %d %N on bitpos %d", rule_number,
+ encoding_type_names, 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;
+ DBG2(DBG_ENC, " %d bytes left, parsing recursively %N",
+ length, payload_type_names, payload_type);
+ status = this->public.parse_payload((parser_t*)this, payload_type, &payload);
+ if (status != SUCCESS)
+ {
+ DBG1(DBG_ENC, " parsing of a %N substructure failed",
+ payload_type_names, 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)
+ {
+ DBG1(DBG_ENC, " not enough input (%d bytes) to parse rule %d %N",
+ length, rule_number, encoding_type_names, this->rules[rule_number].type);
+ return PARSE_ERROR;
+ }
+ if (this->bit_pos)
+ {
+ DBG1(DBG_ENC, " found rule %d %N on bitpos %d", rule_number,
+ encoding_type_names, 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;
+ DBG3(DBG_ENC, " => %b", (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 = 0, spi_size = 0, attribute_length = 0;
+ u_int16_t ts_type = 0;
+ bool attribute_format = FALSE;
+ int rule_number;
+ encoding_rule_t *rule;
+
+ /* create instance of the payload to parse */
+ pld = payload_create(payload_type);
+
+ DBG2(DBG_ENC, "parsing %N payload, %d bytes left",
+ payload_type_names, payload_type, this->input_roof - this->byte_pos);
+
+ DBG3(DBG_ENC, "parsing payload from %b",
+ this->byte_pos, this->input_roof-this->byte_pos);
+
+ if (pld->get_type(pld) == UNKNOWN_PAYLOAD)
+ {
+ DBG1(DBG_ENC, " payload type %d is unknown, handling as %N",
+ payload_type, payload_type_names, 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]);
+ DBG2(DBG_ENC, " parsing rule %d %N",
+ rule_number, encoding_type_names, 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_DATA:
+ {
+ 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:
+ {
+ DBG1(DBG_ENC, " no rule to parse rule %d %N",
+ rule_number, encoding_type_names, rule->type);
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ }
+ /* process next rulue */
+ rule++;
+ }
+
+ *payload = pld;
+ DBG2(DBG_ENC, "parsing %N payload finished",
+ payload_type_names, 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->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/src/charon/encoding/parser.h b/src/charon/encoding/parser.h
new file mode 100644
index 000000000..e9978524c
--- /dev/null
+++ b/src/charon/encoding/parser.h
@@ -0,0 +1,95 @@
+/**
+ * @file parser.h
+ *
+ * @brief Interface of parser_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct parser_t parser_t;
+
+#include <library.h>
+#include <encoding/payloads/encodings.h>
+#include <encoding/payloads/payload.h>
+
+/**
+ * @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/src/charon/encoding/payloads/auth_payload.c b/src/charon/encoding/payloads/auth_payload.c
new file mode 100644
index 000000000..256d6c8a4
--- /dev/null
+++ b/src/charon/encoding/payloads/auth_payload.c
@@ -0,0 +1,265 @@
+/**
+ * @file auth_payload.h
+ *
+ * @brief Implementation of auth_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_empty;
+
+ return (&(this->public));
+}
diff --git a/src/charon/encoding/payloads/auth_payload.h b/src/charon/encoding/payloads/auth_payload.h
new file mode 100644
index 000000000..2db82ec0b
--- /dev/null
+++ b/src/charon/encoding/payloads/auth_payload.h
@@ -0,0 +1,121 @@
+/**
+ * @file auth_payload.h
+ *
+ * @brief Interface of auth_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct auth_payload_t auth_payload_t;
+
+#include <library.h>
+#include <encoding/payloads/payload.h>
+#include <sa/authenticators/authenticator.h>
+
+/**
+ * Length of a auth payload without the auth data in bytes.
+ *
+ * @ingroup payloads
+ */
+#define AUTH_PAYLOAD_HEADER_LENGTH 8
+
+/**
+ * @brief Class representing an IKEv2 AUTH payload.
+ *
+ * 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(void);
+
+
+#endif /* AUTH_PAYLOAD_H_ */
diff --git a/src/charon/encoding/payloads/cert_payload.c b/src/charon/encoding/payloads/cert_payload.c
new file mode 100644
index 000000000..c456f4936
--- /dev/null
+++ b/src/charon/encoding/payloads/cert_payload.c
@@ -0,0 +1,290 @@
+/**
+ * @file cert_payload.c
+ *
+ * @brief Implementation of cert_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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"
+
+
+ENUM(cert_encoding_names, CERT_NONE, CERT_OCSP_CONTENT,
+ "CERT_NONE",
+ "CERT_PKCS7_WRAPPED_X509",
+ "CERT_PGP",
+ "CERT_DNS_SIGNED_KEY",
+ "CERT_X509_SIGNATURE",
+ "CERT_X509_KEY_EXCHANGE",
+ "CERT_KERBEROS_TOKENS",
+ "CERT_CRL",
+ "CERT_ARL",
+ "CERT_SPKI",
+ "CERT_X509_ATTRIBUTE",
+ "CERT_RAW_RSA_KEY",
+ "CERT_X509_HASH_AND_URL",
+ "CERT_X509_HASH_AND_URL_BUNDLE",
+ "CERT_OCSP_CONTENT",
+);
+
+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 >= CERT_ROOF) && (this->cert_encoding <= 200)))
+ {
+ /* reserved IDs */
+ return FAILED;
+ }
+ return SUCCESS;
+}
+
+/**
+ * Implementation of cert_payload_t.get_encoding_rules.
+ */
+static void get_encoding_rules(private_cert_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
+{
+ *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_empty;
+
+ return (&(this->public));
+}
+
+/*
+ * Described in header
+ */
+cert_payload_t *cert_payload_create_from_x509(x509_t *cert)
+{
+ cert_payload_t *this = cert_payload_create();
+
+ this->set_cert_encoding(this, CERT_X509_SIGNATURE);
+ this->set_data(this, cert->get_certificate(cert));
+ return this;
+}
diff --git a/src/charon/encoding/payloads/cert_payload.h b/src/charon/encoding/payloads/cert_payload.h
new file mode 100644
index 000000000..bcb961398
--- /dev/null
+++ b/src/charon/encoding/payloads/cert_payload.h
@@ -0,0 +1,166 @@
+/**
+ * @file cert_payload.h
+ *
+ * @brief Interface of cert_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef enum cert_encoding_t cert_encoding_t;
+typedef struct cert_payload_t cert_payload_t;
+
+#include <library.h>
+#include <crypto/x509.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
+
+/**
+ * @brief Certificate encoding, as described in IKEv2 RFC section 3.6
+ *
+ * @ingroup payloads
+ */
+enum cert_encoding_t {
+ CERT_NONE = 0,
+ CERT_PKCS7_WRAPPED_X509 = 1,
+ CERT_PGP = 2,
+ CERT_DNS_SIGNED_KEY = 3,
+ CERT_X509_SIGNATURE = 4,
+ CERT_KERBEROS_TOKEN = 6,
+ CERT_CRL = 7,
+ CERT_ARL = 8,
+ CERT_SPKI = 9,
+ CERT_X509_ATTRIBUTE = 10,
+ CERT_RAW_RSA_KEY = 11,
+ CERT_X509_HASH_AND_URL = 12,
+ CERT_X509_HASH_AND_URL_BUNDLE = 13,
+ CERT_OCSP_CONTENT = 14, /* from RFC 4806 */
+ CERT_ROOF = 15
+};
+
+/**
+ * string mappings for cert_encoding_t.
+ *
+ * @ingroup payloads
+ */
+extern enum_name_t *cert_encoding_names;
+
+/**
+ * @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(void);
+
+/**
+ * @brief Creates a cert_payload_t object with an X.509 certificate.
+ *
+ * @param cert X.509 certificate
+ * @return cert_payload_t object
+ *
+ * @ingroup payloads
+ */
+cert_payload_t *cert_payload_create_from_x509(x509_t *cert);
+
+#endif /* CERT_PAYLOAD_H_ */
diff --git a/src/charon/encoding/payloads/certreq_payload.c b/src/charon/encoding/payloads/certreq_payload.c
new file mode 100644
index 000000000..46663811a
--- /dev/null
+++ b/src/charon/encoding/payloads/certreq_payload.c
@@ -0,0 +1,335 @@
+/**
+ * @file certreq_payload.c
+ *
+ * @brief Implementation of certreq_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <daemon.h>
+#include <crypto/hashers/hasher.h>
+#include <crypto/ca.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 >= CERT_ROOF) && (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_empty;
+
+ return (&(this->public));
+}
+
+/*
+ * Described in header
+ */
+certreq_payload_t *certreq_payload_create_from_cacert(identification_t *id)
+{
+ x509_t *cacert;
+ rsa_public_key_t *pubkey;
+ chunk_t keyid;
+ certreq_payload_t *this;
+
+ cacert = charon->credentials->get_auth_certificate(charon->credentials, AUTH_CA, id);
+ if (cacert == NULL)
+ {
+ /* no such CA cert */
+ return NULL;
+ }
+
+ this = certreq_payload_create();
+ pubkey = cacert->get_public_key(cacert);
+ keyid = pubkey->get_keyid(pubkey);
+
+ DBG2(DBG_IKE, "requesting certificate issued by '%D'", id);
+ DBG2(DBG_IKE, " with keyid %#B", &keyid);
+
+ this->set_cert_encoding(this, CERT_X509_SIGNATURE);
+ this->set_data(this, keyid);
+ return this;
+}
+
+/*
+ * Described in header
+ */
+certreq_payload_t *certreq_payload_create_from_cacerts(void)
+{
+ certreq_payload_t *this;
+ chunk_t keyids;
+ u_char *pos;
+ ca_info_t *cainfo;
+
+ iterator_t *iterator = charon->credentials->create_cainfo_iterator(charon->credentials);
+ int count = iterator->get_count(iterator);
+
+ if (count == 0)
+ {
+ iterator->destroy(iterator);
+ return NULL;
+ }
+
+ this = certreq_payload_create();
+ keyids = chunk_alloc(count * HASH_SIZE_SHA1);
+ pos = keyids.ptr;
+
+ while (iterator->iterate(iterator, (void**)&cainfo))
+ {
+ x509_t *cacert = cainfo->get_certificate(cainfo);
+ chunk_t keyid = cacert->get_keyid(cacert);
+
+ DBG2(DBG_IKE, "requesting certificate issued by '%D'", cacert->get_subject(cacert));
+ DBG2(DBG_IKE, " with keyid %#B", &keyid);
+ memcpy(pos, keyid.ptr, keyid.len);
+ pos += HASH_SIZE_SHA1;
+ }
+ iterator->destroy(iterator);
+
+ this->set_cert_encoding(this, CERT_X509_SIGNATURE);
+ this->set_data(this, keyids);
+ free(keyids.ptr);
+ return this;
+}
diff --git a/src/charon/encoding/payloads/certreq_payload.h b/src/charon/encoding/payloads/certreq_payload.h
new file mode 100644
index 000000000..2985fdae1
--- /dev/null
+++ b/src/charon/encoding/payloads/certreq_payload.h
@@ -0,0 +1,144 @@
+/**
+ * @file certreq_payload.h
+ *
+ * @brief Interface of certreq_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct certreq_payload_t certreq_payload_t;
+
+#include <library.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
+
+
+/**
+ * @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(void);
+
+/**
+ * @brief Creates a certreq_payload_t object from a ca certificate
+ *
+ * @param id subject distinguished name of CA certificate
+ * @return certreq_payload_t object
+ *
+ * @ingroup payloads
+ */
+certreq_payload_t *certreq_payload_create_from_cacert(identification_t *id);
+
+/**
+ * @brief Creates a certreq_payload_t object from all ca certificates
+ *
+ * @return certreq_payload_t object
+ *
+ * @ingroup payloads
+ */
+certreq_payload_t *certreq_payload_create_from_cacerts(void);
+
+#endif /* CERTREQ_PAYLOAD_H_ */
diff --git a/src/charon/encoding/payloads/configuration_attribute.c b/src/charon/encoding/payloads/configuration_attribute.c
new file mode 100644
index 000000000..0aa82169f
--- /dev/null
+++ b/src/charon/encoding/payloads/configuration_attribute.c
@@ -0,0 +1,313 @@
+/**
+ * @file configuration_attribute.c
+ *
+ * @brief Implementation of configuration_attribute_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <library.h>
+#include <daemon.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;
+};
+
+ENUM_BEGIN(configuration_attribute_type_names, INTERNAL_IP4_ADDRESS, INTERNAL_IP6_ADDRESS,
+ "INTERNAL_IP4_ADDRESS",
+ "INTERNAL_IP4_NETMASK",
+ "INTERNAL_IP4_DNS",
+ "INTERNAL_IP4_NBNS",
+ "INTERNAL_ADDRESS_EXPIRY",
+ "INTERNAL_IP4_DHCP",
+ "APPLICATION_VERSION",
+ "INTERNAL_IP6_ADDRESS");
+ENUM_NEXT(configuration_attribute_type_names, INTERNAL_IP6_DNS, INTERNAL_IP6_SUBNET, INTERNAL_IP6_ADDRESS,
+ "INTERNAL_IP6_DNS",
+ "INTERNAL_IP6_NBNS",
+ "INTERNAL_IP6_DHCP",
+ "INTERNAL_IP4_SUBNET",
+ "SUPPORTED_ATTRIBUTES",
+ "INTERNAL_IP6_SUBNET");
+ENUM_END(configuration_attribute_type_names, INTERNAL_IP6_SUBNET);
+
+/**
+ * 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)
+{
+ bool failed = FALSE;
+
+ if (this->attribute_length != this->attribute_value.len)
+ {
+ DBG1(DBG_ENC, "invalid attribute length");
+ return FAILED;
+ }
+
+ 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:
+ if (this->attribute_length != 0 && this->attribute_length != 4)
+ {
+ failed = TRUE;
+ }
+ break;
+ case INTERNAL_IP4_SUBNET:
+ if (this->attribute_length != 0 && this->attribute_length != 8)
+ {
+ failed = TRUE;
+ }
+ break;
+ case INTERNAL_IP6_ADDRESS:
+ case INTERNAL_IP6_SUBNET:
+ if (this->attribute_length != 0 && this->attribute_length != 17)
+ {
+ failed = TRUE;
+ }
+ break;
+ case INTERNAL_IP6_DNS:
+ case INTERNAL_IP6_NBNS:
+ case INTERNAL_IP6_DHCP:
+ if (this->attribute_length != 0 && this->attribute_length != 16)
+ {
+ failed = TRUE;
+ }
+ break;
+ case SUPPORTED_ATTRIBUTES:
+ if (this->attribute_length % 2)
+ {
+ failed = TRUE;
+ }
+ break;
+ case APPLICATION_VERSION:
+ /* any length acceptable */
+ break;
+ default:
+ DBG1(DBG_ENC, "unknown attribute type %N",
+ configuration_attribute_type_names, this->attribute_type);
+ return FAILED;
+ }
+
+ if (failed)
+ {
+ DBG1(DBG_ENC, "invalid attribute length %d for %N",
+ this->attribute_length, configuration_attribute_type_names,
+ this->attribute_type);
+ 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_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_type.
+ */
+static u_int16_t get_attribute_type (private_configuration_attribute_t *this)
+{
+ return this->attribute_type;
+}
+
+/**
+ * Implementation of configuration_attribute_t.get_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_type = (void (*) (configuration_attribute_t *,u_int16_t type)) set_attribute_type;
+ this->public.get_type = (u_int16_t (*) (configuration_attribute_t *)) get_attribute_type;
+ this->public.get_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_empty;
+ this->attribute_length = 0;
+
+ return (&(this->public));
+}
diff --git a/src/charon/encoding/payloads/configuration_attribute.h b/src/charon/encoding/payloads/configuration_attribute.h
new file mode 100644
index 000000000..5c4f65b14
--- /dev/null
+++ b/src/charon/encoding/payloads/configuration_attribute.h
@@ -0,0 +1,147 @@
+/**
+ * @file configuration_attribute.h
+ *
+ * @brief Interface of configuration_attribute_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef enum configuration_attribute_type_t configuration_attribute_type_t;
+typedef struct configuration_attribute_t configuration_attribute_t;
+
+#include <library.h>
+#include <encoding/payloads/payload.h>
+
+
+/**
+ * Configuration attribute header length in bytes.
+ *
+ * @ingroup payloads
+ */
+#define CONFIGURATION_ATTRIBUTE_HEADER_LENGTH 4
+
+/**
+ * Type of the attribute, as in IKEv2 RFC 3.15.1.
+ *
+ * @ingroup payloads
+ */
+enum configuration_attribute_type_t {
+ INTERNAL_IP4_ADDRESS = 1,
+ 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
+};
+
+/**
+ * enum names for configuration_attribute_type_t.
+ *
+ * @ingroup payloads
+ */
+extern enum_name_t *configuration_attribute_type_names;
+
+/**
+ * @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_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_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_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(void);
+
+#endif /* CONFIGURATION_ATTRIBUTE_H_*/
diff --git a/src/charon/encoding/payloads/cp_payload.c b/src/charon/encoding/payloads/cp_payload.c
new file mode 100644
index 000000000..380ed9681
--- /dev/null
+++ b/src/charon/encoding/payloads/cp_payload.c
@@ -0,0 +1,277 @@
+/**
+ * @file cp_payload.c
+ *
+ * @brief Implementation of cp_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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>
+
+ENUM(config_type_names, CFG_REQUEST, CFG_ACK,
+ "CFG_REQUEST",
+ "CFG_REPLY",
+ "CFG_SET",
+ "CFG_ACK",
+);
+
+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;
+};
+
+/**
+ * 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;
+ configuration_attribute_t *attribute;
+
+ iterator = this->attributes->create_iterator(this->attributes,TRUE);
+ while(iterator->iterate(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;
+}
+
+/**
+ * recompute the length of the payload.
+ */
+static void compute_length(private_cp_payload_t *this)
+{
+ iterator_t *iterator;
+ payload_t *current_attribute;
+ size_t length = CP_PAYLOAD_HEADER_LENGTH;
+
+ iterator = this->attributes->create_iterator(this->attributes,TRUE);
+ while (iterator->iterate(iterator, (void**)&current_attribute))
+ {
+ length += current_attribute->get_length(current_attribute);
+ }
+ iterator->destroy(iterator);
+
+ this->payload_length = length;
+}
+
+/**
+ * Implementation of payload_t.get_length.
+ */
+static size_t get_length(private_cp_payload_t *this)
+{
+ compute_length(this);
+ return this->payload_length;
+}
+
+/**
+ * Implementation of cp_payload_t.create_configuration_attribute_iterator.
+ */
+static iterator_t *create_attribute_iterator (private_cp_payload_t *this)
+{
+ return this->attributes->create_iterator(this->attributes, TRUE);
+}
+
+/**
+ * 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);
+ 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 payload_t.destroy and cp_payload_t.destroy.
+ */
+static void destroy(private_cp_payload_t *this)
+{
+ this->attributes->destroy_offset(this->attributes,
+ offsetof(configuration_attribute_t, destroy));
+ free(this);
+}
+
+/*
+ * 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_attribute_iterator = (iterator_t* (*) (cp_payload_t *)) create_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;
+
+ /* 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/src/charon/encoding/payloads/cp_payload.h b/src/charon/encoding/payloads/cp_payload.h
new file mode 100644
index 000000000..27ff41005
--- /dev/null
+++ b/src/charon/encoding/payloads/cp_payload.h
@@ -0,0 +1,132 @@
+/**
+ * @file cp_payload.h
+ *
+ * @brief Interface of cp_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef enum config_type_t config_type_t;
+typedef struct cp_payload_t cp_payload_t;
+
+#include <library.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
+
+/**
+ * Config Type of an Configuration Payload.
+ *
+ * @ingroup payloads
+ */
+enum config_type_t {
+ CFG_REQUEST = 1,
+ CFG_REPLY = 2,
+ CFG_SET = 3,
+ CFG_ACK = 4,
+};
+
+/**
+ * enum name for config_type_t.
+ *
+ * @ingroup payloads
+ */
+extern enum_name_t *config_type_names;
+
+/**
+ * @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.
+ *
+ * When deleting an attribute using this iterator, the length of this
+ * configuration_attribute_t has to be refreshed by calling get_length()!
+ *
+ * @param this calling cp_payload_t object
+ * @return created iterator_t object
+ */
+ iterator_t *(*create_attribute_iterator) (cp_payload_t *this);
+
+ /**
+ * @brief Adds a configuration_attribute_t object to this object.
+ *
+ * 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(void);
+
+#endif /*CP_PAYLOAD_H_*/
diff --git a/src/charon/encoding/payloads/delete_payload.c b/src/charon/encoding/payloads/delete_payload.c
new file mode 100644
index 000000000..1d42a3af2
--- /dev/null
+++ b/src/charon/encoding/payloads/delete_payload.c
@@ -0,0 +1,299 @@
+/**
+ * @file delete_payload.c
+ *
+ * @brief Implementation of delete_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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;
+
+ /**
+ * List containing u_int32_t spis
+ */
+ linked_list_t *spi_list;
+};
+
+/**
+ * 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)
+{
+ switch (this->protocol_id)
+ {
+ case PROTO_AH:
+ case PROTO_ESP:
+ if (this->spi_size != 4)
+ {
+ return FAILED;
+ }
+ break;
+ case PROTO_IKE:
+ case 0:
+ /* IKE deletion has no spi assigned! */
+ if (this->spi_size != 0)
+ {
+ return FAILED;
+ }
+ break;
+ default:
+ return FAILED;
+ }
+ if (this->spis.len != (this->spi_count * this->spi_size))
+ {
+ 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.get_protocol_id.
+ */
+static protocol_id_t get_protocol_id (private_delete_payload_t *this)
+{
+ return (this->protocol_id);
+}
+
+/**
+ * Implementation of delete_payload_t.add_spi.
+ */
+static void add_spi(private_delete_payload_t *this, u_int32_t spi)
+{
+ /* only add SPIs if AH|ESP, ignore others */
+ if (this->protocol_id == PROTO_AH || this->protocol_id == PROTO_ESP)
+ {
+ this->spi_count += 1;
+ this->spis.len += this->spi_size;
+ this->spis.ptr = realloc(this->spis.ptr, this->spis.len);
+ *(u_int32_t*)(this->spis.ptr + (this->spis.len / this->spi_size - 1)) = spi;
+ if (this->spi_list)
+ {
+ /* reset SPI iterator list */
+ this->spi_list->destroy(this->spi_list);
+ this->spi_list = NULL;
+ }
+ }
+}
+
+/**
+ * Implementation of delete_payload_t.create_spi_iterator.
+ */
+static iterator_t* create_spi_iterator(private_delete_payload_t *this)
+{
+ int i;
+
+ if (this->spi_list == NULL)
+ {
+ this->spi_list = linked_list_create();
+ /* only parse SPIs if AH|ESP */
+ if (this->protocol_id == PROTO_AH || this->protocol_id == PROTO_ESP)
+ {
+ for (i = 0; i < this->spi_count; i++)
+ {
+ this->spi_list->insert_last(this->spi_list, this->spis.ptr + i *
+ this->spi_size);
+ }
+ }
+ }
+ return this->spi_list->create_iterator(this->spi_list, TRUE);
+}
+
+/**
+ * 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);
+ }
+ if (this->spi_list)
+ {
+ this->spi_list->destroy(this->spi_list);
+ }
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+delete_payload_t *delete_payload_create(protocol_id_t protocol_id)
+{
+ 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.get_protocol_id = (protocol_id_t (*) (delete_payload_t *)) get_protocol_id;
+ this->public.add_spi = (void (*) (delete_payload_t *,u_int32_t))add_spi;
+ this->public.create_spi_iterator = (iterator_t* (*) (delete_payload_t *)) create_spi_iterator;
+
+ /* private variables */
+ this->critical = FALSE;
+ this->next_payload = NO_PAYLOAD;
+ this->payload_length = DELETE_PAYLOAD_HEADER_LENGTH;
+ this->protocol_id = protocol_id;
+ this->spi_size = protocol_id == PROTO_AH || protocol_id == PROTO_ESP ? 4 : 0;
+ this->spi_count = 0;
+ this->spis = chunk_empty;
+ this->spi_list = NULL;
+
+ return (&this->public);
+}
diff --git a/src/charon/encoding/payloads/delete_payload.h b/src/charon/encoding/payloads/delete_payload.h
new file mode 100644
index 000000000..508f7fba2
--- /dev/null
+++ b/src/charon/encoding/payloads/delete_payload.h
@@ -0,0 +1,102 @@
+/**
+ * @file delete_payload.h
+ *
+ * @brief Interface of delete_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct delete_payload_t delete_payload_t;
+
+#include <library.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
+
+/**
+ * @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 Get the protocol ID.
+ *
+ * @param this calling delete_payload_t object
+ * @return protocol ID
+ */
+ protocol_id_t (*get_protocol_id) (delete_payload_t *this);
+
+ /**
+ * @brief Add an SPI to the list of deleted SAs.
+ *
+ * @param this calling delete_payload_t object
+ * @param spi spi to add
+ */
+ void (*add_spi) (delete_payload_t *this, u_int32_t spi);
+
+ /**
+ * @brief Get an iterator over the SPIs.
+ *
+ * The iterate() function returns a pointer to a u_int32_t SPI.
+ *
+ * @param this calling delete_payload_t object
+ * @return iterator over SPIs
+ */
+ iterator_t *(*create_spi_iterator) (delete_payload_t *this);
+
+ /**
+ * @brief Destroys an delete_payload_t object.
+ *
+ * @param this delete_payload_t object to destroy
+ */
+ void (*destroy) (delete_payload_t *this);
+};
+
+/**
+ * @brief Creates an empty delete_payload_t object.
+ *
+ * @param protocol_id protocol, such as AH|ESP
+ * @return delete_payload_t object
+ *
+ * @ingroup payloads
+ */
+delete_payload_t *delete_payload_create(protocol_id_t protocol_id);
+
+#endif /* DELETE_PAYLOAD_H_ */
diff --git a/src/charon/encoding/payloads/eap_payload.c b/src/charon/encoding/payloads/eap_payload.c
new file mode 100644
index 000000000..79ab32fe5
--- /dev/null
+++ b/src/charon/encoding/payloads/eap_payload.c
@@ -0,0 +1,331 @@
+/**
+ * @file eap_payload.c
+ *
+ * @brief Implementation of eap_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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"
+
+#include <daemon.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;
+
+ /**
+ * EAP message data, if available
+ */
+ chunk_t data;
+};
+
+/**
+ * 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) },
+ /* chunt to data, starting at "code" */
+ { EAP_DATA, offsetof(private_eap_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 !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Code ! Identifier ! Length !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Type ! Type_Data...
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+*/
+
+/**
+ * Implementation of payload_t.verify.
+ */
+static status_t verify(private_eap_payload_t *this)
+{
+ u_int16_t length;
+ u_int8_t code;
+
+ if (this->data.len < 4)
+ {
+ DBG1(DBG_ENC, "EAP payloads EAP message too short (%d)", this->data.len);
+ return FAILED;
+ }
+ code = *this->data.ptr;
+ length = htons(*(u_int16_t*)(this->data.ptr + 2));
+ if (this->data.len != length)
+ {
+ DBG1(DBG_ENC, "EAP payload length (%d) does not match contained message length (%d)",
+ this->data.len, length);
+ return FAILED;
+ }
+ switch (code)
+ {
+ case EAP_REQUEST:
+ case EAP_RESPONSE:
+ {
+ if (this->data.len < 4)
+ {
+ DBG1(DBG_ENC, "EAP Request/Response does not have any data");
+ return FAILED;
+ }
+ break;
+ }
+ case EAP_SUCCESS:
+ case EAP_FAILURE:
+ {
+ if (this->data.len != 4)
+ {
+ DBG1(DBG_ENC, "EAP Success/Failure has data");
+ return FAILED;
+ }
+ break;
+ }
+ default:
+ return FAILED;
+ }
+ 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.get_data.
+ */
+static chunk_t get_data(private_eap_payload_t *this)
+{
+ return this->data;
+}
+
+/**
+ * Implementation of eap_payload_t.set_data.
+ */
+static void set_data(private_eap_payload_t *this, chunk_t data)
+{
+ chunk_free(&this->data);
+ this->data = chunk_clone(data);
+ this->payload_length = this->data.len + 4;
+}
+
+/**
+ * Implementation of eap_payload_t.get_code.
+ */
+static eap_code_t get_code(private_eap_payload_t *this)
+{
+ if (this->data.len > 0)
+ {
+ return *this->data.ptr;
+ }
+ /* should not happen, as it is verified */
+ return 0;
+}
+
+/**
+ * Implementation of eap_payload_t.get_identifier.
+ */
+static u_int8_t get_identifier(private_eap_payload_t *this)
+{
+ if (this->data.len > 1)
+ {
+ return *(this->data.ptr + 1);
+ }
+ /* should not happen, as it is verified */
+ return 0;
+}
+
+/**
+ * Implementation of eap_payload_t.get_type.
+ */
+static eap_type_t get_type(private_eap_payload_t *this)
+{
+ if (this->data.len > 4)
+ {
+ return *(this->data.ptr + 4);
+ }
+ return 0;
+}
+
+/**
+ * Implementation of payload_t.destroy and eap_payload_t.destroy.
+ */
+static void destroy(private_eap_payload_t *this)
+{
+ chunk_free(&this->data);
+ 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.get_data = (chunk_t (*) (eap_payload_t*))get_data;
+ this->public.set_data = (void (*) (eap_payload_t *,chunk_t))set_data;
+ this->public.get_code = (eap_code_t (*) (eap_payload_t*))get_code;
+ this->public.get_identifier = (u_int8_t (*) (eap_payload_t*))get_identifier;
+ this->public.get_type = (eap_type_t (*) (eap_payload_t*))get_type;
+
+ /* private variables */
+ this->critical = FALSE;
+ this->next_payload = NO_PAYLOAD;
+ this->payload_length = EAP_PAYLOAD_HEADER_LENGTH;
+ this->data = chunk_empty;
+
+ return &(this->public);
+}
+
+/*
+ * Described in header
+ */
+eap_payload_t *eap_payload_create_data(chunk_t data)
+{
+ eap_payload_t *this = eap_payload_create();
+
+ this->set_data(this, data);
+ return this;
+}
+
+/*
+ * Described in header
+ */
+eap_payload_t *eap_payload_create_code(eap_code_t code)
+{
+ eap_payload_t *this = eap_payload_create();
+ chunk_t data = chunk_alloca(4);
+
+ *(data.ptr + 0) = code;
+ *(data.ptr + 1) = 0;
+ *(u_int16_t*)(data.ptr + 2) = htons(data.len);
+
+ this->set_data(this, data);
+ return this;
+}
+
+/*
+ * Described in header
+ */
+eap_payload_t *eap_payload_create_nak()
+{
+ eap_payload_t *this = eap_payload_create();
+ chunk_t data = chunk_alloca(5);
+
+ *(data.ptr + 0) = EAP_RESPONSE;
+ *(data.ptr + 1) = 0;
+ *(u_int16_t*)(data.ptr + 2) = htons(data.len);
+ *(data.ptr + 4) = EAP_NAK;
+
+ this->set_data(this, data);
+ return this;
+}
diff --git a/src/charon/encoding/payloads/eap_payload.h b/src/charon/encoding/payloads/eap_payload.h
new file mode 100644
index 000000000..13c0ade80
--- /dev/null
+++ b/src/charon/encoding/payloads/eap_payload.h
@@ -0,0 +1,149 @@
+/**
+ * @file eap_payload.h
+ *
+ * @brief Interface of eap_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct eap_payload_t eap_payload_t;
+
+#include <library.h>
+#include <encoding/payloads/payload.h>
+#include <sa/authenticators/eap/eap_method.h>
+
+/**
+ * Length of a EAP payload without the EAP Message in bytes.
+ *
+ * @ingroup payloads
+ */
+#define EAP_PAYLOAD_HEADER_LENGTH 4
+
+/**
+ * @brief Class representing an IKEv2 EAP payload.
+ *
+ * The EAP payload format is described in RFC section 3.16.
+ *
+ * @b Constructors:
+ * - eap_payload_create()
+ *
+ * @ingroup payloads
+ */
+struct eap_payload_t {
+
+ /**
+ * The payload_t interface.
+ */
+ payload_t payload_interface;
+
+ /**
+ * @brief Set the contained EAP data.
+ *
+ * This contains the FULL EAP message starting with "code".
+ * Chunk gets cloned.
+ *
+ * @param this calling eap_payload_t object
+ * @param message EAP data
+ */
+ void (*set_data) (eap_payload_t *this, chunk_t data);
+
+ /**
+ * @brief Get the contained EAP data.
+ *
+ * This contains the FULL EAP message starting with "code".
+ *
+ * @param this calling eap_payload_t object
+ * @return EAP data (pointer to internal data)
+ */
+ chunk_t (*get_data) (eap_payload_t *this);
+
+ /**
+ * @brief Get the EAP code.
+ *
+ * @param this calling eap_payload_t object
+ * @return EAP message as chunk_t
+ */
+ eap_code_t (*get_code) (eap_payload_t *this);
+
+ /**
+ * @brief Get the EAP identifier.
+ *
+ * @param this calling eap_payload_t object
+ * @return unique identifier
+ */
+ u_int8_t (*get_identifier) (eap_payload_t *this);
+
+ /**
+ * @brief Get the EAP method type.
+ *
+ * @param this calling eap_payload_t object
+ * @return EAP method type
+ */
+ eap_type_t (*get_type) (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(void);
+
+/**
+ * @brief Creates an eap_payload_t object with data.
+ *
+ * @return eap_payload_t object
+ *
+ * @ingroup payloads
+ */
+eap_payload_t *eap_payload_create_data(chunk_t data);
+
+/**
+ * @brief Creates an eap_payload_t object with a code.
+ *
+ * Could should be either EAP_SUCCESS/EAP_FAILURE, use
+ * constructor above otherwise.
+ *
+ * @return eap_payload_t object
+ *
+ * @ingroup payloads
+ */
+eap_payload_t *eap_payload_create_code(eap_code_t code);
+
+/**
+ * @brief Creates an eap_payload_t EAP_RESPONSE containing an EAP_NAK.
+ *
+ * @return eap_payload_t object
+ *
+ * @ingroup payloads
+ */
+eap_payload_t *eap_payload_create_nak();
+
+#endif /* EAP_PAYLOAD_H_ */
diff --git a/src/charon/encoding/payloads/encodings.c b/src/charon/encoding/payloads/encodings.c
new file mode 100644
index 000000000..55a7cf132
--- /dev/null
+++ b/src/charon/encoding/payloads/encodings.c
@@ -0,0 +1,66 @@
+/**
+ * @file encodings.c
+ *
+ * @brief String mappings of encoding_type_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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"
+
+ENUM(encoding_type_names, U_INT_4, ENCRYPTED_DATA,
+ "U_INT_4",
+ "U_INT_8",
+ "U_INT_16",
+ "U_INT_32",
+ "U_INT_64",
+ "RESERVED_BIT",
+ "RESERVED_BYTE",
+ "FLAG",
+ "PAYLOAD_LENGTH",
+ "HEADER_LENGTH",
+ "SPI_SIZE",
+ "SPI",
+ "KEY_EXCHANGE_DATA",
+ "NOTIFICATION_DATA",
+ "PROPOSALS",
+ "TRANSFORMS",
+ "TRANSFORM_ATTRIBUTES",
+ "CONFIGURATION_ATTRIBUTES",
+ "CONFIGURATION_ATTRIBUTE_VALUE",
+ "ATTRIBUTE_FORMAT",
+ "ATTRIBUTE_TYPE",
+ "ATTRIBUTE_LENGTH_OR_VALUE",
+ "CONFIGURATION_ATTRIBUTE_LENGTH",
+ "ATTRIBUTE_VALUE",
+ "TRAFFIC_SELECTORS",
+ "TS_TYPE",
+ "ADDRESS",
+ "NONCE_DATA",
+ "ID_DATA",
+ "AUTH_DATA",
+ "CERT_DATA",
+ "CERTREQ_DATA",
+ "EAP_DATA",
+ "SPIS",
+ "VID_DATA",
+ "UNKNOWN_DATA",
+ "IKE_SPI",
+ "ENCRYPTED_DATA",
+);
diff --git a/src/charon/encoding/payloads/encodings.h b/src/charon/encoding/payloads/encodings.h
new file mode 100644
index 000000000..5e07fbfab
--- /dev/null
+++ b/src/charon/encoding/payloads/encodings.h
@@ -0,0 +1,537 @@
+/**
+ * @file encodings.h
+ *
+ * @brief Definition of encoding_type_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef enum encoding_type_t encoding_type_t;
+typedef struct encoding_rule_t encoding_rule_t;
+
+#include <library.h>
+
+/**
+ * @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_DATA,
+
+ /**
+ * 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,
+};
+
+/**
+ * enum name for encoding_type_t
+ *
+ * @ingroup payloads
+ */
+extern enum_name_t *encoding_type_names;
+
+/**
+ * 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/src/charon/encoding/payloads/encryption_payload.c b/src/charon/encoding/payloads/encryption_payload.c
new file mode 100644
index 000000000..23b6e8d9f
--- /dev/null
+++ b/src/charon/encoding/payloads/encryption_payload.c
@@ -0,0 +1,646 @@
+/**
+ * @file encryption_payload.c
+ *
+ * @brief Implementation of encryption_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <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;
+};
+
+/**
+ * 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*/
+}
+
+/**
+ * (re-)compute the lenght of the whole payload
+ */
+static void compute_length(private_encryption_payload_t *this)
+{
+ iterator_t *iterator;
+ payload_t *current_payload;
+ size_t block_size, length = 0;
+ iterator = this->payloads->create_iterator(this->payloads, TRUE);
+
+ /* count payload length */
+ while (iterator->iterate(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.get_length.
+ */
+static size_t get_length(private_encryption_payload_t *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);
+ 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);
+}
+
+/**
+ * Generate payload before encryption.
+ */
+static void generate(private_encryption_payload_t *this)
+{
+ payload_t *current_payload, *next_payload;
+ generator_t *generator;
+ iterator_t *iterator;
+
+ /* recalculate length before generating */
+ compute_length(this);
+
+ /* create iterator */
+ iterator = this->payloads->create_iterator(this->payloads, TRUE);
+
+ /* get first payload */
+ if (iterator->iterate(iterator, (void**)&current_payload))
+ {
+ this->next_payload = current_payload->get_type(current_payload);
+ }
+ else
+ {
+ /* no paylads? */
+ DBG2(DBG_ENC, "generating contained payloads, but none available");
+ free(this->decrypted.ptr);
+ this->decrypted = chunk_empty;
+ iterator->destroy(iterator);
+ return;
+ }
+
+ generator = generator_create();
+
+ /* build all payload, except last */
+ while(iterator->iterate(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);
+ DBG2(DBG_ENC, "successfully generated content in encryption payload");
+}
+
+/**
+ * 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)
+ {
+ DBG1(DBG_ENC, "could not encrypt, signer/crypter not set");
+ return INVALID_STATE;
+ }
+
+ /* for random data in iv and padding */
+ randomizer = randomizer_create();
+
+ /* build payload chunk */
+ generate(this);
+
+ DBG2(DBG_ENC, "encrypting payloads");
+ DBG3(DBG_ENC, "data to encrypt %B", &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;
+ }
+
+ DBG3(DBG_ENC, "data before encryption with padding %B", &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)
+ {
+ DBG2(DBG_ENC, "encryption failed");
+ free(iv.ptr);
+ return status;
+ }
+ DBG3(DBG_ENC, "data after encryption %B", &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);
+ DBG3(DBG_ENC, "data after encryption with IV and (invalid) signature %B",
+ &this->encrypted);
+
+ return SUCCESS;
+}
+
+/**
+ * Parse the payloads after decryption.
+ */
+static status_t parse(private_encryption_payload_t *this)
+{
+ parser_t *parser;
+ status_t status;
+ payload_type_t current_payload_type;
+
+ /* 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)
+ {
+ DBG1(DBG_ENC, "%N verification failed",
+ payload_type_names, current_payload->get_type(current_payload));
+ 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);
+ DBG2(DBG_ENC, "succesfully parsed content of encryption payload");
+ 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;
+
+ DBG2(DBG_ENC, "decrypting encryption payload");
+ DBG3(DBG_ENC, "data before decryption with IV and (invalid) signature %B",
+ &this->encrypted);
+
+ if (this->signer == NULL || this->crypter == NULL)
+ {
+ DBG1(DBG_ENC, "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)
+ {
+ DBG1(DBG_ENC, "could not decrypt, invalid input");
+ return FAILED;
+ }
+
+ /* free previus data, if any */
+ free(this->decrypted.ptr);
+
+ DBG3(DBG_ENC, "data before decryption %B", &concatenated);
+
+ status = this->crypter->decrypt(this->crypter, concatenated, iv, &(this->decrypted));
+ if (status != SUCCESS)
+ {
+ DBG1(DBG_ENC, "could not decrypt, decryption failed");
+ return FAILED;
+ }
+ DBG3(DBG_ENC, "data after decryption with padding %B", &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)
+ {
+ DBG1(DBG_ENC, "decryption failed, invalid padding length found. Invalid key?");
+ /* decryption failed :-/ */
+ return FAILED;
+ }
+
+ /* free padding */
+ this->decrypted.ptr = realloc(this->decrypted.ptr, this->decrypted.len);
+ DBG3(DBG_ENC, "data after decryption without padding %B", &this->decrypted);
+ DBG2(DBG_ENC, "decryption successful, trying to parse content");
+ return 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)
+ {
+ DBG1(DBG_ENC, "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;
+ DBG2(DBG_ENC, "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)
+ {
+ DBG1(DBG_ENC, "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)
+ {
+ DBG1(DBG_ENC, "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)
+ {
+ DBG1(DBG_ENC, "signature verification failed");
+ return FAILED;
+ }
+
+ DBG2(DBG_ENC, "signature verification successful");
+ return SUCCESS;
+}
+
+/**
+ * Implementation of payload_t.destroy.
+ */
+static void destroy(private_encryption_payload_t *this)
+{
+ this->payloads->destroy_offset(this->payloads, offsetof(payload_t, destroy));
+ 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;
+
+ /* set default values of the fields */
+ this->critical = FALSE;
+ this->next_payload = NO_PAYLOAD;
+ this->payload_length = ENCRYPTION_PAYLOAD_HEADER_LENGTH;
+ this->encrypted = chunk_empty;
+ this->decrypted = chunk_empty;
+ this->signer = NULL;
+ this->crypter = NULL;
+ this->payloads = linked_list_create();
+
+ return (&(this->public));
+}
diff --git a/src/charon/encoding/payloads/encryption_payload.h b/src/charon/encoding/payloads/encryption_payload.h
new file mode 100644
index 000000000..7cf53619f
--- /dev/null
+++ b/src/charon/encoding/payloads/encryption_payload.h
@@ -0,0 +1,197 @@
+/**
+ * @file encryption_payload.h
+ *
+ * @brief Interface of encryption_payload_t.
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct encryption_payload_t encryption_payload_t;
+
+#include <library.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
+
+
+/**
+ * @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(void);
+
+
+#endif /*ENCRYPTION_PAYLOAD_H_*/
diff --git a/src/charon/encoding/payloads/id_payload.c b/src/charon/encoding/payloads/id_payload.c
new file mode 100644
index 000000000..74c0ce870
--- /dev/null
+++ b/src/charon/encoding/payloads/id_payload.c
@@ -0,0 +1,323 @@
+/**
+ * @file id_payload.h
+ *
+ * @brief Interface of id_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <daemon.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 */
+ DBG1(DBG_ENC, "received ID with reserved type %d", this->id_type);
+ 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_empty;
+ 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/src/charon/encoding/payloads/id_payload.h b/src/charon/encoding/payloads/id_payload.h
new file mode 100644
index 000000000..b67d85d2e
--- /dev/null
+++ b/src/charon/encoding/payloads/id_payload.h
@@ -0,0 +1,172 @@
+/**
+ * @file id_payload.h
+ *
+ * @brief Interface of id_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct id_payload_t id_payload_t;
+
+#include <library.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
+
+/**
+ * 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/src/charon/encoding/payloads/ike_header.c b/src/charon/encoding/payloads/ike_header.c
new file mode 100644
index 000000000..b1b4fbf87
--- /dev/null
+++ b/src/charon/encoding/payloads/ike_header.c
@@ -0,0 +1,406 @@
+/**
+ * @file ike_header.c
+ *
+ * @brief Implementation of ike_header_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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;
+};
+
+ENUM_BEGIN(exchange_type_names, EXCHANGE_TYPE_UNDEFINED, EXCHANGE_TYPE_UNDEFINED,
+ "EXCHANGE_TYPE_UNDEFINED");
+ENUM_NEXT(exchange_type_names, IKE_SA_INIT, INFORMATIONAL, EXCHANGE_TYPE_UNDEFINED,
+ "IKE_SA_INIT",
+ "IKE_AUTH",
+ "CREATE_CHILD_SA",
+ "INFORMATIONAL");
+ENUM_END(exchange_type_names, 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/src/charon/encoding/payloads/ike_header.h b/src/charon/encoding/payloads/ike_header.h
new file mode 100644
index 000000000..95c20f810
--- /dev/null
+++ b/src/charon/encoding/payloads/ike_header.h
@@ -0,0 +1,260 @@
+/**
+ * @file ike_header.h
+ *
+ * @brief Interface of ike_header_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef enum exchange_type_t exchange_type_t;
+typedef struct ike_header_t ike_header_t;
+
+#include <library.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
+
+/**
+ * @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
+};
+
+/**
+ * enum name for exchange_type_t
+ *
+ * @ingroup payloads
+ */
+extern enum_name_t *exchange_type_names;
+
+/**
+ * @brief An object of this type represents an IKEv2 header and is used to
+ * 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(void);
+
+#endif /*IKE_HEADER_H_*/
diff --git a/src/charon/encoding/payloads/ke_payload.c b/src/charon/encoding/payloads/ke_payload.c
new file mode 100644
index 000000000..8926b15f9
--- /dev/null
+++ b/src/charon/encoding/payloads/ke_payload.c
@@ -0,0 +1,277 @@
+/**
+ * @file ke_payload.c
+ *
+ * @brief Implementation of ke_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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.
+ */
+ u_int16_t dh_group_number;
+
+ /**
+ * Key Exchange Data of this KE payload.
+ */
+ chunk_t key_exchange_data;
+};
+
+/**
+ * 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;
+}
+
+/**
+ * recompute the length of the payload.
+ */
+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 payload_t.get_length.
+ */
+static size_t get_length(private_ke_payload_t *this)
+{
+ compute_length(this);
+ return this->payload_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 = chunk_clone(key_exchange_data);
+ 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;
+
+ /* 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 = chunk_empty;
+ this->dh_group_number = MODP_NONE;
+
+ return &this->public;
+}
+
+/*
+ * Described in header
+ */
+ke_payload_t *ke_payload_create_from_diffie_hellman(diffie_hellman_t *dh)
+{
+ private_ke_payload_t *this = (private_ke_payload_t*)ke_payload_create();
+
+ dh->get_my_public_value(dh, &this->key_exchange_data);
+ this->dh_group_number = dh->get_dh_group(dh);
+ compute_length(this);
+
+ return &this->public;
+}
diff --git a/src/charon/encoding/payloads/ke_payload.h b/src/charon/encoding/payloads/ke_payload.h
new file mode 100644
index 000000000..52be8ffe3
--- /dev/null
+++ b/src/charon/encoding/payloads/ke_payload.h
@@ -0,0 +1,121 @@
+/**
+ * @file ke_payload.h
+ *
+ * @brief Interface of ke_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct ke_payload_t ke_payload_t;
+
+#include <library.h>
+#include <encoding/payloads/payload.h>
+#include <encoding/payloads/transform_substructure.h>
+#include <utils/linked_list.h>
+#include <crypto/diffie_hellman.h>
+
+/**
+ * KE payload length in bytes without any key exchange data.
+ *
+ * @ingroup payloads
+ */
+#define KE_PAYLOAD_HEADER_LENGTH 8
+
+/**
+ * @brief Class representing an IKEv2-KE Payload.
+ *
+ * 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(void);
+
+/**
+ * @brief Creates a ke_payload_t from a diffie_hellman_t
+ *
+ * @param diffie_hellman diffie hellman object containing group and key
+ * @return ke_payload_t object
+ *
+ * @ingroup payloads
+ */
+ke_payload_t *ke_payload_create_from_diffie_hellman(diffie_hellman_t *diffie_hellman);
+
+#endif /* KE_PAYLOAD_H_ */
diff --git a/src/charon/encoding/payloads/nonce_payload.c b/src/charon/encoding/payloads/nonce_payload.c
new file mode 100644
index 000000000..8e1fc505e
--- /dev/null
+++ b/src/charon/encoding/payloads/nonce_payload.c
@@ -0,0 +1,232 @@
+/**
+ * @file nonce_payload.h
+ *
+ * @brief Implementation of nonce_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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;
+};
+
+/**
+ * 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;
+}
+
+/**
+ * recompute the length of the payload.
+ */
+static void compute_length(private_nonce_payload_t *this)
+{
+ this->payload_length = NONCE_PAYLOAD_HEADER_LENGTH + this->nonce.len;
+}
+
+/**
+ * Implementation of payload_t.get_length.
+ */
+static size_t get_length(private_nonce_payload_t *this)
+{
+ compute_length(this);
+ return this->payload_length;
+}
+
+/**
+ * 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 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/src/charon/encoding/payloads/nonce_payload.h b/src/charon/encoding/payloads/nonce_payload.h
new file mode 100644
index 000000000..96d83b028
--- /dev/null
+++ b/src/charon/encoding/payloads/nonce_payload.h
@@ -0,0 +1,99 @@
+/**
+ * @file nonce_payload.h
+ *
+ * @brief Interface of nonce_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct nonce_payload_t nonce_payload_t;
+
+#include <library.h>
+#include <encoding/payloads/payload.h>
+
+/**
+ * Nonce size in bytes for nonces sending to other peer.
+ *
+ * @warning Nonce size MUST be between 16 and 256 bytes.
+ *
+ * @ingroup payloads
+ */
+#define NONCE_SIZE 16
+
+/**
+ * Length of a nonce payload without a nonce in bytes.
+ *
+ * @ingroup payloads
+ */
+#define NONCE_PAYLOAD_HEADER_LENGTH 4
+
+/**
+ * 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(void);
+
+
+#endif /*NONCE_PAYLOAD_H_*/
diff --git a/src/charon/encoding/payloads/notify_payload.c b/src/charon/encoding/payloads/notify_payload.c
new file mode 100644
index 000000000..a04901a90
--- /dev/null
+++ b/src/charon/encoding/payloads/notify_payload.c
@@ -0,0 +1,481 @@
+/**
+ * @file notify_payload.c
+ *
+ * @brief Implementation of notify_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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>
+#include <crypto/hashers/hasher.h>
+
+ENUM_BEGIN(notify_type_names, UNSUPPORTED_CRITICAL_PAYLOAD, UNSUPPORTED_CRITICAL_PAYLOAD,
+ "UNSUPPORTED_CRITICAL_PAYLOAD");
+ENUM_NEXT(notify_type_names, INVALID_IKE_SPI, INVALID_MAJOR_VERSION, UNSUPPORTED_CRITICAL_PAYLOAD,
+ "INVALID_IKE_SPI",
+ "INVALID_MAJOR_VERSION");
+ENUM_NEXT(notify_type_names, INVALID_SYNTAX, INVALID_SYNTAX, INVALID_MAJOR_VERSION,
+ "INVALID_SYNTAX");
+ENUM_NEXT(notify_type_names, INVALID_MESSAGE_ID, INVALID_MESSAGE_ID, INVALID_SYNTAX,
+ "INVALID_MESSAGE_ID");
+ENUM_NEXT(notify_type_names, INVALID_SPI, INVALID_SPI, INVALID_MESSAGE_ID,
+ "INVALID_SPI");
+ENUM_NEXT(notify_type_names, NO_PROPOSAL_CHOSEN, NO_PROPOSAL_CHOSEN, INVALID_SPI,
+ "NO_PROPOSAL_CHOSEN");
+ENUM_NEXT(notify_type_names, INVALID_KE_PAYLOAD, INVALID_KE_PAYLOAD, NO_PROPOSAL_CHOSEN,
+ "INVALID_KE_PAYLOAD");
+ENUM_NEXT(notify_type_names, AUTHENTICATION_FAILED, AUTHENTICATION_FAILED, INVALID_KE_PAYLOAD,
+ "AUTHENTICATION_FAILED");
+ENUM_NEXT(notify_type_names, SINGLE_PAIR_REQUIRED, INVALID_SELECTORS, AUTHENTICATION_FAILED,
+ "SINGLE_PAIR_REQUIRED",
+ "NO_ADDITIONAL_SAS",
+ "INTERNAL_ADDRESS_FAILURE",
+ "FAILED_CP_REQUIRED",
+ "TS_UNACCEPTABLE",
+ "INVALID_SELECTORS");
+ENUM_NEXT(notify_type_names, INITIAL_CONTACT, AUTH_LIFETIME, INVALID_SELECTORS,
+ "INITIAL_CONTACT",
+ "SET_WINDOW_SIZE",
+ "ADDITIONAL_TS_POSSIBLE",
+ "IPCOMP_SUPPORTED",
+ "NAT_DETECTION_SOURCE_IP",
+ "NAT_DETECTION_DESTINATION_IP",
+ "COOKIE",
+ "USE_TRANSPORT_MODE",
+ "HTTP_CERT_LOOKUP_SUPPORTED",
+ "REKEY_SA",
+ "ESP_TFC_PADDING_NOT_SUPPORTED",
+ "NON_FIRST_FRAGMENTS_ALSO",
+ "MOBIKE_SUPPORTED",
+ "ADDITIONAL_IP4_ADDRESS",
+ "ADDITIONAL_IP6_ADDRESS",
+ "NO_ADDITIONAL_ADDRESSES",
+ "UPDATE_SA_ADDRESSES",
+ "COOKIE2",
+ "NO_NATS_ALLOWED",
+ "AUTH_LIFETIME");
+ENUM_NEXT(notify_type_names, EAP_ONLY_AUTHENTICATION, EAP_ONLY_AUTHENTICATION, AUTH_LIFETIME,
+ "EAP_ONLY_AUTHENTICATION");
+ENUM_END(notify_type_names, EAP_ONLY_AUTHENTICATION);
+
+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_type;
+
+ /**
+ * Security parameter index (spi).
+ */
+ chunk_t spi;
+
+ /**
+ * Notification data.
+ */
+ chunk_t notification_data;
+};
+
+/**
+ * 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_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)
+{
+ switch (this->protocol_id)
+ {
+ case PROTO_NONE:
+ case PROTO_IKE:
+ case PROTO_AH:
+ case PROTO_ESP:
+ break;
+ default:
+ DBG1(DBG_ENC, "Unknown protocol (%d)", this->protocol_id);
+ return FAILED;
+ }
+
+ switch (this->notify_type)
+ {
+ case INVALID_KE_PAYLOAD:
+ {
+ /* check notification data */
+ diffie_hellman_group_t dh_group;
+ if (this->notification_data.len != 2)
+ {
+ DBG1(DBG_ENC, "invalid notify data length for %N (%d)",
+ notify_type_names, this->notify_type,
+ this->notification_data.len);
+ 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:
+ DBG1(DBG_ENC, "Bad DH group (%d)", dh_group);
+ return FAILED;
+ }
+ break;
+ }
+ case NAT_DETECTION_SOURCE_IP:
+ case NAT_DETECTION_DESTINATION_IP:
+ {
+ if (this->notification_data.len != HASH_SIZE_SHA1)
+ {
+ DBG1(DBG_ENC, "invalid %N notify length",
+ notify_type_names, this->notify_type);
+ return FAILED;
+ }
+ break;
+ }
+ case INVALID_SYNTAX:
+ case INVALID_MAJOR_VERSION:
+ case NO_PROPOSAL_CHOSEN:
+ {
+ if (this->notification_data.len != 0)
+ {
+ DBG1(DBG_ENC, "invalid %N notify",
+ notify_type_names, this->notify_type);
+ return FAILED;
+ }
+ break;
+ }
+ default:
+ /* TODO: verify */
+ break;
+ }
+ 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;
+}
+
+/**
+ * recompute the payloads 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 payload_t.get_length.
+ */
+static size_t get_length(private_notify_payload_t *this)
+{
+ compute_length(this);
+ return this->payload_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_type.
+ */
+static notify_type_t get_notify_type(private_notify_payload_t *this)
+{
+ return this->notify_type;
+}
+
+/**
+ * Implementation of notify_payload_t.set_notify_type.
+ */
+static void set_notify_type(private_notify_payload_t *this, u_int16_t notify_type)
+{
+ this->notify_type = notify_type;
+}
+
+/**
+ * Implementation of notify_payload_t.get_spi.
+ */
+static u_int32_t get_spi(private_notify_payload_t *this)
+{
+ switch (this->protocol_id)
+ {
+ case PROTO_AH:
+ case PROTO_ESP:
+ if (this->spi.len == 4)
+ {
+ return *((u_int32_t*)this->spi.ptr);
+ }
+ default:
+ break;
+ }
+ return 0;
+}
+
+/**
+ * Implementation of notify_payload_t.set_spi.
+ */
+static void set_spi(private_notify_payload_t *this, u_int32_t spi)
+{
+ chunk_free(&this->spi);
+ switch (this->protocol_id)
+ {
+ case PROTO_AH:
+ case PROTO_ESP:
+ this->spi = chunk_alloc(4);
+ *((u_int32_t*)this->spi.ptr) = spi;
+ break;
+ default:
+ break;
+ }
+ this->spi_size = this->spi.len;
+ 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)
+{
+ chunk_free(&this->notification_data);
+ if (notification_data.len > 0)
+ {
+ this->notification_data = chunk_clone(notification_data);
+ }
+ 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)
+{
+ chunk_free(&this->notification_data);
+ chunk_free(&this->spi);
+ 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_type = (notify_type_t (*) (notify_payload_t *)) get_notify_type;
+ this->public.set_notify_type = (void (*) (notify_payload_t *,notify_type_t)) set_notify_type;
+ this->public.get_spi = (u_int32_t (*) (notify_payload_t *)) get_spi;
+ this->public.set_spi = (void (*) (notify_payload_t *,u_int32_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;
+
+ /* 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_type = 0;
+ this->spi.ptr = NULL;
+ this->spi.len = 0;
+ this->spi_size = 0;
+ this->notification_data.ptr = NULL;
+ this->notification_data.len = 0;
+
+ return &this->public;
+}
+
+/*
+ * Described in header.
+ */
+notify_payload_t *notify_payload_create_from_protocol_and_type(protocol_id_t protocol_id, notify_type_t notify_type)
+{
+ notify_payload_t *notify = notify_payload_create();
+
+ notify->set_notify_type(notify,notify_type);
+ notify->set_protocol_id(notify,protocol_id);
+
+ return notify;
+}
diff --git a/src/charon/encoding/payloads/notify_payload.h b/src/charon/encoding/payloads/notify_payload.h
new file mode 100644
index 000000000..431932631
--- /dev/null
+++ b/src/charon/encoding/payloads/notify_payload.h
@@ -0,0 +1,224 @@
+/**
+ * @file notify_payload.h
+ *
+ * @brief Interface of notify_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef enum notify_type_t notify_type_t;
+typedef struct notify_payload_t notify_payload_t;
+
+#include <library.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
+
+/**
+ * @brief Notify message types.
+ *
+ * See IKEv2 RFC 3.10.1.
+ *
+ * @ingroup payloads
+ */
+enum notify_type_t {
+ /* notify error messages */
+ 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_UNACCEPTABLE = 38,
+ INVALID_SELECTORS = 39,
+ /* notify status messages */
+ INITIAL_CONTACT = 16384,
+ SET_WINDOW_SIZE = 16385,
+ ADDITIONAL_TS_POSSIBLE = 16386,
+ IPCOMP_SUPPORTED = 16387,
+ NAT_DETECTION_SOURCE_IP = 16388,
+ NAT_DETECTION_DESTINATION_IP = 16389,
+ COOKIE = 16390,
+ USE_TRANSPORT_MODE = 16391,
+ HTTP_CERT_LOOKUP_SUPPORTED = 16392,
+ REKEY_SA = 16393,
+ ESP_TFC_PADDING_NOT_SUPPORTED = 16394,
+ NON_FIRST_FRAGMENTS_ALSO = 16395,
+ /* mobike extension, RFC4555 */
+ MOBIKE_SUPPORTED = 16396,
+ ADDITIONAL_IP4_ADDRESS = 16397,
+ ADDITIONAL_IP6_ADDRESS = 16398,
+ NO_ADDITIONAL_ADDRESSES = 16399,
+ UPDATE_SA_ADDRESSES = 16400,
+ COOKIE2 = 16401,
+ NO_NATS_ALLOWED = 16402,
+ /* repeated authentication extension, RFC4478 */
+ AUTH_LIFETIME = 16403,
+ /* draft-eronen-ipsec-ikev2-eap-auth, not assigned by IANA yet */
+ EAP_ONLY_AUTHENTICATION = 40960,
+ /* BEET mode, not even a draft yet. private use */
+ USE_BEET_MODE = 40961,
+};
+
+/**
+ * enum name for notify_type_t.
+ *
+ * @ingroup payloads
+ */
+extern enum_name_t *notify_type_names;
+
+/**
+ * @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
+ */
+ notify_type_t (*get_notify_type) (notify_payload_t *this);
+
+ /**
+ * @brief Sets notify message type of this payload.
+ *
+ * @param this calling notify_payload_t object
+ * @param type notify message type to set
+ */
+ void (*set_notify_type) (notify_payload_t *this, notify_type_t type);
+
+ /**
+ * @brief Returns the currently set spi of this payload.
+ *
+ * This is only valid for notifys with protocol AH|ESP
+ *
+ * @param this calling notify_payload_t object
+ * @return SPI value
+ */
+ u_int32_t (*get_spi) (notify_payload_t *this);
+
+ /**
+ * @brief Sets the spi of this payload.
+ *
+ * This is only valid for notifys with protocol AH|ESP
+ *
+ * @param this calling notify_payload_t object
+ * @param spi SPI value
+ */
+ void (*set_spi) (notify_payload_t *this, u_int32_t spi);
+
+ /**
+ * @brief Returns the currently set notification data of payload.
+ *
+ * @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(void);
+
+/**
+ * @brief Creates an notify_payload_t object of specific type for specific protocol id.
+ *
+ * @param protocol_id protocol id (IKE, AH or ESP)
+ * @param type notify type (see notify_type_t)
+ * @return notify_payload_t object
+ *
+ * @ingroup payloads
+ */
+notify_payload_t *notify_payload_create_from_protocol_and_type(protocol_id_t protocol_id, notify_type_t type);
+
+
+#endif /*NOTIFY_PAYLOAD_H_*/
diff --git a/src/charon/encoding/payloads/payload.c b/src/charon/encoding/payloads/payload.c
new file mode 100644
index 000000000..3bd4cdb13
--- /dev/null
+++ b/src/charon/encoding/payloads/payload.c
@@ -0,0 +1,161 @@
+/**
+ * @file payload.c
+ *
+ * @brief Generic constructor to the payload_t interface.
+ *
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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>
+
+
+ENUM_BEGIN(payload_type_names, NO_PAYLOAD, NO_PAYLOAD,
+ "NO_PAYLOAD");
+ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION, EXTENSIBLE_AUTHENTICATION, NO_PAYLOAD,
+ "SECURITY_ASSOCIATION",
+ "KEY_EXCHANGE",
+ "ID_INITIATOR",
+ "ID_RESPONDER",
+ "CERTIFICATE",
+ "CERTIFICATE_REQUEST",
+ "AUTHENTICATION",
+ "NONCE",
+ "NOTIFY",
+ "DELETE",
+ "VENDOR_ID",
+ "TRAFFIC_SELECTOR_INITIATOR",
+ "TRAFFIC_SELECTOR_RESPONDER",
+ "ENCRYPTED",
+ "CONFIGURATION",
+ "EXTENSIBLE_AUTHENTICATION");
+ENUM_NEXT(payload_type_names, HEADER, UNKNOWN_PAYLOAD, EXTENSIBLE_AUTHENTICATION,
+ "HEADER",
+ "PROPOSAL_SUBSTRUCTURE",
+ "TRANSFORM_SUBSTRUCTURE",
+ "TRANSFORM_ATTRIBUTE",
+ "TRAFFIC_SELECTOR_SUBSTRUCTURE",
+ "CONFIGURATION_ATTRIBUTE",
+ "UNKNOWN_PAYLOAD");
+ENUM_END(payload_type_names, UNKNOWN_PAYLOAD);
+
+/* short forms of payload names */
+ENUM_BEGIN(payload_type_short_names, NO_PAYLOAD, NO_PAYLOAD,
+ "--");
+ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION, EXTENSIBLE_AUTHENTICATION, NO_PAYLOAD,
+ "SA",
+ "KE",
+ "IDi",
+ "IDr",
+ "CERT",
+ "CERTREQ",
+ "AUTH",
+ "No",
+ "N",
+ "D",
+ "V",
+ "TSi",
+ "TSr",
+ "E",
+ "CP",
+ "EAP");
+ENUM_NEXT(payload_type_short_names, HEADER, UNKNOWN_PAYLOAD, EXTENSIBLE_AUTHENTICATION,
+ "HDR",
+ "PROP",
+ "TRANS",
+ "TRANSATTR",
+ "TSSUB",
+ "CPATTR",
+ "??");
+ENUM_END(payload_type_short_names, UNKNOWN_PAYLOAD);
+
+/*
+ * 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(0);
+ 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/src/charon/encoding/payloads/payload.h b/src/charon/encoding/payloads/payload.h
new file mode 100644
index 000000000..9a8c2f482
--- /dev/null
+++ b/src/charon/encoding/payloads/payload.h
@@ -0,0 +1,282 @@
+/**
+ * @file payload.h
+ *
+ * @brief Interface payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef enum payload_type_t payload_type_t;
+typedef struct payload_t payload_t;
+
+#include <library.h>
+#include <encoding/payloads/encodings.h>
+
+
+/**
+ * @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,
+};
+
+
+/**
+ * enum names for payload_type_t.
+ */
+extern enum_name_t *payload_type_names;
+
+/**
+ * enum names for payload_type_t in a short form.
+ */
+extern enum_name_t *payload_type_short_names;
+
+/**
+ * @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 instantiate.
+ *
+ * @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/src/charon/encoding/payloads/proposal_substructure.c b/src/charon/encoding/payloads/proposal_substructure.c
new file mode 100644
index 000000000..182d2b6e8
--- /dev/null
+++ b/src/charon/encoding/payloads/proposal_substructure.c
@@ -0,0 +1,603 @@
+/**
+ * @file proposal_substructure.h
+ *
+ * @brief Implementation of proposal_substructure_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <library.h>
+#include <utils/linked_list.h>
+#include <daemon.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;
+};
+
+/**
+ * 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;
+ payload_t *current_transform;
+
+ if ((this->next_payload != NO_PAYLOAD) && (this->next_payload != 2))
+ {
+ /* must be 0 or 2 */
+ DBG1(DBG_ENC, "inconsistent next payload");
+ return FAILED;
+ }
+ if (this->transforms_count != this->transforms->get_count(this->transforms))
+ {
+ /* must be the same! */
+ DBG1(DBG_ENC, "transform count invalid");
+ return FAILED;
+ }
+
+ switch (this->protocol_id)
+ {
+ case PROTO_AH:
+ case PROTO_ESP:
+ if (this->spi.len != 4)
+ {
+ DBG1(DBG_ENC, "invalid SPI length in %N proposal",
+ protocol_id_names, this->protocol_id);
+ return FAILED;
+ }
+ break;
+ case PROTO_IKE:
+ if (this->spi.len != 0 && this->spi.len != 8)
+ {
+ DBG1(DBG_ENC, "invalid SPI length in IKE proposal");
+ return FAILED;
+ }
+ break;
+ default:
+ DBG1(DBG_ENC, "invalid proposal protocol (%d)", this->protocol_id);
+ return FAILED;
+ }
+ if ((this->protocol_id == 0) || (this->protocol_id >= 4))
+ {
+ /* reserved are not supported */
+ DBG1(DBG_ENC, "invalid protocol");
+ return FAILED;
+ }
+
+ iterator = this->transforms->create_iterator(this->transforms,TRUE);
+ while(iterator->iterate(iterator, (void**)&current_transform))
+ {
+ status = current_transform->verify(current_transform);
+ if (status != SUCCESS)
+ {
+ DBG1(DBG_ENC, "TRANSFORM_SUBSTRUCTURE verification failed");
+ 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)
+{
+}
+
+/**
+ * (re-)compute the length of the payload.
+ */
+static void compute_length(private_proposal_substructure_t *this)
+{
+ iterator_t *iterator;
+ payload_t *current_transform;
+ size_t transforms_count = 0;
+ size_t length = PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH;
+
+ iterator = this->transforms->create_iterator(this->transforms,TRUE);
+ while (iterator->iterate(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 payload_t.get_length.
+ */
+static size_t get_length(private_proposal_substructure_t *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);
+ 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;
+ compute_length(this);
+ }
+
+ this->spi.ptr = clalloc(spi.ptr,spi.len);
+ this->spi.len = spi.len;
+ this->spi_size = spi.len;
+ 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_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.get_proposal.
+ */
+proposal_t* get_proposal(private_proposal_substructure_t *this)
+{
+ iterator_t *iterator;
+ transform_substructure_t *transform;
+ proposal_t *proposal;
+ u_int64_t spi;
+
+ proposal = proposal_create(this->protocol_id);
+
+ iterator = this->transforms->create_iterator(this->transforms, TRUE);
+ while (iterator->iterate(iterator, (void**)&transform))
+ {
+ transform_type_t transform_type;
+ u_int16_t transform_id;
+ u_int16_t key_length = 0;
+
+ 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, transform_type, transform_id, key_length);
+ }
+ iterator->destroy(iterator);
+
+ switch (this->spi.len)
+ {
+ case 4:
+ spi = *((u_int32_t*)this->spi.ptr);
+ break;
+ case 8:
+ spi = *((u_int64_t*)this->spi.ptr);
+ break;
+ default:
+ spi = 0;
+ }
+ proposal->set_spi(proposal, spi);
+
+ return proposal;
+}
+
+/**
+ * Implementation of proposal_substructure_t.clone.
+ */
+static private_proposal_substructure_t* clone_(private_proposal_substructure_t *this)
+{
+ private_proposal_substructure_t *clone;
+ iterator_t *transforms;
+ transform_substructure_t *current_transform;
+
+ clone = (private_proposal_substructure_t *) proposal_substructure_create();
+ clone->next_payload = this->next_payload;
+ clone->proposal_number = this->proposal_number;
+ clone->protocol_id = this->protocol_id;
+ clone->spi_size = this->spi_size;
+ if (this->spi.ptr != NULL)
+ {
+ clone->spi.ptr = clalloc(this->spi.ptr,this->spi.len);
+ clone->spi.len = this->spi.len;
+ }
+
+ transforms = this->transforms->create_iterator(this->transforms,FALSE);
+ while (transforms->iterate(transforms, (void**)&current_transform))
+ {
+ current_transform = current_transform->clone(current_transform);
+ clone->public.add_transform_substructure(&clone->public, current_transform);
+ }
+ transforms->destroy(transforms);
+
+ return clone;
+}
+
+/**
+ * Implements payload_t's and proposal_substructure_t's destroy function.
+ * See #payload_s.destroy or proposal_substructure_s.destroy for description.
+ */
+static void destroy(private_proposal_substructure_t *this)
+{
+ this->transforms->destroy_offset(this->transforms,
+ offsetof(transform_substructure_t, destroy));
+ chunk_free(&this->spi);
+ free(this);
+}
+
+/*
+ * 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.set_is_last_proposal = (void (*) (proposal_substructure_t *,bool)) set_is_last_proposal;
+ this->public.get_proposal = (proposal_t* (*) (proposal_substructure_t*))get_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;
+
+ /* 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)
+{
+ 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, ENCRYPTION_ALGORITHM);
+ while (iterator->iterate(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, INTEGRITY_ALGORITHM);
+ while (iterator->iterate(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, PSEUDO_RANDOM_FUNCTION);
+ while (iterator->iterate(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, DIFFIE_HELLMAN_GROUP);
+ while (iterator->iterate(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, EXTENDED_SEQUENCE_NUMBERS);
+ while (iterator->iterate(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);
+
+ /* add SPI, if necessary */
+ switch (proposal->get_protocol(proposal))
+ {
+ case PROTO_AH:
+ case PROTO_ESP:
+ this->spi_size = this->spi.len = 4;
+ this->spi.ptr = malloc(this->spi_size);
+ *((u_int32_t*)this->spi.ptr) = proposal->get_spi(proposal);
+ break;
+ case PROTO_IKE:
+ if (proposal->get_spi(proposal))
+ { /* IKE only uses SPIS when rekeying, but on initial setup */
+ this->spi_size = this->spi.len = 8;
+ this->spi.ptr = malloc(this->spi_size);
+ *((u_int64_t*)this->spi.ptr) = proposal->get_spi(proposal);
+ }
+ break;
+ default:
+ break;
+ }
+ this->proposal_number = 0;
+ this->protocol_id = proposal->get_protocol(proposal);
+
+ return &this->public;
+}
diff --git a/src/charon/encoding/payloads/proposal_substructure.h b/src/charon/encoding/payloads/proposal_substructure.h
new file mode 100644
index 000000000..93a8d7b2f
--- /dev/null
+++ b/src/charon/encoding/payloads/proposal_substructure.h
@@ -0,0 +1,206 @@
+/**
+ * @file proposal_substructure.h
+ *
+ * @brief Interface of proposal_substructure_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct proposal_substructure_t proposal_substructure_t;
+
+#include <library.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
+
+/**
+ * @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 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 Get a proposal_t from the propsal_substructure_t.
+ *
+ * @param this calling proposal_substructure_t object
+ * @return proposal_t
+ */
+ proposal_t * (*get_proposal) (proposal_substructure_t *this);
+
+ /**
+ * @brief Clones an proposal_substructure_t object.
+ *
+ * @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(void);
+
+/**
+ * @brief Creates a proposal_substructure_t from a proposal_t.
+ *
+ * @param proposal proposal to build a substruct out of it
+ * @return proposal_substructure_t object
+ *
+ * @ingroup payloads
+ */
+proposal_substructure_t *proposal_substructure_create_from_proposal(proposal_t *proposal);
+
+
+#endif /*PROPOSAL_SUBSTRUCTURE_H_*/
diff --git a/src/charon/encoding/payloads/sa_payload.c b/src/charon/encoding/payloads/sa_payload.c
new file mode 100644
index 000000000..e264b2123
--- /dev/null
+++ b/src/charon/encoding/payloads/sa_payload.c
@@ -0,0 +1,375 @@
+/**
+ * @file sa_payload.c
+ *
+ * @brief Implementation of sa_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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>
+#include <daemon.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;
+};
+
+/**
+ * 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 expected_number = 1, current_number;
+ status_t status = SUCCESS;
+ iterator_t *iterator;
+ proposal_substructure_t *current_proposal;
+ bool first = TRUE;
+
+ /* check proposal numbering */
+ iterator = this->proposals->create_iterator(this->proposals,TRUE);
+
+ while(iterator->iterate(iterator, (void**)&current_proposal))
+ {
+ current_number = current_proposal->get_proposal_number(current_proposal);
+ if (current_number < expected_number)
+ {
+ if (current_number != (expected_number + 1))
+ {
+ DBG1(DBG_ENC, "proposal number is %d, excepted %d or %d",
+ current_number, expected_number, expected_number + 1);
+ status = FAILED;
+ break;
+ }
+ }
+ else if (current_number < expected_number)
+ {
+ /* must not be smaller then proceeding one */
+ DBG1(DBG_ENC, "proposal number smaller than that of previous proposal");
+ status = FAILED;
+ break;
+ }
+
+ status = current_proposal->payload_interface.verify(&(current_proposal->payload_interface));
+ if (status != SUCCESS)
+ {
+ DBG1(DBG_ENC, "PROPOSAL_SUBSTRUCTURE verification failed");
+ break;
+ }
+ first = FALSE;
+ expected_number = current_number;
+ }
+
+ iterator->destroy(iterator);
+ return status;
+}
+
+
+/**
+ * Implementation of payload_t.destroy and sa_payload_t.destroy.
+ */
+static status_t destroy(private_sa_payload_t *this)
+{
+ this->proposals->destroy_offset(this->proposals,
+ offsetof(proposal_substructure_t, destroy));
+ 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;
+}
+
+/**
+ * recompute length of the payload.
+ */
+static void compute_length (private_sa_payload_t *this)
+{
+ iterator_t *iterator;
+ payload_t *current_proposal;
+ size_t length = SA_PAYLOAD_HEADER_LENGTH;
+
+ iterator = this->proposals->create_iterator(this->proposals,TRUE);
+ while (iterator->iterate(iterator, (void **)&current_proposal))
+ {
+ length += current_proposal->get_length(current_proposal);
+ }
+ iterator->destroy(iterator);
+
+ this->payload_length = length;
+}
+
+/**
+ * Implementation of payload_t.get_length.
+ */
+static size_t get_length(private_sa_payload_t *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;
+ u_int proposal_count = this->proposals->get_count(this->proposals);
+
+ if (proposal_count > 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);
+ proposal->set_proposal_number(proposal, proposal_count + 1);
+ this->proposals->insert_last(this->proposals,(void *) proposal);
+ 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;
+
+ substructure = proposal_substructure_create_from_proposal(proposal);
+ add_proposal_substructure(this, substructure);
+}
+
+/**
+ * Implementation of sa_payload_t.get_proposals.
+ */
+static linked_list_t *get_proposals(private_sa_payload_t *this)
+{
+ int struct_number = 0;
+ int ignore_struct_number = 0;
+ iterator_t *iterator;
+ proposal_substructure_t *proposal_struct;
+ linked_list_t *proposal_list;
+
+ /* this list will hold our proposals */
+ proposal_list = linked_list_create();
+
+ /* we do not support proposals split up to two proposal substructures, as
+ * AH+ESP bundles are not supported in RFC4301 anymore.
+ * To handle such structures safely, we just skip proposals with multiple
+ * protocols.
+ */
+ iterator = this->proposals->create_iterator(this->proposals, TRUE);
+ while (iterator->iterate(iterator, (void **)&proposal_struct))
+ {
+ proposal_t *proposal;
+
+ /* check if a proposal has a single protocol */
+ if (proposal_struct->get_proposal_number(proposal_struct) == struct_number)
+ {
+ if (ignore_struct_number < struct_number)
+ {
+ /* remova an already added, if first of series */
+ proposal_list->remove_last(proposal_list, (void**)&proposal);
+ proposal->destroy(proposal);
+ ignore_struct_number = struct_number;
+ }
+ continue;
+ }
+ struct_number++;
+ proposal = proposal_struct->get_proposal(proposal_struct);
+ if (proposal)
+ {
+ proposal_list->insert_last(proposal_list, proposal);
+ }
+ }
+ iterator->destroy(iterator);
+ return proposal_list;
+}
+
+/*
+ * 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.add_proposal = (void (*) (sa_payload_t*,proposal_t*))add_proposal;
+ this->public.get_proposals = (linked_list_t* (*) (sa_payload_t *)) get_proposals;
+ this->public.destroy = (void (*) (sa_payload_t *)) destroy;
+
+ /* 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->iterate(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/src/charon/encoding/payloads/sa_payload.h b/src/charon/encoding/payloads/sa_payload.h
new file mode 100644
index 000000000..67d687857
--- /dev/null
+++ b/src/charon/encoding/payloads/sa_payload.h
@@ -0,0 +1,141 @@
+/**
+ * @file sa_payload.h
+ *
+ * @brief Interface of sa_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct sa_payload_t sa_payload_t;
+
+#include <library.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
+
+/**
+ * @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(void);
+
+/**
+ * @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/src/charon/encoding/payloads/traffic_selector_substructure.c b/src/charon/encoding/payloads/traffic_selector_substructure.c
new file mode 100644
index 000000000..573139bf3
--- /dev/null
+++ b/src/charon/encoding/payloads/traffic_selector_substructure.c
@@ -0,0 +1,283 @@
+/**
+ * @file traffic_selector_substructure.c
+ *
+ * @brief Interface of traffic_selector_substructure_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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>
+
+
+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;
+};
+
+/**
+ * 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:
+ {
+ if ((this->starting_address.len != 16) ||
+ (this->ending_address.len != 16))
+ {
+ /* ipv6 address must be 16 bytes long */
+ return FAILED;
+ }
+ break;
+ }
+ 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_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;
+}
+
+/**
+ * recompute length field of the payload
+ */
+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.get_traffic_selector = (traffic_selector_t* (*)(traffic_selector_substructure_t*))get_traffic_selector;
+ this->public.destroy = (void (*) (traffic_selector_substructure_t *)) destroy;
+
+ /* private variables */
+ this->payload_length = TRAFFIC_SELECTOR_HEADER_LENGTH;
+ this->start_port = 0;
+ this->end_port = 0;
+ this->starting_address = chunk_empty;
+ this->ending_address = chunk_empty;
+ 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);
+
+ compute_length(this);
+
+ return &(this->public);
+}
diff --git a/src/charon/encoding/payloads/traffic_selector_substructure.h b/src/charon/encoding/payloads/traffic_selector_substructure.h
new file mode 100644
index 000000000..14efccc89
--- /dev/null
+++ b/src/charon/encoding/payloads/traffic_selector_substructure.h
@@ -0,0 +1,172 @@
+/**
+ * @file traffic_selector_substructure.h
+ *
+ * @brief Interface of traffic_selector_substructure_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct traffic_selector_substructure_t traffic_selector_substructure_t;
+
+#include <library.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
+
+/**
+ * @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(void);
+
+/**
+ * @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/src/charon/encoding/payloads/transform_attribute.c b/src/charon/encoding/payloads/transform_attribute.c
new file mode 100644
index 000000000..066885c55
--- /dev/null
+++ b/src/charon/encoding/payloads/transform_attribute.c
@@ -0,0 +1,332 @@
+/**
+ * @file transform_attribute.c
+ *
+ * @brief Implementation of transform_attribute_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <library.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;
+};
+
+
+ENUM_BEGIN(transform_attribute_type_name, ATTRIBUTE_UNDEFINED, ATTRIBUTE_UNDEFINED,
+ "ATTRIBUTE_UNDEFINED");
+ENUM_NEXT(transform_attribute_type_name, KEY_LENGTH, KEY_LENGTH, ATTRIBUTE_UNDEFINED,
+ "KEY_LENGTH");
+ENUM_END(transform_attribute_type_name, KEY_LENGTH);
+
+/**
+ * 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/src/charon/encoding/payloads/transform_attribute.h b/src/charon/encoding/payloads/transform_attribute.h
new file mode 100644
index 000000000..30583b23f
--- /dev/null
+++ b/src/charon/encoding/payloads/transform_attribute.h
@@ -0,0 +1,154 @@
+/**
+ * @file transform_attribute.h
+ *
+ * @brief Interface of transform_attribute_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef enum transform_attribute_type_t transform_attribute_type_t;
+typedef struct transform_attribute_t transform_attribute_t;
+
+#include <library.h>
+#include <encoding/payloads/payload.h>
+
+
+/**
+ * Type of the attribute, as in IKEv2 RFC 3.3.5.
+ *
+ * @ingroup payloads
+ */
+enum transform_attribute_type_t {
+ ATTRIBUTE_UNDEFINED = 16384,
+ KEY_LENGTH = 14
+};
+
+/**
+ * enum name for transform_attribute_type_t.
+ *
+ * @ingroup payloads
+ */
+extern enum_name_t *transform_attribute_type_names;
+
+/**
+ * @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(void);
+
+/**
+ * @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/src/charon/encoding/payloads/transform_substructure.c b/src/charon/encoding/payloads/transform_substructure.c
new file mode 100644
index 000000000..d64d6c754
--- /dev/null
+++ b/src/charon/encoding/payloads/transform_substructure.c
@@ -0,0 +1,409 @@
+/**
+ * @file transform_substructure.h
+ *
+ * @brief Implementation of transform_substructure_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <library.h>
+#include <utils/linked_list.h>
+#include <daemon.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;
+};
+
+
+/**
+ * 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;
+ payload_t *current_attributes;
+
+ if ((this->next_payload != NO_PAYLOAD) && (this->next_payload != 3))
+ {
+ /* must be 0 or 3 */
+ DBG1(DBG_ENC, "inconsistent next payload");
+ return FAILED;
+ }
+
+ switch (this->transform_type)
+ {
+ case ENCRYPTION_ALGORITHM:
+ case PSEUDO_RANDOM_FUNCTION:
+ case INTEGRITY_ALGORITHM:
+ case DIFFIE_HELLMAN_GROUP:
+ case EXTENDED_SEQUENCE_NUMBERS:
+ /* we don't check transform ID, we want to reply
+ * cleanly with NO_PROPOSAL_CHOSEN or so if we don't support it */
+ break;
+ default:
+ {
+ DBG1(DBG_ENC, "invalid transform type: %d", this->transform_type);
+ return FAILED;
+ }
+ }
+ iterator = this->attributes->create_iterator(this->attributes,TRUE);
+
+ while(iterator->iterate(iterator, (void**)&current_attributes))
+ {
+ status = current_attributes->verify(current_attributes);
+ if (status != SUCCESS)
+ {
+ DBG1(DBG_ENC, "TRANSFORM_ATTRIBUTE verification failed");
+ }
+ }
+ 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);
+}
+
+/**
+ * recompute the length of the payload.
+ */
+static void compute_length (private_transform_substructure_t *this)
+{
+ iterator_t *iterator;
+ payload_t *current_attribute;
+ size_t length = TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH;
+
+ iterator = this->attributes->create_iterator(this->attributes,TRUE);
+ while (iterator->iterate(iterator, (void**)&current_attribute))
+ {
+ length += current_attribute->get_length(current_attribute);
+ }
+ iterator->destroy(iterator);
+
+ this->transform_length = length;
+}
+
+/**
+ * Implementation of payload_t.get_length.
+ */
+static size_t get_length(private_transform_substructure_t *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);
+ 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 transform_substructure_t.clone.
+ */
+static transform_substructure_t *clone_(private_transform_substructure_t *this)
+{
+ private_transform_substructure_t *clone;
+ iterator_t *attributes;
+ transform_attribute_t *current_attribute;
+
+ clone = (private_transform_substructure_t *) transform_substructure_create();
+ clone->next_payload = this->next_payload;
+ clone->transform_type = this->transform_type;
+ clone->transform_id = this->transform_id;
+
+ attributes = this->attributes->create_iterator(this->attributes, FALSE);
+ while (attributes->iterate(attributes, (void**)&current_attribute))
+ {
+ current_attribute = current_attribute->clone(current_attribute);
+ clone->public.add_transform_attribute(&clone->public, current_attribute);
+ }
+ attributes->destroy(attributes);
+
+ return &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;
+ transform_attribute_t *current_attribute;
+
+ attributes = this->attributes->create_iterator(this->attributes, TRUE);
+ while (attributes->iterate(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)
+{
+ this->attributes->destroy_offset(this->attributes,
+ offsetof(transform_attribute_t, destroy));
+ 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;
+
+ /* 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 variable length algos */
+ if (transform_type == ENCRYPTION_ALGORITHM &&
+ (transform_id == ENCR_AES_CBC ||
+ transform_id == ENCR_IDEA ||
+ transform_id == ENCR_CAST ||
+ transform_id == ENCR_BLOWFISH))
+ {
+ transform_attribute_t *attribute = transform_attribute_create_key_length(key_length);
+ transform->add_transform_attribute(transform,attribute);
+ }
+
+ return transform;
+}
diff --git a/src/charon/encoding/payloads/transform_substructure.h b/src/charon/encoding/payloads/transform_substructure.h
new file mode 100644
index 000000000..97f587d5d
--- /dev/null
+++ b/src/charon/encoding/payloads/transform_substructure.h
@@ -0,0 +1,198 @@
+/**
+ * @file transform_substructure.h
+ *
+ * @brief Interface of transform_substructure_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct transform_substructure_t transform_substructure_t;
+
+#include <library.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
+
+
+/**
+ * @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(void);
+
+/**
+ * @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/src/charon/encoding/payloads/ts_payload.c b/src/charon/encoding/payloads/ts_payload.c
new file mode 100644
index 000000000..ae89919f6
--- /dev/null
+++ b/src/charon/encoding/payloads/ts_payload.c
@@ -0,0 +1,341 @@
+/**
+ * @file ts_payload.c
+ *
+ * @brief Implementation of ts_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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;
+};
+
+/**
+ * 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;
+ payload_t *current_traffic_selector;
+ 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->iterate(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;
+}
+
+/**
+ * recompute the length of the payload.
+ */
+static void compute_length (private_ts_payload_t *this)
+{
+ iterator_t *iterator;
+ size_t ts_count = 0;
+ size_t length = TS_PAYLOAD_HEADER_LENGTH;
+ payload_t *current_traffic_selector;
+
+ iterator = this->traffic_selectors->create_iterator(this->traffic_selectors,TRUE);
+ while (iterator->iterate(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.get_length.
+ */
+static size_t get_length(private_ts_payload_t *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;
+ traffic_selector_substructure_t *ts_substructure;
+ linked_list_t *ts_list = linked_list_create();
+
+ iterator = this->traffic_selectors->create_iterator(this->traffic_selectors, TRUE);
+ while (iterator->iterate(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 payload_t.destroy and ts_payload_t.destroy.
+ */
+static void destroy(private_ts_payload_t *this)
+{
+ this->traffic_selectors->destroy_offset(this->traffic_selectors,
+ offsetof(payload_t, destroy));
+ 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 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->iterate(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/src/charon/encoding/payloads/ts_payload.h b/src/charon/encoding/payloads/ts_payload.h
new file mode 100644
index 000000000..1addee22c
--- /dev/null
+++ b/src/charon/encoding/payloads/ts_payload.h
@@ -0,0 +1,153 @@
+/**
+ * @file ts_payload.h
+ *
+ * @brief Interface of ts_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct ts_payload_t ts_payload_t;
+
+#include <library.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
+
+
+/**
+ * @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/src/charon/encoding/payloads/unknown_payload.c b/src/charon/encoding/payloads/unknown_payload.c
new file mode 100644
index 000000000..bbe736085
--- /dev/null
+++ b/src/charon/encoding/payloads/unknown_payload.c
@@ -0,0 +1,208 @@
+/**
+ * @file unknown_payload.c
+ *
+ * @brief Implementation of unknown_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_empty;
+
+ return (&(this->public));
+}
diff --git a/src/charon/encoding/payloads/unknown_payload.h b/src/charon/encoding/payloads/unknown_payload.h
new file mode 100644
index 000000000..8d13a03a3
--- /dev/null
+++ b/src/charon/encoding/payloads/unknown_payload.h
@@ -0,0 +1,95 @@
+/**
+ * @file unknown_payload.h
+ *
+ * @brief Interface of unknown_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct unknown_payload_t unknown_payload_t;
+
+#include <library.h>
+#include <encoding/payloads/payload.h>
+
+/**
+ * Header length of the unknown payload.
+ *
+ * @ingroup payloads
+ */
+#define UNKNOWN_PAYLOAD_HEADER_LENGTH 4
+
+/**
+ * @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(void);
+
+
+#endif /* UNKNOWN_PAYLOAD_H_ */
diff --git a/src/charon/encoding/payloads/vendor_id_payload.c b/src/charon/encoding/payloads/vendor_id_payload.c
new file mode 100644
index 000000000..e3a4d2e1f
--- /dev/null
+++ b/src/charon/encoding/payloads/vendor_id_payload.c
@@ -0,0 +1,228 @@
+/**
+ * @file vendor_id_payload.c
+ *
+ * @brief Implementation of vendor_id_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_empty;
+
+ return (&(this->public));
+}
diff --git a/src/charon/encoding/payloads/vendor_id_payload.h b/src/charon/encoding/payloads/vendor_id_payload.h
new file mode 100644
index 000000000..c7eebc155
--- /dev/null
+++ b/src/charon/encoding/payloads/vendor_id_payload.h
@@ -0,0 +1,104 @@
+/**
+ * @file vendor_id_payload.h
+ *
+ * @brief Interface of vendor_id_payload_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct vendor_id_payload_t vendor_id_payload_t;
+
+#include <library.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
+
+
+/**
+ * @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(void);
+
+
+#endif /* VENDOR_ID_PAYLOAD_H_ */
diff --git a/src/charon/network/packet.c b/src/charon/network/packet.c
new file mode 100644
index 000000000..f2fa91569
--- /dev/null
+++ b/src/charon/network/packet.c
@@ -0,0 +1,168 @@
+/**
+ * @file packet.c
+ *
+ * @brief Implementation of packet_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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)
+{
+ DESTROY_IF(this->source);
+ this->source = source;
+}
+
+/**
+ * Implements packet_t.set_destination
+ */
+static void set_destination(private_packet_t *this, host_t *destination)
+{
+ DESTROY_IF(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);
+ }
+ if (this->source != NULL)
+ {
+ other->source = this->source->clone(this->source);
+ }
+ if (this->data.ptr != NULL)
+ {
+ other->data.ptr = clalloc(this->data.ptr,this->data.len);
+ other->data.len = this->data.len;
+ }
+ return &(other->public);
+}
+
+/*
+ * Documented in header
+ */
+packet_t *packet_create(void)
+{
+ 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_empty;
+
+ return &(this->public);
+}
diff --git a/src/charon/network/packet.h b/src/charon/network/packet.h
new file mode 100644
index 000000000..acf953032
--- /dev/null
+++ b/src/charon/network/packet.h
@@ -0,0 +1,134 @@
+/**
+ * @file packet.h
+ *
+ * @brief Interface of packet_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct packet_t packet_t;
+
+#include <library.h>
+#include <utils/host.h>
+
+/**
+ * @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(void);
+
+
+#endif /*PACKET_H_*/
diff --git a/src/charon/network/socket.c b/src/charon/network/socket.c
new file mode 100644
index 000000000..00ba22d5a
--- /dev/null
+++ b/src/charon/network/socket.c
@@ -0,0 +1,755 @@
+/**
+ * @file socket.c
+ *
+ * @brief Implementation of socket_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <sys/ioctl.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/udp.h>
+#include <linux/ipsec.h>
+#include <linux/filter.h>
+#include <net/if.h>
+
+#include "socket.h"
+
+#include <daemon.h>
+
+/* constants for packet handling */
+#define IP_LEN sizeof(struct iphdr)
+#define IP6_LEN sizeof(struct ip6_hdr)
+#define UDP_LEN sizeof(struct udphdr)
+#define MARKER_LEN sizeof(u_int32_t)
+
+/* offsets for packet handling */
+#define IP_PROTO_OFFSET 9
+#define IP6_PROTO_OFFSET 6
+#define IKE_VERSION_OFFSET 17
+#define IKE_LENGTH_OFFSET 24
+
+/* from linux/in.h */
+#ifndef IP_IPSEC_POLICY
+#define IP_IPSEC_POLICY 16
+#endif /*IP_IPSEC_POLICY*/
+
+/* from linux/udp.h */
+#ifndef UDP_ENCAP
+#define UDP_ENCAP 100
+#endif /*UDP_ENCAP*/
+
+#ifndef UDP_ENCAP_ESPINUDP
+#define UDP_ENCAP_ESPINUDP 2
+#endif /*UDP_ENCAP_ESPINUDP*/
+
+/* needed for older kernel headers */
+#ifndef IPV6_2292PKTINFO
+#define IPV6_2292PKTINFO 2
+#endif /*IPV6_2292PKTINFO*/
+
+/* missing on uclibc */
+#ifndef IPV6_IPSEC_POLICY
+#define IPV6_IPSEC_POLICY 34
+#endif /*IPV6_IPSEC_POLICY*/
+
+typedef struct private_socket_t private_socket_t;
+
+/**
+ * Private data of an socket_t object
+ */
+struct private_socket_t{
+ /**
+ * public functions
+ */
+ socket_t public;
+
+ /**
+ * regular port
+ */
+ int port;
+
+ /**
+ * port used for nat-t
+ */
+ int natt_port;
+
+ /**
+ * raw receiver socket for IPv4
+ */
+ int recv4;
+
+ /**
+ * raw receiver socket for IPv6
+ */
+ int recv6;
+
+ /**
+ * send socket on regular port for IPv4
+ */
+ int send4;
+
+ /**
+ * send socket on regular port for IPv6
+ */
+ int send6;
+
+ /**
+ * send socket on nat-t port for IPv4
+ */
+ int send4_natt;
+
+ /**
+ * send socket on nat-t port for IPv6
+ */
+ int send6_natt;
+};
+
+/**
+ * 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;
+ struct udphdr *udp;
+ host_t *source = NULL, *dest = NULL;
+ int bytes_read = 0;
+ int data_offset, oldstate;
+ fd_set rfds;
+
+ FD_ZERO(&rfds);
+
+ if (this->recv4)
+ {
+ FD_SET(this->recv4, &rfds);
+ }
+ if (this->recv6)
+ {
+ FD_SET(this->recv6, &rfds);
+ }
+
+ DBG2(DBG_NET, "waiting for data on raw sockets");
+
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
+ if (select(max(this->recv4, this->recv6) + 1, &rfds, NULL, NULL, NULL) <= 0)
+ {
+ pthread_setcancelstate(oldstate, NULL);
+ return FAILED;
+ }
+ pthread_setcancelstate(oldstate, NULL);
+
+ if (this->recv4 && FD_ISSET(this->recv4, &rfds))
+ {
+ /* IPv4 raw sockets return the IP header. We read src/dest
+ * information directly from the raw header */
+ struct iphdr *ip;
+ struct sockaddr_in src, dst;
+
+ bytes_read = recv(this->recv4, buffer, MAX_PACKET, 0);
+ if (bytes_read < 0)
+ {
+ DBG1(DBG_NET, "error reading from IPv4 socket: %m");
+ return FAILED;
+ }
+ DBG3(DBG_NET, "received IPv4 packet %b", buffer, bytes_read);
+
+ /* read source/dest from raw IP/UDP header */
+ if (bytes_read < IP_LEN + UDP_LEN + MARKER_LEN)
+ {
+ DBG1(DBG_NET, "received IPv4 packet too short (%d bytes)",
+ bytes_read);
+ return FAILED;
+ }
+ ip = (struct iphdr*) buffer;
+ udp = (struct udphdr*) (buffer + IP_LEN);
+ src.sin_family = AF_INET;
+ src.sin_addr.s_addr = ip->saddr;
+ src.sin_port = udp->source;
+ dst.sin_family = AF_INET;
+ dst.sin_addr.s_addr = ip->daddr;
+ dst.sin_port = udp->dest;
+ source = host_create_from_sockaddr((sockaddr_t*)&src);
+ dest = host_create_from_sockaddr((sockaddr_t*)&dst);
+
+ pkt = packet_create();
+ pkt->set_source(pkt, source);
+ pkt->set_destination(pkt, dest);
+ DBG2(DBG_NET, "received packet: from %#H to %#H", source, dest);
+ data_offset = IP_LEN + UDP_LEN;
+ /* remove non esp marker */
+ if (dest->get_port(dest) == this->natt_port)
+ {
+ data_offset += MARKER_LEN;
+ }
+ /* fill in packet */
+ data.len = bytes_read - data_offset;
+ data.ptr = malloc(data.len);
+ memcpy(data.ptr, buffer + data_offset, data.len);
+ pkt->set_data(pkt, data);
+ }
+ else if (this->recv6 && FD_ISSET(this->recv6, &rfds))
+ {
+ /* IPv6 raw sockets return no IP header. We must query
+ * src/dest via socket options/ancillary data */
+ struct msghdr msg;
+ struct cmsghdr *cmsgptr;
+ struct sockaddr_in6 src, dst;
+ struct iovec iov;
+ char ancillary[64];
+
+ msg.msg_name = &src;
+ msg.msg_namelen = sizeof(src);
+ iov.iov_base = buffer;
+ iov.iov_len = sizeof(buffer);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = ancillary;
+ msg.msg_controllen = sizeof(ancillary);
+ msg.msg_flags = 0;
+
+ bytes_read = recvmsg(this->recv6, &msg, 0);
+ if (bytes_read < 0)
+ {
+ DBG1(DBG_NET, "error reading from IPv6 socket: %m");
+ return FAILED;
+ }
+ DBG3(DBG_NET, "received IPv6 packet %b", buffer, bytes_read);
+
+ if (bytes_read < IP_LEN + UDP_LEN + MARKER_LEN)
+ {
+ DBG3(DBG_NET, "received IPv6 packet too short (%d bytes)",
+ bytes_read);
+ return FAILED;
+ }
+
+ /* read ancillary data to get destination address */
+ for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL;
+ cmsgptr = CMSG_NXTHDR(&msg, cmsgptr))
+ {
+ if (cmsgptr->cmsg_len == 0)
+ {
+ DBG1(DBG_NET, "error reading IPv6 ancillary data");
+ return FAILED;
+ }
+ if (cmsgptr->cmsg_level == SOL_IPV6 &&
+ cmsgptr->cmsg_type == IPV6_2292PKTINFO)
+ {
+ struct in6_pktinfo *pktinfo;
+ pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsgptr);
+
+ memset(&dst, 0, sizeof(dst));
+ memcpy(&dst.sin6_addr, &pktinfo->ipi6_addr, sizeof(dst.sin6_addr));
+ dst.sin6_family = AF_INET6;
+ udp = (struct udphdr*) (buffer);
+ dst.sin6_port = udp->dest;
+ src.sin6_port = udp->source;
+ dest = host_create_from_sockaddr((sockaddr_t*)&dst);
+ }
+ }
+ /* ancillary data missing? */
+ if (dest == NULL)
+ {
+ DBG1(DBG_NET, "error reading IPv6 packet header");
+ return FAILED;
+ }
+
+ source = host_create_from_sockaddr((sockaddr_t*)&src);
+
+ pkt = packet_create();
+ pkt->set_source(pkt, source);
+ pkt->set_destination(pkt, dest);
+ DBG2(DBG_NET, "received packet: from %#H to %#H", source, dest);
+ data_offset = UDP_LEN;
+ /* remove non esp marker */
+ if (dest->get_port(dest) == this->natt_port)
+ {
+ data_offset += MARKER_LEN;
+ }
+ /* fill in packet */
+ data.len = bytes_read - data_offset;
+ data.ptr = malloc(data.len);
+ memcpy(data.ptr, buffer + data_offset, data.len);
+ pkt->set_data(pkt, data);
+ }
+ else
+ {
+ /* oops, shouldn't happen */
+ return FAILED;
+ }
+
+ /* return packet */
+ *packet = pkt;
+ return SUCCESS;
+}
+
+/**
+ * implementation of socket_t.send
+ */
+status_t sender(private_socket_t *this, packet_t *packet)
+{
+ int sport, skt, family;
+ ssize_t bytes_sent;
+ chunk_t data, marked;
+ host_t *src, *dst;
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ struct iovec iov;
+
+ src = packet->get_source(packet);
+ dst = packet->get_destination(packet);
+ data = packet->get_data(packet);
+
+ DBG2(DBG_NET, "sending packet: from %#H to %#H", src, dst);
+
+ /* send data */
+ sport = src->get_port(src);
+ family = dst->get_family(dst);
+ if (sport == this->port)
+ {
+ if (family == AF_INET)
+ {
+ skt = this->send4;
+ }
+ else
+ {
+ skt = this->send6;
+ }
+ }
+ else if (sport == this->natt_port)
+ {
+ if (family == AF_INET)
+ {
+ skt = this->send4_natt;
+ }
+ else
+ {
+ skt = this->send6_natt;
+ }
+ /* NAT keepalives without marker */
+ if (data.len != 1 || data.ptr[0] != 0xFF)
+ {
+ /* add non esp marker to packet */
+ if (data.len > MAX_PACKET - MARKER_LEN)
+ {
+ DBG1(DBG_NET, "unable to send packet: it's too big (%d bytes)",
+ data.len);
+ return FAILED;
+ }
+ marked = chunk_alloc(data.len + MARKER_LEN);
+ memset(marked.ptr, 0, MARKER_LEN);
+ memcpy(marked.ptr + MARKER_LEN, data.ptr, data.len);
+ /* let the packet do the clean up for us */
+ packet->set_data(packet, marked);
+ data = marked;
+ }
+ }
+ else
+ {
+ DBG1(DBG_NET, "unable to locate a send socket for port %d", sport);
+ return FAILED;
+ }
+
+ memset(&msg, 0, sizeof(struct msghdr));
+ msg.msg_name = dst->get_sockaddr(dst);;
+ msg.msg_namelen = *dst->get_sockaddr_len(dst);
+ iov.iov_base = data.ptr;
+ iov.iov_len = data.len;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_flags = 0;
+
+ if (!dst->is_anyaddr(dst))
+ {
+ if (family == AF_INET)
+ {
+ char buf[CMSG_SPACE(sizeof(struct in_pktinfo))];
+ struct in_pktinfo *pktinfo;
+ struct sockaddr_in *sin;
+
+ msg.msg_control = buf;
+ msg.msg_controllen = sizeof(buf);
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_IP;
+ cmsg->cmsg_type = IP_PKTINFO;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+ pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg);
+ memset(pktinfo, 0, sizeof(struct in_pktinfo));
+ sin = (struct sockaddr_in*)src->get_sockaddr(src);
+ memcpy(&pktinfo->ipi_spec_dst, &sin->sin_addr, sizeof(struct in_addr));
+ }
+ else
+ {
+ char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
+ struct in6_pktinfo *pktinfo;
+ struct sockaddr_in6 *sin;
+
+ msg.msg_control = buf;
+ msg.msg_controllen = sizeof(buf);
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_IPV6;
+ cmsg->cmsg_type = IPV6_2292PKTINFO;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+ pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsg);
+ memset(pktinfo, 0, sizeof(struct in6_pktinfo));
+ sin = (struct sockaddr_in6*)src->get_sockaddr(src);
+ memcpy(&pktinfo->ipi6_addr, &sin->sin6_addr, sizeof(struct in6_addr));
+ }
+ }
+
+ bytes_sent = sendmsg(skt, &msg, 0);
+
+ if (bytes_sent != data.len)
+ {
+ DBG1(DBG_NET, "error writing to socket: %m");
+ return FAILED;
+ }
+ return SUCCESS;
+}
+
+/**
+ * open a socket to send packets
+ */
+static int open_send_socket(private_socket_t *this, int family, u_int16_t port)
+{
+ int on = TRUE;
+ int type = UDP_ENCAP_ESPINUDP;
+ struct sockaddr_storage addr;
+ u_int sol, ipsec_policy;
+ struct sadb_x_policy policy;
+ int skt;
+
+ memset(&addr, 0, sizeof(addr));
+ /* precalculate constants depending on address family */
+ switch (family)
+ {
+ case AF_INET:
+ {
+ struct sockaddr_in *sin = (struct sockaddr_in *)&addr;
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = INADDR_ANY;
+ sin->sin_port = htons(port);
+ sol = SOL_IP;
+ ipsec_policy = IP_IPSEC_POLICY;
+ break;
+ }
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr;
+ sin6->sin6_family = AF_INET6;
+ memcpy(&sin6->sin6_addr, &in6addr_any, sizeof(in6addr_any));
+ sin6->sin6_port = htons(port);
+ sol = SOL_IPV6;
+ ipsec_policy = IPV6_IPSEC_POLICY;
+ break;
+ }
+ default:
+ return 0;
+ }
+
+ skt = socket(family, SOCK_DGRAM, IPPROTO_UDP);
+ if (skt < 0)
+ {
+ DBG1(DBG_NET, "could not open send socket: %m");
+ return 0;
+ }
+
+ if (setsockopt(skt, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0)
+ {
+ DBG1(DBG_NET, "unable to set SO_REUSEADDR on send socket: %m");
+ close(skt);
+ return 0;
+ }
+
+ /* bypass outgoung IKE traffic on send socket */
+ memset(&policy, 0, sizeof(policy));
+ policy.sadb_x_policy_len = sizeof(policy) / sizeof(u_int64_t);
+ policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY;
+ policy.sadb_x_policy_type = IPSEC_POLICY_BYPASS;
+ policy.sadb_x_policy_dir = IPSEC_DIR_OUTBOUND;
+
+ if (setsockopt(skt, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
+ {
+ DBG1(DBG_NET, "unable to set IPSEC_POLICY on send socket: %m");
+ close(skt);
+ return 0;
+ }
+
+ /* We don't receive packets on the send socket, but we need a INBOUND policy.
+ * Otherwise, UDP decapsulation does not work!!! */
+ policy.sadb_x_policy_dir = IPSEC_DIR_INBOUND;
+ if (setsockopt(skt, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
+ {
+ DBG1(DBG_NET, "unable to set IPSEC_POLICY on send socket: %m");
+ close(skt);
+ return 0;
+ }
+
+ /* bind the send socket */
+ if (bind(skt, (struct sockaddr *)&addr, sizeof(addr)) < 0)
+ {
+ DBG1(DBG_NET, "unable to bind send socket: %m");
+ close(skt);
+ return 0;
+ }
+
+ if (family == AF_INET)
+ {
+ /* enable UDP decapsulation globally, only for one socket needed */
+ if (setsockopt(skt, SOL_UDP, UDP_ENCAP, &type, sizeof(type)) < 0)
+ {
+ DBG1(DBG_NET, "unable to set UDP_ENCAP: %m; NAT-T may fail");
+ }
+ }
+
+ return skt;
+}
+
+/**
+ * open a socket to receive packets
+ */
+static int open_recv_socket(private_socket_t *this, int family)
+{
+ int skt;
+ int on = TRUE;
+ u_int proto_offset, ip_len, sol, ipsec_policy, udp_header, ike_header;
+ struct sadb_x_policy policy;
+
+ /* precalculate constants depending on address family */
+ switch (family)
+ {
+ case AF_INET:
+ proto_offset = IP_PROTO_OFFSET;
+ ip_len = IP_LEN;
+ sol = SOL_IP;
+ ipsec_policy = IP_IPSEC_POLICY;
+ break;
+ case AF_INET6:
+ proto_offset = IP6_PROTO_OFFSET;
+ ip_len = 0; /* IPv6 raw sockets contain no IP header */
+ sol = SOL_IPV6;
+ ipsec_policy = IPV6_IPSEC_POLICY;
+ break;
+ default:
+ return 0;
+ }
+ udp_header = ip_len;
+ ike_header = ip_len + UDP_LEN;
+
+ /* 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[] =
+ {
+ /* Destination Port must be either port or natt_port */
+ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, udp_header + 2),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, this->port, 1, 0),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, this->natt_port, 5, 12),
+ /* port */
+ /* IKE version must be 2.0 */
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, ike_header + IKE_VERSION_OFFSET),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x20, 0, 10),
+ /* packet length is length in IKEv2 header + ip header + udp header */
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, ike_header + IKE_LENGTH_OFFSET),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, ip_len + UDP_LEN),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ /* natt_port */
+ /* nat-t: check for marker */
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, ike_header),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 5),
+ /* nat-t: IKE version must be 2.0 */
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, ike_header + MARKER_LEN + IKE_VERSION_OFFSET),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x20, 0, 3),
+ /* nat-t: packet length is length in IKEv2 header + ip header + udp header + non esp marker */
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, ike_header + MARKER_LEN + IKE_LENGTH_OFFSET),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, ip_len + UDP_LEN + MARKER_LEN),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ /* packet doesn't match, 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
+ };
+
+ /* set up a raw socket */
+ skt = socket(family, SOCK_RAW, IPPROTO_UDP);
+ if (skt < 0)
+ {
+ DBG1(DBG_NET, "unable to create raw socket: %m");
+ return 0;
+ }
+
+ if (setsockopt(skt, SOL_SOCKET, SO_ATTACH_FILTER,
+ &ikev2_filter, sizeof(ikev2_filter)) < 0)
+ {
+ DBG1(DBG_NET, "unable to attach IKEv2 filter to raw socket: %m");
+ close(skt);
+ return 0;
+ }
+
+ if (family == AF_INET6 &&
+ /* we use IPV6_2292PKTINFO, as IPV6_PKTINFO is defined as
+ * 2 or 50 depending on kernel header version */
+ setsockopt(skt, sol, IPV6_2292PKTINFO, &on, sizeof(on)) < 0)
+ {
+ DBG1(DBG_NET, "unable to set IPV6_PKTINFO on raw socket: %m");
+ close(skt);
+ return 0;
+ }
+
+ /* bypass incomining IKE traffic on this socket */
+ memset(&policy, 0, sizeof(policy));
+ policy.sadb_x_policy_len = sizeof(policy) / sizeof(u_int64_t);
+ policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY;
+ policy.sadb_x_policy_type = IPSEC_POLICY_BYPASS;
+ policy.sadb_x_policy_dir = IPSEC_DIR_INBOUND;
+
+ if (setsockopt(skt, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
+ {
+ DBG1(DBG_NET, "unable to set IPSEC_POLICY on raw socket: %m");
+ close(skt);
+ return 0;
+ }
+
+ return skt;
+}
+
+/**
+ * implementation of socket_t.destroy
+ */
+static void destroy(private_socket_t *this)
+{
+ if (this->recv4)
+ {
+ close(this->recv4);
+ }
+ if (this->recv6)
+ {
+ close(this->recv6);
+ }
+ if (this->send4)
+ {
+ close(this->send4);
+ }
+ if (this->send6)
+ {
+ close(this->send6);
+ }
+ if (this->send4_natt)
+ {
+ close(this->send4_natt);
+ }
+ if (this->send6_natt)
+ {
+ close(this->send6_natt);
+ }
+ free(this);
+}
+
+/*
+ * See header for description
+ */
+socket_t *socket_create(u_int16_t port, u_int16_t natt_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.destroy = (void(*)(socket_t*)) destroy;
+
+ this->port = port;
+ this->natt_port = natt_port;
+ this->recv4 = 0;
+ this->recv6 = 0;
+ this->send4 = 0;
+ this->send6 = 0;
+ this->send4_natt = 0;
+ this->send6_natt = 0;
+
+ this->recv4 = open_recv_socket(this, AF_INET);
+ if (this->recv4 == 0)
+ {
+ DBG1(DBG_NET, "could not open IPv4 receive socket, IPv4 disabled");
+ }
+ else
+ {
+ this->send4 = open_send_socket(this, AF_INET, this->port);
+ if (this->send4 == 0)
+ {
+ DBG1(DBG_NET, "could not open IPv4 send socket, IPv4 disabled");
+ close(this->recv4);
+ }
+ else
+ {
+ this->send4_natt = open_send_socket(this, AF_INET, this->natt_port);
+ if (this->send4_natt == 0)
+ {
+ DBG1(DBG_NET, "could not open IPv4 NAT-T send socket");
+ }
+ }
+ }
+
+ this->recv6 = open_recv_socket(this, AF_INET6);
+ if (this->recv6 == 0)
+ {
+ DBG1(DBG_NET, "could not open IPv6 receive socket, IPv6 disabled");
+ }
+ else
+ {
+ this->send6 = open_send_socket(this, AF_INET6, this->port);
+ if (this->send6 == 0)
+ {
+ DBG1(DBG_NET, "could not open IPv6 send socket, IPv6 disabled");
+ close(this->recv6);
+ }
+ else
+ {
+ this->send6_natt = open_send_socket(this, AF_INET6, this->natt_port);
+ if (this->send6_natt == 0)
+ {
+ DBG1(DBG_NET, "could not open IPv6 NAT-T send socket");
+ }
+ }
+ }
+
+ if (!(this->send4 || this->send6) || !(this->recv4 || this->recv6))
+ {
+ DBG1(DBG_NET, "could not create any sockets");
+ destroy(this);
+ charon->kill(charon, "socket initialization failed");
+ }
+
+ return (socket_t*)this;
+}
diff --git a/src/charon/network/socket.h b/src/charon/network/socket.h
new file mode 100644
index 000000000..ef60fa7b6
--- /dev/null
+++ b/src/charon/network/socket.h
@@ -0,0 +1,112 @@
+/**
+ * @file socket.h
+ *
+ * @brief Interface for socket_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct socket_t socket_t;
+
+#include <library.h>
+#include <network/packet.h>
+#include <utils/host.h>
+#include <utils/linked_list.h>
+
+/**
+ * @brief Maximum size of a packet.
+ *
+ * 3000 Bytes should be sufficient, see IKEv2 RFC.
+ *
+ * @ingroup network
+ */
+#define MAX_PACKET 3000
+
+/**
+ * @brief Abstraction of all sockets (IPv6/IPv6 send/receive).
+ *
+ * All available sockets are bound and the receive function
+ * reads from them. To allow binding of other daemons (pluto) to
+ * UDP/500, this implementation uses RAW sockets. An installed
+ * "Linux socket filter" filters out all non-IKEv2 traffic and handles
+ * just IKEv2 messages. An other daemon (pluto) must handle all traffic
+ * seperatly, e.g. ignore IKEv2 traffic, since charon handles that.
+ *
+ * @b Constructors:
+ * - socket_create()
+ *
+ * @ingroup network
+ */
+struct socket_t {
+
+ /**
+ * @brief Receive a packet.
+ *
+ * Reads a packet from the socket and sets source/dest
+ * appropriately.
+ *
+ * @param this socket_t object to work on
+ * @param packet pinter gets address from allocated packet_t
+ * @return
+ * - SUCCESS when packet successfully received
+ * - FAILED when unable to receive
+ */
+ status_t (*receive) (socket_t *this, 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 this 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 *this, packet_t *packet);
+
+ /**
+ * @brief Destroy sockets.
+ *
+ * close sockets and destroy socket_t object
+ *
+ * @param this socket_t to destroy
+ */
+ void (*destroy) (socket_t *this);
+};
+
+/**
+ * @brief Create a socket_t, wich binds multiple sockets.
+ *
+ * @param port port to bind socket to
+ * @param natt_port port to float to in NAT-T
+ * @return socket_t object
+ *
+ * @ingroup network
+ */
+socket_t *socket_create(u_int16_t port, u_int16_t natt_port);
+
+
+#endif /*SOCKET_H_*/
diff --git a/src/charon/queues/event_queue.c b/src/charon/queues/event_queue.c
new file mode 100644
index 000000000..40bcb1ed8
--- /dev/null
+++ b/src/charon/queues/event_queue.c
@@ -0,0 +1,290 @@
+/**
+ * @file event_queue.c
+ *
+ * @brief Implementation of event_queue_t
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <library.h>
+#include <utils/linked_list.h>
+
+
+
+typedef struct event_t event_t;
+
+/**
+ * Event containing a job and a schedule time
+ */
+struct event_t {
+ /**
+ * Time to fire the event.
+ */
+ timeval_t time;
+
+ /**
+ * Every event has its assigned job.
+ */
+ job_t * job;
+};
+
+/**
+ * destroy an event and its job
+ */
+static void event_destroy(event_t *event)
+{
+ event->job->destroy(event->job);
+ free(event);
+}
+
+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 milliseconds
+ */
+static long time_difference(struct timeval *end_time, struct timeval *start_time)
+{
+ time_t s;
+ suseconds_t us;
+
+ s = (end_time->tv_sec - start_time->tv_sec);
+ us = (end_time->tv_usec - start_time->tv_usec);
+ return ((s * 1000) + us/1000);
+}
+
+/**
+ * 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 (TRUE)
+ {
+ 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;
+ free(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_t *current_event;
+ iterator_t *iterator;
+
+ /* create event */
+ event = malloc_thing(event_t);
+ event->time = time;
+ event->job = job;
+
+ pthread_mutex_lock(&(this->mutex));
+
+ /* while just used to break out */
+ while(TRUE)
+ {
+ 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 = this->list->create_iterator(this->list,TRUE);
+ iterator->iterate(iterator, (void**)&current_event);
+ /* first element has not to be checked (already done) */
+ while(iterator->iterate(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;
+
+ time_t s = ms / 1000;
+ suseconds_t us = (ms - s * 1000) * 1000;
+
+ gettimeofday(&current_time, NULL);
+
+ time.tv_usec = (current_time.tv_usec + us) % 1000000;
+ time.tv_sec = current_time.tv_sec + (current_time.tv_usec + us)/1000000 + s;
+
+ this->add_absolute(this, job, time);
+}
+
+
+/**
+ * Implements event_queue_t.destroy.
+ */
+static void event_queue_destroy(private_event_queue_t *this)
+{
+ this->list->destroy_function(this->list, (void*)event_destroy);
+ 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/src/charon/queues/event_queue.h b/src/charon/queues/event_queue.h
new file mode 100644
index 000000000..cd275123b
--- /dev/null
+++ b/src/charon/queues/event_queue.h
@@ -0,0 +1,118 @@
+/**
+ * @file event_queue.h
+ *
+ * @brief Interface of job_queue_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct event_queue_t event_queue_t;
+
+#include <sys/time.h>
+
+#include <library.h>
+#include <queues/jobs/job.h>
+
+/**
+ * @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] time absolute 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(void);
+
+#endif /*EVENT_QUEUE_H_*/
diff --git a/src/charon/queues/job_queue.c b/src/charon/queues/job_queue.c
new file mode 100644
index 000000000..2310ca6ff
--- /dev/null
+++ b/src/charon/queues/job_queue.c
@@ -0,0 +1,139 @@
+/**
+ * @file job_queue.c
+ *
+ * @brief Implementation of job_queue_t
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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)
+{
+ this->list->destroy_offset(this->list, offsetof(job_t, destroy));
+ free(this);
+}
+
+/*
+ *
+ * Documented in header
+ */
+job_queue_t *job_queue_create(void)
+{
+ 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/src/charon/queues/job_queue.h b/src/charon/queues/job_queue.h
new file mode 100644
index 000000000..c971ba514
--- /dev/null
+++ b/src/charon/queues/job_queue.h
@@ -0,0 +1,100 @@
+/**
+ * @file job_queue.h
+ *
+ * @brief Interface of job_queue_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct job_queue_t job_queue_t;
+
+#include <library.h>
+#include <queues/jobs/job.h>
+
+/**
+ * @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(void);
+
+#endif /*JOB_QUEUE_H_*/
diff --git a/src/charon/queues/jobs/acquire_job.c b/src/charon/queues/jobs/acquire_job.c
new file mode 100644
index 000000000..b4ffb258d
--- /dev/null
+++ b/src/charon/queues/jobs/acquire_job.c
@@ -0,0 +1,98 @@
+/**
+ * @file acquire_job.c
+ *
+ * @brief Implementation of acquire_job_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 "acquire_job.h"
+
+#include <daemon.h>
+
+
+typedef struct private_acquire_job_t private_acquire_job_t;
+
+/**
+ * Private data of an acquire_job_t object.
+ */
+struct private_acquire_job_t {
+ /**
+ * Public acquire_job_t interface.
+ */
+ acquire_job_t public;
+
+ /**
+ * reqid of the child to rekey
+ */
+ u_int32_t reqid;
+};
+
+/**
+ * Implementation of job_t.get_type.
+ */
+static job_type_t get_type(private_acquire_job_t *this)
+{
+ return ACQUIRE;
+}
+
+/**
+ * Implementation of job_t.execute.
+ */
+static status_t execute(private_acquire_job_t *this)
+{
+ ike_sa_t *ike_sa;
+
+ ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
+ this->reqid, TRUE);
+ if (ike_sa == NULL)
+ {
+ DBG2(DBG_JOB, "CHILD_SA with reqid %d not found for acquiring",
+ this->reqid);
+ return DESTROY_ME;
+ }
+ ike_sa->acquire(ike_sa, this->reqid);
+
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ return DESTROY_ME;
+}
+
+/**
+ * Implementation of job_t.destroy.
+ */
+static void destroy(private_acquire_job_t *this)
+{
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+acquire_job_t *acquire_job_create(u_int32_t reqid)
+{
+ private_acquire_job_t *this = malloc_thing(private_acquire_job_t);
+
+ /* interface functions */
+ this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
+ this->public.job_interface.execute = (status_t (*) (job_t *)) execute;
+ this->public.job_interface.destroy = (void (*)(job_t*)) destroy;
+
+ /* private variables */
+ this->reqid = reqid;
+
+ return &(this->public);
+}
diff --git a/src/charon/queues/jobs/acquire_job.h b/src/charon/queues/jobs/acquire_job.h
new file mode 100644
index 000000000..54f1b9b5b
--- /dev/null
+++ b/src/charon/queues/jobs/acquire_job.h
@@ -0,0 +1,60 @@
+/**
+ * @file acquire_job.h
+ *
+ * @brief Interface of acquire_job_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 ACQUIRE_JOB_H_
+#define ACQUIRE_JOB_H_
+
+typedef struct acquire_job_t acquire_job_t;
+
+#include <library.h>
+#include <queues/jobs/job.h>
+
+/**
+ * @brief Class representing an ACQUIRE Job.
+ *
+ * This job initiates a CHILD SA on kernel request.
+ *
+ * @b Constructors:
+ * - acquire_job_create()
+ *
+ * @ingroup jobs
+ */
+struct acquire_job_t {
+ /**
+ * The job_t interface.
+ */
+ job_t job_interface;
+};
+
+/**
+ * @brief Creates a job of type ACQUIRE.
+ *
+ * We use the reqid to find the routed CHILD_SA.
+ *
+ * @param reqid reqid of the CHILD_SA to acquire
+ * @return acquire_job_t object
+ *
+ * @ingroup jobs
+ */
+acquire_job_t *acquire_job_create(u_int32_t reqid);
+
+#endif /* REKEY_CHILD_SA_JOB_H_ */
diff --git a/src/charon/queues/jobs/delete_child_sa_job.c b/src/charon/queues/jobs/delete_child_sa_job.c
new file mode 100644
index 000000000..f694696b0
--- /dev/null
+++ b/src/charon/queues/jobs/delete_child_sa_job.c
@@ -0,0 +1,113 @@
+/**
+ * @file delete_child_sa_job.c
+ *
+ * @brief Implementation of delete_child_sa_job_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 "delete_child_sa_job.h"
+
+#include <daemon.h>
+
+
+typedef struct private_delete_child_sa_job_t private_delete_child_sa_job_t;
+
+/**
+ * Private data of an delete_child_sa_job_t object.
+ */
+struct private_delete_child_sa_job_t {
+ /**
+
+ * Public delete_child_sa_job_t interface.
+ */
+ delete_child_sa_job_t public;
+
+ /**
+ * reqid of the CHILD_SA
+ */
+ u_int32_t reqid;
+
+ /**
+ * protocol of the CHILD_SA (ESP/AH)
+ */
+ protocol_id_t protocol;
+
+ /**
+ * inbound SPI of the CHILD_SA
+ */
+ u_int32_t spi;
+};
+
+/**
+ * Implementation of job_t.get_type.
+ */
+static job_type_t get_type(private_delete_child_sa_job_t *this)
+{
+ return DELETE_CHILD_SA;
+}
+
+/**
+ * Implementation of job_t.execute.
+ */
+static status_t execute(private_delete_child_sa_job_t *this)
+{
+ ike_sa_t *ike_sa;
+
+ ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
+ this->reqid, TRUE);
+ if (ike_sa == NULL)
+ {
+ DBG1(DBG_JOB, "CHILD_SA with reqid %d not found for delete",
+ this->reqid);
+ return DESTROY_ME;
+ }
+ ike_sa->delete_child_sa(ike_sa, this->protocol, this->spi);
+
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ return DESTROY_ME;
+}
+
+/**
+ * Implementation of job_t.destroy.
+ */
+static void destroy(private_delete_child_sa_job_t *this)
+{
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+delete_child_sa_job_t *delete_child_sa_job_create(u_int32_t reqid,
+ protocol_id_t protocol,
+ u_int32_t spi)
+{
+ private_delete_child_sa_job_t *this = malloc_thing(private_delete_child_sa_job_t);
+
+ /* interface functions */
+ this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
+ this->public.job_interface.execute = (status_t (*) (job_t *)) execute;
+ this->public.job_interface.destroy = (void (*)(job_t*)) destroy;
+
+ /* private variables */
+ this->reqid = reqid;
+ this->protocol = protocol;
+ this->spi = spi;
+
+ return &(this->public);
+}
diff --git a/src/charon/queues/jobs/delete_child_sa_job.h b/src/charon/queues/jobs/delete_child_sa_job.h
new file mode 100644
index 000000000..9c2e4fa4d
--- /dev/null
+++ b/src/charon/queues/jobs/delete_child_sa_job.h
@@ -0,0 +1,68 @@
+/**
+ * @file delete_child_sa_job.h
+ *
+ * @brief Interface of delete_child_sa_job_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 DELETE_CHILD_SA_JOB_H_
+#define DELETE_CHILD_SA_JOB_H_
+
+typedef struct delete_child_sa_job_t delete_child_sa_job_t;
+
+#include <library.h>
+#include <sa/ike_sa_id.h>
+#include <queues/jobs/job.h>
+#include <config/proposal.h>
+
+
+/**
+ * @brief Class representing an DELETE_CHILD_SA Job.
+ *
+ * This job initiates the delete of a CHILD SA.
+ *
+ * @b Constructors:
+ * - delete_child_sa_job_create()
+ *
+ * @ingroup jobs
+ */
+struct delete_child_sa_job_t {
+ /**
+ * The job_t interface.
+ */
+ job_t job_interface;
+};
+
+/**
+ * @brief Creates a job of type DELETE_CHILD_SA.
+ *
+ * The CHILD_SA is identified by its reqid, protocol (AH/ESP) and its
+ * inbound SPI.
+ *
+ * @param reqid reqid of the CHILD_SA, as used in kernel
+ * @param protocol protocol of the CHILD_SA
+ * @param spi security parameter index of the CHILD_SA
+ * @return delete_child_sa_job_t object
+ *
+ * @ingroup jobs
+ */
+delete_child_sa_job_t *delete_child_sa_job_create(u_int32_t reqid,
+ protocol_id_t protocol,
+ u_int32_t spi);
+
+#endif /* DELETE_CHILD_SA_JOB_H_ */
diff --git a/src/charon/queues/jobs/delete_ike_sa_job.c b/src/charon/queues/jobs/delete_ike_sa_job.c
new file mode 100644
index 000000000..706155aa6
--- /dev/null
+++ b/src/charon/queues/jobs/delete_ike_sa_job.c
@@ -0,0 +1,126 @@
+/**
+ * @file delete_ike_sa_job.c
+ *
+ * @brief Implementation of delete_ike_sa_job_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_ike_sa_job.h"
+
+#include <daemon.h>
+
+typedef struct private_delete_ike_sa_job_t private_delete_ike_sa_job_t;
+
+/**
+ * Private data of an delete_ike_sa_job_t Object
+ */
+struct private_delete_ike_sa_job_t {
+ /**
+ * public delete_ike_sa_job_t interface
+ */
+ delete_ike_sa_job_t public;
+
+ /**
+ * ID of the ike_sa to delete
+ */
+ ike_sa_id_t *ike_sa_id;
+
+ /**
+ * Should the IKE_SA be deleted if it is in ESTABLISHED state?
+ */
+ bool delete_if_established;
+};
+
+/**
+ * Implements job_t.get_type.
+ */
+static job_type_t get_type(private_delete_ike_sa_job_t *this)
+{
+ return DELETE_IKE_SA;
+}
+
+/**
+ * Implementation of job_t.execute.
+ */
+static status_t execute(private_delete_ike_sa_job_t *this)
+{
+ ike_sa_t *ike_sa;
+
+ ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
+ this->ike_sa_id);
+ if (ike_sa)
+ {
+ if (this->delete_if_established)
+ {
+ if (ike_sa->delete(ike_sa) == DESTROY_ME)
+ {
+ charon->ike_sa_manager->checkin_and_destroy(
+ charon->ike_sa_manager, ike_sa);
+ }
+ else
+ {
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ }
+ }
+ else
+ {
+ /* destroy only if not ESTABLISHED */
+ if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED)
+ {
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ }
+ else
+ {
+ DBG1(DBG_JOB, "deleting half open IKE_SA after timeout");
+ charon->ike_sa_manager->checkin_and_destroy(
+ charon->ike_sa_manager, ike_sa);
+ }
+ }
+ }
+ return DESTROY_ME;
+}
+
+/**
+ * Implements job_t.destroy.
+ */
+static void destroy(private_delete_ike_sa_job_t *this)
+{
+ this->ike_sa_id->destroy(this->ike_sa_id);
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+delete_ike_sa_job_t *delete_ike_sa_job_create(ike_sa_id_t *ike_sa_id,
+ bool delete_if_established)
+{
+ private_delete_ike_sa_job_t *this = malloc_thing(private_delete_ike_sa_job_t);
+
+ /* interface functions */
+ this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
+ this->public.job_interface.execute = (status_t (*) (job_t *)) execute;
+ this->public.job_interface.destroy = (void (*)(job_t *)) destroy;;
+
+ /* private variables */
+ this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
+ this->delete_if_established = delete_if_established;
+
+ return &(this->public);
+}
diff --git a/src/charon/queues/jobs/delete_ike_sa_job.h b/src/charon/queues/jobs/delete_ike_sa_job.h
new file mode 100644
index 000000000..43701a354
--- /dev/null
+++ b/src/charon/queues/jobs/delete_ike_sa_job.h
@@ -0,0 +1,66 @@
+/**
+ * @file delete_ike_sa_job.h
+ *
+ * @brief Interface of delete_ike_sa_job_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_IKE_SA_JOB_H_
+#define DELETE_IKE_SA_JOB_H_
+
+typedef struct delete_ike_sa_job_t delete_ike_sa_job_t;
+
+#include <library.h>
+#include <sa/ike_sa_id.h>
+#include <queues/jobs/job.h>
+
+
+/**
+ * @brief Class representing an DELETE_IKE_SA Job.
+ *
+ * This job is responsible for deleting established or half open IKE_SAs.
+ * A half open IKE_SA is every IKE_SA which hasn't reache the SA_ESTABLISHED
+ * state.
+ *
+ * @b Constructors:
+ * - delete_ike_sa_job_create()
+ *
+ * @ingroup jobs
+ */
+struct delete_ike_sa_job_t {
+
+ /**
+ * The job_t interface.
+ */
+ job_t job_interface;
+};
+
+/**
+ * @brief Creates a job of type DELETE_IKE_SA.
+ *
+ * @param ike_sa_id id of the IKE_SA to delete
+ * @param delete_if_established should the IKE_SA be deleted if it is established?
+ * @return created delete_ike_sa_job_t object
+ *
+ * @ingroup jobs
+ */
+delete_ike_sa_job_t *delete_ike_sa_job_create(ike_sa_id_t *ike_sa_id,
+ bool delete_if_established);
+
+#endif /* DELETE_IKE_SA_JOB_H_ */
diff --git a/src/charon/queues/jobs/initiate_job.c b/src/charon/queues/jobs/initiate_job.c
new file mode 100644
index 000000000..af50663d6
--- /dev/null
+++ b/src/charon/queues/jobs/initiate_job.c
@@ -0,0 +1,112 @@
+/**
+ * @file initiate_job.c
+ *
+ * @brief Implementation of initiate_job_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_job.h"
+
+#include <daemon.h>
+
+typedef struct private_initiate_job_t private_initiate_job_t;
+
+/**
+ * Private data of an initiate_job_t Object
+ */
+struct private_initiate_job_t {
+ /**
+ * public initiate_job_t interface
+ */
+ initiate_job_t public;
+
+ /**
+ * associated connection to initiate
+ */
+ connection_t *connection;
+
+ /**
+ * associated policy to initiate
+ */
+ policy_t *policy;
+};
+
+/**
+ * Implements initiate_job_t.get_type.
+ */
+static job_type_t get_type(private_initiate_job_t *this)
+{
+ return INITIATE;
+}
+
+/**
+ * Implementation of job_t.execute.
+ */
+static status_t execute(private_initiate_job_t *this)
+{
+ ike_sa_t *ike_sa;
+
+ ike_sa = charon->ike_sa_manager->checkout_by_peer(charon->ike_sa_manager,
+ this->connection->get_my_host(this->connection),
+ this->connection->get_other_host(this->connection),
+ this->policy->get_my_id(this->policy),
+ this->policy->get_other_id(this->policy));
+
+ if (ike_sa->initiate(ike_sa, this->connection, this->policy) != SUCCESS)
+ {
+ DBG1(DBG_JOB, "initiation failed, going to delete IKE_SA");
+ charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
+ return DESTROY_ME;
+ }
+
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ return DESTROY_ME;
+}
+
+/**
+ * Implements job_t.destroy.
+ */
+static void destroy(private_initiate_job_t *this)
+{
+ this->connection->destroy(this->connection);
+ this->policy->destroy(this->policy);
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+initiate_job_t *initiate_job_create(connection_t *connection, policy_t *policy)
+{
+ private_initiate_job_t *this = malloc_thing(private_initiate_job_t);
+
+ /* interface functions */
+ this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
+ this->public.job_interface.execute = (status_t (*) (job_t *)) execute;
+ this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
+
+ /* private variables */
+ this->connection = connection;
+ this->policy = policy;
+
+ return &this->public;
+}
diff --git a/src/charon/queues/jobs/initiate_job.h b/src/charon/queues/jobs/initiate_job.h
new file mode 100644
index 000000000..af1dd9ece
--- /dev/null
+++ b/src/charon/queues/jobs/initiate_job.h
@@ -0,0 +1,61 @@
+/**
+ * @file initiate_job.h
+ *
+ * @brief Interface of initiate_job_t.
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct initiate_job_t initiate_job_t;
+
+#include <library.h>
+#include <queues/jobs/job.h>
+#include <config/connections/connection.h>
+#include <config/policies/policy.h>
+
+/**
+ * @brief Class representing an INITIATE_IKE_SA Job.
+ *
+ * This job is created if an IKE_SA should be iniated.
+ *
+ * @b Constructors:
+ * - initiate_job_create()
+ *
+ * @ingroup jobs
+ */
+struct initiate_job_t {
+ /**
+ * implements job_t interface
+ */
+ job_t job_interface;
+};
+
+/**
+ * @brief Creates a job of type INITIATE_IKE_SA.
+ *
+ * @param connection connection_t to initialize
+ * @param policy policy to set up
+ * @return initiate_job_t object
+ *
+ * @ingroup jobs
+ */
+initiate_job_t *initiate_job_create(connection_t *connection, policy_t *policy);
+
+#endif /*INITIATE_IKE_SA_JOB_H_*/
diff --git a/src/charon/queues/jobs/job.c b/src/charon/queues/jobs/job.c
new file mode 100644
index 000000000..d32d1bc61
--- /dev/null
+++ b/src/charon/queues/jobs/job.c
@@ -0,0 +1,39 @@
+/**
+ * @file job.c
+ *
+ * @brief Interface additions to job_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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"
+
+ENUM(job_type_names, PROCESS_MESSAGE, SEND_DPD,
+ "PROCESS_MESSAGE",
+ "RETRANSMIT",
+ "INITIATE",
+ "ROUTE",
+ "ACQUIRE",
+ "DELETE_IKE_SA",
+ "DELETE_CHILD_SA",
+ "REKEY_CHILD_SA",
+ "REKEY_IKE_SA",
+ "SEND_KEEPALIVE",
+ "SEND_DPD",
+);
diff --git a/src/charon/queues/jobs/job.h b/src/charon/queues/jobs/job.h
new file mode 100644
index 000000000..28632672d
--- /dev/null
+++ b/src/charon/queues/jobs/job.h
@@ -0,0 +1,165 @@
+/**
+ * @file job.h
+ *
+ * @brief Interface job_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef enum job_type_t job_type_t;
+typedef struct job_t job_t;
+
+#include <library.h>
+
+/**
+ * @brief Definition of the various job types.
+ *
+ * @ingroup jobs
+ */
+enum job_type_t {
+ /**
+ * Process an incoming IKEv2-Message.
+ *
+ * Job is implemented in class process_message_job_t
+ */
+ PROCESS_MESSAGE,
+
+ /**
+ * Retransmit an IKEv2-Message.
+ *
+ * Job is implemented in class retransmit_job_t
+ */
+ RETRANSMIT,
+
+ /**
+ * Set up a CHILD_SA, optional with an IKE_SA.
+ *
+ * Job is implemented in class initiate_job_t
+ */
+ INITIATE,
+
+ /**
+ * Install SPD entries.
+ *
+ * Job is implemented in class route_job_t
+ */
+ ROUTE,
+
+ /**
+ * React on a acquire message from the kernel (e.g. setup CHILD_SA)
+ *
+ * Job is implemented in class acquire_job_t
+ */
+ ACQUIRE,
+
+ /**
+ * Delete an IKE_SA.
+ *
+ * Job is implemented in class delete_ike_sa_job_t
+ */
+ DELETE_IKE_SA,
+
+ /**
+ * Delete a CHILD_SA.
+ *
+ * Job is implemented in class delete_child_sa_job_t
+ */
+ DELETE_CHILD_SA,
+
+ /**
+ * Rekey a CHILD_SA.
+ *
+ * Job is implemented in class rekey_child_sa_job_t
+ */
+ REKEY_CHILD_SA,
+
+ /**
+ * Rekey an IKE_SA.
+ *
+ * Job is implemented in class rekey_ike_sa_job_t
+ */
+ REKEY_IKE_SA,
+
+ /**
+ * Send a keepalive packet.
+ *
+ * Job is implemented in class type send_keepalive_job_t
+ */
+ SEND_KEEPALIVE,
+
+ /**
+ * Send a DPD packet.
+ *
+ * Job is implemented in class type send_dpd_job_t
+ */
+ SEND_DPD
+};
+
+/**
+ * enum name for job_type_t
+ *
+ * @ingroup jobs
+ */
+extern enum_name_t *job_type_names;
+
+
+/**
+ * @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 Execute a job.
+ *
+ * Call the internall job routine to process the
+ * job. If this method returns DESTROY_ME, the job
+ * must be destroyed by the caller.
+ *
+ * @param this calling object
+ * @return status of job execution
+ */
+ status_t (*execute) (job_t *this);
+
+ /**
+ * @brief Destroys a job_t object
+ *
+ * @param job_t calling object
+ */
+ void (*destroy) (job_t *job);
+};
+
+
+#endif /* JOB_H_ */
diff --git a/src/charon/queues/jobs/process_message_job.c b/src/charon/queues/jobs/process_message_job.c
new file mode 100644
index 000000000..ee7484bbd
--- /dev/null
+++ b/src/charon/queues/jobs/process_message_job.c
@@ -0,0 +1,106 @@
+/**
+ * @file process_message_job.h
+ *
+ * @brief Implementation of process_message_job_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2007 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 "process_message_job.h"
+
+#include <daemon.h>
+
+typedef struct private_process_message_job_t private_process_message_job_t;
+
+/**
+ * Private data of an process_message_job_t Object
+ */
+struct private_process_message_job_t {
+ /**
+ * public process_message_job_t interface
+ */
+ process_message_job_t public;
+
+ /**
+ * Message associated with this job
+ */
+ message_t *message;
+};
+
+/**
+ * Implements job_t.get_type.
+ */
+static job_type_t get_type(private_process_message_job_t *this)
+{
+ return PROCESS_MESSAGE;
+}
+
+/**
+ * Implementation of job_t.execute.
+ */
+static status_t execute(private_process_message_job_t *this)
+{
+ ike_sa_t *ike_sa;
+
+ ike_sa = charon->ike_sa_manager->checkout_by_message(charon->ike_sa_manager,
+ this->message);
+ if (ike_sa)
+ {
+ DBG1(DBG_NET, "received packet: from %#H to %#H",
+ this->message->get_source(this->message),
+ this->message->get_destination(this->message));
+ if (ike_sa->process_message(ike_sa, this->message) == DESTROY_ME)
+ {
+ charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
+ ike_sa);
+ }
+ else
+ {
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ }
+ }
+ return DESTROY_ME;
+}
+
+/**
+ * Implements job_t.destroy.
+ */
+static void destroy(private_process_message_job_t *this)
+{
+ this->message->destroy(this->message);
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+process_message_job_t *process_message_job_create(message_t *message)
+{
+ private_process_message_job_t *this = malloc_thing(private_process_message_job_t);
+
+ /* interface functions */
+ this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
+ this->public.job_interface.execute = (status_t (*) (job_t *)) execute;
+ this->public.job_interface.destroy = (void(*)(job_t*))destroy;
+
+ /* private variables */
+ this->message = message;
+
+ return &(this->public);
+}
diff --git a/src/charon/queues/jobs/process_message_job.h b/src/charon/queues/jobs/process_message_job.h
new file mode 100644
index 000000000..2e60a298c
--- /dev/null
+++ b/src/charon/queues/jobs/process_message_job.h
@@ -0,0 +1,58 @@
+/**
+ * @file process_message_job.h
+ *
+ * @brief Interface of process_message_job_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2007 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 PROCESS_MESSAGE_JOB_H_
+#define PROCESS_MESSAGE_JOB_H_
+
+typedef struct process_message_job_t process_message_job_t;
+
+#include <library.h>
+#include <encoding/message.h>
+#include <queues/jobs/job.h>
+
+/**
+ * @brief Class representing an PROCESS_MESSAGE job.
+ *
+ * @b Constructors:
+ * - process_message_job_create()
+ *
+ * @ingroup jobs
+ */
+struct process_message_job_t {
+ /**
+ * implements job_t interface
+ */
+ job_t job_interface;
+};
+
+/**
+ * @brief Creates a job of type PROCESS_MESSAGE.
+ *
+ * @param message message to process
+ * @return created process_message_job_t object
+ *
+ * @ingroup jobs
+ */
+process_message_job_t *process_message_job_create(message_t *message);
+
+#endif /*PROCESS_MESSAGE_JOB_H_*/
diff --git a/src/charon/queues/jobs/rekey_child_sa_job.c b/src/charon/queues/jobs/rekey_child_sa_job.c
new file mode 100644
index 000000000..3422b614d
--- /dev/null
+++ b/src/charon/queues/jobs/rekey_child_sa_job.c
@@ -0,0 +1,112 @@
+/**
+ * @file rekey_child_sa_job.c
+ *
+ * @brief Implementation of rekey_child_sa_job_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 "rekey_child_sa_job.h"
+
+#include <daemon.h>
+
+
+typedef struct private_rekey_child_sa_job_t private_rekey_child_sa_job_t;
+
+/**
+ * Private data of an rekey_child_sa_job_t object.
+ */
+struct private_rekey_child_sa_job_t {
+ /**
+ * Public rekey_child_sa_job_t interface.
+ */
+ rekey_child_sa_job_t public;
+
+ /**
+ * reqid of the child to rekey
+ */
+ u_int32_t reqid;
+
+ /**
+ * protocol of the CHILD_SA (ESP/AH)
+ */
+ protocol_id_t protocol;
+
+ /**
+ * inbound SPI of the CHILD_SA
+ */
+ u_int32_t spi;
+};
+
+/**
+ * Implementation of job_t.get_type.
+ */
+static job_type_t get_type(private_rekey_child_sa_job_t *this)
+{
+ return REKEY_CHILD_SA;
+}
+
+/**
+ * Implementation of job_t.execute.
+ */
+static status_t execute(private_rekey_child_sa_job_t *this)
+{
+ ike_sa_t *ike_sa;
+
+ ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
+ this->reqid, TRUE);
+ if (ike_sa == NULL)
+ {
+ DBG2(DBG_JOB, "CHILD_SA with reqid %d not found for rekeying",
+ this->reqid);
+ return DESTROY_ME;
+ }
+ ike_sa->rekey_child_sa(ike_sa, this->protocol, this->spi);
+
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ return DESTROY_ME;
+}
+
+/**
+ * Implementation of job_t.destroy.
+ */
+static void destroy(private_rekey_child_sa_job_t *this)
+{
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+rekey_child_sa_job_t *rekey_child_sa_job_create(u_int32_t reqid,
+ protocol_id_t protocol,
+ u_int32_t spi)
+{
+ private_rekey_child_sa_job_t *this = malloc_thing(private_rekey_child_sa_job_t);
+
+ /* interface functions */
+ this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
+ this->public.job_interface.execute = (status_t (*) (job_t *)) execute;
+ this->public.job_interface.destroy = (void (*)(job_t*)) destroy;
+
+ /* private variables */
+ this->reqid = reqid;
+ this->protocol = protocol;
+ this->spi = spi;
+
+ return &(this->public);
+}
diff --git a/src/charon/queues/jobs/rekey_child_sa_job.h b/src/charon/queues/jobs/rekey_child_sa_job.h
new file mode 100644
index 000000000..19e1b5d32
--- /dev/null
+++ b/src/charon/queues/jobs/rekey_child_sa_job.h
@@ -0,0 +1,65 @@
+/**
+ * @file rekey_child_sa_job.h
+ *
+ * @brief Interface of rekey_child_sa_job_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 REKEY_CHILD_SA_JOB_H_
+#define REKEY_CHILD_SA_JOB_H_
+
+typedef struct rekey_child_sa_job_t rekey_child_sa_job_t;
+
+#include <library.h>
+#include <sa/ike_sa_id.h>
+#include <queues/jobs/job.h>
+#include <config/proposal.h>
+
+/**
+ * @brief Class representing an REKEY_CHILD_SA Job.
+ *
+ * This job initiates the rekeying of a CHILD SA.
+ *
+ * @b Constructors:
+ * - rekey_child_sa_job_create()
+ *
+ * @ingroup jobs
+ */
+struct rekey_child_sa_job_t {
+ /**
+ * The job_t interface.
+ */
+ job_t job_interface;
+};
+
+/**
+ * @brief Creates a job of type REKEY_CHILD_SA.
+ *
+ * The CHILD_SA is identified by its protocol (AH/ESP) and its
+ * inbound SPI.
+ *
+ * @param reqid reqid of the CHILD_SA to rekey
+ * @param protocol protocol of the CHILD_SA
+ * @param spi security parameter index of the CHILD_SA
+ * @return rekey_child_sa_job_t object
+ *
+ * @ingroup jobs
+ */
+rekey_child_sa_job_t *rekey_child_sa_job_create(u_int32_t reqid, protocol_id_t protocol, u_int32_t spi);
+
+#endif /* REKEY_CHILD_SA_JOB_H_ */
diff --git a/src/charon/queues/jobs/rekey_ike_sa_job.c b/src/charon/queues/jobs/rekey_ike_sa_job.c
new file mode 100644
index 000000000..2539d997e
--- /dev/null
+++ b/src/charon/queues/jobs/rekey_ike_sa_job.c
@@ -0,0 +1,120 @@
+/**
+ * @file rekey_ike_sa_job.c
+ *
+ * @brief Implementation of rekey_ike_sa_job_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 "rekey_ike_sa_job.h"
+
+#include <daemon.h>
+
+
+typedef struct private_rekey_ike_sa_job_t private_rekey_ike_sa_job_t;
+
+/**
+ * Private data of an rekey_ike_sa_job_t object.
+ */
+struct private_rekey_ike_sa_job_t {
+ /**
+ * Public rekey_ike_sa_job_t interface.
+ */
+ rekey_ike_sa_job_t public;
+
+ /**
+ * ID of the IKE_SA to rekey
+ */
+ ike_sa_id_t *ike_sa_id;
+
+ /**
+ * force reauthentication of the peer (full IKE_SA setup)
+ */
+ bool reauth;
+};
+
+/**
+ * Implementation of job_t.get_type.
+ */
+static job_type_t get_type(private_rekey_ike_sa_job_t *this)
+{
+ return REKEY_IKE_SA;
+}
+
+/**
+ * Implementation of job_t.execute.
+ */
+static status_t execute(private_rekey_ike_sa_job_t *this)
+{
+ ike_sa_t *ike_sa;
+ status_t status = SUCCESS;
+
+ ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
+ this->ike_sa_id);
+ if (ike_sa == NULL)
+ {
+ DBG2(DBG_JOB, "IKE_SA %J to rekey not found", this->ike_sa_id);
+ return DESTROY_ME;
+ }
+
+ if (this->reauth)
+ {
+ ike_sa->reestablish(ike_sa);
+ }
+ else
+ {
+ status = ike_sa->rekey(ike_sa);
+ }
+
+ if (status == DESTROY_ME)
+ {
+ charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
+ }
+ else
+ {
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ }
+ return DESTROY_ME;
+}
+
+/**
+ * Implementation of job_t.destroy.
+ */
+static void destroy(private_rekey_ike_sa_job_t *this)
+{
+ this->ike_sa_id->destroy(this->ike_sa_id);
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+rekey_ike_sa_job_t *rekey_ike_sa_job_create(ike_sa_id_t *ike_sa_id, bool reauth)
+{
+ private_rekey_ike_sa_job_t *this = malloc_thing(private_rekey_ike_sa_job_t);
+
+ /* interface functions */
+ this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
+ this->public.job_interface.execute = (status_t (*) (job_t *)) execute;
+ this->public.job_interface.destroy = (void (*)(job_t*)) destroy;
+
+ /* private variables */
+ this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
+ this->reauth = reauth;
+
+ return &(this->public);
+}
diff --git a/src/charon/queues/jobs/rekey_ike_sa_job.h b/src/charon/queues/jobs/rekey_ike_sa_job.h
new file mode 100644
index 000000000..f3e336fb3
--- /dev/null
+++ b/src/charon/queues/jobs/rekey_ike_sa_job.h
@@ -0,0 +1,60 @@
+/**
+ * @file rekey_ike_sa_job.h
+ *
+ * @brief Interface of rekey_ike_sa_job_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 REKEY_IKE_SA_JOB_H_
+#define REKEY_IKE_SA_JOB_H_
+
+typedef struct rekey_ike_sa_job_t rekey_ike_sa_job_t;
+
+#include <library.h>
+#include <sa/ike_sa_id.h>
+#include <queues/jobs/job.h>
+
+/**
+ * @brief Class representing an REKEY_IKE_SA Job.
+ *
+ * This job initiates the rekeying of an IKE_SA.
+ *
+ * @b Constructors:
+ * - rekey_ike_sa_job_create()
+ *
+ * @ingroup jobs
+ */
+struct rekey_ike_sa_job_t {
+ /**
+ * The job_t interface.
+ */
+ job_t job_interface;
+};
+
+/**
+ * @brief Creates a job of type REKEY_IKE_SA.
+ *
+ * @param ike_sa_id ID of the IKE_SA to rekey
+ * @param reauth TRUE to reauthenticate peer, FALSE for rekeying only
+ * @return rekey_ike_sa_job_t object
+ *
+ * @ingroup jobs
+ */
+rekey_ike_sa_job_t *rekey_ike_sa_job_create(ike_sa_id_t *ike_sa_id, bool reauth);
+
+#endif /* REKEY_IKE_SA_JOB_H_ */
diff --git a/src/charon/queues/jobs/retransmit_job.c b/src/charon/queues/jobs/retransmit_job.c
new file mode 100644
index 000000000..5bfa20dfd
--- /dev/null
+++ b/src/charon/queues/jobs/retransmit_job.c
@@ -0,0 +1,109 @@
+/**
+ * @file retransmit_job.c
+ *
+ * @brief Implementation of retransmit_job_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2007 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_job.h"
+
+#include <daemon.h>
+
+typedef struct private_retransmit_job_t private_retransmit_job_t;
+
+/**
+ * Private data of an retransmit_job_t Object.
+ */
+struct private_retransmit_job_t {
+ /**
+ * Public retransmit_job_t interface.
+ */
+ retransmit_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;
+};
+
+/**
+ * Implements job_t.get_type.
+ */
+static job_type_t get_type(private_retransmit_job_t *this)
+{
+ return RETRANSMIT;
+}
+
+/**
+ * Implementation of job_t.execute.
+ */
+static status_t execute(private_retransmit_job_t *this)
+{
+ ike_sa_t *ike_sa;
+
+ ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
+ this->ike_sa_id);
+ if (ike_sa)
+ {
+ if (ike_sa->retransmit(ike_sa, this->message_id) == DESTROY_ME)
+ {
+ /* retransmitted to many times, giving up */
+ charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
+ ike_sa);
+ }
+ else
+ {
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ }
+ }
+ return DESTROY_ME;
+}
+
+/**
+ * Implements job_t.destroy.
+ */
+static void destroy(private_retransmit_job_t *this)
+{
+ this->ike_sa_id->destroy(this->ike_sa_id);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+retransmit_job_t *retransmit_job_create(u_int32_t message_id,ike_sa_id_t *ike_sa_id)
+{
+ private_retransmit_job_t *this = malloc_thing(private_retransmit_job_t);
+
+ /* interface functions */
+ this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
+ this->public.job_interface.execute = (status_t (*) (job_t *)) execute;
+ this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
+
+ /* private variables */
+ this->message_id = message_id;
+ this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
+
+ return &this->public;
+}
diff --git a/src/charon/queues/jobs/retransmit_job.h b/src/charon/queues/jobs/retransmit_job.h
new file mode 100644
index 000000000..19e29b909
--- /dev/null
+++ b/src/charon/queues/jobs/retransmit_job.h
@@ -0,0 +1,64 @@
+/**
+ * @file retransmit_job.h
+ *
+ * @brief Interface of retransmit_job_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2007 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 RETRANSMIT_JOB_H_
+#define RETRANSMIT_JOB_H_
+
+typedef struct retransmit_job_t retransmit_job_t;
+
+#include <library.h>
+#include <queues/jobs/job.h>
+#include <sa/ike_sa_id.h>
+
+/**
+ * @brief Class representing an retransmit Job.
+ *
+ * This job is scheduled every time a request is sent over the
+ * wire. If the response to the request is not received at schedule
+ * time, the retransmission will be initiated.
+ *
+ * @b Constructors:
+ * - retransmit_job_create()
+ *
+ * @ingroup jobs
+ */
+struct retransmit_job_t {
+ /**
+ * The job_t interface.
+ */
+ job_t job_interface;
+};
+
+/**
+ * @brief Creates a job of type retransmit.
+ *
+ * @param message_id message_id of the request to resend
+ * @param ike_sa_id identification of the ike_sa as ike_sa_id_t
+ * @return retransmit_job_t object
+ *
+ * @ingroup jobs
+ */
+retransmit_job_t *retransmit_job_create(u_int32_t message_id,
+ ike_sa_id_t *ike_sa_id);
+
+#endif /* RETRANSMIT_JOB_H_ */
diff --git a/src/charon/queues/jobs/route_job.c b/src/charon/queues/jobs/route_job.c
new file mode 100644
index 000000000..bb6281dcc
--- /dev/null
+++ b/src/charon/queues/jobs/route_job.c
@@ -0,0 +1,125 @@
+/**
+ * @file route_job.c
+ *
+ * @brief Implementation of route_job_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-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 "route_job.h"
+
+#include <daemon.h>
+
+typedef struct private_route_job_t private_route_job_t;
+
+/**
+ * Private data of an route_job_t Object
+ */
+struct private_route_job_t {
+ /**
+ * public route_job_t interface
+ */
+ route_job_t public;
+
+ /**
+ * associated connection to route
+ */
+ connection_t *connection;
+
+ /**
+ * associated policy to route
+ */
+ policy_t *policy;
+
+ /**
+ * route or unroute?
+ */
+ bool route;
+};
+
+/**
+ * Implements route_job_t.get_type.
+ */
+static job_type_t get_type(private_route_job_t *this)
+{
+ return ROUTE;
+}
+
+/**
+ * Implementation of job_t.execute.
+ */
+static status_t execute(private_route_job_t *this)
+{
+ ike_sa_t *ike_sa;
+
+ ike_sa = charon->ike_sa_manager->checkout_by_peer(charon->ike_sa_manager,
+ this->connection->get_my_host(this->connection),
+ this->connection->get_other_host(this->connection),
+ this->policy->get_my_id(this->policy),
+ this->policy->get_other_id(this->policy));
+ if (this->route)
+ {
+ if (ike_sa->route(ike_sa, this->connection, this->policy) != SUCCESS)
+ {
+ DBG1(DBG_JOB, "routing failed");
+ }
+ }
+ else
+ {
+ if (ike_sa->unroute(ike_sa, this->policy) == DESTROY_ME)
+ {
+ DBG1(DBG_JOB, "removing IKE_SA, as last routed CHILD_SA unrouted");
+ charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
+ return DESTROY_ME;
+ }
+ }
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ return DESTROY_ME;
+}
+
+/**
+ * Implements job_t.destroy.
+ */
+static void destroy(private_route_job_t *this)
+{
+ this->connection->destroy(this->connection);
+ this->policy->destroy(this->policy);
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+route_job_t *route_job_create(connection_t *connection, policy_t *policy, bool route)
+{
+ private_route_job_t *this = malloc_thing(private_route_job_t);
+
+ /* interface functions */
+ this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
+ this->public.job_interface.execute = (status_t (*) (job_t *)) execute;
+ this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
+
+ /* private variables */
+ this->connection = connection;
+ this->policy = policy;
+ this->route = route;
+
+ return &this->public;
+}
diff --git a/src/charon/queues/jobs/route_job.h b/src/charon/queues/jobs/route_job.h
new file mode 100644
index 000000000..2743a70ab
--- /dev/null
+++ b/src/charon/queues/jobs/route_job.h
@@ -0,0 +1,59 @@
+/**
+ * @file route_job.h
+ *
+ * @brief Interface of route_job_t.
+ */
+
+/*
+ * Copyright (C) 2005-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 ROUTE_JOB_H_
+#define ROUTE_JOB_H_
+
+typedef struct route_job_t route_job_t;
+
+#include <library.h>
+#include <queues/jobs/job.h>
+#include <config/policies/policy.h>
+#include <config/connections/connection.h>
+
+/**
+ * @brief Class representing an ROUTE Job.
+ *
+ * @b Constructors:
+ * - route_job_create()
+ *
+ * @ingroup jobs
+ */
+struct route_job_t {
+ /**
+ * implements job_t interface
+ */
+ job_t job_interface;
+};
+
+/**
+ * @brief Creates a job of type ROUTE.
+ *
+ * @param connection connection used for routing
+ * @param policy policy to set up
+ * @param route TRUE to route, FALSE to unroute
+ * @return route_job_t object
+ *
+ * @ingroup jobs
+ */
+route_job_t *route_job_create(connection_t *connection, policy_t *policy, bool route);
+
+#endif /*ROUTE_JOB_H_*/
diff --git a/src/charon/queues/jobs/send_dpd_job.c b/src/charon/queues/jobs/send_dpd_job.c
new file mode 100644
index 000000000..7294d78d5
--- /dev/null
+++ b/src/charon/queues/jobs/send_dpd_job.c
@@ -0,0 +1,110 @@
+/**
+ * @file send_dpd_job.c
+ *
+ * @brief Implementation of send_dpd_job_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 "send_dpd_job.h"
+
+#include <sa/ike_sa.h>
+#include <daemon.h>
+
+
+typedef struct private_send_dpd_job_t private_send_dpd_job_t;
+
+/**
+ * Private data of an send_dpd_job_t Object
+ */
+struct private_send_dpd_job_t {
+ /**
+ * public send_dpd_job_t interface
+ */
+ send_dpd_job_t public;
+
+ /**
+ * ID of the IKE_SA which the message belongs to.
+ */
+ ike_sa_id_t *ike_sa_id;
+};
+
+/**
+ * Implements send_dpd_job_t.get_type.
+ */
+static job_type_t get_type(private_send_dpd_job_t *this)
+{
+ return SEND_DPD;
+}
+
+/**
+ * Implementation of job_t.execute.
+ */
+static status_t execute(private_send_dpd_job_t *this)
+{
+ ike_sa_t *ike_sa;
+
+ ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
+ this->ike_sa_id);
+ if (ike_sa == NULL)
+ {
+ return DESTROY_ME;
+ }
+
+ if (ike_sa->send_dpd(ike_sa) == DESTROY_ME)
+ {
+ charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
+ }
+ else
+ {
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ }
+ return DESTROY_ME;
+}
+
+/**
+ * Implements job_t.destroy.
+ */
+static void destroy(private_send_dpd_job_t *this)
+{
+ this->ike_sa_id->destroy(this->ike_sa_id);
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+send_dpd_job_t *send_dpd_job_create(ike_sa_id_t *ike_sa_id)
+{
+ private_send_dpd_job_t *this = malloc_thing(private_send_dpd_job_t);
+
+ /* interface functions */
+ this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
+ this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
+ this->public.job_interface.execute = (status_t (*) (job_t *)) execute;
+
+ /* public functions */
+ this->public.destroy = (void (*)(send_dpd_job_t *)) destroy;
+
+ /* private variables */
+ this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
+
+ return &(this->public);
+}
diff --git a/src/charon/queues/jobs/send_dpd_job.h b/src/charon/queues/jobs/send_dpd_job.h
new file mode 100644
index 000000000..f3900f9a2
--- /dev/null
+++ b/src/charon/queues/jobs/send_dpd_job.h
@@ -0,0 +1,68 @@
+/**
+ * @file send_dpd_job.h
+ *
+ * @brief Interface of send_dpd_job_t.
+ */
+
+/*
+ * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_DPD_JOB_H_
+#define SEND_DPD_JOB_H_
+
+typedef struct send_dpd_job_t send_dpd_job_t;
+
+#include <library.h>
+#include <queues/jobs/job.h>
+#include <config/connections/connection.h>
+#include <sa/ike_sa_id.h>
+
+/**
+ * @brief Class representing a SEND_DPD Job.
+ *
+ * Job to periodically send a Dead Peer Detection (DPD) request,
+ * ie. an IKE request with no payloads other than the encrypted payload
+ * required by the syntax.
+ *
+ * @b Constructors:
+ * - send_dpd_job_create()
+ *
+ * @ingroup jobs
+ */
+struct send_dpd_job_t {
+ /**
+ * implements job_t interface
+ */
+ job_t job_interface;
+
+ /**
+ * @brief Destroys an send_dpd_job_t object.
+ *
+ * @param this send_dpd_job_t object to destroy
+ */
+ void (*destroy) (send_dpd_job_t *this);
+};
+
+/**
+ * @brief Creates a job of type SEND_DPD.
+ *
+ * @param ike_sa_id identification of the ike_sa as ike_sa_id_t object (gets cloned)
+ * @return initiate_ike_sa_job_t object
+ *
+ * @ingroup jobs
+ */
+send_dpd_job_t *send_dpd_job_create(ike_sa_id_t *ike_sa_id);
+
+#endif /*SEND_DPD_JOB_H_*/
diff --git a/src/charon/queues/jobs/send_keepalive_job.c b/src/charon/queues/jobs/send_keepalive_job.c
new file mode 100644
index 000000000..1c1cb288e
--- /dev/null
+++ b/src/charon/queues/jobs/send_keepalive_job.c
@@ -0,0 +1,103 @@
+/**
+ * @file send_keepalive_job.c
+ *
+ * @brief Implementation of send_keepalive_job_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 "send_keepalive_job.h"
+
+#include <sa/ike_sa.h>
+#include <daemon.h>
+
+
+typedef struct private_send_keepalive_job_t private_send_keepalive_job_t;
+
+/**
+ * Private data of an send_keepalive_job_t Object
+ */
+struct private_send_keepalive_job_t {
+ /**
+ * public send_keepalive_job_t interface
+ */
+ send_keepalive_job_t public;
+
+ /**
+ * ID of the IKE_SA which the message belongs to.
+ */
+ ike_sa_id_t *ike_sa_id;
+};
+
+/**
+ * Implements send_keepalive_job_t.get_type.
+ */
+static job_type_t get_type(private_send_keepalive_job_t *this)
+{
+ return SEND_KEEPALIVE;
+}
+
+/**
+ * Implementation of job_t.execute.
+ */
+static status_t execute(private_send_keepalive_job_t *this)
+{
+ ike_sa_t *ike_sa;
+
+ ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
+ this->ike_sa_id);
+ if (ike_sa == NULL)
+ {
+ return DESTROY_ME;
+ }
+ ike_sa->send_keepalive(ike_sa);
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ return DESTROY_ME;
+}
+
+/**
+ * Implements job_t.destroy.
+ */
+static void destroy(private_send_keepalive_job_t *this)
+{
+ this->ike_sa_id->destroy(this->ike_sa_id);
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+send_keepalive_job_t *send_keepalive_job_create(ike_sa_id_t *ike_sa_id)
+{
+ private_send_keepalive_job_t *this = malloc_thing(private_send_keepalive_job_t);
+
+ /* interface functions */
+ this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
+ this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
+ this->public.job_interface.execute = (status_t (*) (job_t *)) execute;
+
+ /* public functions */
+ this->public.destroy = (void (*)(send_keepalive_job_t *)) destroy;
+
+ /* private variables */
+ this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
+
+ return &(this->public);
+}
diff --git a/src/charon/queues/jobs/send_keepalive_job.h b/src/charon/queues/jobs/send_keepalive_job.h
new file mode 100644
index 000000000..c7d05be65
--- /dev/null
+++ b/src/charon/queues/jobs/send_keepalive_job.h
@@ -0,0 +1,67 @@
+/**
+ * @file send_keepalive_job.h
+ *
+ * @brief Interface of send_keepalive_job_t.
+ */
+
+/*
+ * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_KEEPALIVE_JOB_H_
+#define SEND_KEEPALIVE_JOB_H_
+
+typedef struct send_keepalive_job_t send_keepalive_job_t;
+
+#include <library.h>
+#include <queues/jobs/job.h>
+#include <config/connections/connection.h>
+#include <sa/ike_sa_id.h>
+
+/**
+ * @brief Class representing a SEND_KEEPALIVE Job.
+ *
+ * This job will send a NAT keepalive packet if the IKE SA is still alive,
+ * and reinsert itself into the event queue.
+ *
+ * @b Constructors:
+ * - send_keepalive_job_create()
+ *
+ * @ingroup jobs
+ */
+struct send_keepalive_job_t {
+ /**
+ * implements job_t interface
+ */
+ job_t job_interface;
+
+ /**
+ * @brief Destroys an send_keepalive_job_t object.
+ *
+ * @param this send_keepalive_job_t object to destroy
+ */
+ void (*destroy) (send_keepalive_job_t *this);
+};
+
+/**
+ * @brief Creates a job of type SEND_KEEPALIVE.
+ *
+ * @param ike_sa_id identification of the ike_sa as ike_sa_id_t object (gets cloned)
+ * @return initiate_ike_sa_job_t object
+ *
+ * @ingroup jobs
+ */
+send_keepalive_job_t *send_keepalive_job_create(ike_sa_id_t *ike_sa_id);
+
+#endif /*SEND_KEEPALIVE_JOB_H_*/
diff --git a/src/charon/sa/authenticators/authenticator.c b/src/charon/sa/authenticators/authenticator.c
new file mode 100644
index 000000000..707aae9ad
--- /dev/null
+++ b/src/charon/sa/authenticators/authenticator.c
@@ -0,0 +1,56 @@
+/**
+ * @file authenticator.c
+ *
+ * @brief Generic constructor for authenticators.
+ *
+ */
+
+/*
+ * 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 "authenticator.h"
+
+#include <sa/authenticators/rsa_authenticator.h>
+#include <sa/authenticators/psk_authenticator.h>
+#include <sa/authenticators/eap_authenticator.h>
+
+
+ENUM_BEGIN(auth_method_names, AUTH_RSA, AUTH_DSS,
+ "RSA signature",
+ "pre-shared key",
+ "DSS signature");
+ENUM_NEXT(auth_method_names, AUTH_EAP, AUTH_EAP, AUTH_DSS,
+ "EAP");
+ENUM_END(auth_method_names, AUTH_EAP);
+
+/*
+ * Described in header.
+ */
+authenticator_t *authenticator_create(ike_sa_t *ike_sa, auth_method_t auth_method)
+{
+ switch (auth_method)
+ {
+ case AUTH_RSA:
+ return (authenticator_t*)rsa_authenticator_create(ike_sa);
+ case AUTH_PSK:
+ return (authenticator_t*)psk_authenticator_create(ike_sa);
+ case AUTH_EAP:
+ return (authenticator_t*)eap_authenticator_create(ike_sa);
+ default:
+ return NULL;
+ }
+}
diff --git a/src/charon/sa/authenticators/authenticator.h b/src/charon/sa/authenticators/authenticator.h
new file mode 100644
index 000000000..c7b0fc81a
--- /dev/null
+++ b/src/charon/sa/authenticators/authenticator.h
@@ -0,0 +1,139 @@
+/**
+ * @file authenticator.h
+ *
+ * @brief Interface of authenticator_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef enum auth_method_t auth_method_t;
+typedef struct authenticator_t authenticator_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <encoding/payloads/auth_payload.h>
+
+/**
+ * Method to use for authentication.
+ *
+ * @ingroup authenticators
+ */
+enum auth_method_t {
+ /**
+ * Computed as specified in section 2.15 of RFC using
+ * an RSA private key over a PKCS#1 padded hash.
+ */
+ AUTH_RSA = 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
+ */
+ AUTH_PSK = 2,
+
+ /**
+ * Computed as specified in section 2.15 of RFC using a
+ * DSS private key over a SHA-1 hash.
+ */
+ AUTH_DSS = 3,
+
+ /**
+ * EAP authentication. This value is never negotiated and therefore
+ * a value from private use.
+ */
+ AUTH_EAP = 201,
+};
+
+/**
+ * enum names for auth_method_t.
+ *
+ * @ingroup authenticators
+ */
+extern enum_name_t *auth_method_names;
+
+/**
+ * @brief Authenticator interface implemented by the various authenticators.
+ *
+ * Currently the following two AUTH methods are supported:
+ * - shared key message integrity code (AUTH_PSK)
+ * - RSA digital signature (AUTH_RSA)
+ *
+ * @b Constructors:
+ * - authenticator_create()
+ *
+ * @ingroup authenticators
+ */
+struct authenticator_t {
+
+ /**
+ * @brief Verify a received authentication payload.
+ *
+ * @param this calling object
+ * @param ike_sa_init binary representation of received ike_sa_init
+ * @param my_nonce the sent nonce
+ * @param auth_payload authentication payload to verify
+ *
+ * @return
+ * - SUCCESS,
+ * - FAILED if verification failed
+ * - INVALID_ARG if auth_method does not match
+ * - NOT_FOUND if credentials not found
+ */
+ status_t (*verify) (authenticator_t *this, chunk_t ike_sa_init,
+ chunk_t my_nonce, auth_payload_t *auth_payload);
+
+ /**
+ * @brief Build an authentication payload to send to the other peer.
+ *
+ * @param this calling object
+ * @param ike_sa_init binary representation of sent ike_sa_init
+ * @param other_nonce the received nonce
+ * @param[out] auth_payload the resulting authentication payload
+ *
+ * @return
+ * - SUCCESS,
+ * - NOT_FOUND if the data for AUTH method could not be found
+ */
+ status_t (*build) (authenticator_t *this, chunk_t ike_sa_init,
+ chunk_t other_nonce, auth_payload_t **auth_payload);
+
+ /**
+ * @brief Destroys a authenticator_t object.
+ *
+ * @param this calling object
+ */
+ void (*destroy) (authenticator_t *this);
+};
+
+/**
+ * @brief Creates an authenticator for the specified auth method.
+ *
+ * @param ike_sa associated ike_sa
+ * @param auth_method authentication method to use for build()/verify()
+ *
+ * @return authenticator_t object
+ *
+ * @ingroup authenticators
+ */
+authenticator_t *authenticator_create(ike_sa_t *ike_sa, auth_method_t auth_method);
+
+#endif /* AUTHENTICATOR_H_ */
diff --git a/src/charon/sa/authenticators/eap/eap_identity.c b/src/charon/sa/authenticators/eap/eap_identity.c
new file mode 100644
index 000000000..12a8bf7cc
--- /dev/null
+++ b/src/charon/sa/authenticators/eap/eap_identity.c
@@ -0,0 +1,135 @@
+/**
+ * @file eap_identity.c
+ *
+ * @brief Implementation of eap_identity_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "eap_identity.h"
+
+#include <daemon.h>
+#include <library.h>
+
+typedef struct private_eap_identity_t private_eap_identity_t;
+
+/**
+ * Private data of an eap_identity_t object.
+ */
+struct private_eap_identity_t {
+
+ /**
+ * Public authenticator_t interface.
+ */
+ eap_identity_t public;
+
+ /**
+ * ID of the peer
+ */
+ identification_t *peer;
+};
+
+/**
+ * Implementation of eap_method_t.process for the peer
+ */
+static status_t process(private_eap_identity_t *this,
+ eap_payload_t *in, eap_payload_t **out)
+{
+ chunk_t id, hdr;
+
+ hdr = chunk_alloca(5);
+ id = this->peer->get_encoding(this->peer);
+
+ *(hdr.ptr + 0) = EAP_RESPONSE;
+ *(hdr.ptr + 1) = in->get_identifier(in);
+ *(u_int16_t*)(hdr.ptr + 2) = htons(hdr.len + id.len);
+ *(hdr.ptr + 4) = EAP_IDENTITY;
+
+ *out = eap_payload_create_data(chunk_cata("cc", hdr, id));
+ return SUCCESS;
+
+}
+
+/**
+ * Implementation of eap_method_t.initiate for the peer
+ */
+static status_t initiate(private_eap_identity_t *this, eap_payload_t **out)
+{
+ /* peer never initiates */
+ return FAILED;
+}
+
+/**
+ * Implementation of eap_method_t.get_type.
+ */
+static eap_type_t get_type(private_eap_identity_t *this)
+{
+ return EAP_IDENTITY;
+}
+
+/**
+ * Implementation of eap_method_t.get_msk.
+ */
+static status_t get_msk(private_eap_identity_t *this, chunk_t *msk)
+{
+ return FAILED;
+}
+
+/**
+ * Implementation of eap_method_t.is_mutual.
+ */
+static bool is_mutual(private_eap_identity_t *this)
+{
+ return FALSE;
+}
+
+/**
+ * Implementation of eap_method_t.destroy.
+ */
+static void destroy(private_eap_identity_t *this)
+{
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+eap_identity_t *eap_create(eap_role_t role,
+ identification_t *server, identification_t *peer)
+{
+ private_eap_identity_t *this;
+
+ if (role != EAP_PEER)
+ {
+ return NULL;
+ }
+
+ this = malloc_thing(private_eap_identity_t);
+
+ /* public functions */
+ this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))initiate;
+ this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))process;
+ this->public.eap_method_interface.get_type = (eap_type_t(*)(eap_method_t*))get_type;
+ this->public.eap_method_interface.is_mutual = (bool(*)(eap_method_t*))is_mutual;
+ this->public.eap_method_interface.get_msk = (status_t(*)(eap_method_t*,chunk_t*))get_msk;
+ this->public.eap_method_interface.destroy = (void(*)(eap_method_t*))destroy;
+
+ /* private data */
+ this->peer = peer;
+
+ return &this->public;
+}
diff --git a/src/charon/sa/authenticators/eap/eap_identity.h b/src/charon/sa/authenticators/eap/eap_identity.h
new file mode 100644
index 000000000..20f0f0b67
--- /dev/null
+++ b/src/charon/sa/authenticators/eap/eap_identity.h
@@ -0,0 +1,59 @@
+/**
+ * @file eap_identity.h
+ *
+ * @brief Interface of eap_identity_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef EAP_IDENTITY_H_
+#define EAP_IDENTITY_H_
+
+typedef struct eap_identity_t eap_identity_t;
+
+#include <sa/authenticators/eap/eap_method.h>
+
+/**
+ * @brief Implementation of the eap_method_t interface using EAP Identity.
+ *
+ * @b Constructors:
+ * - eap_identity_create()
+ * - eap_client_create() using eap_method EAP_IDENTITY
+ *
+ * @ingroup eap
+ */
+struct eap_identity_t {
+
+ /**
+ * Implemented eap_method_t interface.
+ */
+ eap_method_t eap_method_interface;
+};
+
+/**
+ * @brief Creates the EAP method EAP Identity.
+ *
+ * @param server ID of the EAP server
+ * @param peer ID of the EAP client
+ * @return eap_identity_t object
+ *
+ * @ingroup eap
+ */
+eap_identity_t *eap_create(eap_role_t role,
+ identification_t *server, identification_t *peer);
+
+#endif /* EAP_IDENTITY_H_ */
diff --git a/src/charon/sa/authenticators/eap/eap_method.c b/src/charon/sa/authenticators/eap/eap_method.c
new file mode 100644
index 000000000..a4d8abb58
--- /dev/null
+++ b/src/charon/sa/authenticators/eap/eap_method.c
@@ -0,0 +1,245 @@
+/**
+ * @file eap_method.c
+ *
+ * @brief Generic constructor for eap_methods.
+ *
+ */
+
+/*
+ * 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 <sys/stat.h>
+#include <dirent.h>
+#include <error.h>
+#include <dlfcn.h>
+
+#include "eap_method.h"
+
+#include <daemon.h>
+#include <library.h>
+#include <utils/linked_list.h>
+#include <utils/identification.h>
+
+
+ENUM_BEGIN(eap_type_names, EAP_IDENTITY, EAP_TOKEN_CARD,
+ "EAP_IDENTITY",
+ "EAP_NOTIFICATION",
+ "EAP_NAK",
+ "EAP_MD5",
+ "EAP_ONE_TIME_PASSWORD",
+ "EAP_TOKEN_CARD");
+ENUM_NEXT(eap_type_names, EAP_SIM, EAP_SIM, EAP_TOKEN_CARD,
+ "EAP_SIM");
+ENUM_NEXT(eap_type_names, EAP_AKA, EAP_AKA, EAP_SIM,
+ "EAP_AKA");
+ENUM_END(eap_type_names, EAP_AKA);
+
+ENUM(eap_code_names, EAP_REQUEST, EAP_FAILURE,
+ "EAP_REQUEST",
+ "EAP_RESPONSE",
+ "EAP_SUCCESS",
+ "EAP_FAILURE",
+);
+
+ENUM(eap_role_names, EAP_SERVER, EAP_PEER,
+ "EAP_SERVER",
+ "EAP_PEER",
+);
+
+
+typedef struct module_entry_t module_entry_t;
+
+/**
+ * Representation of a loaded module: EAP type, library handle, constructor
+ */
+struct module_entry_t {
+ eap_type_t type;
+ void *handle;
+ eap_constructor_t constructor;
+};
+
+/** List of module_entry_t's */
+static linked_list_t *modules = NULL;
+
+/**
+ * unload modules at daemon shutdown
+ */
+void eap_method_unload()
+{
+ if (modules)
+ {
+ module_entry_t *entry;
+
+ while (modules->remove_last(modules, (void**)&entry) == SUCCESS)
+ {
+ DBG2(DBG_CFG, "unloaded module for %s", eap_type_names, entry->type);
+ dlclose(entry->handle);
+ free(entry);
+ }
+ modules->destroy(modules);
+ modules = NULL;
+ }
+}
+
+/**
+ * Load EAP modules at daemon startup
+ */
+void eap_method_load(char *directory)
+{
+ struct dirent* entry;
+ struct stat stb;
+ DIR* dir;
+
+ eap_method_unload();
+ modules = linked_list_create();
+
+ if (stat(directory, &stb) == -1 || !(stb.st_mode & S_IFDIR))
+ {
+ DBG1(DBG_CFG, "error opening EAP modules directory %s", directory);
+ return;
+ }
+ if (stb.st_uid != 0)
+ {
+ DBG1(DBG_CFG, "EAP modules directory %s not owned by root, skipped", directory);
+ return;
+ }
+ if (stb.st_mode & S_IWOTH || stb.st_mode & S_IWGRP)
+ {
+ DBG1(DBG_CFG, "EAP modules directory %s writable by others, skipped", directory);
+ return;
+ }
+
+ dir = opendir(directory);
+ if (dir == NULL)
+ {
+ DBG1(DBG_CFG, "error opening EAP modules directory %s", directory);
+ return;
+ }
+
+ DBG1(DBG_CFG, "loading EAP modules from '%s'", directory);
+
+ while ((entry = readdir(dir)) != NULL)
+ {
+ char file[256];
+ module_entry_t module, *loaded_module;
+ eap_method_t *method;
+ identification_t *id;
+ char *ending;
+
+ snprintf(file, sizeof(file), "%s/%s", directory, entry->d_name);
+
+ if (stat(file, &stb) == -1 || !(stb.st_mode & S_IFREG))
+ {
+ DBG2(DBG_CFG, " skipping %s, doesn't look like a file",
+ entry->d_name);
+ continue;
+ }
+ ending = entry->d_name + strlen(entry->d_name) - 3;
+ if (ending <= entry->d_name || !streq(ending, ".so"))
+ {
+ /* skip anything which does not look like a library */
+ DBG2(DBG_CFG, " skipping %s, doesn't look like a library",
+ entry->d_name);
+ continue;
+ }
+ if (stb.st_uid != 0)
+ {
+ DBG1(DBG_CFG, " skipping %s, file is not owned by root", entry->d_name);
+ return;
+ }
+ if (stb.st_mode & S_IWOTH || stb.st_mode & S_IWGRP)
+ {
+ DBG1(DBG_CFG, " skipping %s, file is writeable by others", entry->d_name);
+ continue;
+ }
+
+ /* try to load the library */
+ module.handle = dlopen(file, RTLD_LAZY);
+ if (module.handle == NULL)
+ {
+ DBG1(DBG_CFG, " opening EAP module %s failed: %s", entry->d_name,
+ dlerror());
+ continue;
+ }
+ module.constructor = dlsym(module.handle, "eap_create");
+ if (module.constructor == NULL)
+ {
+ DBG1(DBG_CFG, " EAP module %s has no eap_create() function, skipped",
+ entry->d_name);
+ dlclose(module.handle);
+ continue;
+ }
+
+ /* get the type implemented in the method, create an instance for it */
+ id = identification_create_from_string("john@doe.xyz");
+ method = module.constructor(EAP_SERVER, id, id);
+ if (method == NULL)
+ {
+ method = module.constructor(EAP_PEER, id, id);
+ }
+ id->destroy(id);
+ if (method == NULL)
+ {
+ DBG1(DBG_CFG, " unable to create instance of EAP method %s, skipped",
+ entry->d_name);
+ dlclose(module.handle);
+ continue;
+ }
+ module.type = method->get_type(method);
+ method->destroy(method);
+
+ DBG1(DBG_CFG, " loaded EAP method %N successfully from %s",
+ eap_type_names, module.type, entry->d_name);
+
+ loaded_module = malloc_thing(module_entry_t);
+ memcpy(loaded_module, &module, sizeof(module));
+ modules->insert_last(modules, loaded_module);
+ }
+ closedir(dir);
+}
+
+/*
+ * Described in header.
+ */
+eap_method_t *eap_method_create(eap_type_t type, eap_role_t role,
+ identification_t *server,
+ identification_t *peer)
+{
+ eap_method_t *method = NULL;
+ iterator_t *iterator;
+ module_entry_t *entry;
+
+ iterator = modules->create_iterator(modules, TRUE);
+ while (iterator->iterate(iterator, (void**)&entry))
+ {
+ if (entry->type == type)
+ {
+ method = entry->constructor(role, server, peer);
+ if (method)
+ {
+ break;
+ }
+ }
+ }
+ iterator->destroy(iterator);
+
+ if (method == NULL)
+ {
+ DBG1(DBG_CFG, "no EAP module found for %N %N",
+ eap_type_names, type, eap_role_names, role);
+ }
+ return method;
+}
diff --git a/src/charon/sa/authenticators/eap/eap_method.h b/src/charon/sa/authenticators/eap/eap_method.h
new file mode 100644
index 000000000..d43dc001f
--- /dev/null
+++ b/src/charon/sa/authenticators/eap/eap_method.h
@@ -0,0 +1,242 @@
+/**
+ * @file eap_method.h
+ *
+ * @brief Interface eap_method_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 EAP_METHOD_H_
+#define EAP_METHOD_H_
+
+typedef struct eap_method_t eap_method_t;
+typedef enum eap_role_t eap_role_t;
+typedef enum eap_type_t eap_type_t;
+typedef enum eap_code_t eap_code_t;
+
+#include <library.h>
+#include <utils/identification.h>
+#include <encoding/payloads/eap_payload.h>
+
+/**
+ * Role of an eap_method, SERVER or PEER (client)
+ *
+ * @ingroup eap
+ */
+enum eap_role_t {
+ EAP_SERVER,
+ EAP_PEER,
+};
+/**
+ * enum names for eap_role_t.
+ *
+ * @ingroup eap
+ */
+extern enum_name_t *eap_role_names;
+
+/**
+ * EAP types, defines the EAP method implementation
+ *
+ * @ingroup eap
+ */
+enum eap_type_t {
+ EAP_IDENTITY = 1,
+ EAP_NOTIFICATION = 2,
+ EAP_NAK = 3,
+ EAP_MD5 = 4,
+ EAP_ONE_TIME_PASSWORD = 5,
+ EAP_TOKEN_CARD = 6,
+ EAP_SIM = 18,
+ EAP_AKA = 23,
+};
+
+/**
+ * enum names for eap_type_t.
+ *
+ * @ingroup eap
+ */
+extern enum_name_t *eap_type_names;
+
+/**
+ * EAP code, type of an EAP message
+ *
+ * @ingroup eap
+ */
+enum eap_code_t {
+ EAP_REQUEST = 1,
+ EAP_RESPONSE = 2,
+ EAP_SUCCESS = 3,
+ EAP_FAILURE = 4,
+};
+
+/**
+ * enum names for eap_code_t.
+ *
+ * @ingroup eap
+ */
+extern enum_name_t *eap_code_names;
+
+
+/**
+ * @brief Interface of an EAP method for server and client side.
+ *
+ * An EAP method initiates an EAP exchange and processes requests and
+ * responses. An EAP method may need multiple exchanges before succeeding, and
+ * the eap_authentication may use multiple EAP methods to authenticate a peer.
+ * To accomplish these requirements, all EAP methods have their own
+ * implementation while the eap_authenticatior uses one or more of these
+ * EAP methods. Sending of EAP(SUCCESS/FAILURE) message is not the job
+ * of the method, the eap_authenticator does this.
+ * An EAP method may establish a MSK, this is used the complete the
+ * authentication. Even if a mutual EAP method is used, the traditional
+ * AUTH payloads are required. Only these include the nonces and messages from
+ * ike_sa_init and therefore prevent man in the middle attacks.
+ *
+ * @b Constructors:
+ * - eap_method_create()
+ *
+ * @ingroup eap
+ */
+struct eap_method_t {
+
+ /**
+ * @brief Initiate the EAP exchange.
+ *
+ * initiate() is only useable for server implementations, as clients only
+ * reply to server requests.
+ * A eap_payload is created in "out" if result is NEED_MORE.
+ *
+ * @param this calling object
+ * @param out eap_payload to send to the client
+ * @return
+ * - NEED_MORE, if an other exchange is required
+ * - FAILED, if unable to create eap request payload
+ */
+ status_t (*initiate) (eap_method_t *this, eap_payload_t **out);
+
+ /**
+ * @brief Process a received EAP message.
+ *
+ * A eap_payload is created in "out" if result is NEED_MORE.
+ *
+ * @param this calling object
+ * @param in eap_payload response received
+ * @param out created eap_payload to send
+ * @return
+ * - NEED_MORE, if an other exchange is required
+ * - FAILED, if EAP method failed
+ * - SUCCESS, if EAP method succeeded
+ */
+ status_t (*process) (eap_method_t *this, eap_payload_t *in,
+ eap_payload_t **out);
+
+ /**
+ * @brief Get the EAP type implemented in this method.
+ *
+ * @param this calling object
+ * @return type of the EAP method
+ */
+ eap_type_t (*get_type) (eap_method_t *this);
+
+ /**
+ * @brief Check if this EAP method authenticates the server.
+ *
+ * Some EAP methods provide mutual authentication and
+ * allow authentication using only EAP, if the peer supports it.
+ *
+ * @param this calling object
+ * @return TRUE if methods provides mutual authentication
+ */
+ bool (*is_mutual) (eap_method_t *this);
+
+ /**
+ * @brief Get the MSK established by this EAP method.
+ *
+ * Not all EAP methods establish a shared secret.
+ *
+ * @param this calling object
+ * @param msk chunk receiving internal stored MSK
+ * @return
+ * - SUCCESS, or
+ * - FAILED, if MSK not established (yet)
+ */
+ status_t (*get_msk) (eap_method_t *this, chunk_t *msk);
+
+ /**
+ * @brief Destroys a eap_method_t object.
+ *
+ * @param this calling object
+ */
+ void (*destroy) (eap_method_t *this);
+};
+
+/**
+ * @brief Creates an EAP method for a specific type and role.
+ *
+ * @param eap_type EAP type to use
+ * @param role role of the eap_method, server or peer
+ * @param server ID of acting server
+ * @param peer ID of involved peer (client)
+ * @return eap_method_t object
+ *
+ * @ingroup eap
+ */
+eap_method_t *eap_method_create(eap_type_t eap_type, eap_role_t role,
+ identification_t *server, identification_t *peer);
+
+/**
+ * @brief (Re-)Load all EAP modules in the EAP modules directory.
+ *
+ * For security reasons, the directory and all it's modules must be owned
+ * by root and must not be writeable by someone else.
+ *
+ * @param dir directory of the EAP modules
+ *
+ * @ingroup eap
+ */
+void eap_method_load(char *directory);
+
+/**
+ * @brief Unload all loaded EAP modules
+ *
+ * @ingroup eap
+ */
+void eap_method_unload();
+
+/**
+ * @brief Constructor definition for a pluggable EAP module.
+ *
+ * Each EAP module must define a constructor function which will return
+ * an initialized object with the methods defined in eap_method_t. The
+ * constructor must be named eap_create() and it's signature must be equal
+ * to that of eap_constructor_t.
+ * A module may implement only a single role. If it does not support the role
+ * requested, NULL should be returned. Multiple modules are allowed of the
+ * same EAP type to support seperate implementations of peer/server.
+ *
+ * @param role role the module will play, peer or server
+ * @param server ID of the server to use for credential lookup
+ * @param peer ID of the peer to use for credential lookup
+ * @return implementation of the eap_method_t interface
+ *
+ * @ingroup eap
+ */
+typedef eap_method_t *(*eap_constructor_t)(eap_role_t role,
+ identification_t *server,
+ identification_t *peer);
+
+#endif /* EAP_METHOD_H_ */
diff --git a/src/charon/sa/authenticators/eap/eap_sim.c b/src/charon/sa/authenticators/eap/eap_sim.c
new file mode 100644
index 000000000..3dc59fb6b
--- /dev/null
+++ b/src/charon/sa/authenticators/eap/eap_sim.c
@@ -0,0 +1,703 @@
+/**
+ * @file eap_sim.c
+ *
+ * @brief Implementation of eap_sim_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "eap_sim.h"
+
+#include <dlfcn.h>
+
+#include <daemon.h>
+#include <library.h>
+
+#define MAX_TRIES 3
+
+ENUM(sim_subtype_names, SIM_START, SIM_CLIENT_ERROR,
+ "SIM_START",
+ "SIM_CHALLENGE",
+ "SIM_NOTIFICATION",
+ "SIM_13",
+ "SIM_CLIENT_ERROR",
+);
+
+ENUM_BEGIN(sim_attribute_names, AT_END, AT_CLIENT_ERROR_CODE,
+ "AT_END",
+ "AT_0",
+ "AT_RAND",
+ "AT_AUTN",
+ "AT_RES",
+ "AT_AUTS",
+ "AT_5",
+ "AT_PADDING",
+ "AT_NONCE_MT",
+ "AT_8",
+ "AT_9",
+ "AT_PERMANENT_ID_REQ",
+ "AT_MAC",
+ "AT_NOTIFICATION",
+ "AT_ANY_ID_REQ",
+ "AT_IDENTITY",
+ "AT_VERSION_LIST",
+ "AT_SELECTED_VERSION",
+ "AT_FULLAUTH_ID_REQ",
+ "AT_18",
+ "AT_COUNTER",
+ "AT_COUNTER_TOO_SMALL",
+ "AT_NONCE_S",
+ "AT_CLIENT_ERROR_CODE");
+ENUM_NEXT(sim_attribute_names, AT_IV, AT_RESULT_IND, AT_CLIENT_ERROR_CODE,
+ "AT_IV",
+ "AT_ENCR_DATA",
+ "AT_131",
+ "AT_NEXT_PSEUDONYM",
+ "AT_NEXT_REAUTH_ID",
+ "AT_CHECKCODE",
+ "AT_RESULT_IND");
+ENUM_END(sim_attribute_names, AT_RESULT_IND);
+
+
+typedef struct private_eap_sim_t private_eap_sim_t;
+
+/**
+ * Private data of an eap_sim_t object.
+ */
+struct private_eap_sim_t {
+
+ /**
+ * Public authenticator_t interface.
+ */
+ eap_sim_t public;
+
+ /**
+ * ID of ourself
+ */
+ identification_t *peer;
+
+ /**
+ * SIM cardreader function loaded from library
+ */
+ sim_algo_t alg;
+
+ /**
+ * handle of the loaded library
+ */
+ void *handle;
+
+ /**
+ * how many times we try to authenticate
+ */
+ int tries;
+
+ /**
+ * version this implementation uses
+ */
+ chunk_t version;
+
+ /**
+ * version list received from server
+ */
+ chunk_t version_list;
+
+ /**
+ * Nonce value used in AT_NONCE_MT
+ */
+ chunk_t nonce;
+
+ /**
+ * k_encr key derived from MK
+ */
+ chunk_t k_encr;
+
+ /**
+ * k_auth key derived from MK, used for AT_MAC verification
+ */
+ chunk_t k_auth;
+
+ /**
+ * MSK, used for EAP-SIM based IKEv2 authentication
+ */
+ chunk_t msk;
+
+ /**
+ * EMSK, extendes MSK for further uses
+ */
+ chunk_t emsk;
+};
+
+/** length of the AT_NONCE_MT nonce value */
+#define NONCE_LEN 16
+/** length of the AT_MAC value */
+#define MAC_LEN 16
+/** length of the AT_RAND value */
+#define RAND_LEN 16
+/** length of the k_encr key */
+#define KENCR_LEN 16
+/** length of the k_auth key */
+#define KAUTH_LEN 16
+/** length of the MSK */
+#define MSK_LEN 64
+/** length of the EMSK */
+#define EMSK_LEN 64
+
+/* client error codes used in AT_CLIENT_ERROR_CODE */
+char client_error_general_buf[] = {0x00, 0x01};
+char client_error_unsupported_buf[] = {0x00, 0x02};
+char client_error_insufficient_buf[] = {0x00, 0x03};
+char client_error_notfresh_buf[] = {0x00, 0x04};
+chunk_t client_error_general = chunk_from_buf(client_error_general_buf);
+chunk_t client_error_unsupported = chunk_from_buf(client_error_unsupported_buf);
+chunk_t client_error_insufficient = chunk_from_buf(client_error_insufficient_buf);
+chunk_t client_error_notfresh = chunk_from_buf(client_error_notfresh_buf);
+
+/**
+ * Read EAP and EAP-SIM header, return SIM type
+ */
+static sim_subtype_t read_header(chunk_t *message)
+{
+ sim_subtype_t type;
+
+ if (message->len < 8)
+ {
+ *message = chunk_empty;
+ return 0;
+ }
+ type = *(message->ptr + 5);
+ *message = chunk_skip(*message, 8);
+ return type;
+}
+
+/**
+ * read the next attribute from the chunk data
+ */
+static sim_attribute_t read_attribute(chunk_t *message, chunk_t *data)
+{
+ sim_attribute_t attribute;
+ size_t length;
+
+ DBG3(DBG_IKE, "reading attribute from %B", message);
+
+ if (message->len < 2)
+ {
+ return AT_END;
+ }
+ attribute = *message->ptr++;
+ length = *message->ptr++ * 4 - 2;
+ message->len -= 2;
+ DBG3(DBG_IKE, "found attribute %N with length %d",
+ sim_attribute_names, attribute, length);
+
+ if (length > message->len)
+ {
+ return AT_END;
+ }
+ data->len = length;
+ data->ptr = message->ptr;
+ *message = chunk_skip(*message, length);
+ return attribute;
+}
+
+/**
+ * Build an EAP-SIM payload using a variable length attribute list.
+ * The variable argument takes a sim_attribute_t followed by its data in a chunk.
+ */
+static eap_payload_t *build_payload(private_eap_sim_t *this, u_int8_t identifier,
+ sim_subtype_t type, ...)
+{
+ chunk_t message = chunk_alloca(512);
+ chunk_t pos = message;
+ eap_payload_t *payload;
+ va_list args;
+ sim_attribute_t attr;
+ u_int8_t *mac_pos = NULL;
+ chunk_t mac_data = chunk_empty;
+
+ /* write EAP header, skip length bytes */
+ *pos.ptr++ = EAP_RESPONSE;
+ *pos.ptr++ = identifier;
+ pos.ptr += 2;
+ pos.len -= 4;
+ /* write SIM header with type and subtype, zero reserved bytes */
+ *pos.ptr++ = EAP_SIM;
+ *pos.ptr++ = type;
+ *pos.ptr++ = 0;
+ *pos.ptr++ = 0;
+ pos.len -= 4;
+
+ va_start(args, type);
+ while ((attr = va_arg(args, sim_attribute_t)) != AT_END)
+ {
+ chunk_t data = va_arg(args, chunk_t);
+
+ DBG3(DBG_IKE, "building %N %B", sim_attribute_names, attr, &data);
+
+ /* write attribute header */
+ *pos.ptr++ = attr;
+ pos.len--;
+
+ switch (attr)
+ {
+ case AT_CLIENT_ERROR_CODE:
+ case AT_SELECTED_VERSION:
+ {
+ *pos.ptr = data.len/4 + 1;
+ pos = chunk_skip(pos, 1);
+ memcpy(pos.ptr, data.ptr, data.len);
+ pos = chunk_skip(pos, data.len);
+ break;
+ }
+ case AT_IDENTITY:
+ {
+ /* align up to four byte */
+ if (data.len % 4)
+ {
+ chunk_t tmp = chunk_alloca((data.len/4)*4 + 4);
+ memset(tmp.ptr, 0, tmp.len);
+ memcpy(tmp.ptr, data.ptr, data.len);
+ data = tmp;
+ }
+ *pos.ptr = data.len/4 + 1;
+ pos = chunk_skip(pos, 1);
+ /* actual length in bytes */
+ *(u_int16_t*)pos.ptr = htons(data.len);
+ pos = chunk_skip(pos, sizeof(u_int16_t));
+ memcpy(pos.ptr, data.ptr, data.len);
+ pos = chunk_skip(pos, data.len);
+ break;
+ }
+ case AT_NONCE_MT:
+ {
+ *pos.ptr = data.len/4 + 1;
+ pos = chunk_skip(pos, 1);
+ memset(pos.ptr, 0, 2);
+ pos = chunk_skip(pos, 2);
+ memcpy(pos.ptr, data.ptr, data.len);
+ pos = chunk_skip(pos, data.len);
+ break;
+ }
+ case AT_MAC:
+ {
+ *pos.ptr++ = 5; pos.len--;
+ *pos.ptr++ = 0; pos.len--;
+ *pos.ptr++ = 0; pos.len--;
+ mac_pos = pos.ptr;
+ memset(mac_pos, 0, MAC_LEN);
+ pos = chunk_skip(pos, MAC_LEN);
+ mac_data = data;
+ break;
+ }
+ case AT_RAND:
+ {
+ *pos.ptr++ = data.len/4 + 1; pos.len--;
+ *pos.ptr++ = 0; pos.len--;
+ *pos.ptr++ = 0; pos.len--;
+ memcpy(pos.ptr, data.ptr, data.len);
+ pos = chunk_skip(pos, data.len);
+ break;
+ }
+ default:
+ DBG1(DBG_IKE, "no rule to build EAP_SIM attribute %N, skipped",
+ sim_attribute_names, attr);
+ break;
+ }
+ }
+ va_end(args);
+
+ /* calculate message length, write into header */
+ message.len = pos.ptr - message.ptr;
+ *(u_int16_t*)(message.ptr + 2) = htons(message.len);
+
+ /* create MAC if AT_MAC attribte was included. Append supplied va_arg
+ * chunk mac_data to "to-sign" chunk */
+ if (mac_pos)
+ {
+ signer_t *signer = signer_create(AUTH_HMAC_SHA1_128);
+ signer->set_key(signer, this->k_auth);
+ mac_data = chunk_cata("cc", message, mac_data);
+ signer->get_signature(signer, mac_data, mac_pos);
+ DBG3(DBG_IKE, "AT_MAC signature of %B\n is %b",
+ &mac_data, mac_pos, MAC_LEN);
+ signer->destroy(signer);
+ }
+
+ payload = eap_payload_create_data(message);
+
+ DBG3(DBG_IKE, "created EAP message %B", &message);
+ return payload;
+}
+
+/**
+ * process an EAP-SIM/Request/Start message
+ */
+static status_t process_start(private_eap_sim_t *this, eap_payload_t *in,
+ eap_payload_t **out)
+{
+ chunk_t message, data;
+ sim_attribute_t attribute, include_id = AT_END;
+ u_int8_t identifier;
+
+ identifier = in->get_identifier(in);
+ message = in->get_data(in);
+ read_header(&message);
+
+ while ((attribute = read_attribute(&message, &data)) != AT_END)
+ {
+ switch (attribute)
+ {
+ case AT_VERSION_LIST:
+ {
+ /* check if server supports our implementation */
+ bool found = FALSE;
+ if (data.len > 2)
+ {
+ /* read actual length first */
+ data.len = min(data.len, ntohs(*(u_int16_t*)data.ptr) + 2);
+ data = chunk_skip(data, 2);
+ chunk_free(&this->version_list);
+ this->version_list = chunk_clone(data);
+ while (data.len >= this->version.len)
+ {
+ if (memeq(data.ptr, this->version.ptr, this->version.len))
+ {
+ found = TRUE;
+ break;
+ }
+ data = chunk_skip(data, this->version.len);
+ }
+ }
+ if (!found)
+ {
+ DBG1(DBG_IKE, "server does not support EAP_SIM "
+ "version number %#B", &this->version);
+ *out = build_payload(this, identifier, SIM_CLIENT_ERROR,
+ AT_CLIENT_ERROR_CODE, client_error_unsupported,
+ AT_END);
+ return NEED_MORE;
+ }
+ break;
+ }
+ case AT_PERMANENT_ID_REQ:
+ case AT_FULLAUTH_ID_REQ:
+ case AT_ANY_ID_REQ:
+ /* only include AT_IDENTITY if requested */
+ include_id = AT_IDENTITY;
+ break;
+ default:
+ DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N",
+ sim_attribute_names, attribute);
+ break;
+ }
+ }
+
+ /* build payload. If "include_id" is AT_END, AT_IDENTITY is ommited */
+ *out = build_payload(this, identifier, SIM_START,
+ AT_SELECTED_VERSION, this->version,
+ AT_NONCE_MT, this->nonce,
+ include_id, this->peer->get_encoding(this->peer),
+ AT_END);
+ return NEED_MORE;
+}
+
+/**
+ * process an EAP-SIM/Request/Challenge message
+ */
+static status_t process_challenge(private_eap_sim_t *this, eap_payload_t *in,
+ eap_payload_t **out)
+{
+ chunk_t message, data, tmp, kcs, kc, sreses, sres, mk;
+ sim_attribute_t attribute;
+ u_int8_t identifier, i;
+ chunk_t mac = chunk_empty, rands = chunk_empty;
+ signer_t *signer;
+ hasher_t *hasher;
+ prf_t *prf;
+
+ if (this->tries-- <= 0)
+ {
+ /* give up without notification. This hack is required as some buggy
+ * server implementations won't respect our client-error. */
+ return FAILED;
+ }
+
+ identifier = in->get_identifier(in);
+ message = in->get_data(in);
+ read_header(&message);
+
+ while ((attribute = read_attribute(&message, &data)) != AT_END)
+ {
+ switch (attribute)
+ {
+ case AT_RAND:
+ {
+ rands = chunk_skip(data, 2);
+ break;
+ }
+ case AT_MAC:
+ {
+ /* backup MAC, zero it inline for later verification */
+ data = chunk_skip(data, 2);
+ mac = chunk_clonea(data);
+ memset(data.ptr, 0, data.len);
+ break;
+ }
+ default:
+ DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N",
+ sim_attribute_names, attribute);
+ break;
+ }
+ }
+
+ /* excepting two or three RAND, each 16 bytes. We require two valid
+ * and different RANDs */
+ if ((rands.len != 2 * RAND_LEN && rands.len != 3 * RAND_LEN) ||
+ memeq(rands.ptr, rands.ptr + RAND_LEN, RAND_LEN))
+ {
+ DBG1(DBG_IKE, "no valid AT_RAND received");
+ *out = build_payload(this, identifier, SIM_CLIENT_ERROR,
+ AT_CLIENT_ERROR_CODE, client_error_insufficient,
+ AT_END);
+ return FAILED;
+ }
+ if (mac.len != MAC_LEN)
+ {
+ DBG1(DBG_IKE, "no valid AT_MAC received");
+ *out = build_payload(this, identifier, SIM_CLIENT_ERROR,
+ AT_CLIENT_ERROR_CODE, client_error_general,
+ AT_END);
+ return NEED_MORE;
+ }
+
+ /* get two or three KCs/SRESes from SIM using RANDs */
+ kcs = kc = chunk_alloca(rands.len / 2);
+ sreses = sres = chunk_alloca(rands.len / 4);
+ while (rands.len > 0)
+ {
+ int kc_len = kc.len, sres_len = sres.len;
+
+ if (this->alg(rands.ptr, RAND_LEN, sres.ptr, &sres_len, kc.ptr, &kc_len))
+ {
+ DBG1(DBG_IKE, "unable to get triplets from SIM");
+ *out = build_payload(this, identifier, SIM_CLIENT_ERROR,
+ AT_CLIENT_ERROR_CODE, client_error_general,
+ AT_END);
+ return NEED_MORE;
+ }
+ DBG3(DBG_IKE, "got triplet for RAND %b\n Kc %b\n SRES %b",
+ rands.ptr, RAND_LEN, sres.ptr, sres_len, kc.ptr, kc_len);
+ kc = chunk_skip(kc, kc_len);
+ sres = chunk_skip(sres, sres_len);
+ rands = chunk_skip(rands, RAND_LEN);
+ }
+
+ /* build MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */
+ tmp = chunk_cata("ccccc", this->peer->get_encoding(this->peer), kcs,
+ this->nonce, this->version_list, this->version);
+ hasher = hasher_create(HASH_SHA1);
+ mk = chunk_alloca(hasher->get_hash_size(hasher));
+ hasher->get_hash(hasher, tmp, mk.ptr);
+ hasher->destroy(hasher);
+ DBG3(DBG_IKE, "MK = SHA1(%B\n) = %B", &tmp, &mk);
+
+ /* K_encr | K_auth | MSK | EMSK = prf() | prf() | prf() | prf()
+ * FIPS PRF has 320 bit block size, we need 160 byte for keys
+ * => run prf four times */
+ prf = prf_create(PRF_FIPS_SHA1_160);
+ prf->set_key(prf, mk);
+ tmp = chunk_alloca(prf->get_block_size(prf) * 4);
+ for (i = 0; i < 4; i++)
+ {
+ prf->get_bytes(prf, chunk_empty, tmp.ptr + tmp.len / 4 * i);
+ }
+ prf->destroy(prf);
+ chunk_free(&this->k_encr);
+ chunk_free(&this->k_auth);
+ chunk_free(&this->msk);
+ chunk_free(&this->emsk);
+ chunk_split(tmp, "aaaa", KENCR_LEN, &this->k_encr, KAUTH_LEN, &this->k_auth,
+ MSK_LEN, &this->msk, EMSK_LEN, &this->emsk);
+ DBG3(DBG_IKE, "K_encr %B\nK_auth %B\nMSK %B\nEMSK %B",
+ &this->k_encr, &this->k_auth, &this->msk, &this->emsk);
+
+ /* verify AT_MAC attribute, signature is over "EAP packet | NONCE_MT" */
+ signer = signer_create(AUTH_HMAC_SHA1_128);
+ signer->set_key(signer, this->k_auth);
+ tmp = chunk_cata("cc", in->get_data(in), this->nonce);
+ if (!signer->verify_signature(signer, tmp, mac))
+ {
+ DBG1(DBG_IKE, "AT_MAC verification failed");
+ signer->destroy(signer);
+ *out = build_payload(this, identifier, SIM_CLIENT_ERROR,
+ AT_CLIENT_ERROR_CODE, client_error_general,
+ AT_END);
+ return NEED_MORE;
+ }
+ signer->destroy(signer);
+
+ /* build response, AT_MAC is built over "EAP packet | n*SRES" */
+ *out = build_payload(this, identifier, SIM_CHALLENGE,
+ AT_MAC, sreses,
+ AT_END);
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of eap_method_t.process for the peer
+ */
+static status_t process(private_eap_sim_t *this,
+ eap_payload_t *in, eap_payload_t **out)
+{
+ sim_subtype_t type;
+ chunk_t message;
+
+ message = in->get_data(in);
+ type = read_header(&message);
+
+ switch (type)
+ {
+ case SIM_START:
+ return process_start(this, in, out);
+ case SIM_CHALLENGE:
+ return process_challenge(this, in, out);
+ default:
+ DBG1(DBG_IKE, "unable to process EAP_SIM subtype %N",
+ sim_subtype_names, type);
+ *out = build_payload(this, in->get_identifier(in), SIM_CLIENT_ERROR,
+ AT_CLIENT_ERROR_CODE, client_error_general, AT_END);
+ return NEED_MORE;
+ }
+}
+
+/**
+ * Implementation of eap_method_t.initiate for the peer
+ */
+static status_t initiate(private_eap_sim_t *this, eap_payload_t **out)
+{
+ /* peer never initiates */
+ return FAILED;
+}
+
+/**
+ * Implementation of eap_method_t.get_type.
+ */
+static eap_type_t get_type(private_eap_sim_t *this)
+{
+ return EAP_SIM;
+}
+
+/**
+ * Implementation of eap_method_t.get_msk.
+ */
+static status_t get_msk(private_eap_sim_t *this, chunk_t *msk)
+{
+ if (this->msk.ptr)
+ {
+ *msk = this->msk;
+ return SUCCESS;
+ }
+ return FAILED;
+}
+
+/**
+ * Implementation of eap_method_t.is_mutual.
+ */
+static bool is_mutual(private_eap_sim_t *this)
+{
+ return TRUE;
+}
+
+/**
+ * Implementation of eap_method_t.destroy.
+ */
+static void destroy(private_eap_sim_t *this)
+{
+ dlclose(this->handle);
+ chunk_free(&this->nonce);
+ chunk_free(&this->version_list);
+ chunk_free(&this->k_auth);
+ chunk_free(&this->k_encr);
+ chunk_free(&this->msk);
+ chunk_free(&this->emsk);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+eap_sim_t *eap_create(eap_role_t role,
+ identification_t *server, identification_t *peer)
+{
+ private_eap_sim_t *this;
+ randomizer_t *randomizer;
+ static char version[] = {0x00,0x01};
+
+ if (role != EAP_PEER)
+ {
+ return NULL;
+ }
+ this = malloc_thing(private_eap_sim_t);
+
+ this->handle = dlopen(SIM_READER_LIB, RTLD_LAZY);
+ if (this->handle == NULL)
+ {
+ DBG1(DBG_IKE, "unable to open SIM reader '%s'", SIM_READER_LIB);
+ free(this);
+ return NULL;
+ }
+ this->alg = dlsym(this->handle, SIM_READER_ALG);
+ if (this->alg == NULL)
+ {
+ DBG1(DBG_IKE, "unable to open SIM reader function '%s' in '%s'",
+ SIM_READER_ALG, SIM_READER_LIB);
+ dlclose(this->handle);
+ free(this);
+ return NULL;
+ }
+
+ randomizer = randomizer_create();
+ if (randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_LEN,
+ &this->nonce))
+ {
+ DBG1(DBG_IKE, "unable to generate NONCE for EAP_SIM");
+ randomizer->destroy(randomizer);
+ free(this);
+ return NULL;
+ }
+ randomizer->destroy(randomizer);
+
+ /* public functions */
+ this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))initiate;
+ this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))process;
+ this->public.eap_method_interface.get_type = (eap_type_t(*)(eap_method_t*))get_type;
+ this->public.eap_method_interface.is_mutual = (bool(*)(eap_method_t*))is_mutual;
+ this->public.eap_method_interface.get_msk = (status_t(*)(eap_method_t*,chunk_t*))get_msk;
+ this->public.eap_method_interface.destroy = (void(*)(eap_method_t*))destroy;
+
+ /* private data */
+ this->peer = peer;
+ this->tries = MAX_TRIES;
+ this->version.ptr = version;
+ this->version.len = sizeof(version);
+ this->version_list = chunk_empty;
+ this->k_auth = chunk_empty;
+ this->k_encr = chunk_empty;
+ this->msk = chunk_empty;
+ this->emsk = chunk_empty;
+
+ return &this->public;
+}
diff --git a/src/charon/sa/authenticators/eap/eap_sim.h b/src/charon/sa/authenticators/eap/eap_sim.h
new file mode 100644
index 000000000..10640babe
--- /dev/null
+++ b/src/charon/sa/authenticators/eap/eap_sim.h
@@ -0,0 +1,141 @@
+/**
+ * @file eap_sim.h
+ *
+ * @brief Interface of eap_sim_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef EAP_SIM_H_
+#define EAP_SIM_H_
+
+typedef struct eap_sim_t eap_sim_t;
+typedef enum sim_subtype_t sim_subtype_t;
+typedef enum sim_attribute_t sim_attribute_t;
+
+#include <sa/authenticators/eap/eap_method.h>
+
+/**
+ * Subtypes of SIM messages
+ */
+enum sim_subtype_t {
+ SIM_START = 10,
+ SIM_CHALLENGE = 11,
+ SIM_NOTIFICATION = 12,
+ SIM_CLIENT_ERROR = 14,
+};
+
+/**
+ * enum names for sim_subtype_t
+ */
+extern enum_name_t *sim_subtype_names;
+
+enum sim_attribute_t {
+ /** defines the end of attribute list */
+ AT_END = -1,
+ AT_RAND = 1,
+ AT_AUTN = 2,
+ AT_RES = 3,
+ AT_AUTS = 4,
+ AT_PADDING = 6,
+ AT_NONCE_MT = 7,
+ AT_PERMANENT_ID_REQ = 10,
+ AT_MAC = 11,
+ AT_NOTIFICATION = 12,
+ AT_ANY_ID_REQ = 13,
+ AT_IDENTITY = 14,
+ AT_VERSION_LIST = 15,
+ AT_SELECTED_VERSION = 16,
+ AT_FULLAUTH_ID_REQ = 17,
+ AT_COUNTER = 19,
+ AT_COUNTER_TOO_SMALL = 20,
+ AT_NONCE_S = 21,
+ AT_CLIENT_ERROR_CODE = 22,
+ AT_IV = 129,
+ AT_ENCR_DATA = 130,
+ AT_NEXT_PSEUDONYM = 132,
+ AT_NEXT_REAUTH_ID = 133,
+ AT_CHECKCODE = 134,
+ AT_RESULT_IND = 135,
+};
+
+/**
+ * enum names for sim_subtype_t
+ */
+extern enum_name_t *sim_attribute_names;
+
+/**
+ * @brief Cardreaders SIM function.
+ *
+ * @param rand RAND to run algo with
+ * @param rand_length length of value in rand
+ * @param sres buffer to get SRES
+ * @param sres_length size of buffer in sres, returns bytes written to SRES
+ * @param kc buffer to get Kc
+ * @param kc_length size of buffer in Kc, returns bytes written to Kc
+ * @return zero on success
+ */
+typedef int (*sim_algo_t)(const unsigned char *rand, int rand_length,
+ unsigned char *sres, int *sres_length,
+ unsigned char *kc, int *kc_length);
+
+#ifndef SIM_READER_LIB
+/** the library containing the cardreader with the SIM function */
+#error SIM_READER_LIB not specified, use --with-sim-reader option
+#endif /* SIM_READER_LIB */
+
+#ifndef SIM_READER_ALG
+/** the SIM_READER_LIB's algorithm, uses sim_algo_t signature */
+#define SIM_READER_ALG "sim_run_alg"
+#endif /* SIM_READER_ALG */
+
+
+/**
+ * @brief Implementation of the eap_method_t interface using EAP-SIM.
+ *
+ * This EAP-SIM client implementation uses another pluggable library to
+ * access the SIM card. This module is specified using the SIM_READER_LIB
+ * definition. The function to run the algorithm has the sim_algo_t type and
+ * is named as SIM_READER_ALG is defined.
+ *
+ * @b Constructors:
+ * - eap_create() of this module
+ * - eap_client_create() using eap_method EAP_SIM
+ *
+ * @ingroup eap
+ */
+struct eap_sim_t {
+
+ /**
+ * Implemented eap_method_t interface.
+ */
+ eap_method_t eap_method_interface;
+};
+
+/**
+ * @brief Creates the EAP method EAP-SIM.
+ *
+ * @param server ID of the EAP server
+ * @param peer ID of the EAP client
+ * @return eap_sim_t object
+ *
+ * @ingroup eap
+ */
+eap_sim_t *eap_create(eap_role_t role,
+ identification_t *server, identification_t *peer);
+
+#endif /* EAP_SIM_H_ */
diff --git a/src/charon/sa/authenticators/eap_authenticator.c b/src/charon/sa/authenticators/eap_authenticator.c
new file mode 100644
index 000000000..6c8ca8d8f
--- /dev/null
+++ b/src/charon/sa/authenticators/eap_authenticator.c
@@ -0,0 +1,360 @@
+/**
+ * @file eap_authenticator.c
+ *
+ * @brief Implementation of eap_authenticator_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 "eap_authenticator.h"
+
+#include <daemon.h>
+#include <config/policies/policy.h>
+#include <sa/authenticators/eap/eap_method.h>
+
+typedef struct private_eap_authenticator_t private_eap_authenticator_t;
+
+/**
+ * Private data of an eap_authenticator_t object.
+ */
+struct private_eap_authenticator_t {
+
+ /**
+ * Public authenticator_t interface.
+ */
+ eap_authenticator_t public;
+
+ /**
+ * Assigned IKE_SA
+ */
+ ike_sa_t *ike_sa;
+
+ /**
+ * Role of this authenticator, PEER or SERVER
+ */
+ eap_role_t role;
+
+ /**
+ * Current EAP method processing
+ */
+ eap_method_t *method;
+
+ /**
+ * MSK used to build and verify auth payload
+ */
+ chunk_t msk;
+};
+
+extern chunk_t build_shared_key_signature(chunk_t ike_sa_init, chunk_t nonce,
+ chunk_t secret, identification_t *id,
+ prf_t *prf_skp, prf_t *prf);
+
+/**
+ * Implementation of authenticator_t.verify.
+ */
+static status_t verify(private_eap_authenticator_t *this, chunk_t ike_sa_init,
+ chunk_t my_nonce, auth_payload_t *auth_payload)
+{
+ chunk_t auth_data, recv_auth_data;
+ identification_t *other_id = this->ike_sa->get_other_id(this->ike_sa);
+
+ auth_data = build_shared_key_signature(ike_sa_init, my_nonce, this->msk,
+ other_id, this->ike_sa->get_auth_verify(this->ike_sa),
+ this->ike_sa->get_prf(this->ike_sa));
+
+ recv_auth_data = auth_payload->get_data(auth_payload);
+ if (!chunk_equals(auth_data, recv_auth_data))
+ {
+ DBG1(DBG_IKE, "verification of AUTH payload created from EAP MSK failed");
+ chunk_free(&auth_data);
+ return FAILED;
+ }
+ chunk_free(&auth_data);
+
+ DBG1(DBG_IKE, "authentication of '%D' with %N successful",
+ other_id, auth_method_names, AUTH_EAP);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of authenticator_t.build.
+ */
+static status_t build(private_eap_authenticator_t *this, chunk_t ike_sa_init,
+ chunk_t other_nonce, auth_payload_t **auth_payload)
+{
+ chunk_t auth_data;
+ identification_t *my_id = this->ike_sa->get_my_id(this->ike_sa);
+
+ DBG1(DBG_IKE, "authentication of '%D' (myself) with %N",
+ my_id, auth_method_names, AUTH_EAP);
+
+ auth_data = build_shared_key_signature(ike_sa_init, other_nonce, this->msk,
+ my_id, this->ike_sa->get_auth_build(this->ike_sa),
+ this->ike_sa->get_prf(this->ike_sa));
+
+ *auth_payload = auth_payload_create();
+ (*auth_payload)->set_auth_method(*auth_payload, AUTH_PSK);
+ (*auth_payload)->set_data(*auth_payload, auth_data);
+ chunk_free(&auth_data);
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of eap_authenticator_t.initiate
+ */
+static status_t initiate(private_eap_authenticator_t *this, eap_type_t type,
+ eap_payload_t **out)
+{
+ /* if initiate() is called, role is always server */
+ this->role = EAP_SERVER;
+
+ if (type == 0)
+ {
+ DBG1(DBG_IKE,
+ "client requested EAP authentication, but configuration forbids it");
+ *out = eap_payload_create_code(EAP_FAILURE);
+ return FAILED;
+ }
+
+ DBG1(DBG_IKE, "requesting %N authentication", eap_type_names, type);
+ this->method = eap_method_create(type, this->role,
+ this->ike_sa->get_my_id(this->ike_sa),
+ this->ike_sa->get_other_id(this->ike_sa));
+
+ if (this->method == NULL)
+ {
+ DBG1(DBG_IKE, "configured EAP server method %N not supported, sending %N",
+ eap_type_names, type, eap_code_names, EAP_FAILURE);
+ *out = eap_payload_create_code(EAP_FAILURE);
+ return FAILED;
+ }
+ if (this->method->initiate(this->method, out) != NEED_MORE)
+ {
+ DBG1(DBG_IKE, "failed to initiate %N, sending %N",
+ eap_type_names, type, eap_code_names, EAP_FAILURE);
+ *out = eap_payload_create_code(EAP_FAILURE);
+ return FAILED;
+ }
+ return NEED_MORE;
+}
+
+/**
+ * Processing method for a peer
+ */
+static status_t process_peer(private_eap_authenticator_t *this,
+ eap_payload_t *in, eap_payload_t **out)
+{
+ eap_type_t type = in->get_type(in);
+
+ if (type == EAP_IDENTITY)
+ {
+ eap_method_t *method = eap_method_create(type, EAP_PEER,
+ this->ike_sa->get_other_id(this->ike_sa),
+ this->ike_sa->get_my_id(this->ike_sa));
+
+ if (method == NULL || method->process(method, in, out) != SUCCESS)
+ {
+ DBG1(DBG_IKE, "EAP server requested %N, but unable to process",
+ eap_type_names, type);
+ DESTROY_IF(method);
+ return FAILED;
+ }
+
+ DBG1(DBG_IKE, "EAP server requested %N, sending IKE identity",
+ eap_type_names, type);
+
+ method->destroy(method);
+ return NEED_MORE;
+ }
+
+ /* create an eap_method for the first call */
+ if (this->method == NULL)
+ {
+ DBG1(DBG_IKE, "EAP server requested %N authentication",
+ eap_type_names, type);
+ this->method = eap_method_create(type, EAP_PEER,
+ this->ike_sa->get_other_id(this->ike_sa),
+ this->ike_sa->get_my_id(this->ike_sa));
+ if (this->method == NULL)
+ {
+ DBG1(DBG_IKE, "EAP server requested unsupported "
+ "EAP method %N, sending EAP_NAK", eap_type_names, type);
+ *out = eap_payload_create_nak();
+ return NEED_MORE;
+ }
+ }
+
+ switch (this->method->process(this->method, in, out))
+ {
+ case NEED_MORE:
+ return NEED_MORE;
+ case SUCCESS:
+ DBG1(DBG_IKE, "EAP method %N succeded",
+ eap_type_names, this->method->get_type(this->method));
+ return SUCCESS;
+ case FAILED:
+ default:
+ DBG1(DBG_IKE, "EAP method %N failed",
+ eap_type_names, this->method->get_type(this->method));
+ return FAILED;
+ }
+}
+
+/**
+ * Processing method for a server
+ */
+static status_t process_server(private_eap_authenticator_t *this,
+ eap_payload_t *in, eap_payload_t **out)
+{
+ switch (this->method->process(this->method, in, out))
+ {
+ case NEED_MORE:
+ return NEED_MORE;
+ case SUCCESS:
+ if (this->method->get_msk(this->method, &this->msk) == SUCCESS)
+ {
+ DBG1(DBG_IKE, "EAP method %N succeded, MSK established",
+ eap_type_names, this->method->get_type(this->method));
+ this->msk = chunk_clone(this->msk);
+ *out = eap_payload_create_code(EAP_SUCCESS);
+ return SUCCESS;
+ }
+ DBG1(DBG_IKE, "EAP method %N succeded, but no MSK established",
+ eap_type_names, this->method->get_type(this->method));
+ *out = eap_payload_create_code(EAP_FAILURE);
+ return FAILED;
+ case FAILED:
+ default:
+ DBG1(DBG_IKE, "EAP method %N failed for peer %D",
+ eap_type_names, this->method->get_type(this->method),
+ this->ike_sa->get_other_id(this->ike_sa));
+ *out = eap_payload_create_code(EAP_FAILURE);
+ return FAILED;
+ }
+}
+
+/**
+ * Implementation of eap_authenticator_t.process
+ */
+static status_t process(private_eap_authenticator_t *this, eap_payload_t *in,
+ eap_payload_t **out)
+{
+ eap_code_t code = in->get_code(in);
+
+ switch (this->role)
+ {
+ case EAP_SERVER:
+ {
+ switch (code)
+ {
+ case EAP_RESPONSE:
+ {
+ return process_server(this, in, out);
+ }
+ default:
+ {
+ DBG1(DBG_IKE, "received %N, sending %N",
+ eap_code_names, code, eap_code_names, EAP_FAILURE);
+ *out = eap_payload_create_code(EAP_FAILURE);
+ return FAILED;
+ }
+ }
+ }
+ case EAP_PEER:
+ {
+ switch (code)
+ {
+ case EAP_REQUEST:
+ {
+ return process_peer(this, in, out);
+ }
+ case EAP_SUCCESS:
+ {
+ if (this->method->get_msk(this->method, &this->msk) == SUCCESS)
+ {
+ this->msk = chunk_clone(this->msk);
+ return SUCCESS;
+ }
+ DBG1(DBG_IKE, "EAP method %N has no MSK established",
+ eap_type_names, this->method->get_type(this->method));
+ return FAILED;
+ }
+ case EAP_FAILURE:
+ default:
+ {
+ DBG1(DBG_IKE, "received %N, EAP authentication failed",
+ eap_code_names, code);
+ return FAILED;
+ }
+ }
+ }
+ default:
+ {
+ return FAILED;
+ }
+ }
+}
+
+/**
+ * Implementation of authenticator_t.is_mutual.
+ */
+static bool is_mutual(private_eap_authenticator_t *this)
+{
+ if (this->method)
+ {
+ return this->method->is_mutual(this->method);
+ }
+ return FALSE;
+}
+
+/**
+ * Implementation of authenticator_t.destroy.
+ */
+static void destroy(private_eap_authenticator_t *this)
+{
+ DESTROY_IF(this->method);
+ chunk_free(&this->msk);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+eap_authenticator_t *eap_authenticator_create(ike_sa_t *ike_sa)
+{
+ private_eap_authenticator_t *this = malloc_thing(private_eap_authenticator_t);
+
+ /* public functions */
+ this->public.authenticator_interface.verify = (status_t(*)(authenticator_t*,chunk_t,chunk_t,auth_payload_t*))verify;
+ this->public.authenticator_interface.build = (status_t(*)(authenticator_t*,chunk_t,chunk_t,auth_payload_t**))build;
+ this->public.authenticator_interface.destroy = (void(*)(authenticator_t*))destroy;
+
+ this->public.is_mutual = (bool(*)(eap_authenticator_t*))is_mutual;
+ this->public.initiate = (status_t(*)(eap_authenticator_t*,eap_type_t,eap_payload_t**))initiate;
+ this->public.process = (status_t(*)(eap_authenticator_t*,eap_payload_t*,eap_payload_t**))process;
+
+ /* private data */
+ this->ike_sa = ike_sa;
+ this->role = EAP_PEER;
+ this->method = NULL;
+ this->msk = chunk_empty;
+
+ return &this->public;
+}
diff --git a/src/charon/sa/authenticators/eap_authenticator.h b/src/charon/sa/authenticators/eap_authenticator.h
new file mode 100644
index 000000000..ffa162343
--- /dev/null
+++ b/src/charon/sa/authenticators/eap_authenticator.h
@@ -0,0 +1,156 @@
+/**
+ * @file eap_authenticator.h
+ *
+ * @brief Interface of eap_authenticator_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 EAP_AUTHENTICATOR_H_
+#define EAP_AUTHENTICATOR_H_
+
+typedef struct eap_authenticator_t eap_authenticator_t;
+
+#include <sa/authenticators/authenticator.h>
+#include <encoding/payloads/eap_payload.h>
+
+/**
+ * @brief Implementation of the authenticator_t interface using AUTH_EAP.
+ *
+ * Authentication using EAP involves the most complex authenticator. It stays
+ * alive over multiple ike_auth transactions and handles multiple EAP
+ * messages.
+ * EAP authentication must be clearly distinguished between using
+ * mutual EAP methods and using methods not providing server authentication.
+ * If no mutual authentication is used, the server must prove it's identity
+ * by traditional AUTH methods (RSA, psk). Only when the EAP method is mutual,
+ * the client should accept an EAP-only authentication.
+ * RFC4306 does always use traditional authentiction, EAP only authentication
+ * is described in the internet draft draft-eronen-ipsec-ikev2-eap-auth-05.txt.
+ *
+ * @verbatim
+ ike_sa_init
+ ------------------------->
+ <-------------------------
+ followed by multiple ike_auth:
+
+ +--------+ +--------+
+ | EAP | ID, SA, TS, N(EAP_ONLY) | EAP |
+ | client | ---------------------------> | server |
+ | | ID, [AUTH,] EAP | | AUTH payload is
+ | | <--------------------------- | | only included if
+ | | EAP | | authentication
+ | | ---------------------------> | | is not mutual.
+ | | EAP | |
+ | | <--------------------------- | |
+ | | EAP | |
+ | | ---------------------------> | |
+ | | EAP(SUCCESS) | |
+ | | <--------------------------- | |
+ | | AUTH | | If EAP establishes
+ | | ---------------------------> | | a session key, AUTH
+ | | AUTH, SA, TS | | payloads use this
+ | | <--------------------------- | | key, not SK_pi/pr
+ +--------+ +--------+
+
+ @endverbatim
+ * @b Constructors:
+ * - eap_authenticator_create()
+ * - authenticator_create() using auth_method AUTH_EAP
+ *
+ * @ingroup authenticators
+ */
+struct eap_authenticator_t {
+
+ /**
+ * Implemented authenticator_t interface.
+ */
+ authenticator_t authenticator_interface;
+
+ /**
+ * @brief Check if the EAP method was/is mutual and secure.
+ *
+ * RFC4306 proposes to authenticate the EAP responder (server) by standard
+ * IKEv2 methods (RSA, psk). Not all, but some EAP methods
+ * provide mutual authentication, which would result in a redundant
+ * authentication. If the client supports EAP_ONLY_AUTHENTICATION, and
+ * the the server provides mutual authentication, authentication using
+ * RSA/PSK may be omitted. If the server did not include a traditional
+ * AUTH payload, the client must verify that the server initiated mutual
+ * EAP authentication before it can trust the server.
+ *
+ * @param this calling object
+ * @return TRUE, if no AUTH payload required, FALSE otherwise
+ */
+ bool (*is_mutual) (eap_authenticator_t* this);
+
+ /**
+ * @brief Initiate the EAP exchange.
+ *
+ * The server initiates EAP exchanges, so the client never calls
+ * this method. If initiate() returns NEED_MORE, the EAP authentication
+ * process started. In any case, a payload is created in "out".
+ *
+ * @param this calling object
+ * @param type EAP method to use to authenticate client
+ * @param out created initiaal EAP message to send
+ * @return
+ * - FAILED, if initiation failed
+ * - NEED_MORE, if more EAP exchanges reqired
+ */
+ status_t (*initiate) (eap_authenticator_t* this, eap_type_t type,
+ eap_payload_t **out);
+
+ /**
+ * @brief Process an EAP message.
+ *
+ * After receiving an EAP message "in", the peer/server processes
+ * the payload and creates a reply/subsequent request.
+ * The server side always returns NEED_MORE if another EAP message
+ * is excepted from the client, SUCCESS if EAP exchange completed and
+ * "out" is EAP_SUCCES, or FAILED if the EAP exchange failed with
+ * a EAP_FAILURE payload in "out". Anyway, a payload in "out" is always
+ * created.
+ * The peer (client) side only creates a "out" payload if result is
+ * NEED_MORE, a SUCCESS/FAILED is returned whenever a
+ * EAP_SUCCESS/EAP_FAILURE message is received in "in".
+ * If a SUCCESS is returned (on any side), the EAP authentication was
+ * successful and the AUTH payload can be exchanged.
+ *
+ * @param this calling object
+ * @param in received EAP message
+ * @param out created EAP message to send
+ * @return
+ * - FAILED, if authentication/EAP exchange failed
+ * - SUCCESS, if authentication completed
+ * - NEED_MORE, if more EAP exchanges reqired
+ */
+ status_t (*process) (eap_authenticator_t* this,
+ eap_payload_t *in, eap_payload_t **out);
+};
+
+/**
+ * @brief Creates an authenticator for AUTH_EAP.
+ *
+ * @param ike_sa associated ike_sa
+ * @return eap_authenticator_t object
+ *
+ * @ingroup authenticators
+ */
+eap_authenticator_t *eap_authenticator_create(ike_sa_t *ike_sa);
+
+#endif /* EAP_AUTHENTICATOR_H_ */
diff --git a/src/charon/sa/authenticators/psk_authenticator.c b/src/charon/sa/authenticators/psk_authenticator.c
new file mode 100644
index 000000000..43aec0971
--- /dev/null
+++ b/src/charon/sa/authenticators/psk_authenticator.c
@@ -0,0 +1,204 @@
+/**
+ * @file psk_authenticator.c
+ *
+ * @brief Implementation of psk_authenticator_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 "psk_authenticator.h"
+
+#include <config/policies/policy.h>
+#include <daemon.h>
+
+/**
+ * Key pad for the AUTH method SHARED_KEY_MESSAGE_INTEGRITY_CODE.
+ */
+#define IKEV2_KEY_PAD "Key Pad for IKEv2"
+#define IKEV2_KEY_PAD_LENGTH 17
+
+
+typedef struct private_psk_authenticator_t private_psk_authenticator_t;
+
+/**
+ * Private data of an psk_authenticator_t object.
+ */
+struct private_psk_authenticator_t {
+
+ /**
+ * Public authenticator_t interface.
+ */
+ psk_authenticator_t public;
+
+ /**
+ * Assigned IKE_SA
+ */
+ ike_sa_t *ike_sa;
+};
+
+/**
+ * Builds the octets to be signed as described in section 2.15 of RFC 4306
+ */
+chunk_t build_tbs_octets(chunk_t ike_sa_init, chunk_t nonce,
+ identification_t *id, prf_t *prf)
+{
+ u_int8_t id_header_buf[] = {0x00, 0x00, 0x00, 0x00};
+ chunk_t id_header = chunk_from_buf(id_header_buf);
+ chunk_t id_with_header, id_prfd, id_encoding;
+
+ id_header_buf[0] = id->get_type(id);
+ id_encoding = id->get_encoding(id);
+
+ id_with_header = chunk_cat("cc", id_header, id_encoding);
+ prf->allocate_bytes(prf, id_with_header, &id_prfd);
+ chunk_free(&id_with_header);
+
+ return chunk_cat("ccm", ike_sa_init, nonce, id_prfd);
+}
+
+/**
+ * Creates the AUTH data using auth method SHARED_KEY_MESSAGE_INTEGRITY_CODE.
+ */
+chunk_t build_shared_key_signature(chunk_t ike_sa_init, chunk_t nonce,
+ chunk_t secret, identification_t *id,
+ prf_t *prf_skp, prf_t *prf)
+{
+ chunk_t key_pad, key, auth_data, octets;
+
+ octets = build_tbs_octets(ike_sa_init, nonce, id, prf_skp);
+ /* AUTH = prf(prf(Shared Secret,"Key Pad for IKEv2"), <msg octets>) */
+ key_pad.ptr = IKEV2_KEY_PAD;
+ key_pad.len = IKEV2_KEY_PAD_LENGTH;
+ prf->set_key(prf, secret);
+ prf->allocate_bytes(prf, key_pad, &key);
+ prf->set_key(prf, key);
+ prf->allocate_bytes(prf, octets, &auth_data);
+ DBG3(DBG_IKE, "octets = message + nonce + prf(Sk_px, IDx') %B", &octets);
+ DBG3(DBG_IKE, "secret %B", &secret);
+ DBG3(DBG_IKE, "keypad %B", &key_pad);
+ DBG3(DBG_IKE, "prf(secret, keypad) %B", &key);
+ DBG3(DBG_IKE, "AUTH = prf(prf(secret, keypad), octets) %B", &auth_data);
+ chunk_free(&octets);
+ chunk_free(&key);
+
+ return auth_data;
+}
+
+/**
+ * Implementation of authenticator_t.verify.
+ */
+static status_t verify(private_psk_authenticator_t *this, chunk_t ike_sa_init,
+ chunk_t my_nonce, auth_payload_t *auth_payload)
+{
+ status_t status;
+ chunk_t auth_data, recv_auth_data, shared_key;
+ identification_t *my_id, *other_id;
+
+ my_id = this->ike_sa->get_my_id(this->ike_sa);
+ other_id = this->ike_sa->get_other_id(this->ike_sa);
+ status = charon->credentials->get_shared_key(charon->credentials, my_id,
+ other_id, &shared_key);
+ if (status != SUCCESS)
+ {
+ DBG1(DBG_IKE, "no shared key found for '%D' - '%D'", my_id, other_id);
+ return status;
+ }
+
+ auth_data = build_shared_key_signature(ike_sa_init, my_nonce, shared_key,
+ other_id, this->ike_sa->get_auth_verify(this->ike_sa),
+ this->ike_sa->get_prf(this->ike_sa));
+ chunk_free(&shared_key);
+
+ recv_auth_data = auth_payload->get_data(auth_payload);
+ if (auth_data.len != recv_auth_data.len ||
+ !memeq(auth_data.ptr, recv_auth_data.ptr, auth_data.len))
+ {
+ DBG1(DBG_IKE, "PSK MAC verification failed");
+ chunk_free(&auth_data);
+ return FAILED;
+ }
+ chunk_free(&auth_data);
+
+ DBG1(DBG_IKE, "authentication of '%D' with %N successful",
+ other_id, auth_method_names, AUTH_PSK);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of authenticator_t.build.
+ */
+static status_t build(private_psk_authenticator_t *this, chunk_t ike_sa_init,
+ chunk_t other_nonce, auth_payload_t **auth_payload)
+{
+ chunk_t shared_key;
+ chunk_t auth_data;
+ status_t status;
+ identification_t *my_id, *other_id;
+
+ my_id = this->ike_sa->get_my_id(this->ike_sa);
+ other_id = this->ike_sa->get_other_id(this->ike_sa);
+ DBG1(DBG_IKE, "authentication of '%D' (myself) with %N",
+ my_id, auth_method_names, AUTH_PSK);
+ status = charon->credentials->get_shared_key(charon->credentials, my_id,
+ other_id, &shared_key);
+ if (status != SUCCESS)
+ {
+ DBG1(DBG_IKE, "no shared key found for '%D' - '%D'", my_id, other_id);
+ return status;
+ }
+
+ auth_data = build_shared_key_signature(ike_sa_init, other_nonce, shared_key,
+ my_id, this->ike_sa->get_auth_build(this->ike_sa),
+ this->ike_sa->get_prf(this->ike_sa));
+ DBG2(DBG_IKE, "successfully created shared key MAC");
+ chunk_free(&shared_key);
+ *auth_payload = auth_payload_create();
+ (*auth_payload)->set_auth_method(*auth_payload, AUTH_PSK);
+ (*auth_payload)->set_data(*auth_payload, auth_data);
+
+ chunk_free(&auth_data);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of authenticator_t.destroy.
+ */
+static void destroy(private_psk_authenticator_t *this)
+{
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+psk_authenticator_t *psk_authenticator_create(ike_sa_t *ike_sa)
+{
+ private_psk_authenticator_t *this = malloc_thing(private_psk_authenticator_t);
+
+ /* public functions */
+ this->public.authenticator_interface.verify = (status_t(*)(authenticator_t*,chunk_t,chunk_t,auth_payload_t*))verify;
+ this->public.authenticator_interface.build = (status_t(*)(authenticator_t*,chunk_t,chunk_t,auth_payload_t**))build;
+ this->public.authenticator_interface.destroy = (void(*)(authenticator_t*))destroy;
+
+ /* private data */
+ this->ike_sa = ike_sa;
+
+ return &this->public;
+}
diff --git a/src/charon/sa/authenticators/psk_authenticator.h b/src/charon/sa/authenticators/psk_authenticator.h
new file mode 100644
index 000000000..c1c5bcaac
--- /dev/null
+++ b/src/charon/sa/authenticators/psk_authenticator.h
@@ -0,0 +1,57 @@
+/**
+ * @file psk_authenticator.h
+ *
+ * @brief Interface of psk_authenticator_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 PSK_AUTHENTICATOR_H_
+#define PSK_AUTHENTICATOR_H_
+
+typedef struct psk_authenticator_t psk_authenticator_t;
+
+#include <sa/authenticators/authenticator.h>
+
+/**
+ * @brief Implementation of the authenticator_t interface using AUTH_PSK.
+ *
+ * @b Constructors:
+ * - psk_authenticator_create()
+ * - authenticator_create() using auth_method AUTH_PSK
+ *
+ * @ingroup authenticators
+ */
+struct psk_authenticator_t {
+
+ /**
+ * Implemented authenticator_t interface.
+ */
+ authenticator_t authenticator_interface;
+};
+
+/**
+ * @brief Creates an authenticator for AUTH_PSK.
+ *
+ * @param ike_sa associated ike_sa
+ * @return psk_authenticator_t object
+ *
+ * @ingroup authenticators
+ */
+psk_authenticator_t *psk_authenticator_create(ike_sa_t *ike_sa);
+
+#endif /* PSK_AUTHENTICATOR_H_ */
diff --git a/src/charon/sa/authenticators/rsa_authenticator.c b/src/charon/sa/authenticators/rsa_authenticator.c
new file mode 100644
index 000000000..dfa01e332
--- /dev/null
+++ b/src/charon/sa/authenticators/rsa_authenticator.c
@@ -0,0 +1,180 @@
+/**
+ * @file rsa_authenticator.c
+ *
+ * @brief Implementation of rsa_authenticator_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_authenticator.h"
+
+#include <config/policies/policy.h>
+#include <daemon.h>
+
+
+typedef struct private_rsa_authenticator_t private_rsa_authenticator_t;
+
+/**
+ * Private data of an rsa_authenticator_t object.
+ */
+struct private_rsa_authenticator_t {
+
+ /**
+ * Public authenticator_t interface.
+ */
+ rsa_authenticator_t public;
+
+ /**
+ * Assigned IKE_SA
+ */
+ ike_sa_t *ike_sa;
+};
+
+/**
+ * Function implemented in psk_authenticator.c
+ */
+extern chunk_t build_tbs_octets(chunk_t ike_sa_init, chunk_t nonce,
+ identification_t *id, prf_t *prf);
+
+/**
+ * Implementation of authenticator_t.verify.
+ */
+static status_t verify(private_rsa_authenticator_t *this, chunk_t ike_sa_init,
+ chunk_t my_nonce, auth_payload_t *auth_payload)
+{
+ status_t status;
+ chunk_t auth_data, octets;
+ rsa_public_key_t *public_key;
+ identification_t *other_id;
+
+ other_id = this->ike_sa->get_other_id(this->ike_sa);
+
+ if (auth_payload->get_auth_method(auth_payload) != AUTH_RSA)
+ {
+ return INVALID_ARG;
+ }
+ auth_data = auth_payload->get_data(auth_payload);
+ public_key = charon->credentials->get_trusted_public_key(charon->credentials,
+ other_id);
+ if (public_key == NULL)
+ {
+ DBG1(DBG_IKE, "no RSA public key found for '%D'", other_id);
+ return NOT_FOUND;
+ }
+ octets = build_tbs_octets(ike_sa_init, my_nonce, other_id,
+ this->ike_sa->get_auth_verify(this->ike_sa));
+ status = public_key->verify_emsa_pkcs1_signature(public_key, octets, auth_data);
+ chunk_free(&octets);
+
+ if (status != SUCCESS)
+ {
+ DBG1(DBG_IKE, "RSA signature verification failed");
+ return status;
+ }
+
+ DBG1(DBG_IKE, "authentication of '%D' with %N successful",
+ other_id, auth_method_names, AUTH_RSA);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of authenticator_t.build.
+ */
+static status_t build(private_rsa_authenticator_t *this, chunk_t ike_sa_init,
+ chunk_t other_nonce, auth_payload_t **auth_payload)
+{
+ chunk_t chunk;
+ chunk_t octets;
+ chunk_t auth_data;
+ status_t status;
+ rsa_public_key_t *my_pubkey;
+ rsa_private_key_t *my_key;
+ identification_t *my_id;
+
+ my_id = this->ike_sa->get_my_id(this->ike_sa);
+ DBG1(DBG_IKE, "authentication of '%D' (myself) with %N",
+ my_id, auth_method_names, AUTH_RSA);
+ DBG2(DBG_IKE, "looking for RSA public key belonging to '%D'", my_id);
+
+ my_pubkey = charon->credentials->get_rsa_public_key(charon->credentials, my_id);
+ if (my_pubkey == NULL)
+ {
+ DBG1(DBG_IKE, "no RSA public key found for '%D'", my_id);
+ return NOT_FOUND;
+ }
+ DBG2(DBG_IKE, "matching RSA public key found");
+ chunk = my_pubkey->get_keyid(my_pubkey);
+ DBG2(DBG_IKE, "looking for RSA private key with keyid %#B", &chunk);
+ my_key = charon->credentials->get_rsa_private_key(charon->credentials, my_pubkey);
+ if (my_key == NULL)
+ {
+ DBG1(DBG_IKE, "no RSA private key found with for %D with keyid %#B",
+ my_id, &chunk);
+ return NOT_FOUND;
+ }
+ DBG2(DBG_IKE, "matching RSA private key found");
+
+ octets = build_tbs_octets(ike_sa_init, other_nonce, my_id,
+ this->ike_sa->get_auth_build(this->ike_sa));
+ status = my_key->build_emsa_pkcs1_signature(my_key, HASH_SHA1, octets, &auth_data);
+ chunk_free(&octets);
+
+ if (status != SUCCESS)
+ {
+ my_key->destroy(my_key);
+ DBG1(DBG_IKE, "build signature of SHA1 hash failed");
+ return status;
+ }
+ DBG2(DBG_IKE, "successfully signed with RSA private key");
+
+ *auth_payload = auth_payload_create();
+ (*auth_payload)->set_auth_method(*auth_payload, AUTH_RSA);
+ (*auth_payload)->set_data(*auth_payload, auth_data);
+
+ my_key->destroy(my_key);
+ chunk_free(&auth_data);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of authenticator_t.destroy.
+ */
+static void destroy(private_rsa_authenticator_t *this)
+{
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+rsa_authenticator_t *rsa_authenticator_create(ike_sa_t *ike_sa)
+{
+ private_rsa_authenticator_t *this = malloc_thing(private_rsa_authenticator_t);
+
+ /* public functions */
+ this->public.authenticator_interface.verify = (status_t(*)(authenticator_t*,chunk_t,chunk_t,auth_payload_t*))verify;
+ this->public.authenticator_interface.build = (status_t(*)(authenticator_t*,chunk_t,chunk_t,auth_payload_t**))build;
+ this->public.authenticator_interface.destroy = (void(*)(authenticator_t*))destroy;
+
+ /* private data */
+ this->ike_sa = ike_sa;
+
+ return &this->public;
+}
diff --git a/src/charon/sa/authenticators/rsa_authenticator.h b/src/charon/sa/authenticators/rsa_authenticator.h
new file mode 100644
index 000000000..cc5cc0150
--- /dev/null
+++ b/src/charon/sa/authenticators/rsa_authenticator.h
@@ -0,0 +1,57 @@
+/**
+ * @file rsa_authenticator.h
+ *
+ * @brief Interface of rsa_authenticator_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 RSA_AUTHENTICATOR_H_
+#define RSA_AUTHENTICATOR_H_
+
+typedef struct rsa_authenticator_t rsa_authenticator_t;
+
+#include <sa/authenticators/authenticator.h>
+
+/**
+ * @brief Implementation of the authenticator_t interface using AUTH_RSA.
+ *
+ * @b Constructors:
+ * - rsa_authenticator_create()
+ * - authenticator_create() using auth_method AUTH_RSA
+ *
+ * @ingroup authenticators
+ */
+struct rsa_authenticator_t {
+
+ /**
+ * Implemented authenticator_t interface.
+ */
+ authenticator_t authenticator_interface;
+};
+
+/**
+ * @brief Creates an authenticator for AUTH_RSA.
+ *
+ * @param ike_sa associated ike_sa
+ * @return rsa_authenticator_t object
+ *
+ * @ingroup authenticators
+ */
+rsa_authenticator_t *rsa_authenticator_create(ike_sa_t *ike_sa);
+
+#endif /* RSA_AUTHENTICATOR_H_ */
diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c
new file mode 100644
index 000000000..19131389d
--- /dev/null
+++ b/src/charon/sa/child_sa.c
@@ -0,0 +1,1130 @@
+/**
+ * @file child_sa.c
+ *
+ * @brief Implementation of child_sa_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2007 Martin Willi
+ * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 "child_sa.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <printf.h>
+
+#include <daemon.h>
+
+ENUM(child_sa_state_names, CHILD_CREATED, CHILD_DELETING,
+ "CREATED",
+ "ROUTED",
+ "INSTALLED",
+ "REKEYING",
+ "DELETING",
+);
+
+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 {
+ /**
+ * Traffic selector for us
+ */
+ traffic_selector_t *my_ts;
+
+ /**
+ * Traffic selector for other
+ */
+ traffic_selector_t *other_ts;
+};
+
+typedef struct private_child_sa_t private_child_sa_t;
+
+/**
+ * Private data of a child_sa_t bject.
+ */
+struct private_child_sa_t {
+ /**
+ * Public interface of child_sa_t.
+ */
+ child_sa_t public;
+
+ struct {
+ /** address of peer */
+ host_t *addr;
+ /** id of peer */
+ identification_t *id;
+ /** actual used SPI, 0 if unused */
+ u_int32_t spi;
+ } me, other;
+
+ /**
+ * Allocated SPI for a ESP proposal candidates
+ */
+ u_int32_t alloc_esp_spi;
+
+ /**
+ * Allocated SPI for a AH proposal candidates
+ */
+ u_int32_t alloc_ah_spi;
+
+ /**
+ * Protocol used to protect this SA, ESP|AH
+ */
+ protocol_id_t protocol;
+
+ /**
+ * List containing sa_policy_t objects
+ */
+ linked_list_t *policies;
+
+ /**
+ * Seperate list for local traffic selectors
+ */
+ linked_list_t *my_ts;
+
+ /**
+ * Seperate list for remote traffic selectors
+ */
+ linked_list_t *other_ts;
+
+ /**
+ * reqid used for this child_sa
+ */
+ u_int32_t reqid;
+
+ /**
+ * encryption algorithm used for this SA
+ */
+ algorithm_t encryption;
+
+ /**
+ * integrity protection algorithm used for this SA
+ */
+ algorithm_t integrity;
+
+ /**
+ * time, on which SA was installed
+ */
+ time_t install_time;
+
+ /**
+ * absolute time when rekeying is sceduled
+ */
+ time_t rekey_time;
+
+ /**
+ * state of the CHILD_SA
+ */
+ child_sa_state_t state;
+
+ /**
+ * Specifies if NAT traversal is used
+ */
+ bool use_natt;
+
+ /**
+ * mode this SA uses, tunnel/transport
+ */
+ mode_t mode;
+
+ /**
+ * virtual IP assinged to local host
+ */
+ host_t *virtual_ip;
+
+ /**
+ * policy used to create this child
+ */
+ policy_t *policy;
+};
+
+/**
+ * Implementation of child_sa_t.get_name.
+ */
+static char *get_name(private_child_sa_t *this)
+{
+ return this->policy->get_name(this->policy);;
+}
+
+/**
+ * Implements child_sa_t.get_reqid
+ */
+static u_int32_t get_reqid(private_child_sa_t *this)
+{
+ return this->reqid;
+}
+
+/**
+ * Implements child_sa_t.get_spi
+ */
+u_int32_t get_spi(private_child_sa_t *this, bool inbound)
+{
+ if (inbound)
+ {
+ return this->me.spi;
+ }
+ return this->other.spi;
+}
+
+/**
+ * Implements child_sa_t.get_protocol
+ */
+protocol_id_t get_protocol(private_child_sa_t *this)
+{
+ return this->protocol;
+}
+
+/**
+ * Implements child_sa_t.get_state
+ */
+static child_sa_state_t get_state(private_child_sa_t *this)
+{
+ return this->state;
+}
+
+/**
+ * Implements child_sa_t.get_policy
+ */
+static policy_t* get_policy(private_child_sa_t *this)
+{
+ return this->policy;
+}
+
+/**
+ * Run the up/down script
+ */
+static void updown(private_child_sa_t *this, bool up)
+{
+ sa_policy_t *policy;
+ iterator_t *iterator;
+ char *script;
+
+ script = this->policy->get_updown(this->policy);
+
+ if (script == NULL)
+ {
+ return;
+ }
+
+ iterator = this->policies->create_iterator(this->policies, TRUE);
+ while (iterator->iterate(iterator, (void**)&policy))
+ {
+ char command[1024];
+ char *ifname = NULL;
+ char *my_client, *other_client, *my_client_mask, *other_client_mask;
+ char *pos, *virtual_ip;
+ FILE *shell;
+
+ /* get subnet/bits from string */
+ asprintf(&my_client, "%R", policy->my_ts);
+ pos = strchr(my_client, '/');
+ *pos = '\0';
+ my_client_mask = pos + 1;
+ pos = strchr(my_client_mask, '[');
+ if (pos)
+ {
+ *pos = '\0';
+ }
+ asprintf(&other_client, "%R", policy->other_ts);
+ pos = strchr(other_client, '/');
+ *pos = '\0';
+ other_client_mask = pos + 1;
+ pos = strchr(other_client_mask, '[');
+ if (pos)
+ {
+ *pos = '\0';
+ }
+
+ if (this->virtual_ip)
+ {
+ asprintf(&virtual_ip, "PLUTO_MY_SOURCEIP='%H' ",
+ this->virtual_ip);
+ }
+ else
+ {
+ asprintf(&virtual_ip, "");
+ }
+
+ ifname = charon->kernel_interface->get_interface(charon->kernel_interface,
+ this->me.addr);
+
+ /* build the command with all env variables.
+ * TODO: PLUTO_PEER_CA and PLUTO_NEXT_HOP are currently missing
+ */
+ snprintf(command, sizeof(command),
+ "2>&1 "
+ "PLUTO_VERSION='1.1' "
+ "PLUTO_VERB='%s%s%s' "
+ "PLUTO_CONNECTION='%s' "
+ "PLUTO_INTERFACE='%s' "
+ "PLUTO_REQID='%u' "
+ "PLUTO_ME='%H' "
+ "PLUTO_MY_ID='%D' "
+ "PLUTO_MY_CLIENT='%s/%s' "
+ "PLUTO_MY_CLIENT_NET='%s' "
+ "PLUTO_MY_CLIENT_MASK='%s' "
+ "PLUTO_MY_PORT='%u' "
+ "PLUTO_MY_PROTOCOL='%u' "
+ "PLUTO_PEER='%H' "
+ "PLUTO_PEER_ID='%D' "
+ "PLUTO_PEER_CLIENT='%s/%s' "
+ "PLUTO_PEER_CLIENT_NET='%s' "
+ "PLUTO_PEER_CLIENT_MASK='%s' "
+ "PLUTO_PEER_PORT='%u' "
+ "PLUTO_PEER_PROTOCOL='%u' "
+ "%s"
+ "%s"
+ "%s",
+ up ? "up" : "down",
+ policy->my_ts->is_host(policy->my_ts,
+ this->me.addr) ? "-host" : "-client",
+ this->me.addr->get_family(this->me.addr) == AF_INET ? "" : "-ipv6",
+ this->policy->get_name(this->policy),
+ ifname ? ifname : "(unknown)",
+ this->reqid,
+ this->me.addr,
+ this->me.id,
+ my_client, my_client_mask,
+ my_client, my_client_mask,
+ policy->my_ts->get_from_port(policy->my_ts),
+ policy->my_ts->get_protocol(policy->my_ts),
+ this->other.addr,
+ this->other.id,
+ other_client, other_client_mask,
+ other_client, other_client_mask,
+ policy->other_ts->get_from_port(policy->other_ts),
+ policy->other_ts->get_protocol(policy->other_ts),
+ virtual_ip,
+ this->policy->get_hostaccess(this->policy) ?
+ "PLUTO_HOST_ACCESS='1' " : "",
+ script);
+ free(ifname);
+ free(my_client);
+ free(other_client);
+ free(virtual_ip);
+
+ shell = popen(command, "r");
+
+ if (shell == NULL)
+ {
+ DBG1(DBG_CHD, "could not execute updown script '%s'", script);
+ return;
+ }
+
+ while (TRUE)
+ {
+ char resp[128];
+
+ if (fgets(resp, sizeof(resp), shell) == NULL)
+ {
+ if (ferror(shell))
+ {
+ DBG1(DBG_CHD, "error reading output from updown script");
+ return;
+ }
+ else
+ {
+ break;
+ }
+ }
+ else
+ {
+ char *e = resp + strlen(resp);
+ if (e > resp && e[-1] == '\n')
+ { /* trim trailing '\n' */
+ e[-1] = '\0';
+ }
+ DBG1(DBG_CHD, "updown: %s", resp);
+ }
+ }
+ pclose(shell);
+ }
+ iterator->destroy(iterator);
+}
+
+/**
+ * Implements child_sa_t.set_state
+ */
+static void set_state(private_child_sa_t *this, child_sa_state_t state)
+{
+ this->state = state;
+ if (state == CHILD_INSTALLED)
+ {
+ updown(this, TRUE);
+ }
+}
+
+/**
+ * Allocate SPI for a single proposal
+ */
+static status_t alloc_proposal(private_child_sa_t *this, proposal_t *proposal)
+{
+ protocol_id_t protocol = proposal->get_protocol(proposal);
+
+ if (protocol == PROTO_AH)
+ {
+ /* get a new spi for AH, if not already done */
+ if (this->alloc_ah_spi == 0)
+ {
+ if (charon->kernel_interface->get_spi(
+ charon->kernel_interface,
+ this->other.addr, this->me.addr,
+ PROTO_AH, this->reqid,
+ &this->alloc_ah_spi) != SUCCESS)
+ {
+ return FAILED;
+ }
+ }
+ proposal->set_spi(proposal, this->alloc_ah_spi);
+ }
+ if (protocol == PROTO_ESP)
+ {
+ /* get a new spi for ESP, if not already done */
+ if (this->alloc_esp_spi == 0)
+ {
+ if (charon->kernel_interface->get_spi(
+ charon->kernel_interface,
+ this->other.addr, this->me.addr,
+ PROTO_ESP, this->reqid,
+ &this->alloc_esp_spi) != SUCCESS)
+ {
+ return FAILED;
+ }
+ }
+ proposal->set_spi(proposal, this->alloc_esp_spi);
+ }
+ return SUCCESS;
+}
+
+
+/**
+ * Implements child_sa_t.alloc
+ */
+static status_t alloc(private_child_sa_t *this, linked_list_t *proposals)
+{
+ iterator_t *iterator;
+ proposal_t *proposal;
+
+ /* iterator through proposals to update spis */
+ iterator = proposals->create_iterator(proposals, TRUE);
+ while(iterator->iterate(iterator, (void**)&proposal))
+ {
+ if (alloc_proposal(this, proposal) != SUCCESS)
+ {
+ iterator->destroy(iterator);
+ return FAILED;
+ }
+ }
+ iterator->destroy(iterator);
+ return SUCCESS;
+}
+
+static status_t install(private_child_sa_t *this, proposal_t *proposal,
+ mode_t mode, prf_plus_t *prf_plus, bool mine)
+{
+ u_int32_t spi, soft, hard;;
+ algorithm_t *enc_algo, *int_algo;
+ algorithm_t enc_algo_none = {ENCR_UNDEFINED, 0};
+ algorithm_t int_algo_none = {AUTH_UNDEFINED, 0};
+ host_t *src;
+ host_t *dst;
+ natt_conf_t *natt;
+ status_t status;
+
+ this->protocol = proposal->get_protocol(proposal);
+
+ /* now we have to decide which spi to use. Use self allocated, if "mine",
+ * or the one in the proposal, if not "mine" (others). Additionally,
+ * source and dest host switch depending on the role */
+ if (mine)
+ {
+ /* if we have allocated SPIs for AH and ESP, we must delete the unused
+ * one. */
+ if (this->protocol == PROTO_ESP)
+ {
+ this->me.spi = this->alloc_esp_spi;
+ if (this->alloc_ah_spi)
+ {
+ charon->kernel_interface->del_sa(charon->kernel_interface, this->me.addr,
+ this->alloc_ah_spi, PROTO_AH);
+ }
+ }
+ else
+ {
+ this->me.spi = this->alloc_ah_spi;
+ if (this->alloc_esp_spi)
+ {
+ charon->kernel_interface->del_sa(charon->kernel_interface, this->me.addr,
+ this->alloc_esp_spi, PROTO_ESP);
+ }
+ }
+ spi = this->me.spi;
+ dst = this->me.addr;
+ src = this->other.addr;
+ }
+ else
+ {
+ this->other.spi = proposal->get_spi(proposal);
+ spi = this->other.spi;
+ src = this->me.addr;
+ dst = this->other.addr;
+ }
+
+ DBG2(DBG_CHD, "adding %s %N SA", mine ? "inbound" : "outbound",
+ protocol_id_names, this->protocol);
+
+ /* select encryption algo */
+ if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &enc_algo))
+ {
+ DBG2(DBG_CHD, " using %N for encryption",
+ encryption_algorithm_names, enc_algo->algorithm);
+ }
+ else
+ {
+ enc_algo = &enc_algo_none;
+ }
+
+ /* select integrity algo */
+ if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &int_algo))
+ {
+ DBG2(DBG_CHD, " using %N for integrity",
+ integrity_algorithm_names, int_algo->algorithm);
+ }
+ else
+ {
+ int_algo = &int_algo_none;
+ }
+
+ /* setup nat-t */
+ if (this->use_natt)
+ {
+ natt = alloca(sizeof(natt_conf_t));
+ natt->sport = src->get_port(src);
+ natt->dport = dst->get_port(dst);
+ }
+ else
+ {
+ natt = NULL;
+ }
+
+ soft = this->policy->get_soft_lifetime(this->policy);
+ hard = this->policy->get_hard_lifetime(this->policy);
+
+ /* send SA down to the kernel */
+ DBG2(DBG_CHD, " SPI 0x%.8x, src %H dst %H", ntohl(spi), src, dst);
+ status = charon->kernel_interface->add_sa(charon->kernel_interface,
+ src, dst, spi, this->protocol,
+ this->reqid, mine ? soft : 0,
+ hard, enc_algo, int_algo,
+ prf_plus, natt, mode, mine);
+
+ this->encryption = *enc_algo;
+ this->integrity = *int_algo;
+ this->install_time = time(NULL);
+ this->rekey_time = soft;
+
+ return status;
+}
+
+static status_t add(private_child_sa_t *this, proposal_t *proposal,
+ mode_t mode, prf_plus_t *prf_plus)
+{
+ u_int32_t outbound_spi, inbound_spi;
+
+ /* backup outbound spi, as alloc overwrites it */
+ outbound_spi = proposal->get_spi(proposal);
+
+ /* get SPIs inbound SAs */
+ if (alloc_proposal(this, proposal) != SUCCESS)
+ {
+ return FAILED;
+ }
+ inbound_spi = proposal->get_spi(proposal);
+
+ /* install inbound SAs */
+ if (install(this, proposal, mode, prf_plus, TRUE) != SUCCESS)
+ {
+ return FAILED;
+ }
+
+ /* install outbound SAs, restore spi*/
+ proposal->set_spi(proposal, outbound_spi);
+ if (install(this, proposal, mode, prf_plus, FALSE) != SUCCESS)
+ {
+ return FAILED;
+ }
+ proposal->set_spi(proposal, inbound_spi);
+
+ return SUCCESS;
+}
+
+static status_t update(private_child_sa_t *this, proposal_t *proposal,
+ mode_t mode, prf_plus_t *prf_plus)
+{
+ u_int32_t inbound_spi;
+
+ /* backup received spi, as install() overwrites it */
+ inbound_spi = proposal->get_spi(proposal);
+
+ /* install outbound SAs */
+ if (install(this, proposal, mode, prf_plus, FALSE) != SUCCESS)
+ {
+ return FAILED;
+ }
+
+ /* restore spi */
+ proposal->set_spi(proposal, inbound_spi);
+ /* install inbound SAs */
+ if (install(this, proposal, mode, prf_plus, TRUE) != 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, mode_t mode)
+{
+ iterator_t *my_iter, *other_iter;
+ traffic_selector_t *my_ts, *other_ts;
+ /* use low prio for ROUTED policies */
+ bool high_prio = (this->state != CHILD_CREATED);
+
+ /* 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->iterate(my_iter, (void**)&my_ts))
+ {
+ other_iter->reset(other_iter);
+ while (other_iter->iterate(other_iter, (void**)&other_ts))
+ {
+ /* set up policies for every entry in my_ts_list to every entry in other_ts_list */
+ status_t status;
+ sa_policy_t *policy;
+
+ if (my_ts->get_type(my_ts) != other_ts->get_type(other_ts))
+ {
+ DBG2(DBG_CHD,
+ "CHILD_SA policy uses two different IP families, ignored");
+ continue;
+ }
+
+ /* only set up policies if protocol matches, or if one is zero (any) */
+ if (my_ts->get_protocol(my_ts) != other_ts->get_protocol(other_ts) &&
+ my_ts->get_protocol(my_ts) && other_ts->get_protocol(other_ts))
+ {
+ DBG2(DBG_CHD,
+ "CHILD_SA policy uses two different protocols, ignored");
+ continue;
+ }
+
+ /* install 3 policies: out, in and forward */
+ status = charon->kernel_interface->add_policy(charon->kernel_interface,
+ this->me.addr, this->other.addr, my_ts, other_ts, POLICY_OUT,
+ this->protocol, this->reqid, high_prio, mode, FALSE);
+
+ status |= charon->kernel_interface->add_policy(charon->kernel_interface,
+ this->other.addr, this->me.addr, other_ts, my_ts, POLICY_IN,
+ this->protocol, this->reqid, high_prio, mode, FALSE);
+
+ status |= charon->kernel_interface->add_policy(charon->kernel_interface,
+ this->other.addr, this->me.addr, other_ts, my_ts, POLICY_FWD,
+ this->protocol, this->reqid, high_prio, mode, FALSE);
+
+ if (status != SUCCESS)
+ {
+ my_iter->destroy(my_iter);
+ other_iter->destroy(other_iter);
+ return status;
+ }
+
+ /* store policy to delete/update them later */
+ policy = malloc_thing(sa_policy_t);
+ policy->my_ts = my_ts->clone(my_ts);
+ policy->other_ts = other_ts->clone(other_ts);
+ this->policies->insert_last(this->policies, (void*)policy);
+ /* add to separate list to query them via get_*_traffic_selectors() */
+ this->my_ts->insert_last(this->my_ts, (void*)policy->my_ts);
+ this->other_ts->insert_last(this->other_ts, (void*)policy->other_ts);
+ }
+ }
+ my_iter->destroy(my_iter);
+ other_iter->destroy(other_iter);
+
+ /* switch to routed state if no SAD entry set up */
+ if (this->state == CHILD_CREATED)
+ {
+ this->state = CHILD_ROUTED;
+ }
+ /* needed to update hosts */
+ this->mode = mode;
+ return SUCCESS;
+}
+
+/**
+ * Implementation of child_sa_t.get_my_traffic_selectors.
+ */
+static linked_list_t *get_my_traffic_selectors(private_child_sa_t *this)
+{
+ return this->my_ts;
+}
+
+/**
+ * Implementation of child_sa_t.get_my_traffic_selectors.
+ */
+static linked_list_t *get_other_traffic_selectors(private_child_sa_t *this)
+{
+ return this->other_ts;
+}
+
+/**
+ * Implementation of child_sa_t.get_use_time
+ */
+static status_t get_use_time(private_child_sa_t *this, bool inbound, time_t *use_time)
+{
+ iterator_t *iterator;
+ sa_policy_t *policy;
+ status_t status = FAILED;
+
+ *use_time = UNDEFINED_TIME;
+
+ iterator = this->policies->create_iterator(this->policies, TRUE);
+ while (iterator->iterate(iterator, (void**)&policy))
+ {
+ if (inbound)
+ {
+ time_t in = UNDEFINED_TIME, fwd = UNDEFINED_TIME;
+
+ status = charon->kernel_interface->query_policy(
+ charon->kernel_interface,
+ policy->other_ts, policy->my_ts,
+ POLICY_IN, (u_int32_t*)&in);
+ status |= charon->kernel_interface->query_policy(
+ charon->kernel_interface,
+ policy->other_ts, policy->my_ts,
+ POLICY_FWD, (u_int32_t*)&fwd);
+ *use_time = max(in, fwd);
+ }
+ else
+ {
+ status = charon->kernel_interface->query_policy(
+ charon->kernel_interface,
+ policy->my_ts, policy->other_ts,
+ POLICY_OUT, (u_int32_t*)use_time);
+ }
+ }
+ iterator->destroy(iterator);
+ return status;
+}
+
+/**
+ * output handler in printf()
+ */
+static int print(FILE *stream, const struct printf_info *info,
+ const void *const *args)
+{
+ private_child_sa_t *this = *((private_child_sa_t**)(args[0]));
+ iterator_t *iterator;
+ sa_policy_t *policy;
+ u_int32_t now, rekeying;
+ u_int32_t use, use_in, use_fwd;
+ status_t status;
+ size_t written = 0;
+
+ if (this == NULL)
+ {
+ return fprintf(stream, "(null)");
+ }
+
+ now = time(NULL);
+
+ written += fprintf(stream, "%12s{%d}: %N, %N",
+ this->policy->get_name(this->policy), this->reqid,
+ child_sa_state_names, this->state,
+ mode_names, this->mode);
+
+ if (this->state == CHILD_INSTALLED)
+ {
+ written += fprintf(stream, ", %N SPIs: 0x%0x_i 0x%0x_o",
+ protocol_id_names, this->protocol,
+ htonl(this->me.spi), htonl(this->other.spi));
+
+ if (info->alt)
+ {
+ written += fprintf(stream, "\n%12s{%d}: ",
+ this->policy->get_name(this->policy),
+ this->reqid);
+
+ if (this->protocol == PROTO_ESP)
+ {
+ written += fprintf(stream, "%N", encryption_algorithm_names,
+ this->encryption.algorithm);
+
+ if (this->encryption.key_size)
+ {
+ written += fprintf(stream, "-%d", this->encryption.key_size);
+ }
+ written += fprintf(stream, "/");
+ }
+
+ written += fprintf(stream, "%N", integrity_algorithm_names,
+ this->integrity.algorithm);
+ if (this->integrity.key_size)
+ {
+ written += fprintf(stream, "-%d", this->integrity.key_size);
+ }
+ written += fprintf(stream, ", rekeying ");
+
+ /* calculate rekey times */
+ if (this->rekey_time)
+ {
+ rekeying = this->install_time + this->rekey_time - now;
+ written += fprintf(stream, "in %ds", rekeying);
+ }
+ else
+ {
+ written += fprintf(stream, "disabled");
+ }
+ }
+ }
+ iterator = this->policies->create_iterator(this->policies, TRUE);
+ while (iterator->iterate(iterator, (void**)&policy))
+ {
+ written += fprintf(stream, "\n%12s{%d}: %R===%R, last use: ",
+ this->policy->get_name(this->policy), this->reqid,
+ policy->my_ts, policy->other_ts);
+
+ /* query time of last policy use */
+
+ /* inbound: POLICY_IN or POLICY_FWD */
+ status = charon->kernel_interface->query_policy(charon->kernel_interface,
+ policy->other_ts, policy->my_ts, POLICY_IN, &use_in);
+ use_in = (status == SUCCESS)? use_in : 0;
+ status = charon->kernel_interface->query_policy(charon->kernel_interface,
+ policy->other_ts, policy->my_ts, POLICY_FWD, &use_fwd);
+ use_fwd = (status == SUCCESS)? use_fwd : 0;
+ use = max(use_in, use_fwd);
+ if (use)
+ {
+ written += fprintf(stream, "%ds_i ", now - use);
+ }
+ else
+ {
+ written += fprintf(stream, "no_i ");
+ }
+
+ /* outbound: POLICY_OUT */
+ status = charon->kernel_interface->query_policy(charon->kernel_interface,
+ policy->my_ts, policy->other_ts, POLICY_OUT, &use);
+ if (status == SUCCESS && use)
+ {
+ written += fprintf(stream, "%ds_o ", now - use);
+ }
+ else
+ {
+ written += fprintf(stream, "no_o ");
+ }
+ }
+ iterator->destroy(iterator);
+ return written;
+}
+
+/**
+ * register printf() handlers
+ */
+static void __attribute__ ((constructor))print_register()
+{
+ register_printf_function(PRINTF_CHILD_SA, print, arginfo_ptr);
+}
+
+/**
+ * Update the host adress/port of a SA
+ */
+static status_t update_sa_hosts(private_child_sa_t *this, host_t *new_me, host_t *new_other,
+ int my_changes, int other_changes, bool mine)
+{
+ host_t *src, *dst, *new_src, *new_dst;
+ int src_changes, dst_changes;
+ status_t status;
+ u_int32_t spi;
+
+ if (mine)
+ {
+ src = this->other.addr;
+ dst = this->me.addr;
+ new_src = new_other;
+ new_dst = new_me;
+ src_changes = other_changes;
+ dst_changes = my_changes;
+ spi = this->other.spi;
+ }
+ else
+ {
+ src = this->me.addr;
+ dst = this->other.addr;
+ new_src = new_me;
+ new_dst = new_other;
+ src_changes = my_changes;
+ dst_changes = other_changes;
+ spi = this->me.spi;
+ }
+
+ DBG2(DBG_CHD, "updating %N SA 0x%x, from %#H..#H to %#H..%#H",
+ protocol_id_names, this->protocol, ntohl(spi), src, dst, new_src, new_dst);
+
+ status = charon->kernel_interface->update_sa(charon->kernel_interface,
+ dst, spi, this->protocol,
+ new_src, new_dst,
+ src_changes, dst_changes);
+
+ if (status != SUCCESS)
+ {
+ return FAILED;
+ }
+ return SUCCESS;
+}
+
+/**
+ * Update the host adress/port of a policy
+ */
+static status_t update_policy_hosts(private_child_sa_t *this, host_t *new_me, host_t *new_other)
+{
+ iterator_t *iterator;
+ sa_policy_t *policy;
+ status_t status;
+ /* we always use high priorities, as hosts getting updated are INSTALLED */
+
+ iterator = this->policies->create_iterator(this->policies, TRUE);
+ while (iterator->iterate(iterator, (void**)&policy))
+ {
+ status = charon->kernel_interface->add_policy(
+ charon->kernel_interface,
+ new_me, new_other,
+ policy->my_ts, policy->other_ts,
+ POLICY_OUT, this->protocol, this->reqid, TRUE, this->mode, TRUE);
+
+ status |= charon->kernel_interface->add_policy(
+ charon->kernel_interface,
+ new_other, new_me,
+ policy->other_ts, policy->my_ts,
+ POLICY_IN, this->protocol, this->reqid, TRUE, this->mode, TRUE);
+
+ status |= charon->kernel_interface->add_policy(
+ charon->kernel_interface,
+ new_other, new_me,
+ policy->other_ts, policy->my_ts,
+ POLICY_FWD, this->protocol, this->reqid, TRUE, this->mode, TRUE);
+
+ if (status != SUCCESS)
+ {
+ iterator->destroy(iterator);
+ return FAILED;
+ }
+ }
+ iterator->destroy(iterator);
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of child_sa_t.update_hosts.
+ */
+static status_t update_hosts(private_child_sa_t *this, host_t *new_me, host_t *new_other,
+ host_diff_t my_changes, host_diff_t other_changes)
+{
+ if (!my_changes && !other_changes)
+ {
+ return SUCCESS;
+ }
+
+ /* update our (initator) SAs */
+ if (update_sa_hosts(this, new_me, new_other, my_changes, other_changes, TRUE) != SUCCESS)
+ {
+ return FAILED;
+ }
+
+ /* update his (responder) SAs */
+ if (update_sa_hosts(this, new_me, new_other, my_changes, other_changes, FALSE) != SUCCESS)
+ {
+ return FAILED;
+ }
+
+ /* update policies */
+ if (my_changes & HOST_DIFF_ADDR || other_changes & HOST_DIFF_ADDR)
+ {
+ if (update_policy_hosts(this, new_me, new_other) != SUCCESS)
+ {
+ return FAILED;
+ }
+ }
+
+ /* update hosts */
+ if (my_changes)
+ {
+ this->me.addr->destroy(this->me.addr);
+ this->me.addr = new_me->clone(new_me);
+ }
+
+ if (other_changes)
+ {
+ this->other.addr->destroy(this->other.addr);
+ this->other.addr = new_other->clone(new_other);
+ }
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of child_sa_t.set_virtual_ip.
+ */
+static void set_virtual_ip(private_child_sa_t *this, host_t *ip)
+{
+ this->virtual_ip = ip->clone(ip);
+}
+
+/**
+ * Implementation of child_sa_t.destroy.
+ */
+static void destroy(private_child_sa_t *this)
+{
+ sa_policy_t *policy;
+
+ if (this->state == CHILD_DELETING || this->state == CHILD_INSTALLED)
+ {
+ updown(this, FALSE);
+ }
+
+ /* delete SAs in the kernel, if they are set up */
+ if (this->me.spi)
+ {
+ charon->kernel_interface->del_sa(charon->kernel_interface,
+ this->me.addr, this->me.spi, this->protocol);
+ }
+ if (this->alloc_esp_spi && this->alloc_esp_spi != this->me.spi)
+ {
+ charon->kernel_interface->del_sa(charon->kernel_interface,
+ this->me.addr, this->alloc_esp_spi, PROTO_ESP);
+ }
+ if (this->alloc_ah_spi && this->alloc_ah_spi != this->me.spi)
+ {
+ charon->kernel_interface->del_sa(charon->kernel_interface,
+ this->me.addr, this->alloc_ah_spi, PROTO_AH);
+ }
+ if (this->other.spi)
+ {
+ charon->kernel_interface->del_sa(charon->kernel_interface,
+ this->other.addr, this->other.spi, this->protocol);
+ }
+
+ /* delete all policies in the kernel */
+ while (this->policies->remove_last(this->policies, (void**)&policy) == SUCCESS)
+ {
+ /* let rekeyed policies, as they are used by another child_sa */
+ charon->kernel_interface->del_policy(charon->kernel_interface,
+ policy->my_ts, policy->other_ts,
+ POLICY_OUT);
+
+ charon->kernel_interface->del_policy(charon->kernel_interface,
+ policy->other_ts, policy->my_ts,
+ POLICY_IN);
+
+ charon->kernel_interface->del_policy(charon->kernel_interface,
+ policy->other_ts, policy->my_ts,
+ POLICY_FWD);
+ policy->my_ts->destroy(policy->my_ts);
+ policy->other_ts->destroy(policy->other_ts);
+ free(policy);
+ }
+ this->policies->destroy(this->policies);
+
+ this->my_ts->destroy(this->my_ts);
+ this->other_ts->destroy(this->other_ts);
+ this->me.addr->destroy(this->me.addr);
+ this->other.addr->destroy(this->other.addr);
+ this->me.id->destroy(this->me.id);
+ this->other.id->destroy(this->other.id);
+ this->policy->destroy(this->policy);
+ DESTROY_IF(this->virtual_ip);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+child_sa_t * child_sa_create(host_t *me, host_t* other,
+ identification_t *my_id, identification_t *other_id,
+ policy_t *policy, u_int32_t rekey, bool use_natt)
+{
+ static u_int32_t reqid = 0;
+ private_child_sa_t *this = malloc_thing(private_child_sa_t);
+
+ /* public functions */
+ this->public.get_name = (char*(*)(child_sa_t*))get_name;
+ this->public.get_reqid = (u_int32_t(*)(child_sa_t*))get_reqid;
+ this->public.get_spi = (u_int32_t(*)(child_sa_t*, bool))get_spi;
+ this->public.get_protocol = (protocol_id_t(*)(child_sa_t*))get_protocol;
+ this->public.alloc = (status_t(*)(child_sa_t*,linked_list_t*))alloc;
+ this->public.add = (status_t(*)(child_sa_t*,proposal_t*,mode_t,prf_plus_t*))add;
+ this->public.update = (status_t(*)(child_sa_t*,proposal_t*,mode_t,prf_plus_t*))update;
+ this->public.update_hosts = (status_t (*)(child_sa_t*,host_t*,host_t*,host_diff_t,host_diff_t))update_hosts;
+ this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*,mode_t))add_policies;
+ this->public.get_my_traffic_selectors = (linked_list_t*(*)(child_sa_t*))get_my_traffic_selectors;
+ this->public.get_other_traffic_selectors = (linked_list_t*(*)(child_sa_t*))get_other_traffic_selectors;
+ this->public.get_use_time = (status_t (*)(child_sa_t*,bool,time_t*))get_use_time;
+ this->public.set_state = (void(*)(child_sa_t*,child_sa_state_t))set_state;
+ this->public.get_state = (child_sa_state_t(*)(child_sa_t*))get_state;
+ this->public.get_policy = (policy_t*(*)(child_sa_t*))get_policy;
+ this->public.set_virtual_ip = (void(*)(child_sa_t*,host_t*))set_virtual_ip;
+ this->public.destroy = (void(*)(child_sa_t*))destroy;
+
+ /* private data */
+ this->me.addr = me->clone(me);
+ this->other.addr = other->clone(other);
+ this->me.id = my_id->clone(my_id);
+ this->other.id = other_id->clone(other_id);
+ this->me.spi = 0;
+ this->other.spi = 0;
+ this->alloc_ah_spi = 0;
+ this->alloc_esp_spi = 0;
+ this->use_natt = use_natt;
+ this->state = CHILD_CREATED;
+ /* reuse old reqid if we are rekeying an existing CHILD_SA */
+ this->reqid = rekey ? rekey : ++reqid;
+ this->encryption.algorithm = ENCR_UNDEFINED;
+ this->encryption.key_size = 0;
+ this->integrity.algorithm = AUTH_UNDEFINED;
+ this->encryption.key_size = 0;
+ this->policies = linked_list_create();
+ this->my_ts = linked_list_create();
+ this->other_ts = linked_list_create();
+ this->protocol = PROTO_NONE;
+ this->mode = MODE_TUNNEL;
+ this->virtual_ip = NULL;
+ this->policy = policy;
+ policy->get_ref(policy);
+
+ return &this->public;
+}
diff --git a/src/charon/sa/child_sa.h b/src/charon/sa/child_sa.h
new file mode 100644
index 000000000..216e56659
--- /dev/null
+++ b/src/charon/sa/child_sa.h
@@ -0,0 +1,298 @@
+/**
+ * @file child_sa.h
+ *
+ * @brief Interface of child_sa_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2006-2007 Martin Willi
+ * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef enum child_sa_state_t child_sa_state_t;
+typedef struct child_sa_t child_sa_t;
+
+#include <library.h>
+#include <crypto/prf_plus.h>
+#include <encoding/payloads/proposal_substructure.h>
+#include <config/proposal.h>
+#include <config/policies/policy.h>
+
+/**
+ * Where we should start with reqid enumeration
+ */
+#define REQID_START 2000000000
+
+/**
+ * @brief States of a CHILD_SA
+ */
+enum child_sa_state_t {
+
+ /**
+ * Just created, uninstalled CHILD_SA
+ */
+ CHILD_CREATED,
+
+ /**
+ * Installed SPD, but no SAD entries
+ */
+ CHILD_ROUTED,
+
+ /**
+ * Installed an in-use CHILD_SA
+ */
+ CHILD_INSTALLED,
+
+ /**
+ * CHILD_SA which is rekeying
+ */
+ CHILD_REKEYING,
+
+ /**
+ * CHILD_SA in progress of delete
+ */
+ CHILD_DELETING,
+};
+
+/**
+ * enum strings for child_sa_state_t.
+ */
+extern enum_name_t *child_sa_state_names;
+
+/**
+ * @brief Represents an IPsec SAs between two hosts.
+ *
+ * A child_sa_t contains two SAs. SAs for both
+ * directions are managed in one child_sa_t object. Both
+ * SAs and the policies have the same reqid.
+ *
+ * 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 Get the name of the policy this CHILD_SA uses.
+ *
+ * @param this calling object
+ * @return name
+ */
+ char* (*get_name) (child_sa_t *this);
+
+ /**
+ * @brief Get the reqid of the CHILD SA.
+ *
+ * Every CHILD_SA has a reqid. The kernel uses this ID to
+ * identify it.
+ *
+ * @param this calling object
+ * @return reqid of the CHILD SA
+ */
+ u_int32_t (*get_reqid)(child_sa_t *this);
+
+ /**
+ * @brief Get the SPI of this CHILD_SA.
+ *
+ * Set the boolean parameter inbound to TRUE to
+ * get the SPI for which we receive packets, use
+ * FALSE to get those we use for sending packets.
+ *
+ * @param this calling object
+ * @param inbound TRUE to get inbound SPI, FALSE for outbound.
+ * @return spi of the CHILD SA
+ */
+ u_int32_t (*get_spi) (child_sa_t *this, bool inbound);
+
+ /**
+ * @brief Get the protocol which this CHILD_SA uses to protect traffic.
+ *
+ * @param this calling object
+ * @return AH | ESP
+ */
+ protocol_id_t (*get_protocol) (child_sa_t *this);
+
+ /**
+ * @brief Allocate SPIs for given proposals.
+ *
+ * Since the kernel manages SPIs for us, we need
+ * to allocate them. If a 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 proposals list of proposals for which SPIs are allocated
+ */
+ status_t (*alloc)(child_sa_t *this, linked_list_t* proposals);
+
+ /**
+ * @brief Install the kernel SAs for a proposal, without previous SPI allocation.
+ *
+ * @param this calling object
+ * @param proposal proposal for which SPIs are allocated
+ * @param mode mode for the CHILD_SA
+ * @param prf_plus key material to use for key derivation
+ * @return SUCCESS or FAILED
+ */
+ status_t (*add)(child_sa_t *this, proposal_t *proposal, mode_t mode,
+ prf_plus_t *prf_plus);
+
+ /**
+ * @brief Install the kernel SAs for a proposal, after SPIs have been allocated.
+ *
+ * Updates an SA, for which SPIs are already allocated via alloc().
+ *
+ * @param this calling object
+ * @param proposal proposal for which SPIs are allocated
+ * @param mode mode for the CHILD_SA
+ * @param prf_plus key material to use for key derivation
+ * @return SUCCESS or FAILED
+ */
+ status_t (*update)(child_sa_t *this, proposal_t *proposal, mode_t mode,
+ prf_plus_t *prf_plus);
+
+ /**
+ * @brief Update the hosts in the kernel SAs and policies
+ *
+ * @warning only call this after update() has been called.
+ *
+ * @param this calling object
+ * @param new_me the new local host
+ * @param new_other the new remote host
+ * @param my_diff differences to apply for me
+ * @param other_diff differences to apply for other
+ * @return SUCCESS or FAILED
+ */
+ status_t (*update_hosts)(child_sa_t *this, host_t *new_me, host_t *new_other,
+ host_diff_t my_diff, host_diff_t other_diff);
+
+ /**
+ * @brief Install the policies using some traffic selectors.
+ *
+ * Supplied lists of traffic_selector_t's specify the policies
+ * to use for this child sa.
+ *
+ * @param this calling object
+ * @param my_ts traffic selectors for local site
+ * @param other_ts traffic selectors for remote site
+ * @param mode mode for the SA: tunnel/transport
+ * @return SUCCESS or FAILED
+ */
+ status_t (*add_policies)(child_sa_t *this, linked_list_t *my_ts_list,
+ linked_list_t *other_ts_list, mode_t mode);
+
+ /**
+ * @brief Get the traffic selectors of added policies of local host.
+ *
+ * @param this calling object
+ * @return list of traffic selectors
+ */
+ linked_list_t* (*get_my_traffic_selectors) (child_sa_t *this);
+
+ /**
+ * @brief Get the traffic selectors of added policies of remote host.
+ *
+ * @param this calling object
+ * @return list of traffic selectors
+ */
+ linked_list_t* (*get_other_traffic_selectors) (child_sa_t *this);
+
+ /**
+ * @brief Get the time of this child_sa_t's last use (i.e. last use of any of its policies)
+ *
+ * @param this calling object
+ * @param inbound query for in- or outbound usage
+ * @param use_time the time
+ * @return SUCCESS or FAILED
+ */
+ status_t (*get_use_time) (child_sa_t *this, bool inbound, time_t *use_time);
+
+ /**
+ * @brief Get the state of the CHILD_SA.
+ *
+ * @param this calling object
+ */
+ child_sa_state_t (*get_state) (child_sa_t *this);
+
+ /**
+ * @brief Set the state of the CHILD_SA.
+ *
+ * @param this calling object
+ */
+ void (*set_state) (child_sa_t *this, child_sa_state_t state);
+
+ /**
+ * @brief Get the policy used to set up this child sa.
+ *
+ * @param this calling object
+ * @return policy
+ */
+ policy_t* (*get_policy) (child_sa_t *this);
+
+ /**
+ * @brief Set the virtual IP used received from IRAS.
+ *
+ * To allow proper setup of firewall rules, the virtual IP is required
+ * for filtering.
+ *
+ * @param this calling object
+ * @param ip own virtual IP
+ */
+ void (*set_virtual_ip) (child_sa_t *this, host_t *ip);
+
+ /**
+ * @brief Destroys a child_sa.
+ *
+ * @param this calling object
+ */
+ void (*destroy) (child_sa_t *this);
+};
+
+/**
+ * @brief Constructor to create a new child_sa_t.
+ *
+ * @param me own address
+ * @param other remote address
+ * @param my_id id of own peer
+ * @param other_id id of remote peer
+ * @param policy policy this CHILD_SA instantiates
+ * @param reqid reqid of old CHILD_SA when rekeying, 0 otherwise
+ * @param use_natt TRUE if NAT traversal is used
+ * @return child_sa_t object
+ *
+ * @ingroup sa
+ */
+child_sa_t * child_sa_create(host_t *me, host_t *other,
+ identification_t *my_id, identification_t* other_id,
+ policy_t *policy, u_int32_t reqid, bool use_natt);
+
+#endif /*CHILD_SA_H_*/
diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c
new file mode 100644
index 000000000..68aba3064
--- /dev/null
+++ b/src/charon/sa/ike_sa.c
@@ -0,0 +1,2032 @@
+/**
+ * @file ike_sa.c
+ *
+ * @brief Implementation of ike_sa_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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/time.h>
+#include <string.h>
+#include <printf.h>
+#include <sys/stat.h>
+
+#include "ike_sa.h"
+
+#include <library.h>
+#include <daemon.h>
+#include <utils/linked_list.h>
+#include <utils/lexparser.h>
+#include <crypto/diffie_hellman.h>
+#include <crypto/prf_plus.h>
+#include <crypto/crypters/crypter.h>
+#include <crypto/hashers/hasher.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 <encoding/payloads/ts_payload.h>
+#include <sa/task_manager.h>
+#include <sa/tasks/ike_init.h>
+#include <sa/tasks/ike_natd.h>
+#include <sa/tasks/ike_auth.h>
+#include <sa/tasks/ike_config.h>
+#include <sa/tasks/ike_cert.h>
+#include <sa/tasks/ike_rekey.h>
+#include <sa/tasks/ike_delete.h>
+#include <sa/tasks/ike_dpd.h>
+#include <sa/tasks/child_create.h>
+#include <sa/tasks/child_delete.h>
+#include <sa/tasks/child_rekey.h>
+#include <queues/jobs/retransmit_job.h>
+#include <queues/jobs/delete_ike_sa_job.h>
+#include <queues/jobs/send_dpd_job.h>
+#include <queues/jobs/send_keepalive_job.h>
+#include <queues/jobs/rekey_ike_sa_job.h>
+#include <queues/jobs/route_job.h>
+#include <queues/jobs/initiate_job.h>
+
+
+#ifndef RESOLV_CONF
+#define RESOLV_CONF "/etc/resolv.conf"
+#endif
+
+ENUM(ike_sa_state_names, IKE_CREATED, IKE_DELETING,
+ "CREATED",
+ "CONNECTING",
+ "ESTABLISHED",
+ "REKEYING",
+ "DELETING",
+);
+
+typedef struct private_ike_sa_t private_ike_sa_t;
+
+/**
+ * Private data of an ike_sa_t object.
+ */
+struct private_ike_sa_t {
+
+ /**
+ * Public members
+ */
+ ike_sa_t public;
+
+ /**
+ * Identifier for the current IKE_SA.
+ */
+ ike_sa_id_t *ike_sa_id;
+
+ /**
+ * unique numerical ID for this IKE_SA.
+ */
+ u_int32_t unique_id;
+
+ /**
+ * Current state of the IKE_SA
+ */
+ ike_sa_state_t state;
+
+ /**
+ * connection used to establish this IKE_SA.
+ */
+ connection_t *connection;
+
+ /**
+ * Peer and authentication information to establish IKE_SA.
+ */
+ policy_t *policy;
+
+ /**
+ * Juggles tasks to process messages
+ */
+ task_manager_t *task_manager;
+
+ /**
+ * Address of local host
+ */
+ host_t *my_host;
+
+ /**
+ * Address of remote host
+ */
+ host_t *other_host;
+
+ /**
+ * Identification used for us
+ */
+ identification_t *my_id;
+
+ /**
+ * Identification used for other
+ */
+ identification_t *other_id;
+
+ /**
+ * Linked List containing the child sa's of the current IKE_SA.
+ */
+ linked_list_t *child_sas;
+
+ /**
+ * crypter for inbound traffic
+ */
+ crypter_t *crypter_in;
+
+ /**
+ * crypter for outbound traffic
+ */
+ crypter_t *crypter_out;
+
+ /**
+ * Signer for inbound traffic
+ */
+ signer_t *signer_in;
+
+ /**
+ * Signer for outbound traffic
+ */
+ signer_t *signer_out;
+
+ /**
+ * Multi purpose prf, set key, use it, forget it
+ */
+ prf_t *prf;
+
+ /**
+ * Prf function for derivating keymat child SAs
+ */
+ prf_t *child_prf;
+
+ /**
+ * PRF to build outging authentication data
+ */
+ prf_t *auth_build;
+
+ /**
+ * PRF to verify incoming authentication data
+ */
+ prf_t *auth_verify;
+
+ /**
+ * NAT status of local host.
+ */
+ bool nat_here;
+
+ /**
+ * NAT status of remote host.
+ */
+ bool nat_there;
+
+ /**
+ * Virtual IP on local host, if any
+ */
+ host_t *my_virtual_ip;
+
+ /**
+ * Virtual IP on remote host, if any
+ */
+ host_t *other_virtual_ip;
+
+ /**
+ * List of DNS servers installed by us
+ */
+ linked_list_t *dns_servers;
+
+ /**
+ * Timestamps for this IKE_SA
+ */
+ struct {
+ /** last IKE message received */
+ u_int32_t inbound;
+ /** last IKE message sent */
+ u_int32_t outbound;
+ /** when IKE_SA became established */
+ u_int32_t established;
+ /** when IKE_SA gets rekeyed */
+ u_int32_t rekey;
+ /** when IKE_SA gets deleted */
+ u_int32_t delete;
+ } time;
+
+ /**
+ * how many times we have retried so far (keyingtries)
+ */
+ u_int32_t keyingtry;
+};
+
+/**
+ * get the time of the latest traffic processed by the kernel
+ */
+static time_t get_use_time(private_ike_sa_t* this, bool inbound)
+{
+ iterator_t *iterator;
+ child_sa_t *child_sa;
+ time_t latest = 0, use_time;
+
+ iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
+ while (iterator->iterate(iterator, (void**)&child_sa))
+ {
+ if (child_sa->get_use_time(child_sa, inbound, &use_time) == SUCCESS)
+ {
+ latest = max(latest, use_time);
+ }
+ }
+ iterator->destroy(iterator);
+
+ if (inbound)
+ {
+ return max(this->time.inbound, latest);
+ }
+ else
+ {
+ return max(this->time.outbound, latest);
+ }
+}
+
+/**
+ * Implementation of ike_sa_t.get_unique_id
+ */
+static u_int32_t get_unique_id(private_ike_sa_t *this)
+{
+ return this->unique_id;
+}
+
+/**
+ * Implementation of ike_sa_t.get_name.
+ */
+static char *get_name(private_ike_sa_t *this)
+{
+ if (this->connection)
+ {
+ return this->connection->get_name(this->connection);
+ }
+ return "(unnamed)";
+}
+
+/**
+ * Implementation of ike_sa_t.get_connection
+ */
+static connection_t* get_connection(private_ike_sa_t *this)
+{
+ return this->connection;
+}
+
+/**
+ * Implementation of ike_sa_t.set_connection
+ */
+static void set_connection(private_ike_sa_t *this, connection_t *connection)
+{
+ this->connection = connection;
+ connection->get_ref(connection);
+}
+
+/**
+ * Implementation of ike_sa_t.get_policy
+ */
+static policy_t *get_policy(private_ike_sa_t *this)
+{
+ return this->policy;
+}
+
+/**
+ * Implementation of ike_sa_t.set_policy
+ */
+static void set_policy(private_ike_sa_t *this, policy_t *policy)
+{
+ policy->get_ref(policy);
+ this->policy = policy;
+}
+
+/**
+ * Implementation of ike_sa_t.get_my_host.
+ */
+static host_t *get_my_host(private_ike_sa_t *this)
+{
+ return this->my_host;
+}
+
+/**
+ * Implementation of ike_sa_t.set_my_host.
+ */
+static void set_my_host(private_ike_sa_t *this, host_t *me)
+{
+ DESTROY_IF(this->my_host);
+ this->my_host = me;
+}
+
+/**
+ * Implementation of ike_sa_t.get_other_host.
+ */
+static host_t *get_other_host(private_ike_sa_t *this)
+{
+ return this->other_host;
+}
+
+/**
+ * Implementation of ike_sa_t.set_other_host.
+ */
+static void set_other_host(private_ike_sa_t *this, host_t *other)
+{
+ DESTROY_IF(this->other_host);
+ this->other_host = other;
+}
+
+/**
+ * Implementation of ike_sa_t.send_dpd
+ */
+static status_t send_dpd(private_ike_sa_t *this)
+{
+ send_dpd_job_t *job;
+ time_t diff, delay;
+
+ delay = this->connection->get_dpd_delay(this->connection);
+
+ if (delay == 0)
+ {
+ /* DPD disabled */
+ return SUCCESS;
+ }
+
+ if (this->task_manager->busy(this->task_manager))
+ {
+ /* an exchange is in the air, no need to start a DPD check */
+ diff = 0;
+ }
+ else
+ {
+ /* check if there was any inbound traffic */
+ time_t last_in, now;
+ last_in = get_use_time(this, TRUE);
+ now = time(NULL);
+ diff = now - last_in;
+ if (diff >= delay)
+ {
+ /* to long ago, initiate dead peer detection */
+ task_t *task;
+
+ task = (task_t*)ike_dpd_create(TRUE);
+ diff = 0;
+ DBG1(DBG_IKE, "sending DPD request");
+
+ this->task_manager->queue_task(this->task_manager, task);
+ this->task_manager->initiate(this->task_manager);
+ }
+ }
+ /* recheck in "interval" seconds */
+ job = send_dpd_job_create(this->ike_sa_id);
+ charon->event_queue->add_relative(charon->event_queue, (job_t*)job,
+ (delay - diff) * 1000);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of ike_sa_t.send_keepalive
+ */
+static void send_keepalive(private_ike_sa_t *this)
+{
+ send_keepalive_job_t *job;
+ time_t last_out, now, diff, interval;
+
+ last_out = get_use_time(this, FALSE);
+ now = time(NULL);
+
+ diff = now - last_out;
+ interval = charon->configuration->get_keepalive_interval(charon->configuration);
+
+ if (diff >= interval)
+ {
+ packet_t *packet;
+ chunk_t data;
+
+ packet = packet_create();
+ packet->set_source(packet, this->my_host->clone(this->my_host));
+ packet->set_destination(packet, this->other_host->clone(this->other_host));
+ data.ptr = malloc(1);
+ data.ptr[0] = 0xFF;
+ data.len = 1;
+ packet->set_data(packet, data);
+ charon->sender->send(charon->sender, packet);
+ DBG1(DBG_IKE, "sending keep alive");
+ diff = 0;
+ }
+ job = send_keepalive_job_create(this->ike_sa_id);
+ charon->event_queue->add_relative(charon->event_queue, (job_t*)job,
+ (interval - diff) * 1000);
+}
+
+/**
+ * Implementation of ike_sa_t.get_state.
+ */
+static ike_sa_state_t get_state(private_ike_sa_t *this)
+{
+ return this->state;
+}
+
+/**
+ * Implementation of ike_sa_t.set_state.
+ */
+static void set_state(private_ike_sa_t *this, ike_sa_state_t state)
+{
+ DBG1(DBG_IKE, "IKE_SA state change: %N => %N",
+ ike_sa_state_names, this->state,
+ ike_sa_state_names, state);
+
+ switch (state)
+ {
+ case IKE_ESTABLISHED:
+ {
+ if (this->state == IKE_CONNECTING)
+ {
+ job_t *job;
+ u_int32_t now = time(NULL);
+ u_int32_t soft, hard;
+ bool reauth;
+
+ this->time.established = now;
+ /* start DPD checks */
+ send_dpd(this);
+
+ /* schedule rekeying/reauthentication */
+ soft = this->connection->get_soft_lifetime(this->connection);
+ hard = this->connection->get_hard_lifetime(this->connection);
+ reauth = this->connection->get_reauth(this->connection);
+ DBG1(DBG_IKE, "scheduling %s in %ds, maximum lifetime %ds",
+ reauth ? "reauthentication": "rekeying", soft, hard);
+
+ if (soft)
+ {
+ this->time.rekey = now + soft;
+ job = (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, reauth);
+ charon->event_queue->add_relative(charon->event_queue, job,
+ soft * 1000);
+ }
+
+ if (hard)
+ {
+ this->time.delete = now + hard;
+ job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE);
+ charon->event_queue->add_relative(charon->event_queue, job,
+ hard * 1000);
+ }
+ }
+ break;
+ }
+ case IKE_DELETING:
+ {
+ /* delete may fail if a packet gets lost, so set a timeout */
+ job_t *job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE);
+ charon->event_queue->add_relative(charon->event_queue, job,
+ charon->configuration->get_half_open_ike_sa_timeout(
+ charon->configuration));
+ break;
+ }
+ default:
+ break;
+ }
+
+ this->state = state;
+}
+
+/**
+ * Implementation of ike_sa_t.reset
+ */
+static void reset(private_ike_sa_t *this)
+{
+ /* the responder ID is reset, as peer may choose another one */
+ if (this->ike_sa_id->is_initiator(this->ike_sa_id))
+ {
+ this->ike_sa_id->set_responder_spi(this->ike_sa_id, 0);
+ }
+
+ set_state(this, IKE_CREATED);
+
+ this->task_manager->reset(this->task_manager);
+}
+
+/**
+ * Update connection host, as addresses may change (NAT)
+ */
+static void update_hosts(private_ike_sa_t *this, host_t *me, host_t *other)
+{
+ iterator_t *iterator = NULL;
+ child_sa_t *child_sa = NULL;
+ host_diff_t my_diff, other_diff;
+
+ if (this->my_host->is_anyaddr(this->my_host) ||
+ this->other_host->is_anyaddr(this->other_host))
+ {
+ /* on first received message */
+ this->my_host->destroy(this->my_host);
+ this->my_host = me->clone(me);
+ this->other_host->destroy(this->other_host);
+ this->other_host = other->clone(other);
+ return;
+ }
+
+ my_diff = me->get_differences(me, this->my_host);
+ other_diff = other->get_differences(other, this->other_host);
+
+ if (!my_diff && !other_diff)
+ {
+ return;
+ }
+
+ if (my_diff)
+ {
+ this->my_host->destroy(this->my_host);
+ this->my_host = me->clone(me);
+ }
+
+ if (!this->nat_here)
+ {
+ /* update without restrictions if we are not NATted */
+ if (other_diff)
+ {
+ this->other_host->destroy(this->other_host);
+ this->other_host = other->clone(other);
+ }
+ }
+ else
+ {
+ /* if we are natted, only port may change */
+ if (other_diff & HOST_DIFF_ADDR)
+ {
+ return;
+ }
+ else if (other_diff & HOST_DIFF_PORT)
+ {
+ this->other_host->set_port(this->other_host, other->get_port(other));
+ }
+ }
+ iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
+ while (iterator->iterate(iterator, (void**)&child_sa))
+ {
+ child_sa->update_hosts(child_sa, this->my_host, this->other_host,
+ my_diff, other_diff);
+ }
+ iterator->destroy(iterator);
+}
+
+/**
+ * Implementation of ike_sa_t.generate
+ */
+static status_t generate_message(private_ike_sa_t *this, message_t *message,
+ packet_t **packet)
+{
+ this->time.outbound = time(NULL);
+ message->set_ike_sa_id(message, this->ike_sa_id);
+ message->set_destination(message, this->other_host->clone(this->other_host));
+ message->set_source(message, this->my_host->clone(this->my_host));
+ return message->generate(message, this->crypter_out, this->signer_out, packet);
+}
+
+/**
+ * send a notify back to the sender
+ */
+static void send_notify_response(private_ike_sa_t *this, message_t *request,
+ notify_type_t type)
+{
+ message_t *response;
+ packet_t *packet;
+
+ response = message_create();
+ response->set_exchange_type(response, request->get_exchange_type(request));
+ response->set_request(response, FALSE);
+ response->set_message_id(response, request->get_message_id(request));
+ response->add_notify(response, FALSE, type, chunk_empty);
+ if (this->my_host->is_anyaddr(this->my_host))
+ {
+ this->my_host->destroy(this->my_host);
+ this->my_host = request->get_destination(request);
+ this->my_host = this->my_host->clone(this->my_host);
+ }
+ if (this->other_host->is_anyaddr(this->other_host))
+ {
+ this->other_host->destroy(this->other_host);
+ this->other_host = request->get_source(request);
+ this->other_host = this->other_host->clone(this->other_host);
+ }
+ if (generate_message(this, response, &packet) == SUCCESS)
+ {
+ charon->sender->send(charon->sender, packet);
+ }
+ response->destroy(response);
+}
+
+/**
+ * Implementation of ike_sa_t.process_message.
+ */
+static status_t process_message(private_ike_sa_t *this, message_t *message)
+{
+ status_t status;
+ bool is_request;
+
+ is_request = message->get_request(message);
+
+ status = message->parse_body(message, this->crypter_in, this->signer_in);
+ if (status != SUCCESS)
+ {
+
+ if (is_request)
+ {
+ switch (status)
+ {
+ case NOT_SUPPORTED:
+ DBG1(DBG_IKE, "ciritcal unknown payloads found");
+ if (is_request)
+ {
+ send_notify_response(this, message, UNSUPPORTED_CRITICAL_PAYLOAD);
+ }
+ break;
+ case PARSE_ERROR:
+ DBG1(DBG_IKE, "message parsing failed");
+ if (is_request)
+ {
+ send_notify_response(this, message, INVALID_SYNTAX);
+ }
+ break;
+ case VERIFY_ERROR:
+ DBG1(DBG_IKE, "message verification failed");
+ if (is_request)
+ {
+ send_notify_response(this, message, INVALID_SYNTAX);
+ }
+ break;
+ case FAILED:
+ DBG1(DBG_IKE, "integrity check failed");
+ /* ignored */
+ break;
+ case INVALID_STATE:
+ DBG1(DBG_IKE, "found encrypted message, but no keys available");
+ if (is_request)
+ {
+ send_notify_response(this, message, INVALID_SYNTAX);
+ }
+ default:
+ break;
+ }
+ }
+ DBG1(DBG_IKE, "%N %s with message ID %d processing failed",
+ exchange_type_names, message->get_exchange_type(message),
+ message->get_request(message) ? "request" : "response",
+ message->get_message_id(message));
+ return status;
+ }
+ else
+ {
+ host_t *me, *other;
+
+ me = message->get_destination(message);
+ other = message->get_source(message);
+
+ /* if this IKE_SA is virgin, we check for a connection */
+ if (this->connection == NULL)
+ {
+ job_t *job;
+ this->connection = charon->connections->get_connection_by_hosts(
+ charon->connections, me, other);
+ if (this->connection == NULL)
+ {
+ /* no connection found for these hosts, destroy */
+ DBG1(DBG_IKE, "no connection found for %H...%H, sending %N",
+ me, other, notify_type_names, NO_PROPOSAL_CHOSEN);
+ send_notify_response(this, message, NO_PROPOSAL_CHOSEN);
+ return DESTROY_ME;
+ }
+ /* add a timeout if peer does not establish it completely */
+ job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, FALSE);
+ charon->event_queue->add_relative(charon->event_queue, job,
+ charon->configuration->get_half_open_ike_sa_timeout(
+ charon->configuration));
+ }
+
+ /* check if message is trustworthy, and update connection information */
+ if (this->state == IKE_CREATED ||
+ message->get_exchange_type(message) != IKE_SA_INIT)
+ {
+ update_hosts(this, me, other);
+ this->time.inbound = time(NULL);
+ }
+ return this->task_manager->process_message(this->task_manager, message);
+ }
+}
+
+/**
+ * apply the connection/policy information to this IKE_SA
+ */
+static void apply_config(private_ike_sa_t *this,
+ connection_t *connection, policy_t *policy)
+{
+ host_t *me, *other;
+ identification_t *my_id, *other_id;
+
+ if (this->connection == NULL && this->policy == NULL)
+ {
+ this->connection = connection;
+ connection->get_ref(connection);
+ this->policy = policy;
+ policy->get_ref(policy);
+
+ me = connection->get_my_host(connection);
+ other = connection->get_other_host(connection);
+ my_id = policy->get_my_id(policy);
+ other_id = policy->get_other_id(policy);
+ set_my_host(this, me->clone(me));
+ set_other_host(this, other->clone(other));
+ DESTROY_IF(this->my_id);
+ DESTROY_IF(this->other_id);
+ this->my_id = my_id->clone(my_id);
+ this->other_id = other_id->clone(other_id);
+ }
+}
+
+/**
+ * Implementation of ike_sa_t.initiate.
+ */
+static status_t initiate(private_ike_sa_t *this,
+ connection_t *connection, policy_t *policy)
+{
+ task_t *task;
+
+ if (this->state == IKE_CREATED)
+ {
+ /* if we aren't established/establishing, do so */
+ apply_config(this, connection, policy);
+
+ if (this->other_host->is_anyaddr(this->other_host))
+ {
+ SIG(IKE_UP_START, "initiating IKE_SA");
+ SIG(IKE_UP_FAILED, "unable to initiate to %%any");
+ return DESTROY_ME;
+ }
+
+ task = (task_t*)ike_init_create(&this->public, TRUE, NULL);
+ this->task_manager->queue_task(this->task_manager, task);
+ task = (task_t*)ike_natd_create(&this->public, TRUE);
+ this->task_manager->queue_task(this->task_manager, task);
+ task = (task_t*)ike_cert_create(&this->public, TRUE);
+ this->task_manager->queue_task(this->task_manager, task);
+ task = (task_t*)ike_auth_create(&this->public, TRUE);
+ this->task_manager->queue_task(this->task_manager, task);
+ task = (task_t*)ike_config_create(&this->public, policy);
+ this->task_manager->queue_task(this->task_manager, task);
+ }
+
+ task = (task_t*)child_create_create(&this->public, policy);
+ this->task_manager->queue_task(this->task_manager, task);
+
+ return this->task_manager->initiate(this->task_manager);
+}
+
+/**
+ * Implementation of ike_sa_t.acquire.
+ */
+static status_t acquire(private_ike_sa_t *this, u_int32_t reqid)
+{
+ policy_t *policy;
+ iterator_t *iterator;
+ child_sa_t *current, *child_sa = NULL;
+ task_t *task;
+ child_create_t *child_create;
+
+ if (this->state == IKE_DELETING)
+ {
+ SIG(CHILD_UP_START, "acquiring CHILD_SA on kernel request");
+ SIG(CHILD_UP_FAILED, "acquiring CHILD_SA (reqid %d) failed: "
+ "IKE_SA is deleting", reqid);
+ return FAILED;
+ }
+
+ /* find CHILD_SA */
+ iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
+ while (iterator->iterate(iterator, (void**)&current))
+ {
+ if (current->get_reqid(current) == reqid)
+ {
+ child_sa = current;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ if (!child_sa)
+ {
+ SIG(CHILD_UP_START, "acquiring CHILD_SA on kernel request");
+ SIG(CHILD_UP_FAILED, "acquiring CHILD_SA (reqid %d) failed: "
+ "CHILD_SA not found", reqid);
+ return FAILED;
+ }
+
+ policy = child_sa->get_policy(child_sa);
+
+ if (this->state == IKE_CREATED)
+ {
+ task = (task_t*)ike_init_create(&this->public, TRUE, NULL);
+ this->task_manager->queue_task(this->task_manager, task);
+ task = (task_t*)ike_natd_create(&this->public, TRUE);
+ this->task_manager->queue_task(this->task_manager, task);
+ task = (task_t*)ike_cert_create(&this->public, TRUE);
+ this->task_manager->queue_task(this->task_manager, task);
+ task = (task_t*)ike_auth_create(&this->public, TRUE);
+ this->task_manager->queue_task(this->task_manager, task);
+ task = (task_t*)ike_config_create(&this->public, policy);
+ this->task_manager->queue_task(this->task_manager, task);
+ }
+
+ child_create = child_create_create(&this->public, policy);
+ child_create->use_reqid(child_create, reqid);
+ this->task_manager->queue_task(this->task_manager, (task_t*)child_create);
+
+ return this->task_manager->initiate(this->task_manager);
+}
+
+/**
+ * compare two lists of traffic selectors for equality
+ */
+static bool ts_list_equals(linked_list_t *l1, linked_list_t *l2)
+{
+ bool equals = TRUE;
+ iterator_t *i1, *i2;
+ traffic_selector_t *t1, *t2;
+
+ if (l1->get_count(l1) != l2->get_count(l2))
+ {
+ return FALSE;
+ }
+
+ i1 = l1->create_iterator(l1, TRUE);
+ i2 = l2->create_iterator(l2, TRUE);
+ while (i1->iterate(i1, (void**)&t1) && i2->iterate(i2, (void**)&t2))
+ {
+ if (!t1->equals(t1, t2))
+ {
+ equals = FALSE;
+ break;
+ }
+ }
+ i1->destroy(i1);
+ i2->destroy(i2);
+ return equals;
+}
+
+/**
+ * Implementation of ike_sa_t.route.
+ */
+static status_t route(private_ike_sa_t *this, connection_t *connection, policy_t *policy)
+{
+ child_sa_t *child_sa = NULL;
+ iterator_t *iterator;
+ linked_list_t *my_ts, *other_ts;
+ status_t status;
+
+ SIG(CHILD_ROUTE_START, "routing CHILD_SA");
+
+ /* check if not already routed*/
+ iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
+ while (iterator->iterate(iterator, (void**)&child_sa))
+ {
+ if (child_sa->get_state(child_sa) == CHILD_ROUTED)
+ {
+ linked_list_t *my_ts_conf, *other_ts_conf;
+
+ my_ts = child_sa->get_my_traffic_selectors(child_sa);
+ other_ts = child_sa->get_other_traffic_selectors(child_sa);
+
+ my_ts_conf = policy->get_my_traffic_selectors(policy, this->my_host);
+ other_ts_conf = policy->get_other_traffic_selectors(policy, this->other_host);
+
+ if (ts_list_equals(my_ts, my_ts_conf) &&
+ ts_list_equals(other_ts, other_ts_conf))
+ {
+ iterator->destroy(iterator);
+ my_ts_conf->destroy_offset(my_ts_conf, offsetof(traffic_selector_t, destroy));
+ other_ts_conf->destroy_offset(other_ts_conf, offsetof(traffic_selector_t, destroy));
+ SIG(CHILD_ROUTE_FAILED, "CHILD_SA with such a policy already routed");
+ return FAILED;
+ }
+ my_ts_conf->destroy_offset(my_ts_conf, offsetof(traffic_selector_t, destroy));
+ other_ts_conf->destroy_offset(other_ts_conf, offsetof(traffic_selector_t, destroy));
+ }
+ }
+ iterator->destroy(iterator);
+
+ switch (this->state)
+ {
+ case IKE_DELETING:
+ case IKE_REKEYING:
+ SIG(CHILD_ROUTE_FAILED,
+ "unable to route CHILD_SA, as its IKE_SA gets deleted");
+ return FAILED;
+ case IKE_CREATED:
+ /* apply connection information, we need it to acquire */
+ apply_config(this, connection, policy);
+ break;
+ case IKE_CONNECTING:
+ case IKE_ESTABLISHED:
+ default:
+ break;
+ }
+
+ /* install kernel policies */
+ child_sa = child_sa_create(this->my_host, this->other_host,
+ this->my_id, this->other_id, policy, FALSE, 0);
+
+ my_ts = policy->get_my_traffic_selectors(policy, this->my_host);
+ other_ts = policy->get_other_traffic_selectors(policy, this->other_host);
+ status = child_sa->add_policies(child_sa, my_ts, other_ts,
+ policy->get_mode(policy));
+ my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
+ other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
+ this->child_sas->insert_last(this->child_sas, child_sa);
+ SIG(CHILD_ROUTE_SUCCESS, "CHILD_SA routed");
+ return status;
+}
+
+/**
+ * Implementation of ike_sa_t.unroute.
+ */
+static status_t unroute(private_ike_sa_t *this, policy_t *policy)
+{
+ iterator_t *iterator;
+ child_sa_t *child_sa = NULL;
+ bool found = FALSE;
+ linked_list_t *my_ts, *other_ts, *my_ts_conf, *other_ts_conf;
+
+ SIG(CHILD_UNROUTE_START, "unrouting CHILD_SA");
+
+ /* find CHILD_SA in ROUTED state */
+ iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
+ while (iterator->iterate(iterator, (void**)&child_sa))
+ {
+ if (child_sa->get_state(child_sa) == CHILD_ROUTED)
+ {
+ my_ts = child_sa->get_my_traffic_selectors(child_sa);
+ other_ts = child_sa->get_other_traffic_selectors(child_sa);
+
+ my_ts_conf = policy->get_my_traffic_selectors(policy, this->my_host);
+ other_ts_conf = policy->get_other_traffic_selectors(policy, this->other_host);
+
+ if (ts_list_equals(my_ts, my_ts_conf) &&
+ ts_list_equals(other_ts, other_ts_conf))
+ {
+ iterator->remove(iterator);
+ SIG(CHILD_UNROUTE_SUCCESS, "CHILD_SA unrouted");
+ child_sa->destroy(child_sa);
+ my_ts_conf->destroy_offset(my_ts_conf, offsetof(traffic_selector_t, destroy));
+ other_ts_conf->destroy_offset(other_ts_conf, offsetof(traffic_selector_t, destroy));
+ found = TRUE;
+ break;
+ }
+ my_ts_conf->destroy_offset(my_ts_conf, offsetof(traffic_selector_t, destroy));
+ other_ts_conf->destroy_offset(other_ts_conf, offsetof(traffic_selector_t, destroy));
+ }
+ }
+ iterator->destroy(iterator);
+
+ if (!found)
+ {
+ SIG(CHILD_UNROUTE_FAILED, "CHILD_SA to unroute not found");
+ return FAILED;
+ }
+ /* if we are not established, and we have no more routed childs, remove whole SA */
+ if (this->state == IKE_CREATED &&
+ this->child_sas->get_count(this->child_sas) == 0)
+ {
+ return DESTROY_ME;
+ }
+ return SUCCESS;
+}
+
+/**
+ * Implementation of ike_sa_t.retransmit.
+ */
+static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id)
+{
+ this->time.outbound = time(NULL);
+ if (this->task_manager->retransmit(this->task_manager, message_id) != SUCCESS)
+ {
+ policy_t *policy;
+ child_sa_t* child_sa;
+ linked_list_t *to_route, *to_restart;
+ iterator_t *iterator;
+
+ /* send a proper signal to brief interested bus listeners */
+ switch (this->state)
+ {
+ case IKE_CONNECTING:
+ {
+ /* retry IKE_SA_INIT if we have multiple keyingtries */
+ u_int32_t tries = this->connection->get_keyingtries(this->connection);
+ this->keyingtry++;
+ if (tries == 0 || tries > this->keyingtry)
+ {
+ SIG(IKE_UP_FAILED, "peer not responding, trying again "
+ "(%d/%d) in background ", this->keyingtry + 1, tries);
+ reset(this);
+ return this->task_manager->initiate(this->task_manager);
+ }
+ SIG(IKE_UP_FAILED, "establishing IKE_SA failed, peer not responding");
+ break;
+ }
+ case IKE_REKEYING:
+ SIG(IKE_REKEY_FAILED, "rekeying IKE_SA failed, peer not responding");
+ break;
+ case IKE_DELETING:
+ SIG(IKE_DOWN_FAILED, "proper IKE_SA delete failed, peer not responding");
+ break;
+ default:
+ break;
+ }
+
+ /* summarize how we have to handle each child */
+ to_route = linked_list_create();
+ to_restart = linked_list_create();
+ iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
+ while (iterator->iterate(iterator, (void**)&child_sa))
+ {
+ policy = child_sa->get_policy(child_sa);
+
+ if (child_sa->get_state(child_sa) == CHILD_ROUTED)
+ {
+ /* reroute routed CHILD_SAs */
+ to_route->insert_last(to_route, policy);
+ }
+ else
+ {
+ /* use DPD action for established CHILD_SAs */
+ switch (policy->get_dpd_action(policy))
+ {
+ case DPD_ROUTE:
+ to_route->insert_last(to_route, policy);
+ break;
+ case DPD_RESTART:
+ to_restart->insert_last(to_restart, policy);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ iterator->destroy(iterator);
+
+ /* create a new IKE_SA if we have to route or to restart */
+ if (to_route->get_count(to_route) || to_restart->get_count(to_restart))
+ {
+ private_ike_sa_t *new;
+ task_t *task;
+
+ new = (private_ike_sa_t*)charon->ike_sa_manager->checkout_new(
+ charon->ike_sa_manager, TRUE);
+
+ apply_config(new, this->connection, this->policy);
+ /* use actual used host, not the wildcarded one in connection */
+ new->other_host->destroy(new->other_host);
+ new->other_host = this->other_host->clone(this->other_host);
+
+ /* install routes */
+ while (to_route->remove_last(to_route, (void**)&policy) == SUCCESS)
+ {
+ route(new, new->connection, policy);
+ }
+
+ /* restart children */
+ if (to_restart->get_count(to_restart))
+ {
+ task = (task_t*)ike_init_create(&new->public, TRUE, NULL);
+ new->task_manager->queue_task(new->task_manager, task);
+ task = (task_t*)ike_natd_create(&new->public, TRUE);
+ new->task_manager->queue_task(new->task_manager, task);
+ task = (task_t*)ike_cert_create(&new->public, TRUE);
+ new->task_manager->queue_task(new->task_manager, task);
+ task = (task_t*)ike_config_create(&new->public, new->policy);
+ new->task_manager->queue_task(new->task_manager, task);
+ task = (task_t*)ike_auth_create(&new->public, TRUE);
+ new->task_manager->queue_task(new->task_manager, task);
+
+ while (to_restart->remove_last(to_restart, (void**)&policy) == SUCCESS)
+ {
+ task = (task_t*)child_create_create(&new->public, policy);
+ new->task_manager->queue_task(new->task_manager, task);
+ }
+ new->task_manager->initiate(new->task_manager);
+ }
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, &new->public);
+ }
+ to_route->destroy(to_route);
+ to_restart->destroy(to_restart);
+ return DESTROY_ME;
+ }
+ return SUCCESS;
+}
+
+/**
+ * Implementation of ike_sa_t.get_prf.
+ */
+static prf_t *get_prf(private_ike_sa_t *this)
+{
+ return this->prf;
+}
+
+/**
+ * Implementation of ike_sa_t.get_prf.
+ */
+static prf_t *get_child_prf(private_ike_sa_t *this)
+{
+ return this->child_prf;
+}
+
+/**
+ * Implementation of ike_sa_t.get_auth_bild
+ */
+static prf_t *get_auth_build(private_ike_sa_t *this)
+{
+ return this->auth_build;
+}
+
+/**
+ * Implementation of ike_sa_t.get_auth_verify
+ */
+static prf_t *get_auth_verify(private_ike_sa_t *this)
+{
+ return this->auth_verify;
+}
+
+/**
+ * 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_id.
+ */
+static identification_t* get_my_id(private_ike_sa_t *this)
+{
+ return this->my_id;
+}
+
+/**
+ * Implementation of ike_sa_t.set_my_id.
+ */
+static void set_my_id(private_ike_sa_t *this, identification_t *me)
+{
+ DESTROY_IF(this->my_id);
+ this->my_id = me;
+}
+
+/**
+ * Implementation of ike_sa_t.get_other_id.
+ */
+static identification_t* get_other_id(private_ike_sa_t *this)
+{
+ return this->other_id;
+}
+
+/**
+ * Implementation of ike_sa_t.set_other_id.
+ */
+static void set_other_id(private_ike_sa_t *this, identification_t *other)
+{
+ DESTROY_IF(this->other_id);
+ this->other_id = other;
+}
+
+/**
+ * Implementation of ike_sa_t.derive_keys.
+ */
+static status_t derive_keys(private_ike_sa_t *this,
+ proposal_t *proposal, chunk_t secret,
+ chunk_t nonce_i, chunk_t nonce_r,
+ bool initiator, prf_t *child_prf, prf_t *old_prf)
+{
+ prf_plus_t *prf_plus;
+ chunk_t skeyseed, key, nonces, prf_plus_seed;
+ algorithm_t *algo;
+ size_t key_size;
+ crypter_t *crypter_i, *crypter_r;
+ signer_t *signer_i, *signer_r;
+ prf_t *prf_i, *prf_r;
+ u_int8_t spi_i_buf[sizeof(u_int64_t)], spi_r_buf[sizeof(u_int64_t)];
+ chunk_t spi_i = chunk_from_buf(spi_i_buf);
+ chunk_t spi_r = chunk_from_buf(spi_r_buf);
+
+ /* Create SAs general purpose PRF first, we may use it here */
+ if (!proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &algo))
+ {
+ DBG1(DBG_IKE, "key derivation failed: no PSEUDO_RANDOM_FUNCTION");;
+ return FAILED;
+ }
+ this->prf = prf_create(algo->algorithm);
+ if (this->prf == NULL)
+ {
+ DBG1(DBG_IKE, "key derivation failed: PSEUDO_RANDOM_FUNCTION "
+ "%N not supported!", pseudo_random_function_names, algo->algorithm);
+ return FAILED;
+ }
+
+ DBG4(DBG_IKE, "shared Diffie Hellman secret %B", &secret);
+ nonces = chunk_cat("cc", nonce_i, nonce_r);
+ *((u_int64_t*)spi_i.ptr) = this->ike_sa_id->get_initiator_spi(this->ike_sa_id);
+ *((u_int64_t*)spi_r.ptr) = this->ike_sa_id->get_responder_spi(this->ike_sa_id);
+ prf_plus_seed = chunk_cat("ccc", nonces, spi_i, spi_r);
+
+ /* KEYMAT = prf+ (SKEYSEED, Ni | Nr | SPIi | SPIr)
+ *
+ * if we are rekeying, SKEYSEED is built on another way
+ */
+ if (child_prf == NULL) /* not rekeying */
+ {
+ /* SKEYSEED = prf(Ni | Nr, g^ir) */
+ this->prf->set_key(this->prf, nonces);
+ this->prf->allocate_bytes(this->prf, secret, &skeyseed);
+ DBG4(DBG_IKE, "SKEYSEED %B", &skeyseed);
+ this->prf->set_key(this->prf, skeyseed);
+ chunk_free(&skeyseed);
+ chunk_free(&secret);
+ prf_plus = prf_plus_create(this->prf, prf_plus_seed);
+ }
+ else
+ {
+ /* SKEYSEED = prf(SK_d (old), [g^ir (new)] | Ni | Nr)
+ * use OLD SAs PRF functions for both prf_plus and prf */
+ secret = chunk_cat("mc", secret, nonces);
+ child_prf->allocate_bytes(child_prf, secret, &skeyseed);
+ DBG4(DBG_IKE, "SKEYSEED %B", &skeyseed);
+ old_prf->set_key(old_prf, skeyseed);
+ chunk_free(&skeyseed);
+ chunk_free(&secret);
+ prf_plus = prf_plus_create(old_prf, prf_plus_seed);
+ }
+ chunk_free(&nonces);
+ chunk_free(&prf_plus_seed);
+
+ /* KEYMAT = SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr */
+
+ /* SK_d is used for generating CHILD_SA key mat => child_prf */
+ proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &algo);
+ this->child_prf = prf_create(algo->algorithm);
+ key_size = this->child_prf->get_key_size(this->child_prf);
+ prf_plus->allocate_bytes(prf_plus, key_size, &key);
+ DBG4(DBG_IKE, "Sk_d secret %B", &key);
+ this->child_prf->set_key(this->child_prf, key);
+ chunk_free(&key);
+
+ /* SK_ai/SK_ar used for integrity protection => signer_in/signer_out */
+ if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &algo))
+ {
+ DBG1(DBG_IKE, "key derivation failed: no INTEGRITY_ALGORITHM");
+ return FAILED;
+ }
+ signer_i = signer_create(algo->algorithm);
+ signer_r = signer_create(algo->algorithm);
+ if (signer_i == NULL || signer_r == NULL)
+ {
+ DBG1(DBG_IKE, "key derivation failed: INTEGRITY_ALGORITHM "
+ "%N not supported!", integrity_algorithm_names ,algo->algorithm);
+ return FAILED;
+ }
+ key_size = signer_i->get_key_size(signer_i);
+
+ prf_plus->allocate_bytes(prf_plus, key_size, &key);
+ DBG4(DBG_IKE, "Sk_ai secret %B", &key);
+ signer_i->set_key(signer_i, key);
+ chunk_free(&key);
+
+ prf_plus->allocate_bytes(prf_plus, key_size, &key);
+ DBG4(DBG_IKE, "Sk_ar secret %B", &key);
+ signer_r->set_key(signer_r, key);
+ chunk_free(&key);
+
+ if (initiator)
+ {
+ this->signer_in = signer_r;
+ this->signer_out = signer_i;
+ }
+ else
+ {
+ this->signer_in = signer_i;
+ this->signer_out = signer_r;
+ }
+
+ /* SK_ei/SK_er used for encryption => crypter_in/crypter_out */
+ if (!proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &algo))
+ {
+ DBG1(DBG_IKE, "key derivation failed: no ENCRYPTION_ALGORITHM");
+ return FAILED;
+ }
+ crypter_i = crypter_create(algo->algorithm, algo->key_size / 8);
+ crypter_r = crypter_create(algo->algorithm, algo->key_size / 8);
+ if (crypter_i == NULL || crypter_r == NULL)
+ {
+ DBG1(DBG_IKE, "key derivation failed: ENCRYPTION_ALGORITHM "
+ "%N (key size %d) not supported!",
+ encryption_algorithm_names, algo->algorithm, algo->key_size);
+ return FAILED;
+ }
+ key_size = crypter_i->get_key_size(crypter_i);
+
+ prf_plus->allocate_bytes(prf_plus, key_size, &key);
+ DBG4(DBG_IKE, "Sk_ei secret %B", &key);
+ crypter_i->set_key(crypter_i, key);
+ chunk_free(&key);
+
+ prf_plus->allocate_bytes(prf_plus, key_size, &key);
+ DBG4(DBG_IKE, "Sk_er secret %B", &key);
+ crypter_r->set_key(crypter_r, key);
+ chunk_free(&key);
+
+ if (initiator)
+ {
+ this->crypter_in = crypter_r;
+ this->crypter_out = crypter_i;
+ }
+ else
+ {
+ this->crypter_in = crypter_i;
+ this->crypter_out = crypter_r;
+ }
+
+ /* SK_pi/SK_pr used for authentication => prf_auth_i, prf_auth_r */
+ proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &algo);
+ prf_i = prf_create(algo->algorithm);
+ prf_r = prf_create(algo->algorithm);
+
+ key_size = prf_i->get_key_size(prf_i);
+ prf_plus->allocate_bytes(prf_plus, key_size, &key);
+ DBG4(DBG_IKE, "Sk_pi secret %B", &key);
+ prf_i->set_key(prf_i, key);
+ chunk_free(&key);
+
+ prf_plus->allocate_bytes(prf_plus, key_size, &key);
+ DBG4(DBG_IKE, "Sk_pr secret %B", &key);
+ prf_r->set_key(prf_r, key);
+ chunk_free(&key);
+
+ if (initiator)
+ {
+ this->auth_verify = prf_r;
+ this->auth_build = prf_i;
+ }
+ else
+ {
+ this->auth_verify = prf_i;
+ this->auth_build = prf_r;
+ }
+
+ /* all done, prf_plus not needed anymore */
+ prf_plus->destroy(prf_plus);
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of ike_sa_t.add_child_sa.
+ */
+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 ike_sa_t.get_child_sa.
+ */
+static child_sa_t* get_child_sa(private_ike_sa_t *this, protocol_id_t protocol,
+ u_int32_t spi, bool inbound)
+{
+ iterator_t *iterator;
+ child_sa_t *current, *found = NULL;
+
+ iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
+ while (iterator->iterate(iterator, (void**)&current))
+ {
+ if (current->get_spi(current, inbound) == spi &&
+ current->get_protocol(current) == protocol)
+ {
+ found = current;
+ }
+ }
+ iterator->destroy(iterator);
+ return found;
+}
+
+/**
+ * Implementation of ike_sa_t.create_child_sa_iterator.
+ */
+static iterator_t* create_child_sa_iterator(private_ike_sa_t *this)
+{
+ return this->child_sas->create_iterator(this->child_sas, TRUE);
+}
+
+/**
+ * Implementation of ike_sa_t.rekey_child_sa.
+ */
+static status_t rekey_child_sa(private_ike_sa_t *this, protocol_id_t protocol, u_int32_t spi)
+{
+ child_sa_t *child_sa;
+ child_rekey_t *child_rekey;
+
+ child_sa = get_child_sa(this, protocol, spi, TRUE);
+ if (child_sa)
+ {
+ child_rekey = child_rekey_create(&this->public, child_sa);
+ this->task_manager->queue_task(this->task_manager, &child_rekey->task);
+ return this->task_manager->initiate(this->task_manager);
+ }
+ return FAILED;
+}
+
+/**
+ * Implementation of ike_sa_t.delete_child_sa.
+ */
+static status_t delete_child_sa(private_ike_sa_t *this, protocol_id_t protocol, u_int32_t spi)
+{
+ child_sa_t *child_sa;
+ child_delete_t *child_delete;
+
+ child_sa = get_child_sa(this, protocol, spi, TRUE);
+ if (child_sa)
+ {
+ child_delete = child_delete_create(&this->public, child_sa);
+ this->task_manager->queue_task(this->task_manager, &child_delete->task);
+ return this->task_manager->initiate(this->task_manager);
+ }
+ return FAILED;
+}
+
+/**
+ * Implementation of ike_sa_t.destroy_child_sa.
+ */
+static status_t destroy_child_sa(private_ike_sa_t *this, protocol_id_t protocol,
+ u_int32_t spi)
+{
+ iterator_t *iterator;
+ child_sa_t *child_sa;
+ status_t status = NOT_FOUND;
+
+ iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
+ while (iterator->iterate(iterator, (void**)&child_sa))
+ {
+ if (child_sa->get_protocol(child_sa) == protocol &&
+ child_sa->get_spi(child_sa, TRUE) == spi)
+ {
+ child_sa->destroy(child_sa);
+ iterator->remove(iterator);
+ status = SUCCESS;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ return status;
+}
+
+/**
+ * Implementation of public_ike_sa_t.delete.
+ */
+static status_t delete_(private_ike_sa_t *this)
+{
+ ike_delete_t *ike_delete;
+
+ switch (this->state)
+ {
+ case IKE_ESTABLISHED:
+ DBG1(DBG_IKE, "deleting IKE_SA");
+ /* do not log when rekeyed */
+ case IKE_REKEYING:
+ ike_delete = ike_delete_create(&this->public, TRUE);
+ this->task_manager->queue_task(this->task_manager, &ike_delete->task);
+ return this->task_manager->initiate(this->task_manager);
+ default:
+ DBG1(DBG_IKE, "destroying IKE_SA in state %N without notification",
+ ike_sa_state_names, this->state);
+ break;
+ }
+ return DESTROY_ME;
+}
+
+/**
+ * Implementation of ike_sa_t.rekey.
+ */
+static status_t rekey(private_ike_sa_t *this)
+{
+ ike_rekey_t *ike_rekey;
+
+ ike_rekey = ike_rekey_create(&this->public, TRUE);
+
+ this->task_manager->queue_task(this->task_manager, &ike_rekey->task);
+ return this->task_manager->initiate(this->task_manager);
+}
+
+/**
+ * Implementation of ike_sa_t.reestablish
+ */
+static void reestablish(private_ike_sa_t *this)
+{
+ private_ike_sa_t *other;
+ iterator_t *iterator;
+ child_sa_t *child_sa;
+ policy_t *policy;
+ task_t *task;
+ job_t *job;
+
+ other = (private_ike_sa_t*)charon->ike_sa_manager->checkout_new(
+ charon->ike_sa_manager, TRUE);
+
+ apply_config(other, this->connection, this->policy);
+ other->other_host->destroy(other->other_host);
+ other->other_host = this->other_host->clone(this->other_host);
+
+ if (this->state == IKE_ESTABLISHED)
+ {
+ task = (task_t*)ike_init_create(&other->public, TRUE, NULL);
+ other->task_manager->queue_task(other->task_manager, task);
+ task = (task_t*)ike_natd_create(&other->public, TRUE);
+ other->task_manager->queue_task(other->task_manager, task);
+ task = (task_t*)ike_cert_create(&other->public, TRUE);
+ other->task_manager->queue_task(other->task_manager, task);
+ task = (task_t*)ike_config_create(&other->public, other->policy);
+ other->task_manager->queue_task(other->task_manager, task);
+ task = (task_t*)ike_auth_create(&other->public, TRUE);
+ other->task_manager->queue_task(other->task_manager, task);
+ }
+
+ other->task_manager->adopt_tasks(other->task_manager, this->task_manager);
+
+ /* Create task for established children, adopt routed children directly */
+ iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
+ while(iterator->iterate(iterator, (void**)&child_sa))
+ {
+ switch (child_sa->get_state(child_sa))
+ {
+ case CHILD_ROUTED:
+ {
+ iterator->remove(iterator);
+ other->child_sas->insert_first(other->child_sas, child_sa);
+ break;
+ }
+ default:
+ {
+ policy = child_sa->get_policy(child_sa);
+ task = (task_t*)child_create_create(&other->public, policy);
+ other->task_manager->queue_task(other->task_manager, task);
+ break;
+ }
+ }
+ }
+ iterator->destroy(iterator);
+
+ other->task_manager->initiate(other->task_manager);
+
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, &other->public);
+
+ job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE);
+ charon->job_queue->add(charon->job_queue, job);
+}
+
+/**
+ * Implementation of ike_sa_t.inherit.
+ */
+static status_t inherit(private_ike_sa_t *this, private_ike_sa_t *other)
+{
+ child_sa_t *child_sa;
+ host_t *ip;
+
+ /* apply hosts and ids */
+ 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);
+ this->my_host = other->my_host->clone(other->my_host);
+ this->other_host = other->other_host->clone(other->other_host);
+ this->my_id = other->my_id->clone(other->my_id);
+ this->other_id = other->other_id->clone(other->other_id);
+
+ /* apply virtual assigned IPs... */
+ if (other->my_virtual_ip)
+ {
+ this->my_virtual_ip = other->my_virtual_ip;
+ other->my_virtual_ip = NULL;
+ }
+ if (other->other_virtual_ip)
+ {
+ this->other_virtual_ip = other->other_virtual_ip;
+ other->other_virtual_ip = NULL;
+ }
+
+ /* ... and DNS servers */
+ while (other->dns_servers->remove_last(other->dns_servers,
+ (void**)&ip) == SUCCESS)
+ {
+ this->dns_servers->insert_first(this->dns_servers, ip);
+ }
+
+ /* adopt all children */
+ while (other->child_sas->remove_last(other->child_sas,
+ (void**)&child_sa) == SUCCESS)
+ {
+ this->child_sas->insert_first(this->child_sas, (void*)child_sa);
+ }
+
+ /* move pending tasks to the new IKE_SA */
+ this->task_manager->adopt_tasks(this->task_manager, other->task_manager);
+
+ /* we have to initate here, there may be new tasks to handle */
+ return this->task_manager->initiate(this->task_manager);
+}
+
+/**
+ * Implementation of ike_sa_t.is_natt_enabled.
+ */
+static bool is_natt_enabled(private_ike_sa_t *this)
+{
+ return this->nat_here || this->nat_there;
+}
+
+/**
+ * Implementation of ike_sa_t.enable_natt.
+ */
+static void enable_natt(private_ike_sa_t *this, bool local)
+{
+ if (local)
+ {
+ DBG1(DBG_IKE, "local host is behind NAT, scheduling keep alives");
+ this->nat_here = TRUE;
+ send_keepalive(this);
+ }
+ else
+ {
+ DBG1(DBG_IKE, "remote host is behind NAT");
+ this->nat_there = TRUE;
+ }
+}
+
+/**
+ * Implementation of ike_sa_t.set_virtual_ip
+ */
+static void set_virtual_ip(private_ike_sa_t *this, bool local, host_t *ip)
+{
+ if (local)
+ {
+ DBG1(DBG_IKE, "installing new virtual IP %H", ip);
+ if (this->my_virtual_ip)
+ {
+ DBG1(DBG_IKE, "removing old virtual IP %H", this->my_virtual_ip);
+ charon->kernel_interface->del_ip(charon->kernel_interface,
+ this->my_virtual_ip,
+ this->my_host);
+ this->my_virtual_ip->destroy(this->my_virtual_ip);
+ }
+ if (charon->kernel_interface->add_ip(charon->kernel_interface, ip,
+ this->my_host) == SUCCESS)
+ {
+ this->my_virtual_ip = ip->clone(ip);
+ }
+ else
+ {
+ DBG1(DBG_IKE, "installing virtual IP %H failed", ip);
+ this->my_virtual_ip = NULL;
+ }
+ }
+ else
+ {
+ DESTROY_IF(this->other_virtual_ip);
+ this->other_virtual_ip = ip->clone(ip);
+ }
+}
+
+/**
+ * Implementation of ike_sa_t.get_virtual_ip
+ */
+static host_t* get_virtual_ip(private_ike_sa_t *this, bool local)
+{
+ if (local)
+ {
+ return this->my_virtual_ip;
+ }
+ else
+ {
+ return this->other_virtual_ip;
+ }
+}
+
+/**
+ * Implementation of ike_sa_t.remove_dns_server
+ */
+static void remove_dns_servers(private_ike_sa_t *this)
+{
+ FILE *file;
+ struct stat stats;
+ chunk_t contents, line, orig_line, token;
+ char string[INET6_ADDRSTRLEN];
+ host_t *ip;
+ iterator_t *iterator;
+
+ if (this->dns_servers->get_count(this->dns_servers) == 0)
+ {
+ /* don't touch anything if we have no nameservers installed */
+ return;
+ }
+
+ file = fopen(RESOLV_CONF, "r");
+ if (file == NULL || stat(RESOLV_CONF, &stats) != 0)
+ {
+ DBG1(DBG_IKE, "unable to open DNS configuration file %s: %m", RESOLV_CONF);
+ return;
+ }
+
+ contents = chunk_alloca((size_t)stats.st_size);
+
+ if (fread(contents.ptr, 1, contents.len, file) != contents.len)
+ {
+ DBG1(DBG_IKE, "unable to read DNS configuration file: %m");
+ fclose(file);
+ return;
+ }
+
+ fclose(file);
+ file = fopen(RESOLV_CONF, "w");
+ if (file == NULL)
+ {
+ DBG1(DBG_IKE, "unable to open DNS configuration file %s: %m", RESOLV_CONF);
+ return;
+ }
+
+ iterator = this->dns_servers->create_iterator(this->dns_servers, TRUE);
+ while (fetchline(&contents, &line))
+ {
+ bool found = FALSE;
+ orig_line = line;
+ if (extract_token(&token, ' ', &line) &&
+ strncasecmp(token.ptr, "nameserver", token.len) == 0)
+ {
+ if (!extract_token(&token, ' ', &line))
+ {
+ token = line;
+ }
+ iterator->reset(iterator);
+ while (iterator->iterate(iterator, (void**)&ip))
+ {
+ snprintf(string, sizeof(string), "%H", ip);
+ if (strlen(string) == token.len &&
+ strncmp(token.ptr, string, token.len) == 0)
+ {
+ iterator->remove(iterator);
+ ip->destroy(ip);
+ found = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ /* write line untouched back to file */
+ fwrite(orig_line.ptr, orig_line.len, 1, file);
+ fprintf(file, "\n");
+ }
+ }
+ iterator->destroy(iterator);
+ fclose(file);
+}
+
+/**
+ * Implementation of ike_sa_t.add_dns_server
+ */
+static void add_dns_server(private_ike_sa_t *this, host_t *dns)
+{
+ FILE *file;
+ struct stat stats;
+ chunk_t contents;
+
+ DBG1(DBG_IKE, "installing DNS server %H", dns);
+
+ file = fopen(RESOLV_CONF, "a+");
+ if (file == NULL || stat(RESOLV_CONF, &stats) != 0)
+ {
+ DBG1(DBG_IKE, "unable to open DNS configuration file %s: %m", RESOLV_CONF);
+ return;
+ }
+
+ contents = chunk_alloca(stats.st_size);
+
+ if (fread(contents.ptr, 1, contents.len, file) != contents.len)
+ {
+ DBG1(DBG_IKE, "unable to read DNS configuration file: %m");
+ fclose(file);
+ return;
+ }
+
+ fclose(file);
+ file = fopen(RESOLV_CONF, "w");
+ if (file == NULL)
+ {
+ DBG1(DBG_IKE, "unable to open DNS configuration file %s: %m", RESOLV_CONF);
+ return;
+ }
+
+ if (fprintf(file, "nameserver %H # added by strongSwan, assigned by %D\n",
+ dns, this->other_id) < 0)
+ {
+ DBG1(DBG_IKE, "unable to write DNS configuration: %m");
+ }
+ else
+ {
+ this->dns_servers->insert_last(this->dns_servers, dns->clone(dns));
+ }
+ fwrite(contents.ptr, contents.len, 1, file);
+
+ fclose(file);
+}
+
+/**
+ * output handler in printf()
+ */
+static int print(FILE *stream, const struct printf_info *info,
+ const void *const *args)
+{
+ int written = 0;
+ bool reauth = FALSE;
+ private_ike_sa_t *this = *((private_ike_sa_t**)(args[0]));
+
+ if (this->connection)
+ {
+ reauth = this->connection->get_reauth(this->connection);
+ }
+
+ if (this == NULL)
+ {
+ return fprintf(stream, "(null)");
+ }
+
+ written = fprintf(stream, "%12s[%d]: %N, %H[%D]...%H[%D]", get_name(this),
+ this->unique_id, ike_sa_state_names, this->state,
+ this->my_host, this->my_id, this->other_host,
+ this->other_id);
+ written += fprintf(stream, "\n%12s[%d]: IKE SPIs: %J, %s in %ds",
+ get_name(this), this->unique_id, this->ike_sa_id,
+ this->connection && reauth? "reauthentication":"rekeying",
+ this->time.rekey - time(NULL));
+
+ if (info->alt)
+ {
+
+ }
+ return written;
+}
+
+/**
+ * register printf() handlers
+ */
+static void __attribute__ ((constructor))print_register()
+{
+ register_printf_function(PRINTF_IKE_SA, print, arginfo_ptr);
+}
+
+/**
+ * Implementation of ike_sa_t.destroy.
+ */
+static void destroy(private_ike_sa_t *this)
+{
+ this->child_sas->destroy_offset(this->child_sas, offsetof(child_sa_t, destroy));
+
+ DESTROY_IF(this->crypter_in);
+ DESTROY_IF(this->crypter_out);
+ DESTROY_IF(this->signer_in);
+ DESTROY_IF(this->signer_out);
+ DESTROY_IF(this->prf);
+ DESTROY_IF(this->child_prf);
+ DESTROY_IF(this->auth_verify);
+ DESTROY_IF(this->auth_build);
+
+ if (this->my_virtual_ip)
+ {
+ charon->kernel_interface->del_ip(charon->kernel_interface,
+ this->my_virtual_ip, this->my_host);
+ this->my_virtual_ip->destroy(this->my_virtual_ip);
+ }
+ DESTROY_IF(this->other_virtual_ip);
+
+ remove_dns_servers(this);
+ this->dns_servers->destroy_offset(this->dns_servers, offsetof(host_t, destroy));
+
+ DESTROY_IF(this->my_host);
+ DESTROY_IF(this->other_host);
+ DESTROY_IF(this->my_id);
+ DESTROY_IF(this->other_id);
+
+ DESTROY_IF(this->connection);
+ DESTROY_IF(this->policy);
+
+ this->ike_sa_id->destroy(this->ike_sa_id);
+ this->task_manager->destroy(this->task_manager);
+ 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);
+ static u_int32_t unique_id = 0;
+
+ /* Public functions */
+ this->public.get_state = (ike_sa_state_t(*)(ike_sa_t*)) get_state;
+ this->public.set_state = (void(*)(ike_sa_t*,ike_sa_state_t)) set_state;
+ this->public.get_name = (char*(*)(ike_sa_t*))get_name;
+ this->public.process_message = (status_t(*)(ike_sa_t*, message_t*)) process_message;
+ this->public.initiate = (status_t(*)(ike_sa_t*,connection_t*,policy_t*)) initiate;
+ this->public.route = (status_t(*)(ike_sa_t*,connection_t*,policy_t*)) route;
+ this->public.unroute = (status_t(*)(ike_sa_t*,policy_t*)) unroute;
+ this->public.acquire = (status_t(*)(ike_sa_t*,u_int32_t)) acquire;
+ this->public.get_connection = (connection_t*(*)(ike_sa_t*))get_connection;
+ this->public.set_connection = (void(*)(ike_sa_t*,connection_t*))set_connection;
+ this->public.get_policy = (policy_t*(*)(ike_sa_t*))get_policy;
+ this->public.set_policy = (void(*)(ike_sa_t*,policy_t*))set_policy;
+ this->public.get_id = (ike_sa_id_t*(*)(ike_sa_t*)) get_id;
+ this->public.get_my_host = (host_t*(*)(ike_sa_t*)) get_my_host;
+ this->public.set_my_host = (void(*)(ike_sa_t*,host_t*)) set_my_host;
+ this->public.get_other_host = (host_t*(*)(ike_sa_t*)) get_other_host;
+ this->public.set_other_host = (void(*)(ike_sa_t*,host_t*)) set_other_host;
+ this->public.get_my_id = (identification_t*(*)(ike_sa_t*)) get_my_id;
+ this->public.set_my_id = (void(*)(ike_sa_t*,identification_t*)) set_my_id;
+ this->public.get_other_id = (identification_t*(*)(ike_sa_t*)) get_other_id;
+ this->public.set_other_id = (void(*)(ike_sa_t*,identification_t*)) set_other_id;
+ this->public.retransmit = (status_t (*) (ike_sa_t *, u_int32_t)) retransmit;
+ this->public.delete = (status_t(*)(ike_sa_t*))delete_;
+ this->public.destroy = (void(*)(ike_sa_t*))destroy;
+ this->public.send_dpd = (status_t (*)(ike_sa_t*)) send_dpd;
+ this->public.send_keepalive = (void (*)(ike_sa_t*)) send_keepalive;
+ this->public.get_prf = (prf_t *(*) (ike_sa_t *)) get_prf;
+ this->public.get_child_prf = (prf_t *(*) (ike_sa_t *)) get_child_prf;
+ this->public.get_auth_verify = (prf_t *(*) (ike_sa_t *)) get_auth_verify;
+ this->public.get_auth_build = (prf_t *(*) (ike_sa_t *)) get_auth_build;
+ this->public.derive_keys = (status_t (*) (ike_sa_t *,proposal_t*,chunk_t,chunk_t,chunk_t,bool,prf_t*,prf_t*)) derive_keys;
+ this->public.add_child_sa = (void (*) (ike_sa_t*,child_sa_t*)) add_child_sa;
+ this->public.get_child_sa = (child_sa_t* (*)(ike_sa_t*,protocol_id_t,u_int32_t,bool)) get_child_sa;
+ this->public.create_child_sa_iterator = (iterator_t* (*)(ike_sa_t*)) create_child_sa_iterator;
+ this->public.rekey_child_sa = (status_t(*)(ike_sa_t*,protocol_id_t,u_int32_t)) rekey_child_sa;
+ this->public.delete_child_sa = (status_t(*)(ike_sa_t*,protocol_id_t,u_int32_t)) delete_child_sa;
+ this->public.destroy_child_sa = (status_t (*)(ike_sa_t*,protocol_id_t,u_int32_t))destroy_child_sa;
+ this->public.enable_natt = (void(*)(ike_sa_t*, bool)) enable_natt;
+ this->public.is_natt_enabled = (bool(*)(ike_sa_t*)) is_natt_enabled;
+ this->public.rekey = (status_t(*)(ike_sa_t*))rekey;
+ this->public.reestablish = (void(*)(ike_sa_t*))reestablish;
+ this->public.inherit = (status_t(*)(ike_sa_t*,ike_sa_t*))inherit;
+ this->public.generate_message = (status_t(*)(ike_sa_t*,message_t*,packet_t**))generate_message;
+ this->public.reset = (void(*)(ike_sa_t*))reset;
+ this->public.get_unique_id = (u_int32_t(*)(ike_sa_t*))get_unique_id;
+ this->public.set_virtual_ip = (void(*)(ike_sa_t*,bool,host_t*))set_virtual_ip;
+ this->public.get_virtual_ip = (host_t*(*)(ike_sa_t*,bool))get_virtual_ip;
+ this->public.add_dns_server = (void(*)(ike_sa_t*,host_t*))add_dns_server;
+
+ /* initialize private fields */
+ this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
+ this->child_sas = linked_list_create();
+ this->my_host = host_create_any(AF_INET);
+ this->other_host = host_create_any(AF_INET);
+ this->my_id = identification_create_from_encoding(ID_ANY, chunk_empty);
+ this->other_id = identification_create_from_encoding(ID_ANY, chunk_empty);
+ this->crypter_in = NULL;
+ this->crypter_out = NULL;
+ this->signer_in = NULL;
+ this->signer_out = NULL;
+ this->prf = NULL;
+ this->auth_verify = NULL;
+ this->auth_build = NULL;
+ this->child_prf = NULL;
+ this->nat_here = FALSE;
+ this->nat_there = FALSE;
+ this->state = IKE_CREATED;
+ this->time.inbound = this->time.outbound = time(NULL);
+ this->time.established = 0;
+ this->time.rekey = 0;
+ this->time.delete = 0;
+ this->connection = NULL;
+ this->policy = NULL;
+ this->task_manager = task_manager_create(&this->public);
+ this->unique_id = ++unique_id;
+ this->my_virtual_ip = NULL;
+ this->other_virtual_ip = NULL;
+ this->dns_servers = linked_list_create();
+ this->keyingtry = 0;
+
+ return &this->public;
+}
diff --git a/src/charon/sa/ike_sa.h b/src/charon/sa/ike_sa.h
new file mode 100644
index 000000000..604ec94a9
--- /dev/null
+++ b/src/charon/sa/ike_sa.h
@@ -0,0 +1,649 @@
+/**
+ * @file ike_sa.h
+ *
+ * @brief Interface of ike_sa_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef enum ike_sa_state_t ike_sa_state_t;
+typedef struct ike_sa_t ike_sa_t;
+
+#include <library.h>
+#include <encoding/message.h>
+#include <encoding/payloads/proposal_substructure.h>
+#include <sa/ike_sa_id.h>
+#include <sa/child_sa.h>
+#include <sa/tasks/task.h>
+#include <config/configuration.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 <config/proposal.h>
+
+/**
+ * @brief State of an IKE_SA.
+ *
+ * An IKE_SA passes various states in its lifetime. A newly created
+ * SA is in the state CREATED.
+ * @verbatim
+ +----------------+
+ ¦ SA_CREATED ¦
+ +----------------+
+ ¦
+ on initiate()---> ¦ <----- on IKE_SA_INIT received
+ V
+ +----------------+
+ ¦ SA_CONNECTING ¦
+ +----------------+
+ ¦
+ ¦ <----- on IKE_AUTH successfully completed
+ V
+ +----------------+
+ ¦ SA_ESTABLISHED ¦-------------------------+ <-- on rekeying
+ +----------------+ ¦
+ ¦ V
+ on delete()---> ¦ <----- on IKE_SA +-------------+
+ ¦ delete request ¦ SA_REKEYING ¦
+ ¦ received +-------------+
+ V ¦
+ +----------------+ ¦
+ ¦ SA_DELETING ¦<------------------------+ <-- after rekeying
+ +----------------+
+ ¦
+ ¦ <----- after delete() acknowledged
+ ¦
+ \V/
+ X
+ / \
+ @endverbatim
+ *
+ * @ingroup sa
+ */
+enum ike_sa_state_t {
+
+ /**
+ * IKE_SA just got created, but is not initiating nor responding yet.
+ */
+ IKE_CREATED,
+
+ /**
+ * IKE_SA gets initiated actively or passively
+ */
+ IKE_CONNECTING,
+
+ /**
+ * IKE_SA is fully established
+ */
+ IKE_ESTABLISHED,
+
+ /**
+ * IKE_SA rekeying in progress
+ */
+ IKE_REKEYING,
+
+ /**
+ * IKE_SA is in progress of deletion
+ */
+ IKE_DELETING,
+};
+
+/**
+ * enum names for ike_sa_state_t.
+ */
+extern enum_name_t *ike_sa_state_names;
+
+/**
+ * @brief Class ike_sa_t representing an IKE_SA.
+ *
+ * An IKE_SA contains crypto information related to a connection
+ * with a peer. It contains multiple IPsec CHILD_SA, for which
+ * it is responsible. All traffic is handled by an IKE_SA, using
+ * the task manager and its tasks.
+ *
+ * @b Constructors:
+ * - ike_sa_create()
+ *
+ * @ingroup sa
+ */
+struct ike_sa_t {
+
+ /**
+ * @brief Get the id of the SA.
+ *
+ * Returned ike_sa_id_t object is not getting cloned!
+ *
+ * @param this calling object
+ * @return ike_sa's ike_sa_id_t
+ */
+ ike_sa_id_t* (*get_id) (ike_sa_t *this);
+
+ /**
+ * @brief Get the numerical ID uniquely defining this IKE_SA.
+ *
+ * @param this calling object
+ * @return unique ID
+ */
+ u_int32_t (*get_unique_id) (ike_sa_t *this);
+
+ /**
+ * @brief Get the state of the IKE_SA.
+ *
+ * @param this calling object
+ * @return state of the IKE_SA
+ */
+ ike_sa_state_t (*get_state) (ike_sa_t *this);
+
+ /**
+ * @brief Set the state of the IKE_SA.
+ *
+ * @param this calling object
+ * @param state state to set for the IKE_SA
+ */
+ void (*set_state) (ike_sa_t *this, ike_sa_state_t ike_sa);
+
+ /**
+ * @brief Get the name of the connection this IKE_SA uses.
+ *
+ * @param this calling object
+ * @return name
+ */
+ char* (*get_name) (ike_sa_t *this);
+
+ /**
+ * @brief Get the own host address.
+ *
+ * @param this calling object
+ * @return host address
+ */
+ host_t* (*get_my_host) (ike_sa_t *this);
+
+ /**
+ * @brief Set the own host address.
+ *
+ * @param this calling object
+ * @param me host address
+ */
+ void (*set_my_host) (ike_sa_t *this, host_t *me);
+
+ /**
+ * @brief Get the other peers host address.
+ *
+ * @param this calling object
+ * @return host address
+ */
+ host_t* (*get_other_host) (ike_sa_t *this);
+
+ /**
+ * @brief Set the others host address.
+ *
+ * @param this calling object
+ * @param other host address
+ */
+ void (*set_other_host) (ike_sa_t *this, host_t *other);
+
+ /**
+ * @brief Get the own identification.
+ *
+ * @param this calling object
+ * @return identification
+ */
+ identification_t* (*get_my_id) (ike_sa_t *this);
+
+ /**
+ * @brief Set the own identification.
+ *
+ * @param this calling object
+ * @param me identification
+ */
+ void (*set_my_id) (ike_sa_t *this, identification_t *me);
+
+ /**
+ * @brief Get the other peers identification.
+ *
+ * @param this calling object
+ * @return identification
+ */
+ identification_t* (*get_other_id) (ike_sa_t *this);
+
+ /**
+ * @brief Set the other peers identification.
+ *
+ * @param this calling object
+ * @param other identification
+ */
+ void (*set_other_id) (ike_sa_t *this, identification_t *other);
+
+ /**
+ * @brief Get the connection used by this IKE_SA.
+ *
+ * @param this calling object
+ * @return connection
+ */
+ connection_t* (*get_connection) (ike_sa_t *this);
+
+ /**
+ * @brief Set the connection to use with this IKE_SA.
+ *
+ * @param this calling object
+ * @param connection connection to use
+ */
+ void (*set_connection) (ike_sa_t *this, connection_t* connection);
+
+ /**
+ * @brief Get the policy used by this IKE_SA.
+ *
+ * @param this calling object
+ * @return policy
+ */
+ policy_t* (*get_policy) (ike_sa_t *this);
+
+ /**
+ * @brief Set the policy to use with this IKE_SA.
+ *
+ * @param this calling object
+ * @param policy policy to use
+ */
+ void (*set_policy) (ike_sa_t *this, policy_t *policy);
+
+ /**
+ * @brief Initiate a new connection.
+ *
+ * The policy/connection 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
+ * @param policy policy to set up
+ * @return
+ * - SUCCESS if initialization started
+ * - DESTROY_ME if initialization failed and IKE_SA MUST be deleted
+ */
+ status_t (*initiate) (ike_sa_t *this, connection_t *connection, policy_t *policy);
+
+ /**
+ * @brief Route a policy in the kernel.
+ *
+ * Installs the policies in the kernel. If traffic matches,
+ * the kernel requests connection setup from the IKE_SA via acquire().
+ *
+ * @param this calling object
+ * @param connection connection definition used for routing
+ * @param policy policy to route
+ * @return
+ * - SUCCESS if routed successfully
+ * - FAILED if routing failed
+ */
+ status_t (*route) (ike_sa_t *this, connection_t *connection, policy_t *policy);
+
+ /**
+ * @brief Unroute a policy in the kernel previously routed.
+ *
+ * @param this calling object
+ * @param policy policy to route
+ * @return
+ * - SUCCESS if route removed
+ * - DESTROY_ME if last route was removed from
+ * an IKE_SA which was not established
+ */
+ status_t (*unroute) (ike_sa_t *this, policy_t *policy);
+
+ /**
+ * @brief Acquire connection setup for a policy.
+ *
+ * If an installed policy raises an acquire, the kernel calls
+ * this function to establish the CHILD_SA (and maybe the IKE_SA).
+ *
+ * @param this calling object
+ * @param reqid reqid of the CHILD_SA the policy belongs to.
+ * @return
+ * - SUCCESS if initialization started
+ * - DESTROY_ME if initialization failed and IKE_SA MUST be deleted
+ */
+ status_t (*acquire) (ike_sa_t *this, u_int32_t reqid);
+
+ /**
+ * @brief Initiates the deletion of an IKE_SA.
+ *
+ * Sends a delete message to the remote peer and waits for
+ * its response. If the response comes in, or a timeout occurs,
+ * the IKE SA gets deleted.
+ *
+ * @param this calling object
+ * @return
+ * - SUCCESS if deletion is initialized
+ * - INVALID_STATE, if the IKE_SA is not in
+ * an established state and can not be
+ * delete (but destroyed).
+ */
+ status_t (*delete) (ike_sa_t *this);
+
+ /**
+ * @brief Processes a incoming IKEv2-Message.
+ *
+ * Message processing may fail. If a critical failure occurs,
+ * process_message() return DESTROY_ME. Then the caller must
+ * destroy the IKE_SA immediatly, as it is unusable.
+ *
+ * @param this calling object
+ * @param message message to process
+ * @return
+ * - SUCCESS
+ * - FAILED
+ * - DESTROY_ME if this IKE_SA MUST be deleted
+ */
+ status_t (*process_message) (ike_sa_t *this, message_t *message);
+
+ /**
+ * @brief Generate a IKE message to send it to the peer.
+ *
+ * This method generates all payloads in the message and encrypts/signs
+ * the packet.
+ *
+ * @param this calling object
+ * @param message message to generate
+ * @param packet generated output packet
+ * @return
+ * - SUCCESS
+ * - FAILED
+ * - DESTROY_ME if this IKE_SA MUST be deleted
+ */
+ status_t (*generate_message) (ike_sa_t *this, message_t *message,
+ packet_t **packet);
+
+ /**
+ * @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) (ike_sa_t *this, u_int32_t message_id);
+
+ /**
+ * @brief Sends a DPD request to the peer.
+ *
+ * To check if a peer is still alive, periodic
+ * empty INFORMATIONAL messages are sent if no
+ * other traffic was received.
+ *
+ * @param this calling object
+ * @return
+ * - SUCCESS
+ * - DESTROY_ME, if peer did not respond
+ */
+ status_t (*send_dpd) (ike_sa_t *this);
+
+ /**
+ * @brief Sends a keep alive packet.
+ *
+ * To refresh NAT tables in a NAT router
+ * between the peers, periodic empty
+ * UDP packets are sent if no other traffic
+ * was sent.
+ *
+ * @param this calling object
+ */
+ void (*send_keepalive) (ike_sa_t *this);
+
+ /**
+ * @brief Check if NAT traversal is enabled for this IKE_SA.
+ *
+ * @param this calling object
+ * @return TRUE if NAT traversal enabled
+ */
+ bool (*is_natt_enabled) (ike_sa_t *this);
+
+ /**
+ * @brief Enable NAT detection for this IKE_SA.
+ *
+ * If a Network address translation is detected with
+ * NAT_DETECTION notifys, a SA must switch to ports
+ * 4500. To enable this behavior, call enable_natt().
+ * It is relevant which peer is NATted, this is specified
+ * with the "local" parameter. Call it twice when both
+ * are NATted.
+ *
+ * @param this calling object
+ * @param local TRUE, if we are NATted, FALSE if other
+ */
+ void (*enable_natt) (ike_sa_t *this, bool local);
+
+ /**
+ * @brief Derive all keys and create the transforms for IKE communication.
+ *
+ * Keys are derived using the diffie hellman secret, nonces and internal
+ * stored SPIs.
+ * Key derivation differs when an IKE_SA is set up to replace an
+ * existing IKE_SA (rekeying). The SK_d key from the old IKE_SA
+ * is included in the derivation process.
+ *
+ * @param this calling object
+ * @param proposal proposal which contains algorithms to use
+ * @param secret secret derived from DH exchange, gets freed
+ * @param nonce_i initiators nonce
+ * @param nonce_r responders nonce
+ * @param initiator TRUE if initiator, FALSE otherwise
+ * @param child_prf PRF with SK_d key when rekeying, NULL otherwise
+ * @param old_prf general purpose PRF of old SA when rekeying
+ */
+ status_t (*derive_keys)(ike_sa_t *this, proposal_t* proposal, chunk_t secret,
+ chunk_t nonce_i, chunk_t nonce_r,
+ bool initiator, prf_t *child_prf, prf_t *old_prf);
+
+ /**
+ * @brief Get the multi purpose prf.
+ *
+ * @param this calling object
+ * @return pointer to prf_t object
+ */
+ prf_t *(*get_prf) (ike_sa_t *this);
+
+ /**
+ * @brief Get the prf-object, which is used to derive keys for child SAs.
+ *
+ * @param this calling object
+ * @return pointer to prf_t object
+ */
+ prf_t *(*get_child_prf) (ike_sa_t *this);
+
+ /**
+ * @brief Get the prf to build outgoing authentication data.
+ *
+ * @param this calling object
+ * @return pointer to prf_t object
+ */
+ prf_t *(*get_auth_build) (ike_sa_t *this);
+
+ /**
+ * @brief Get the prf to verify incoming authentication data.
+ *
+ * @param this calling object
+ * @return pointer to prf_t object
+ */
+ prf_t *(*get_auth_verify) (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) (ike_sa_t *this, child_sa_t *child_sa);
+
+ /**
+ * @brief Get a CHILD_SA identified by protocol and SPI.
+ *
+ * @param this calling object
+ * @param protocol protocol of the SA
+ * @param spi SPI of the CHILD_SA
+ * @param inbound TRUE if SPI is inbound, FALSE if outbound
+ * @return child_sa, or NULL if none found
+ */
+ child_sa_t* (*get_child_sa) (ike_sa_t *this, protocol_id_t protocol,
+ u_int32_t spi, bool inbound);
+
+ /**
+ * @brief Create an iterator over all CHILD_SAs.
+ *
+ * @param this calling object
+ * @return iterator
+ */
+ iterator_t* (*create_child_sa_iterator) (ike_sa_t *this);
+
+ /**
+ * @brief Rekey the CHILD SA with the specified reqid.
+ *
+ * Looks for a CHILD SA owned by this IKE_SA, and start the rekeing.
+ *
+ * @param this calling object
+ * @param protocol protocol of the SA
+ * @param spi inbound SPI of the CHILD_SA
+ * @return
+ * - NOT_FOUND, if IKE_SA has no such CHILD_SA
+ * - SUCCESS, if rekeying initiated
+ */
+ status_t (*rekey_child_sa) (ike_sa_t *this, protocol_id_t protocol, u_int32_t spi);
+
+ /**
+ * @brief Close the CHILD SA with the specified protocol/SPI.
+ *
+ * Looks for a CHILD SA owned by this IKE_SA, deletes it and
+ * notify's the remote peer about the delete. The associated
+ * states and policies in the kernel get deleted, if they exist.
+ *
+ * @param this calling object
+ * @param protocol protocol of the SA
+ * @param spi inbound SPI of the CHILD_SA
+ * @return
+ * - NOT_FOUND, if IKE_SA has no such CHILD_SA
+ * - SUCCESS, if delete message sent
+ */
+ status_t (*delete_child_sa) (ike_sa_t *this, protocol_id_t protocol, u_int32_t spi);
+
+ /**
+ * @brief Destroy a CHILD SA with the specified protocol/SPI.
+ *
+ * Looks for a CHILD SA owned by this IKE_SA and destroys it.
+ *
+ * @param this calling object
+ * @param protocol protocol of the SA
+ * @param spi inbound SPI of the CHILD_SA
+ * @return
+ * - NOT_FOUND, if IKE_SA has no such CHILD_SA
+ * - SUCCESS
+ */
+ status_t (*destroy_child_sa) (ike_sa_t *this, protocol_id_t protocol, u_int32_t spi);
+
+ /**
+ * @brief Rekey the IKE_SA.
+ *
+ * Sets up a new IKE_SA, moves all CHILDs to it and deletes this IKE_SA.
+ *
+ * @param this calling object
+ * @return - SUCCESS, if IKE_SA rekeying initiated
+ */
+ status_t (*rekey) (ike_sa_t *this);
+
+ /**
+ * @brief Restablish the IKE_SA.
+ *
+ * Create a completely new IKE_SA with authentication, recreates all children
+ * within the IKE_SA, but lets the old IKE_SA untouched.
+ *
+ * @param this calling object
+ */
+ void (*reestablish) (ike_sa_t *this);
+
+ /**
+ * @brief Set the virtual IP to use for this IKE_SA and its children.
+ *
+ * The virtual IP is assigned per IKE_SA, not per CHILD_SA. It has the same
+ * lifetime as the IKE_SA.
+ *
+ * @param this calling object
+ */
+ void (*set_virtual_ip) (ike_sa_t *this, bool local, host_t *ip);
+
+ /**
+ * @brief Get the virtual IP configured.
+ *
+ * @param this calling object
+ * @param local TRUE to get local virtual IP, FALSE for remote
+ */
+ host_t* (*get_virtual_ip) (ike_sa_t *this, bool local);
+
+ /**
+ * @brief Add a DNS server to the system.
+ *
+ * An IRAS may send a DNS server. To use it, it is installed on the
+ * system. The DNS entry has a lifetime until the IKE_SA gets closed.
+ *
+ * @param this calling object
+ * @param dns DNS server to install on the system
+ */
+ void (*add_dns_server) (ike_sa_t *this, host_t *dns);
+
+ /**
+ * @brief Inherit all attributes of other to this after rekeying.
+ *
+ * When rekeying is completed, all CHILD_SAs, the virtual IP and all
+ * outstanding tasks are moved from other to this.
+ * As this call may initiate inherited tasks, a status is returned.
+ *
+ * @param this calling object
+ * @param other other task to inherit from
+ * @return DESTROY_ME if initiation of inherited task failed
+ */
+ status_t (*inherit) (ike_sa_t *this, ike_sa_t *other);
+
+ /**
+ * @brief Reset the IKE_SA, useable when initiating fails
+ *
+ * @param this calling object
+ */
+ void (*reset) (ike_sa_t *this);
+
+ /**
+ * @brief Destroys a ike_sa_t object.
+ *
+ * @param this calling object
+ */
+ void (*destroy) (ike_sa_t *this);
+};
+
+/**
+ * @brief Creates an ike_sa_t object with a specific ID.
+ *
+ * @param ike_sa_id ike_sa_id_t object to associate with new IKE_SA
+ * @return ike_sa_t object
+ *
+ * @ingroup sa
+ */
+ike_sa_t *ike_sa_create(ike_sa_id_t *ike_sa_id);
+
+#endif /* IKE_SA_H_ */
diff --git a/src/charon/sa/ike_sa_id.c b/src/charon/sa/ike_sa_id.c
new file mode 100644
index 000000000..c143fc0ba
--- /dev/null
+++ b/src/charon/sa/ike_sa_id.c
@@ -0,0 +1,215 @@
+/**
+ * @file ike_sa_id.c
+ *
+ * @brief Implementation of ike_sa_id_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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"
+
+#include <printf.h>
+#include <stdio.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);
+}
+
+/**
+ * output handler in printf()
+ */
+static int print(FILE *stream, const struct printf_info *info,
+ const void *const *args)
+{
+ private_ike_sa_id_t *this = *((private_ike_sa_id_t**)(args[0]));
+
+ if (this == NULL)
+ {
+ return fprintf(stream, "(null)");
+ }
+ return fprintf(stream, "0x%0llx_i%s 0x%0llx_r%s",
+ this->initiator_spi,
+ this->is_initiator_flag ? "*" : "",
+ this->responder_spi,
+ this->is_initiator_flag ? "" : "*");
+}
+
+/**
+ * register printf() handlers
+ */
+static void __attribute__ ((constructor))print_register()
+{
+ register_printf_function(PRINTF_IKE_SA_ID, print, arginfo_ptr);
+}
+
+/**
+ * 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/src/charon/sa/ike_sa_id.h b/src/charon/sa/ike_sa_id.h
new file mode 100644
index 000000000..0606b7222
--- /dev/null
+++ b/src/charon/sa/ike_sa_id.h
@@ -0,0 +1,147 @@
+/**
+ * @file ike_sa_id.h
+ *
+ * @brief Interface of ike_sa_id_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct ike_sa_id_t ike_sa_id_t;
+
+#include <library.h>
+
+
+/**
+ * @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/src/charon/sa/ike_sa_manager.c b/src/charon/sa/ike_sa_manager.c
new file mode 100644
index 000000000..791ef805e
--- /dev/null
+++ b/src/charon/sa/ike_sa_manager.c
@@ -0,0 +1,914 @@
+/**
+ * @file ike_sa_manager.c
+ *
+ * @brief Implementation of ike_sa_mananger_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <bus/bus.h>
+#include <utils/linked_list.h>
+
+typedef struct entry_t entry_t;
+
+/**
+ * An entry in the linked list, contains IKE_SA, locking and lookup data.
+ */
+struct entry_t {
+
+ /**
+ * 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;
+
+ /**
+ * hash of the IKE_SA_INIT message, used to detect retransmissions
+ */
+ chunk_t init_hash;
+
+ /**
+ * message ID currently processing, if any
+ */
+ u_int32_t message_id;
+};
+
+/**
+ * Implementation of entry_t.destroy.
+ */
+static status_t entry_destroy(entry_t *this)
+{
+ /* also destroy IKE SA */
+ this->ike_sa->destroy(this->ike_sa);
+ this->ike_sa_id->destroy(this->ike_sa_id);
+ chunk_free(&this->init_hash);
+ free(this);
+ return SUCCESS;
+}
+
+/**
+ * Creates a new entry for the ike_sa_t list.
+ */
+static entry_t *entry_create(ike_sa_id_t *ike_sa_id)
+{
+ entry_t *this = malloc_thing(entry_t);
+
+ 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;
+ this->message_id = -1;
+ this->init_hash = chunk_empty;
+
+ /* 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;
+
+ /**
+ * Lock for exclusivly accessing the manager.
+ */
+ pthread_mutex_t mutex;
+
+ /**
+ * Linked list with entries for the ike_sa_t objects.
+ */
+ linked_list_t *ike_sa_list;
+
+ /**
+ * A randomizer, to get random SPIs for our side
+ */
+ randomizer_t *randomizer;
+
+ /**
+ * SHA1 hasher for IKE_SA_INIT retransmit detection
+ */
+ hasher_t *hasher;
+};
+
+/**
+ * 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, entry_t **entry)
+{
+ linked_list_t *list = this->ike_sa_list;
+ iterator_t *iterator;
+ entry_t *current;
+ status_t status;
+
+ /* create iterator over list of ike_sa's */
+ iterator = list->create_iterator(list, TRUE);
+
+ /* default status */
+ status = NOT_FOUND;
+
+ while (iterator->iterate(iterator, (void**)&current))
+ {
+ if (current->ike_sa_id->equals(current->ike_sa_id, ike_sa_id))
+ {
+ DBG2(DBG_MGR, "found entry by both SPIs");
+ *entry = current;
+ status = SUCCESS;
+ break;
+ }
+ if (ike_sa_id->get_responder_spi(ike_sa_id) == 0 ||
+ 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)) &&
+ (current->ike_sa_id->is_initiator(ike_sa_id) ==
+ ike_sa_id->is_initiator(current->ike_sa_id)))
+ {
+ DBG2(DBG_MGR, "found entry by initiator SPI");
+ *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, entry_t **entry)
+{
+ linked_list_t *list = this->ike_sa_list;
+ iterator_t *iterator;
+ entry_t *current;
+ status_t status;
+
+ iterator = list->create_iterator(list, TRUE);
+
+ /* default status */
+ status = NOT_FOUND;
+
+ while (iterator->iterate(iterator, (void**)&current))
+ {
+ /* only pointers are compared */
+ if (current->ike_sa == ike_sa)
+ {
+ DBG2(DBG_MGR, "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, entry_t *entry)
+{
+ linked_list_t *list = this->ike_sa_list;
+ iterator_t *iterator;
+ entry_t *current;
+ status_t status;
+
+ iterator = list->create_iterator(list, TRUE);
+
+ status = NOT_FOUND;
+
+ while (iterator->iterate(iterator, (void**)&current))
+ {
+ if (current == entry)
+ {
+ /* mark it, so now new threads can get this entry */
+ entry->driveout_new_threads = TRUE;
+ /* wait until all workers have done their work */
+ while (entry->waiting_threads)
+ {
+ /* wake up all */
+ pthread_cond_broadcast(&(entry->condvar));
+ /* they will wake us again when their work is done */
+ pthread_cond_wait(&(entry->condvar), &(this->mutex));
+ }
+
+ DBG2(DBG_MGR, "found entry by pointer, deleting it");
+ iterator->remove(iterator);
+ entry_destroy(entry);
+ status = SUCCESS;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ return status;
+}
+
+/**
+ * Wait until no other thread is using an IKE_SA, return FALSE if entry not
+ * acquireable
+ */
+static bool wait_for_entry(private_ike_sa_manager_t *this, entry_t *entry)
+{
+ if (entry->driveout_new_threads)
+ {
+ /* we are not allowed to get this */
+ return FALSE;
+ }
+ 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, get next one */
+ if (entry->driveout_waiting_threads)
+ {
+ /* we must signal here, others may be waiting on it, too */
+ pthread_cond_signal(&(entry->condvar));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * Implementation of private_ike_sa_manager_t.get_next_spi.
+ */
+static u_int64_t get_next_spi(private_ike_sa_manager_t *this)
+{
+ u_int64_t spi;
+
+ this->randomizer->get_pseudo_random_bytes(this->randomizer, sizeof(spi),
+ (u_int8_t*)&spi);
+ return spi;
+}
+
+/**
+ * Implementation of of ike_sa_manager.checkout.
+ */
+static ike_sa_t* checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
+{
+ ike_sa_t *ike_sa = NULL;
+ entry_t *entry;
+
+ DBG2(DBG_MGR, "checkout IKE_SA: %J, %d IKE_SAs in manager",
+ ike_sa_id, this->ike_sa_list->get_count(this->ike_sa_list));
+
+ pthread_mutex_lock(&(this->mutex));
+ if (get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS)
+ {
+ if (wait_for_entry(this, entry))
+ {
+ DBG2(DBG_MGR, "IKE_SA successfully checked out");
+ entry->checked_out = TRUE;
+ ike_sa = entry->ike_sa;
+ }
+ }
+ pthread_mutex_unlock(&this->mutex);
+ charon->bus->set_sa(charon->bus, ike_sa);
+ return ike_sa;
+}
+
+/**
+ * Implementation of of ike_sa_manager.checkout_new.
+ */
+static ike_sa_t *checkout_new(private_ike_sa_manager_t* this, bool initiator)
+{
+ entry_t *entry;
+ ike_sa_id_t *id;
+
+ if (initiator)
+ {
+ id = ike_sa_id_create(get_next_spi(this), 0, TRUE);
+ }
+ else
+ {
+ id = ike_sa_id_create(0, get_next_spi(this), FALSE);
+ }
+ entry = entry_create(id);
+ pthread_mutex_lock(&this->mutex);
+ this->ike_sa_list->insert_last(this->ike_sa_list, entry);
+ entry->checked_out = TRUE;
+ pthread_mutex_unlock(&this->mutex);
+ DBG2(DBG_MGR, "created IKE_SA: %J, %d IKE_SAs in manager",
+ id, this->ike_sa_list->get_count(this->ike_sa_list));
+ return entry->ike_sa;
+}
+
+/**
+ * Implementation of of ike_sa_manager.checkout_by_id.
+ */
+static ike_sa_t* checkout_by_message(private_ike_sa_manager_t* this,
+ message_t *message)
+{
+ entry_t *entry;
+ ike_sa_t *ike_sa = NULL;
+ ike_sa_id_t *id = message->get_ike_sa_id(message);
+ id = id->clone(id);
+ id->switch_initiator(id);
+
+ DBG2(DBG_MGR, "checkout IKE_SA: %J by message, %d IKE_SAs in manager",
+ id, this->ike_sa_list->get_count(this->ike_sa_list));
+
+ if (message->get_request(message) &&
+ message->get_exchange_type(message) == IKE_SA_INIT)
+ {
+ /* IKE_SA_INIT request. Check for an IKE_SA with such a message hash. */
+ iterator_t *iterator;
+ chunk_t data, hash;
+
+ data = message->get_packet_data(message);
+ this->hasher->allocate_hash(this->hasher, data, &hash);
+ chunk_free(&data);
+
+ pthread_mutex_lock(&this->mutex);
+ iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
+ while (iterator->iterate(iterator, (void**)&entry))
+ {
+ if (chunk_equals(hash, entry->init_hash))
+ {
+ if (entry->message_id == 0)
+ {
+ iterator->destroy(iterator);
+ pthread_mutex_unlock(&this->mutex);
+ chunk_free(&hash);
+ id->destroy(id);
+ DBG1(DBG_MGR, "ignoring IKE_SA_INIT, already processing");
+ return NULL;
+ }
+ else if (wait_for_entry(this, entry))
+ {
+ DBG2(DBG_MGR, "IKE_SA checked out by hash");
+ entry->checked_out = TRUE;
+ entry->message_id = message->get_message_id(message);
+ ike_sa = entry->ike_sa;
+ }
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ pthread_mutex_unlock(&this->mutex);
+
+ if (ike_sa == NULL)
+ {
+ if (id->get_responder_spi(id) == 0 &&
+ message->get_exchange_type(message) == IKE_SA_INIT)
+ {
+ /* no IKE_SA found, create a new one */
+ id->set_responder_spi(id, get_next_spi(this));
+ entry = entry_create(id);
+
+ pthread_mutex_lock(&this->mutex);
+ this->ike_sa_list->insert_last(this->ike_sa_list, entry);
+ entry->checked_out = TRUE;
+ entry->message_id = message->get_message_id(message);
+ pthread_mutex_unlock(&this->mutex);
+ entry->init_hash = hash;
+ ike_sa = entry->ike_sa;
+ }
+ else
+ {
+ DBG1(DBG_MGR, "ignoring message for %J, no such IKE_SA", id);
+ }
+ }
+ else
+ {
+ chunk_free(&hash);
+ }
+ id->destroy(id);
+ charon->bus->set_sa(charon->bus, ike_sa);
+ return ike_sa;
+ }
+
+ pthread_mutex_lock(&(this->mutex));
+ if (get_entry_by_id(this, id, &entry) == SUCCESS)
+ {
+ /* only check out if we are not processing this request */
+ if (message->get_request(message) &&
+ message->get_message_id(message) == entry->message_id)
+ {
+ DBG1(DBG_MGR, "ignoring request with ID %d, already processing",
+ entry->message_id);
+ }
+ else if (wait_for_entry(this, entry))
+ {
+ ike_sa_id_t *ike_id = entry->ike_sa->get_id(entry->ike_sa);
+ DBG2(DBG_MGR, "IKE_SA successfully checked out");
+ entry->checked_out = TRUE;
+ entry->message_id = message->get_message_id(message);
+ if (ike_id->get_responder_spi(ike_id) == 0)
+ {
+ ike_id->set_responder_spi(ike_id, id->get_responder_spi(id));
+ }
+ ike_sa = entry->ike_sa;
+ }
+ }
+ pthread_mutex_unlock(&this->mutex);
+ id->destroy(id);
+ charon->bus->set_sa(charon->bus, ike_sa);
+ return ike_sa;
+}
+
+/**
+ * Implementation of of ike_sa_manager.checkout_by_id.
+ */
+static ike_sa_t* checkout_by_peer(private_ike_sa_manager_t *this,
+ host_t *my_host, host_t *other_host,
+ identification_t *my_id,
+ identification_t *other_id)
+{
+ iterator_t *iterator;
+ entry_t *entry;
+ ike_sa_t *ike_sa = NULL;
+
+ pthread_mutex_lock(&(this->mutex));
+
+ iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
+ while (iterator->iterate(iterator, (void**)&entry))
+ {
+ identification_t *found_my_id, *found_other_id;
+ host_t *found_my_host, *found_other_host;
+ int wc;
+
+ if (!wait_for_entry(this, entry))
+ {
+ continue;
+ }
+
+ if (entry->ike_sa->get_state(entry->ike_sa) == IKE_DELETING)
+ {
+ /* skip IKE_SA which are not useable */
+ continue;
+ }
+
+ found_my_id = entry->ike_sa->get_my_id(entry->ike_sa);
+ found_other_id = entry->ike_sa->get_other_id(entry->ike_sa);
+ found_my_host = entry->ike_sa->get_my_host(entry->ike_sa);
+ found_other_host = entry->ike_sa->get_other_host(entry->ike_sa);
+
+ if (found_my_id->get_type(found_my_id) == ID_ANY &&
+ found_other_id->get_type(found_other_id) == ID_ANY)
+ {
+ /* IKE_SA has no IDs yet, so we can't use it */
+ continue;
+ }
+
+ /* compare ID and hosts. Supplied ID may contain wildcards, and IP
+ * may be %any. */
+ if ((found_my_host->is_anyaddr(found_my_host) ||
+ my_host->ip_equals(my_host, found_my_host)) &&
+ (found_other_host->is_anyaddr(found_other_host) ||
+ other_host->ip_equals(other_host, found_other_host)) &&
+ found_my_id->matches(found_my_id, my_id, &wc) &&
+ found_other_id->matches(found_other_id, other_id, &wc))
+ {
+ /* looks good, we take this one */
+ DBG2(DBG_MGR, "found an existing IKE_SA for %H[%D]...%H[%D]",
+ my_host, other_host, my_id, other_id);
+ entry->checked_out = TRUE;
+ ike_sa = entry->ike_sa;
+ }
+ }
+ iterator->destroy(iterator);
+
+ if (!ike_sa)
+ {
+ u_int64_t initiator_spi;
+ entry_t *new_entry;
+ ike_sa_id_t *new_ike_sa_id;
+
+ initiator_spi = 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_entry = entry_create(new_ike_sa_id);
+ DBG2(DBG_MGR, "created IKE_SA: %J", new_ike_sa_id);
+ new_ike_sa_id->destroy(new_ike_sa_id);
+
+ this->ike_sa_list->insert_last(this->ike_sa_list, new_entry);
+
+ /* check ike_sa out */
+ DBG2(DBG_MGR, "new IKE_SA created for IDs [%D]...[%D]", my_id, other_id);
+ new_entry->checked_out = TRUE;
+ ike_sa = new_entry->ike_sa;
+ }
+ pthread_mutex_unlock(&(this->mutex));
+ charon->bus->set_sa(charon->bus, ike_sa);
+ return ike_sa;
+}
+
+/**
+ * Implementation of of ike_sa_manager.checkout_by_id.
+ */
+static ike_sa_t* checkout_by_id(private_ike_sa_manager_t *this, u_int32_t id,
+ bool child)
+{
+ iterator_t *iterator, *children;
+ entry_t *entry;
+ ike_sa_t *ike_sa = NULL;
+ child_sa_t *child_sa;
+
+ pthread_mutex_lock(&(this->mutex));
+
+ iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
+ while (iterator->iterate(iterator, (void**)&entry))
+ {
+ if (wait_for_entry(this, entry))
+ {
+ /* look for a child with such a reqid ... */
+ if (child)
+ {
+ children = entry->ike_sa->create_child_sa_iterator(entry->ike_sa);
+ while (children->iterate(children, (void**)&child_sa))
+ {
+ if (child_sa->get_reqid(child_sa) == id)
+ {
+ ike_sa = entry->ike_sa;
+ break;
+ }
+ }
+ children->destroy(children);
+ }
+ else /* ... or for a IKE_SA with such a unique id */
+ {
+ if (entry->ike_sa->get_unique_id(entry->ike_sa) == id)
+ {
+ ike_sa = entry->ike_sa;
+ }
+ }
+ /* got one, return */
+ if (ike_sa)
+ {
+ entry->checked_out = TRUE;
+ break;
+ }
+ }
+ }
+ iterator->destroy(iterator);
+ pthread_mutex_unlock(&(this->mutex));
+
+ charon->bus->set_sa(charon->bus, ike_sa);
+ return ike_sa;
+}
+
+/**
+ * Implementation of of ike_sa_manager.checkout_by_name.
+ */
+static ike_sa_t* checkout_by_name(private_ike_sa_manager_t *this, char *name,
+ bool child)
+{
+ iterator_t *iterator, *children;
+ entry_t *entry;
+ ike_sa_t *ike_sa = NULL;
+ child_sa_t *child_sa;
+
+ pthread_mutex_lock(&(this->mutex));
+
+ iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
+ while (iterator->iterate(iterator, (void**)&entry))
+ {
+ if (wait_for_entry(this, entry))
+ {
+ /* look for a child with such a policy name ... */
+ if (child)
+ {
+ children = entry->ike_sa->create_child_sa_iterator(entry->ike_sa);
+ while (children->iterate(children, (void**)&child_sa))
+ {
+ if (streq(child_sa->get_name(child_sa), name))
+ {
+ ike_sa = entry->ike_sa;
+ break;
+ }
+ }
+ children->destroy(children);
+ }
+ else /* ... or for a IKE_SA with such a connection name */
+ {
+ if (streq(entry->ike_sa->get_name(entry->ike_sa), name))
+ {
+ ike_sa = entry->ike_sa;
+ }
+ }
+ /* got one, return */
+ if (ike_sa)
+ {
+ entry->checked_out = TRUE;
+ break;
+ }
+ }
+ }
+ iterator->destroy(iterator);
+ pthread_mutex_unlock(&(this->mutex));
+
+ charon->bus->set_sa(charon->bus, ike_sa);
+ return ike_sa;
+}
+
+/**
+ * Iterator hook for iterate, gets ike_sas instead of entries
+ */
+static bool iterator_hook(private_ike_sa_manager_t* this, entry_t *in,
+ ike_sa_t **out)
+{
+ /* check out entry */
+ if (wait_for_entry(this, in))
+ {
+ *out = in->ike_sa;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * Implementation of ike_sa_manager_t.create_iterator.
+ */
+static iterator_t *create_iterator(private_ike_sa_manager_t* this)
+{
+ iterator_t *iterator = this->ike_sa_list->create_iterator_locked(
+ this->ike_sa_list, &this->mutex);
+ /* register hook to iterator over ike_sas, not entries */
+ iterator->set_iterator_hook(iterator, (iterator_hook_t*)iterator_hook, this);
+ return iterator;
+}
+
+/**
+ * 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;
+ entry_t *entry;
+ ike_sa_id_t *ike_sa_id;
+
+ ike_sa_id = ike_sa->get_id(ike_sa);
+
+ DBG2(DBG_MGR, "checkin IKE_SA: %J", ike_sa_id);
+
+ pthread_mutex_lock(&(this->mutex));
+
+ /* look for the entry */
+ if (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;
+ entry->message_id = -1;
+ DBG2(DBG_MGR, "check-in of IKE_SA successful.");
+ pthread_cond_signal(&(entry->condvar));
+ retval = SUCCESS;
+ }
+ else
+ {
+ DBG2(DBG_MGR, "tried to check in nonexisting IKE_SA");
+ /* this SA is no more, this REALLY should not happen */
+ retval = NOT_FOUND;
+ }
+
+ DBG2(DBG_MGR, "%d IKE_SAs in manager now",
+ this->ike_sa_list->get_count(this->ike_sa_list));
+ pthread_mutex_unlock(&(this->mutex));
+
+ charon->bus->set_sa(charon->bus, NULL);
+ return retval;
+}
+
+
+/**
+ * Implementation of ike_sa_manager_t.checkin_and_destroy.
+ */
+static status_t checkin_and_destroy(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.
+ */
+ entry_t *entry;
+ status_t retval;
+ ike_sa_id_t *ike_sa_id;
+
+ ike_sa_id = ike_sa->get_id(ike_sa);
+ DBG2(DBG_MGR, "checkin and destroy IKE_SA: %J", ike_sa_id);
+
+ pthread_mutex_lock(&(this->mutex));
+
+ if (get_entry_by_sa(this, ike_sa, &entry) == SUCCESS)
+ {
+ /* drive out waiting threads, as we are in hurry */
+ entry->driveout_waiting_threads = TRUE;
+
+ delete_entry(this, entry);
+
+ DBG2(DBG_MGR, "check-in and destroy of IKE_SA successful");
+ retval = SUCCESS;
+ }
+ else
+ {
+ DBG2(DBG_MGR, "tried to check-in and delete nonexisting IKE_SA");
+ retval = NOT_FOUND;
+ }
+
+ pthread_mutex_unlock(&(this->mutex));
+ charon->bus->set_sa(charon->bus, ike_sa);
+ return retval;
+}
+
+/**
+ * Implementation of ike_sa_manager_t.get_half_open_count.
+ */
+static int get_half_open_count(private_ike_sa_manager_t *this, host_t *ip)
+{
+ iterator_t *iterator;
+ entry_t *entry;
+ int count = 0;
+
+ pthread_mutex_lock(&(this->mutex));
+ iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
+ while (iterator->iterate(iterator, (void**)&entry))
+ {
+ /* we check if we have a responder CONNECTING IKE_SA without checkout */
+ if (!entry->ike_sa_id->is_initiator(entry->ike_sa_id) &&
+ entry->ike_sa->get_state(entry->ike_sa) == IKE_CONNECTING)
+ {
+ /* if we have a host, we have wait until no other uses the IKE_SA */
+ if (ip)
+ {
+ if (wait_for_entry(this, entry) && ip->ip_equals(ip,
+ entry->ike_sa->get_other_host(entry->ike_sa)))
+ {
+ count++;
+ }
+ }
+ else
+ {
+ count++;
+ }
+ }
+ }
+ iterator->destroy(iterator);
+
+ pthread_mutex_unlock(&(this->mutex));
+ return count;
+}
+
+/**
+ * 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;
+ entry_t *entry;
+
+ pthread_mutex_lock(&(this->mutex));
+ DBG2(DBG_MGR, "going to destroy IKE_SA manager and all managed IKE_SA's");
+ /* Step 1: drive out all waiting threads */
+ DBG2(DBG_MGR, "set driveout flags for all stored IKE_SA's");
+ iterator = list->create_iterator(list, TRUE);
+ while (iterator->iterate(iterator, (void**)&entry))
+ {
+ /* do not accept new threads, drive out waiting threads */
+ entry->driveout_new_threads = TRUE;
+ entry->driveout_waiting_threads = TRUE;
+ }
+ DBG2(DBG_MGR, "wait for all threads to leave IKE_SA's");
+ /* Step 2: wait until all are gone */
+ iterator->reset(iterator);
+ while (iterator->iterate(iterator, (void**)&entry))
+ {
+ while (entry->waiting_threads)
+ {
+ /* wake up all */
+ pthread_cond_broadcast(&(entry->condvar));
+ /* go sleeping until they are gone */
+ pthread_cond_wait(&(entry->condvar), &(this->mutex));
+ }
+ }
+ DBG2(DBG_MGR, "delete all IKE_SA's");
+ /* Step 3: initiate deletion of all IKE_SAs */
+ iterator->reset(iterator);
+ while (iterator->iterate(iterator, (void**)&entry))
+ {
+ entry->ike_sa->delete(entry->ike_sa);
+ }
+ iterator->destroy(iterator);
+
+ DBG2(DBG_MGR, "destroy all entries");
+ /* Step 4: destroy all entries */
+ list->destroy_function(list, (void*)entry_destroy);
+ pthread_mutex_unlock(&(this->mutex));
+
+ this->randomizer->destroy(this->randomizer);
+ this->hasher->destroy(this->hasher);
+
+ 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.checkout = (ike_sa_t*(*)(ike_sa_manager_t*, ike_sa_id_t*))checkout;
+ this->public.checkout_new = (ike_sa_t*(*)(ike_sa_manager_t*,bool))checkout_new;
+ this->public.checkout_by_message = (ike_sa_t*(*)(ike_sa_manager_t*,message_t*))checkout_by_message;
+ this->public.checkout_by_peer = (ike_sa_t*(*)(ike_sa_manager_t*,host_t*,host_t*,identification_t*,identification_t*))checkout_by_peer;
+ this->public.checkout_by_id = (ike_sa_t*(*)(ike_sa_manager_t*,u_int32_t,bool))checkout_by_id;
+ this->public.checkout_by_name = (ike_sa_t*(*)(ike_sa_manager_t*,char*,bool))checkout_by_name;
+ this->public.create_iterator = (iterator_t*(*)(ike_sa_manager_t*))create_iterator;
+ this->public.checkin = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin;
+ this->public.checkin_and_destroy = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin_and_destroy;
+ this->public.get_half_open_count = (int(*)(ike_sa_manager_t*,host_t*))get_half_open_count;
+
+ /* initialize private variables */
+ this->ike_sa_list = linked_list_create();
+ pthread_mutex_init(&this->mutex, NULL);
+ this->randomizer = randomizer_create();
+ this->hasher = hasher_create(HASH_SHA1);
+
+ return &this->public;
+}
diff --git a/src/charon/sa/ike_sa_manager.h b/src/charon/sa/ike_sa_manager.h
new file mode 100644
index 000000000..1125e5d16
--- /dev/null
+++ b/src/charon/sa/ike_sa_manager.h
@@ -0,0 +1,231 @@
+/**
+ * @file ike_sa_manager.h
+ *
+ * @brief Interface of ike_sa_manager_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct ike_sa_manager_t ike_sa_manager_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <encoding/message.h>
+
+/**
+ * @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 existing IKE_SA.
+ *
+ * @param this the manager object
+ * @param ike_sa_id the SA identifier, will be updated
+ * @returns
+ * - checked out IKE_SA if found
+ * - NULL, if specified IKE_SA is not found.
+ */
+ ike_sa_t* (*checkout) (ike_sa_manager_t* this, ike_sa_id_t *sa_id);
+
+ /**
+ * @brief Create and check out a new IKE_SA.
+ *
+ * @param this the manager object
+ * @param initiator TRUE for initiator, FALSE otherwise
+ * @returns created andchecked out IKE_SA
+ */
+ ike_sa_t* (*checkout_new) (ike_sa_manager_t* this, bool initiator);
+
+ /**
+ * @brief Checkout an IKE_SA by a message.
+ *
+ * In some situations, it is necessary that the manager knows the
+ * message to use for the checkout. This has the folloing reasons:
+ *
+ * 1. If the targeted IKE_SA is already processing a message, we do not
+ * check it out if the message ID is the same.
+ * 2. If it is an IKE_SA_INIT request, we have to check if it is a
+ * retransmission. If so, we have to drop the message, we would
+ * create another unneded IKE_SA for each retransmitted packet.
+ *
+ * A call to checkout_by_message() returns a (maybe new created) IKE_SA.
+ * If processing the message does not make sense (for the reasons above),
+ * NULL is returned.
+ *
+ * @param this the manager object
+ * @param ike_sa_id the SA identifier, will be updated
+ * @returns
+ * - checked out/created IKE_SA
+ * - NULL to not process message further
+ */
+ ike_sa_t* (*checkout_by_message) (ike_sa_manager_t* this, message_t *message);
+
+ /**
+ * @brief Checkout an existing IKE_SA by hosts and identifications.
+ *
+ * Allows the lookup of an IKE_SA by user IDs and hosts. It returns the
+ * first found occurence, if there are multiple candidates. Supplied IDs
+ * may contain wildcards, hosts may be %any.
+ * If no IKE_SA is found, a new one is created. This is also the case when
+ * the found IKE_SA is in the DELETING state.
+ *
+ * @param this the manager object
+ * @param my_host address of our host
+ * @param other_id address of remote host
+ * @param my_id ID used by us
+ * @param other_id ID used by remote
+ * @return checked out/created IKE_SA
+ */
+ ike_sa_t* (*checkout_by_peer) (ike_sa_manager_t* this,
+ host_t *my_host, host_t* other_host,
+ identification_t *my_id,
+ identification_t *other_id);
+
+ /**
+ * @brief Check out an IKE_SA a unique ID.
+ *
+ * Every IKE_SA and every CHILD_SA is uniquely identified by an ID.
+ * These checkout function uses, depending
+ * on the child parameter, the unique ID of the IKE_SA or the reqid
+ * of one of a IKE_SAs CHILD_SA.
+ *
+ * @param this the manager object
+ * @param id unique ID of the object
+ * @param child TRUE to use CHILD, FALSE to use IKE_SA
+ * @return
+ * - checked out IKE_SA, if found
+ * - NULL, if not found
+ */
+ ike_sa_t* (*checkout_by_id) (ike_sa_manager_t* this, u_int32_t id,
+ bool child);
+
+ /**
+ * @brief Check out an IKE_SA by the policy/connection name.
+ *
+ * Check out the IKE_SA by the connections name or by a CHILD_SAs policy
+ * name.
+ *
+ * @param this the manager object
+ * @param name name of the connection/policy
+ * @param child TRUE to use policy name, FALSE to use conn name
+ * @return
+ * - checked out IKE_SA, if found
+ * - NULL, if not found
+ */
+ ike_sa_t* (*checkout_by_name) (ike_sa_manager_t* this, char *name,
+ bool child);
+
+ /**
+ * @brief Create an iterator over all stored IKE_SAs.
+ *
+ * The avoid synchronization issues, the iterator locks access
+ * to the manager exclusively, until it gets destroyed.
+ * This iterator is for reading only! Writing will corrupt the manager.
+ *
+ * @param this the manager object
+ * @return iterator over all IKE_SAs.
+ */
+ iterator_t *(*create_iterator) (ike_sa_manager_t* this);
+
+ /**
+ * @brief Checkin the SA after usage.
+ *
+ * @warning the SA pointer MUST NOT be used after checkin!
+ * The SA must be checked out again!
+ *
+ * @param this the manager object
+ * @param ike_sa_id the SA identifier, will be updated
+ * @param ike_sa checked out SA
+ * @returns
+ * - 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 Destroy a checked out SA.
+ *
+ * The IKE SA is destroyed without notification of the remote peer.
+ * Use this only if the other peer doesn't respond or behaves not
+ * as predicted.
+ * Checking in and destruction is an atomic operation (for the IKE_SA),
+ * so this can be called if the SA is in a "unclean" state, without the
+ * risk that another thread can get the SA.
+ *
+ * @param this the manager object
+ * @param ike_sa SA to delete
+ * @returns
+ * - SUCCESS if found
+ * - NOT_FOUND when no such SA is available
+ */
+ status_t (*checkin_and_destroy) (ike_sa_manager_t* this, ike_sa_t *ike_sa);
+
+ /**
+ * @brief Get the number of IKE_SAs which are in the connecting state.
+ *
+ * To prevent the server from resource exhaustion, cookies and other
+ * mechanisms are used. The number of half open IKE_SAs is a good
+ * indicator to see if a peer is flooding the server.
+ * If a host is supplied, only the number of half open IKE_SAs initiated
+ * from this IP are counted.
+ * Only SAs for which we are the responder are counted.
+ *
+ * @param this the manager object
+ * @param ip NULL for all, IP for half open IKE_SAs with IP
+ * @return number of half open IKE_SAs
+ */
+ int (*get_half_open_count) (ike_sa_manager_t *this, host_t *ip);
+
+ /**
+ * @brief Destroys the manager with all associated SAs.
+ *
+ * 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(void);
+
+#endif /*IKE_SA_MANAGER_H_*/
diff --git a/src/charon/sa/task_manager.c b/src/charon/sa/task_manager.c
new file mode 100644
index 000000000..844300735
--- /dev/null
+++ b/src/charon/sa/task_manager.c
@@ -0,0 +1,854 @@
+/**
+ * @file task_manager.c
+ *
+ * @brief Implementation of task_manager_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 "task_manager.h"
+
+#include <daemon.h>
+#include <sa/tasks/ike_init.h>
+#include <sa/tasks/ike_natd.h>
+#include <sa/tasks/ike_auth.h>
+#include <sa/tasks/ike_cert.h>
+#include <sa/tasks/ike_rekey.h>
+#include <sa/tasks/ike_delete.h>
+#include <sa/tasks/ike_config.h>
+#include <sa/tasks/ike_dpd.h>
+#include <sa/tasks/child_create.h>
+#include <sa/tasks/child_rekey.h>
+#include <sa/tasks/child_delete.h>
+#include <encoding/payloads/delete_payload.h>
+#include <queues/jobs/retransmit_job.h>
+
+typedef struct exchange_t exchange_t;
+
+/**
+ * An exchange in the air, used do detect and handle retransmission
+ */
+struct exchange_t {
+
+ /**
+ * Message ID used for this transaction
+ */
+ u_int32_t mid;
+
+ /**
+ * generated packet for retransmission
+ */
+ packet_t *packet;
+};
+
+typedef struct private_task_manager_t private_task_manager_t;
+
+/**
+ * private data of the task manager
+ */
+struct private_task_manager_t {
+
+ /**
+ * public functions
+ */
+ task_manager_t public;
+
+ /**
+ * associated IKE_SA we are serving
+ */
+ ike_sa_t *ike_sa;
+
+ /**
+ * Exchange we are currently handling as responder
+ */
+ struct {
+ /**
+ * Message ID of the exchange
+ */
+ u_int32_t mid;
+
+ /**
+ * packet for retransmission
+ */
+ packet_t *packet;
+
+ } responding;
+
+ /**
+ * Exchange we are currently handling as initiator
+ */
+ struct {
+ /**
+ * Message ID of the exchange
+ */
+ u_int32_t mid;
+
+ /**
+ * how many times we have retransmitted so far
+ */
+ u_int retransmitted;
+
+ /**
+ * packet for retransmission
+ */
+ packet_t *packet;
+
+ /**
+ * type of the initated exchange
+ */
+ exchange_type_t type;
+
+ } initiating;
+
+ /**
+ * List of queued tasks not yet in action
+ */
+ linked_list_t *queued_tasks;
+
+ /**
+ * List of active tasks, initiated by ourselve
+ */
+ linked_list_t *active_tasks;
+
+ /**
+ * List of tasks initiated by peer
+ */
+ linked_list_t *passive_tasks;
+};
+
+/**
+ * flush all tasks in the task manager
+ */
+static void flush(private_task_manager_t *this)
+{
+ task_t *task;
+
+ this->queued_tasks->destroy_offset(this->queued_tasks,
+ offsetof(task_t, destroy));
+ this->passive_tasks->destroy_offset(this->passive_tasks,
+ offsetof(task_t, destroy));
+
+ /* emmit outstanding signals for tasks */
+ while (this->active_tasks->remove_last(this->active_tasks,
+ (void**)&task) == SUCCESS)
+ {
+ switch (task->get_type(task))
+ {
+ case IKE_AUTH:
+ SIG(IKE_UP_FAILED, "establishing IKE_SA failed");
+ break;
+ case IKE_DELETE:
+ SIG(IKE_DOWN_FAILED, "IKE_SA deleted");
+ break;
+ case IKE_REKEY:
+ SIG(IKE_REKEY_FAILED, "rekeying IKE_SA failed");
+ break;
+ case CHILD_CREATE:
+ SIG(CHILD_UP_FAILED, "establishing CHILD_SA failed");
+ break;
+ case CHILD_DELETE:
+ SIG(CHILD_DOWN_FAILED, "deleting CHILD_SA failed");
+ break;
+ case CHILD_REKEY:
+ SIG(IKE_REKEY_FAILED, "rekeying CHILD_SA failed");
+ break;
+ default:
+ break;
+ }
+ task->destroy(task);
+ }
+ this->queued_tasks = linked_list_create();
+ this->passive_tasks = linked_list_create();
+}
+
+/**
+ * move a task of a specific type from the queue to the active list
+ */
+static bool activate_task(private_task_manager_t *this, task_type_t type)
+{
+ iterator_t *iterator;
+ task_t *task;
+ bool found = FALSE;
+
+ iterator = this->queued_tasks->create_iterator(this->queued_tasks, TRUE);
+ while (iterator->iterate(iterator, (void**)&task))
+ {
+ if (task->get_type(task) == type)
+ {
+ DBG2(DBG_IKE, " activating %N task", task_type_names, type);
+ iterator->remove(iterator);
+ this->active_tasks->insert_last(this->active_tasks, task);
+ found = TRUE;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ return found;
+}
+
+/**
+ * Implementation of task_manager_t.retransmit
+ */
+static status_t retransmit(private_task_manager_t *this, u_int32_t message_id)
+{
+ if (message_id == this->initiating.mid)
+ {
+ u_int32_t timeout;
+ job_t *job;
+
+ timeout = charon->configuration->get_retransmit_timeout(
+ charon->configuration, this->initiating.retransmitted);
+ if (timeout == 0)
+ {
+ DBG1(DBG_IKE, "giving up after %d retransmits",
+ this->initiating.retransmitted - 1);
+ return DESTROY_ME;
+ }
+
+ if (this->initiating.retransmitted)
+ {
+ DBG1(DBG_IKE, "retransmit %d of request with message ID %d",
+ this->initiating.retransmitted, message_id);
+ }
+ this->initiating.retransmitted++;
+
+ charon->sender->send(charon->sender,
+ this->initiating.packet->clone(this->initiating.packet));
+ job = (job_t*)retransmit_job_create(this->initiating.mid,
+ this->ike_sa->get_id(this->ike_sa));
+ charon->event_queue->add_relative(charon->event_queue, job, timeout);
+ }
+ return SUCCESS;
+}
+
+/**
+ * build a request using the active task list
+ * Implementation of task_manager_t.initiate
+ */
+static status_t build_request(private_task_manager_t *this)
+{
+ iterator_t *iterator;
+ task_t *task;
+ message_t *message;
+ status_t status;
+ exchange_type_t exchange = 0;
+
+ if (this->initiating.type != EXCHANGE_TYPE_UNDEFINED)
+ {
+ DBG2(DBG_IKE, "delaying task initiation, exchange in progress");
+ /* do not initiate if we already have a message in the air */
+ return SUCCESS;
+ }
+
+ if (this->active_tasks->get_count(this->active_tasks) == 0)
+ {
+ DBG2(DBG_IKE, "activating new tasks");
+ switch (this->ike_sa->get_state(this->ike_sa))
+ {
+ case IKE_CREATED:
+ if (activate_task(this, IKE_INIT))
+ {
+ exchange = IKE_SA_INIT;
+ activate_task(this, IKE_NATD);
+ activate_task(this, IKE_CERT);
+ activate_task(this, IKE_AUTHENTICATE);
+ activate_task(this, IKE_CONFIG);
+ activate_task(this, CHILD_CREATE);
+ }
+ break;
+ case IKE_ESTABLISHED:
+ if (activate_task(this, CHILD_CREATE))
+ {
+ exchange = CREATE_CHILD_SA;
+ activate_task(this, IKE_CONFIG);
+ break;
+ }
+ if (activate_task(this, CHILD_DELETE))
+ {
+ exchange = INFORMATIONAL;
+ break;
+ }
+ if (activate_task(this, CHILD_REKEY))
+ {
+ exchange = CREATE_CHILD_SA;
+ break;
+ }
+ if (activate_task(this, IKE_DELETE))
+ {
+ exchange = INFORMATIONAL;
+ break;
+ }
+ if (activate_task(this, IKE_REKEY))
+ {
+ exchange = CREATE_CHILD_SA;
+ break;
+ }
+ if (activate_task(this, IKE_DEADPEER))
+ {
+ exchange = INFORMATIONAL;
+ break;
+ }
+ case IKE_REKEYING:
+ if (activate_task(this, IKE_DELETE))
+ {
+ exchange = INFORMATIONAL;
+ break;
+ }
+ case IKE_DELETING:
+ default:
+ break;
+ }
+ }
+ else
+ {
+ DBG2(DBG_IKE, "reinitiating already active tasks");
+ iterator = this->active_tasks->create_iterator(this->active_tasks, TRUE);
+ while (iterator->iterate(iterator, (void**)&task))
+ {
+ DBG2(DBG_IKE, " %N task", task_type_names, task->get_type(task));
+ switch (task->get_type(task))
+ {
+ case IKE_INIT:
+ exchange = IKE_SA_INIT;
+ break;
+ case IKE_AUTHENTICATE:
+ exchange = IKE_AUTH;
+ break;
+ default:
+ continue;
+ }
+ break;
+ }
+ iterator->destroy(iterator);
+ }
+
+ if (exchange == 0)
+ {
+ DBG2(DBG_IKE, "nothing to initiate");
+ /* nothing to do yet... */
+ return SUCCESS;
+ }
+
+ message = message_create();
+ message->set_message_id(message, this->initiating.mid);
+ message->set_exchange_type(message, exchange);
+ this->initiating.type = exchange;
+ this->initiating.retransmitted = 0;
+
+ iterator = this->active_tasks->create_iterator(this->active_tasks, TRUE);
+ while (iterator->iterate(iterator, (void*)&task))
+ {
+ switch (task->build(task, message))
+ {
+ case SUCCESS:
+ /* task completed, remove it */
+ iterator->remove(iterator);
+ task->destroy(task);
+ break;
+ case NEED_MORE:
+ /* processed, but task needs another exchange */
+ break;
+ case FAILED:
+ default:
+ /* critical failure, destroy IKE_SA */
+ iterator->destroy(iterator);
+ message->destroy(message);
+ flush(this);
+ return DESTROY_ME;
+ }
+ }
+ iterator->destroy(iterator);
+
+ DESTROY_IF(this->initiating.packet);
+ status = this->ike_sa->generate_message(this->ike_sa, message,
+ &this->initiating.packet);
+ message->destroy(message);
+ if (status != SUCCESS)
+ {
+ /* message generation failed. There is nothing more to do than to
+ * close the SA */
+ flush(this);
+ return DESTROY_ME;
+ }
+
+ return retransmit(this, this->initiating.mid);
+}
+
+/**
+ * handle an incoming response message
+ */
+static status_t process_response(private_task_manager_t *this,
+ message_t *message)
+{
+ iterator_t *iterator;
+ task_t *task;
+
+ if (message->get_exchange_type(message) != this->initiating.type)
+ {
+ DBG1(DBG_IKE, "received %N response, but expected %N",
+ exchange_type_names, message->get_exchange_type(message),
+ exchange_type_names, this->initiating.type);
+ return DESTROY_ME;
+ }
+
+ iterator = this->active_tasks->create_iterator(this->active_tasks, TRUE);
+ while (iterator->iterate(iterator, (void*)&task))
+ {
+ switch (task->process(task, message))
+ {
+ case SUCCESS:
+ /* task completed, remove it */
+ iterator->remove(iterator);
+ task->destroy(task);
+ break;
+ case NEED_MORE:
+ /* processed, but task needs another exchange */
+ break;
+ case FAILED:
+ default:
+ /* critical failure, destroy IKE_SA */
+ iterator->destroy(iterator);
+ return DESTROY_ME;
+ }
+ }
+ iterator->destroy(iterator);
+
+ this->initiating.mid++;
+ this->initiating.type = EXCHANGE_TYPE_UNDEFINED;
+
+ return build_request(this);
+}
+
+/**
+ * handle exchange collisions
+ */
+static void handle_collisions(private_task_manager_t *this, task_t *task)
+{
+ iterator_t *iterator;
+ task_t *active;
+ task_type_t type;
+
+ type = task->get_type(task);
+
+ /* do we have to check */
+ if (type == IKE_REKEY || type == CHILD_REKEY ||
+ type == CHILD_DELETE || type == IKE_DELETE)
+ {
+ /* find an exchange collision, and notify these tasks */
+ iterator = this->active_tasks->create_iterator(this->active_tasks, TRUE);
+ while (iterator->iterate(iterator, (void**)&active))
+ {
+ switch (active->get_type(active))
+ {
+ case IKE_REKEY:
+ if (type == IKE_REKEY || type == IKE_DELETE)
+ {
+ ike_rekey_t *rekey = (ike_rekey_t*)active;
+ rekey->collide(rekey, task);
+ break;
+ }
+ continue;
+ case CHILD_REKEY:
+ if (type == CHILD_REKEY || type == CHILD_DELETE)
+ {
+ child_rekey_t *rekey = (child_rekey_t*)active;
+ rekey->collide(rekey, task);
+ break;
+ }
+ continue;
+ default:
+ continue;
+ }
+ iterator->destroy(iterator);
+ return;
+ }
+ iterator->destroy(iterator);
+ }
+ /* destroy task if not registered in any active task */
+ task->destroy(task);
+}
+
+/**
+ * build a response depending on the "passive" task list
+ */
+static status_t build_response(private_task_manager_t *this,
+ exchange_type_t exchange)
+{
+ iterator_t *iterator;
+ task_t *task;
+ message_t *message;
+ bool delete = FALSE;
+ status_t status;
+
+ message = message_create();
+ message->set_exchange_type(message, exchange);
+ message->set_message_id(message, this->responding.mid);
+ message->set_request(message, FALSE);
+
+ iterator = this->passive_tasks->create_iterator(this->passive_tasks, TRUE);
+ while (iterator->iterate(iterator, (void*)&task))
+ {
+ switch (task->build(task, message))
+ {
+ case SUCCESS:
+ /* task completed, remove it */
+ iterator->remove(iterator);
+ handle_collisions(this, task);
+ case NEED_MORE:
+ /* processed, but task needs another exchange */
+ break;
+ case FAILED:
+ default:
+ /* destroy IKE_SA, but SEND response first */
+ delete = TRUE;
+ break;
+ }
+ if (delete)
+ {
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+
+ /* remove resonder SPI if IKE_SA_INIT failed */
+ if (delete && exchange == IKE_SA_INIT)
+ {
+ ike_sa_id_t *id = this->ike_sa->get_id(this->ike_sa);
+ id->set_responder_spi(id, 0);
+ }
+
+ /* message complete, send it */
+ DESTROY_IF(this->responding.packet);
+ status = this->ike_sa->generate_message(this->ike_sa, message,
+ &this->responding.packet);
+ message->destroy(message);
+ if (status != SUCCESS)
+ {
+ return DESTROY_ME;
+ }
+
+ charon->sender->send(charon->sender,
+ this->responding.packet->clone(this->responding.packet));
+ if (delete)
+ {
+ return DESTROY_ME;
+ }
+ return SUCCESS;
+}
+
+/**
+ * handle an incoming request message
+ */
+static status_t process_request(private_task_manager_t *this,
+ message_t *message)
+{
+ iterator_t *iterator;
+ task_t *task = NULL;
+ exchange_type_t exchange;
+ payload_t *payload;
+ notify_payload_t *notify;
+
+ exchange = message->get_exchange_type(message);
+
+ /* create tasks depending on request type */
+ switch (exchange)
+ {
+ case IKE_SA_INIT:
+ {
+ task = (task_t*)ike_init_create(this->ike_sa, FALSE, NULL);
+ this->passive_tasks->insert_last(this->passive_tasks, task);
+ task = (task_t*)ike_natd_create(this->ike_sa, FALSE);
+ this->passive_tasks->insert_last(this->passive_tasks, task);
+ task = (task_t*)ike_cert_create(this->ike_sa, FALSE);
+ this->passive_tasks->insert_last(this->passive_tasks, task);
+ task = (task_t*)ike_auth_create(this->ike_sa, FALSE);
+ this->passive_tasks->insert_last(this->passive_tasks, task);
+ task = (task_t*)ike_config_create(this->ike_sa, NULL);
+ this->passive_tasks->insert_last(this->passive_tasks, task);
+ task = (task_t*)child_create_create(this->ike_sa, NULL);
+ this->passive_tasks->insert_last(this->passive_tasks, task);
+ break;
+ }
+ case CREATE_CHILD_SA:
+ {
+ bool notify_found = FALSE, ts_found = FALSE;
+ iterator = message->get_payload_iterator(message);
+ while (iterator->iterate(iterator, (void**)&payload))
+ {
+ switch (payload->get_type(payload))
+ {
+ case NOTIFY:
+ {
+ /* if we find a rekey notify, its CHILD_SA rekeying */
+ notify = (notify_payload_t*)payload;
+ if (notify->get_notify_type(notify) == REKEY_SA &&
+ (notify->get_protocol_id(notify) == PROTO_AH ||
+ notify->get_protocol_id(notify) == PROTO_ESP))
+ {
+ notify_found = TRUE;
+ }
+ break;
+ }
+ case TRAFFIC_SELECTOR_INITIATOR:
+ case TRAFFIC_SELECTOR_RESPONDER:
+ {
+ /* if we don't find a TS, its IKE rekeying */
+ ts_found = TRUE;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+
+ if (ts_found)
+ {
+ if (notify_found)
+ {
+ task = (task_t*)child_rekey_create(this->ike_sa, NULL);
+ }
+ else
+ {
+ task = (task_t*)child_create_create(this->ike_sa, NULL);
+ }
+ }
+ else
+ {
+ task = (task_t*)ike_rekey_create(this->ike_sa, FALSE);
+ }
+ this->passive_tasks->insert_last(this->passive_tasks, task);
+ break;
+ }
+ case INFORMATIONAL:
+ {
+ delete_payload_t *delete;
+
+ delete = (delete_payload_t*)message->get_payload(message, DELETE);
+ if (delete)
+ {
+ if (delete->get_protocol_id(delete) == PROTO_IKE)
+ {
+ task = (task_t*)ike_delete_create(this->ike_sa, FALSE);
+ this->passive_tasks->insert_last(this->passive_tasks, task);
+ }
+ else
+ {
+ task = (task_t*)child_delete_create(this->ike_sa, NULL);
+ this->passive_tasks->insert_last(this->passive_tasks, task);
+ }
+ }
+ else
+ {
+ task = (task_t*)ike_dpd_create(FALSE);
+ this->passive_tasks->insert_last(this->passive_tasks, task);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ /* let the tasks process the message */
+ iterator = this->passive_tasks->create_iterator(this->passive_tasks, TRUE);
+ while (iterator->iterate(iterator, (void*)&task))
+ {
+ switch (task->process(task, message))
+ {
+ case SUCCESS:
+ /* task completed, remove it */
+ iterator->remove(iterator);
+ task->destroy(task);
+ break;
+ case NEED_MORE:
+ /* processed, but task needs at least another call to build() */
+ break;
+ case FAILED:
+ default:
+ /* critical failure, destroy IKE_SA */
+ iterator->destroy(iterator);
+ return DESTROY_ME;
+ }
+ }
+ iterator->destroy(iterator);
+
+ return build_response(this, exchange);
+}
+
+/**
+ * Implementation of task_manager_t.process_message
+ */
+static status_t process_message(private_task_manager_t *this, message_t *msg)
+{
+ u_int32_t mid = msg->get_message_id(msg);
+
+ if (msg->get_request(msg))
+ {
+ if (mid == this->responding.mid)
+ {
+ if (process_request(this, msg) != SUCCESS)
+ {
+ flush(this);
+ return DESTROY_ME;
+ }
+ this->responding.mid++;
+ }
+ else if ((mid == this->responding.mid - 1) && this->responding.packet)
+ {
+ DBG1(DBG_IKE, "received retransmit of request with ID %d, "
+ "retransmitting response", mid);
+ charon->sender->send(charon->sender,
+ this->responding.packet->clone(this->responding.packet));
+ }
+ else
+ {
+ DBG1(DBG_IKE, "received message ID %d, excepted %d. Ignored",
+ mid, this->responding.mid);
+ }
+ }
+ else
+ {
+ if (mid == this->initiating.mid)
+ {
+ if (process_response(this, msg) != SUCCESS)
+ {
+ flush(this);
+ return DESTROY_ME;
+ }
+ }
+ else
+ {
+ DBG1(DBG_IKE, "received message ID %d, excepted %d. Ignored",
+ mid, this->initiating.mid);
+ return SUCCESS;
+ }
+ }
+ return SUCCESS;
+}
+
+/**
+ * Implementation of task_manager_t.queue_task
+ */
+static void queue_task(private_task_manager_t *this, task_t *task)
+{
+ DBG2(DBG_IKE, "queueing %N task", task_type_names, task->get_type(task));
+ this->queued_tasks->insert_last(this->queued_tasks, task);
+}
+
+/**
+ * Implementation of task_manager_t.adopt_tasks
+ */
+static void adopt_tasks(private_task_manager_t *this, private_task_manager_t *other)
+{
+ task_t *task;
+
+ /* move queued tasks from other to this */
+ while (other->queued_tasks->remove_last(other->queued_tasks,
+ (void**)&task) == SUCCESS)
+ {
+ DBG2(DBG_IKE, "migrating %N task", task_type_names, task->get_type(task));
+ task->migrate(task, this->ike_sa);
+ this->queued_tasks->insert_first(this->queued_tasks, task);
+ }
+
+ /* reset active tasks and move them to others queued tasks */
+ while (other->active_tasks->remove_last(other->active_tasks,
+ (void**)&task) == SUCCESS)
+ {
+ DBG2(DBG_IKE, "migrating %N task", task_type_names, task->get_type(task));
+ task->migrate(task, this->ike_sa);
+ this->queued_tasks->insert_first(this->queued_tasks, task);
+ }
+}
+
+/**
+ * Implementation of task_manager_t.busy
+ */
+static bool busy(private_task_manager_t *this)
+{
+ return (this->active_tasks->get_count(this->active_tasks) > 0);
+}
+
+/**
+ * Implementation of task_manager_t.reset
+ */
+static void reset(private_task_manager_t *this)
+{
+ task_t *task;
+
+ /* reset message counters and retransmit packets */
+ DESTROY_IF(this->responding.packet);
+ DESTROY_IF(this->initiating.packet);
+ this->responding.packet = NULL;
+ this->initiating.packet = NULL;
+ this->responding.mid = 0;
+ this->initiating.mid = -1;
+ this->initiating.type = EXCHANGE_TYPE_UNDEFINED;
+
+ /* reset active tasks */
+ while (this->active_tasks->remove_last(this->active_tasks,
+ (void**)&task) == SUCCESS)
+ {
+ task->migrate(task, this->ike_sa);
+ this->queued_tasks->insert_first(this->queued_tasks, task);
+ }
+}
+
+/**
+ * Implementation of task_manager_t.destroy
+ */
+static void destroy(private_task_manager_t *this)
+{
+ flush(this);
+
+ this->active_tasks->destroy(this->active_tasks);
+ this->queued_tasks->destroy(this->queued_tasks);
+ this->passive_tasks->destroy(this->passive_tasks);
+
+ DESTROY_IF(this->responding.packet);
+ DESTROY_IF(this->initiating.packet);
+ free(this);
+}
+
+/*
+ * see header file
+ */
+task_manager_t *task_manager_create(ike_sa_t *ike_sa)
+{
+ private_task_manager_t *this = malloc_thing(private_task_manager_t);
+
+ this->public.process_message = (status_t(*)(task_manager_t*,message_t*))process_message;
+ this->public.queue_task = (void(*)(task_manager_t*,task_t*))queue_task;
+ this->public.initiate = (status_t(*)(task_manager_t*))build_request;
+ this->public.retransmit = (status_t(*)(task_manager_t*,u_int32_t))retransmit;
+ this->public.reset = (void(*)(task_manager_t*))reset;
+ this->public.adopt_tasks = (void(*)(task_manager_t*,task_manager_t*))adopt_tasks;
+ this->public.busy = (bool(*)(task_manager_t*))busy;
+ this->public.destroy = (void(*)(task_manager_t*))destroy;
+
+ this->ike_sa = ike_sa;
+ this->responding.packet = NULL;
+ this->initiating.packet = NULL;
+ this->responding.mid = 0;
+ this->initiating.mid = 0;
+ this->initiating.type = EXCHANGE_TYPE_UNDEFINED;
+ this->queued_tasks = linked_list_create();
+ this->active_tasks = linked_list_create();
+ this->passive_tasks = linked_list_create();
+
+ return &this->public;
+}
diff --git a/src/charon/sa/task_manager.h b/src/charon/sa/task_manager.h
new file mode 100644
index 000000000..c766d4a65
--- /dev/null
+++ b/src/charon/sa/task_manager.h
@@ -0,0 +1,144 @@
+/**
+ * @file task_manager.h
+ *
+ * @brief Interface of task_manager_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 TASK_MANAGER_H_
+#define TASK_MANAGER_H_
+
+typedef struct task_manager_t task_manager_t;
+
+#include <library.h>
+#include <encoding/message.h>
+#include <sa/ike_sa.h>
+#include <sa/tasks/task.h>
+
+/**
+ * @brief The task manager, juggles task and handles message exchanges.
+ *
+ * On incoming requests, the task manager creates new tasks on demand and
+ * juggles the request through all available tasks. Each task inspects the
+ * request and adds payloads as necessary to the response.
+ * On outgoing requests, the task manager delivers the request through the tasks
+ * to build it, the response gets processed by each task to complete.
+ * The task manager has an internal Queue to store task which should get
+ * completed.
+ * For the initial IKE_SA setup, several tasks are queued: One for the
+ * unauthenticated IKE_SA setup, one for authentication, one for CHILD_SA setup
+ * and maybe one for virtual IP assignement.
+ *
+ * @b Constructors:
+ * - task_manager_create()
+ *
+ * @ingroup sa
+ */
+struct task_manager_t {
+
+ /**
+ * @brief Process an incoming message.
+ *
+ * @param this calling object
+ * @param message message to add payloads to
+ * @return
+ * - DESTROY_ME if IKE_SA must be closed
+ * - SUCCESS otherwise
+ */
+ status_t (*process_message) (task_manager_t *this, message_t *message);
+
+ /**
+ * @brief Initiate an exchange with the currently queued tasks.
+ *
+ * @param this calling object
+ */
+ status_t (*initiate) (task_manager_t *this);
+
+ /**
+ * @brief Queue a task in the manager.
+ *
+ * @param this calling object
+ * @param task task to queue
+ */
+ void (*queue_task) (task_manager_t *this, task_t *task);
+
+ /**
+ * @brief Retransmit a request if it hasn't been acknowledged yet.
+ *
+ * A return value of INVALID_STATE means that the message was already
+ * acknowledged and has not to be retransmitted. A return value of SUCCESS
+ * means retransmission was required and the message has been resent.
+ *
+ * @param this calling object
+ * @param message_id ID of the message to retransmit
+ * @return
+ * - INVALID_STATE if retransmission not required
+ * - SUCCESS if retransmission sent
+ */
+ status_t (*retransmit) (task_manager_t *this, u_int32_t message_id);
+
+ /**
+ * @brief Migrate all tasks from other to this.
+ *
+ * To rekey or reestablish an IKE_SA completely, all queued or active
+ * tasks should get migrated to the new IKE_SA.
+ *
+ * @param this manager which gets all tasks
+ * @param other manager which gives away its tasks
+ */
+ void (*adopt_tasks) (task_manager_t *this, task_manager_t *other);
+
+ /**
+ * @brief Reset message ID counters of the task manager.
+ *
+ * The IKEv2 protocol requires to restart exchanges with message IDs
+ * reset to zero (INVALID_KE_PAYLOAD, COOKIES, ...). The reset() method
+ * resets the message IDs and resets all active tasks using the migrate()
+ * method.
+ *
+ * @param this calling object
+ * @param other manager which gives away its tasks
+ */
+ void (*reset) (task_manager_t *this);
+
+ /**
+ * @brief Check if we are currently waiting for a reply.
+ *
+ * @param this calling object
+ * @return TRUE if we are waiting, FALSE otherwise
+ */
+ bool (*busy) (task_manager_t *this);
+
+ /**
+ * @brief Destroy the task_manager_t.
+ *
+ * @param this calling object
+ */
+ void (*destroy) (task_manager_t *this);
+};
+
+/**
+ * @brief Create an instance of the task manager.
+ *
+ * @param ike_sa IKE_SA to manage.
+ *
+ * @ingroup sa
+ */
+task_manager_t *task_manager_create(ike_sa_t *ike_sa);
+
+#endif /* TASK_MANAGER_H_ */
diff --git a/src/charon/sa/tasks/child_create.c b/src/charon/sa/tasks/child_create.c
new file mode 100644
index 000000000..781d679f2
--- /dev/null
+++ b/src/charon/sa/tasks/child_create.c
@@ -0,0 +1,804 @@
+/**
+ * @file child_create.c
+ *
+ * @brief Implementation of the child_create task.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2007 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_create.h"
+
+#include <daemon.h>
+#include <crypto/diffie_hellman.h>
+#include <encoding/payloads/sa_payload.h>
+#include <encoding/payloads/ts_payload.h>
+#include <encoding/payloads/nonce_payload.h>
+#include <encoding/payloads/notify_payload.h>
+
+
+typedef struct private_child_create_t private_child_create_t;
+
+/**
+ * Private members of a child_create_t task.
+ */
+struct private_child_create_t {
+
+ /**
+ * Public methods and task_t interface.
+ */
+ child_create_t public;
+
+ /**
+ * Assigned IKE_SA.
+ */
+ ike_sa_t *ike_sa;
+
+ /**
+ * Are we the initiator?
+ */
+ bool initiator;
+
+ /**
+ * nonce chosen by us
+ */
+ chunk_t my_nonce;
+
+ /**
+ * nonce chosen by peer
+ */
+ chunk_t other_nonce;
+
+ /**
+ * policy to create the CHILD_SA from
+ */
+ policy_t *policy;
+
+ /**
+ * list of proposal candidates
+ */
+ linked_list_t *proposals;
+
+ /**
+ * selected proposal to use for CHILD_SA
+ */
+ proposal_t *proposal;
+
+ /**
+ * traffic selectors for initiators side
+ */
+ linked_list_t *tsi;
+
+ /**
+ * traffic selectors for responders side
+ */
+ linked_list_t *tsr;
+
+ /**
+ * mode the new CHILD_SA uses (transport/tunnel/beet)
+ */
+ mode_t mode;
+
+ /**
+ * reqid to use if we are rekeying
+ */
+ u_int32_t reqid;
+
+ /**
+ * CHILD_SA which gets established
+ */
+ child_sa_t *child_sa;
+
+ /**
+ * successfully established the CHILD?
+ */
+ bool established;
+};
+
+/**
+ * get the nonce from a message
+ */
+static status_t get_nonce(message_t *message, chunk_t *nonce)
+{
+ nonce_payload_t *payload;
+
+ payload = (nonce_payload_t*)message->get_payload(message, NONCE);
+ if (payload == NULL)
+ {
+ return FAILED;
+ }
+ *nonce = payload->get_nonce(payload);
+ return NEED_MORE;
+}
+
+/**
+ * generate a new nonce to include in a CREATE_CHILD_SA message
+ */
+static status_t generate_nonce(chunk_t *nonce)
+{
+ status_t status;
+ randomizer_t *randomizer = randomizer_create();
+
+ status = randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE,
+ nonce);
+ randomizer->destroy(randomizer);
+ if (status != SUCCESS)
+ {
+ DBG1(DBG_IKE, "error generating random nonce value");
+ return FAILED;
+ }
+ return SUCCESS;
+}
+
+/**
+ * Check a list of traffic selectors if any selector belongs to host
+ */
+static bool ts_list_is_host(linked_list_t *list, host_t *host)
+{
+ traffic_selector_t *ts;
+ bool is_host = TRUE;
+ iterator_t *iterator = list->create_iterator(list, TRUE);
+
+ while (is_host && iterator->iterate(iterator, (void**)&ts))
+ {
+ is_host = is_host && ts->is_host(ts, host);
+ }
+ iterator->destroy(iterator);
+ return is_host;
+}
+
+/**
+ * Install a CHILD_SA for usage
+ */
+static status_t select_and_install(private_child_create_t *this)
+{
+ prf_plus_t *prf_plus;
+ status_t status;
+ chunk_t nonce_i, nonce_r, seed;
+ linked_list_t *my_ts, *other_ts;
+ host_t *me, *other, *other_vip, *my_vip;
+
+ if (this->proposals == NULL || this->tsi == NULL || this->tsr == NULL)
+ {
+ SIG(CHILD_UP_FAILED, "SA/TS payloads missing in message");
+ return FAILED;
+ }
+
+ if (this->initiator)
+ {
+ nonce_i = this->my_nonce;
+ nonce_r = this->other_nonce;
+ my_ts = this->tsi;
+ other_ts = this->tsr;
+ }
+ else
+ {
+ nonce_r = this->my_nonce;
+ nonce_i = this->other_nonce;
+ my_ts = this->tsr;
+ other_ts = this->tsi;
+ }
+
+ me = this->ike_sa->get_my_host(this->ike_sa);
+ other = this->ike_sa->get_other_host(this->ike_sa);
+ my_vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
+ other_vip = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE);
+
+ this->proposal = this->policy->select_proposal(this->policy, this->proposals);
+
+ if (this->proposal == NULL)
+ {
+ SIG(CHILD_UP_FAILED, "no acceptable proposal found");
+ return FAILED;
+ }
+
+ if (this->initiator && my_vip)
+ { /* if we have a virtual IP, shorten our TS to the minimum */
+ my_ts = this->policy->select_my_traffic_selectors(this->policy, my_ts,
+ my_vip);
+ /* to setup firewall rules correctly, CHILD_SA needs the virtual IP */
+ this->child_sa->set_virtual_ip(this->child_sa, my_vip);
+ }
+ else
+ { /* shorten in the host2host case only */
+ my_ts = this->policy->select_my_traffic_selectors(this->policy,
+ my_ts, me);
+ }
+ if (other_vip)
+ { /* if other has a virtual IP, shorten it's traffic selectors to it */
+ other_ts = this->policy->select_other_traffic_selectors(this->policy,
+ other_ts, other_vip);
+ }
+ else
+ { /* use his host for the host2host case */
+ other_ts = this->policy->select_other_traffic_selectors(this->policy,
+ other_ts, other);
+ }
+ this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
+ this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
+ if (this->initiator)
+ {
+ this->tsi = my_ts;
+ this->tsr = other_ts;
+ }
+ else
+ {
+ this->tsr = my_ts;
+ this->tsi = other_ts;
+ }
+
+ if (this->tsi->get_count(this->tsi) == 0 ||
+ this->tsr->get_count(this->tsr) == 0)
+ {
+ SIG(CHILD_UP_FAILED, "no acceptable traffic selectors found");
+ return FAILED;
+ }
+
+ if (!this->initiator)
+ {
+ /* check if requested mode is acceptable, downgrade if required */
+ switch (this->mode)
+ {
+ case MODE_TRANSPORT:
+ if (!ts_list_is_host(this->tsi, other) ||
+ !ts_list_is_host(this->tsr, me))
+ {
+ this->mode = MODE_TUNNEL;
+ DBG1(DBG_IKE, "not using tranport mode, not host-to-host");
+ }
+ else if (this->ike_sa->is_natt_enabled(this->ike_sa))
+ {
+ this->mode = MODE_TUNNEL;
+ DBG1(DBG_IKE, "not using tranport mode, connection NATed");
+ }
+ break;
+ case MODE_BEET:
+ if (!ts_list_is_host(this->tsi, NULL) ||
+ !ts_list_is_host(this->tsr, NULL))
+ {
+ this->mode = MODE_TUNNEL;
+ DBG1(DBG_IKE, "not using BEET mode, not host-to-host");
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ seed = chunk_cata("cc", nonce_i, nonce_r);
+ prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed);
+
+ if (this->initiator)
+ {
+ status = this->child_sa->update(this->child_sa, this->proposal,
+ this->mode, prf_plus);
+ }
+ else
+ {
+ status = this->child_sa->add(this->child_sa, this->proposal,
+ this->mode, prf_plus);
+ }
+ prf_plus->destroy(prf_plus);
+
+ if (status != SUCCESS)
+ {
+ SIG(CHILD_UP_FAILED, "unable to install IPsec SA (SAD) in kernel");
+ return status;
+ }
+
+ status = this->child_sa->add_policies(this->child_sa, my_ts, other_ts,
+ this->mode);
+
+ if (status != SUCCESS)
+ {
+ SIG(CHILD_UP_FAILED, "unable to install IPsec policies (SPD) in kernel");
+ return status;
+ }
+ /* add to IKE_SA, and remove from task */
+ this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
+ this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
+ this->established = TRUE;
+ return SUCCESS;
+}
+
+/**
+ * build the payloads for the message
+ */
+static void build_payloads(private_child_create_t *this, message_t *message)
+{
+ sa_payload_t *sa_payload;
+ ts_payload_t *ts_payload;
+ nonce_payload_t *nonce_payload;
+
+ /* add SA payload */
+ if (this->initiator)
+ {
+ sa_payload = sa_payload_create_from_proposal_list(this->proposals);
+ }
+ else
+ {
+ sa_payload = sa_payload_create_from_proposal(this->proposal);
+ }
+ message->add_payload(message, (payload_t*)sa_payload);
+
+ /* add nonce payload if not in IKE_AUTH */
+ if (message->get_exchange_type(message) == CREATE_CHILD_SA)
+ {
+ nonce_payload = nonce_payload_create();
+ nonce_payload->set_nonce(nonce_payload, this->my_nonce);
+ message->add_payload(message, (payload_t*)nonce_payload);
+ }
+
+ /* add TSi/TSr payloads */
+ ts_payload = ts_payload_create_from_traffic_selectors(TRUE, this->tsi);
+ message->add_payload(message, (payload_t*)ts_payload);
+ ts_payload = ts_payload_create_from_traffic_selectors(FALSE, this->tsr);
+ message->add_payload(message, (payload_t*)ts_payload);
+
+ /* add a notify if we are not in tunnel mode */
+ switch (this->mode)
+ {
+ case MODE_TRANSPORT:
+ message->add_notify(message, FALSE, USE_TRANSPORT_MODE, chunk_empty);
+ break;
+ case MODE_BEET:
+ message->add_notify(message, FALSE, USE_BEET_MODE, chunk_empty);
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * Read payloads from message
+ */
+static void process_payloads(private_child_create_t *this, message_t *message)
+{
+ iterator_t *iterator;
+ payload_t *payload;
+ sa_payload_t *sa_payload;
+ ts_payload_t *ts_payload;
+ notify_payload_t *notify_payload;
+
+ /* defaults to TUNNEL mode */
+ this->mode = MODE_TUNNEL;
+
+ iterator = message->get_payload_iterator(message);
+ while (iterator->iterate(iterator, (void**)&payload))
+ {
+ switch (payload->get_type(payload))
+ {
+ case SECURITY_ASSOCIATION:
+ sa_payload = (sa_payload_t*)payload;
+ this->proposals = sa_payload->get_proposals(sa_payload);
+ break;
+ case TRAFFIC_SELECTOR_INITIATOR:
+ ts_payload = (ts_payload_t*)payload;
+ this->tsi = ts_payload->get_traffic_selectors(ts_payload);
+ break;
+ case TRAFFIC_SELECTOR_RESPONDER:
+ ts_payload = (ts_payload_t*)payload;
+ this->tsr = ts_payload->get_traffic_selectors(ts_payload);
+ break;
+ case NOTIFY:
+ notify_payload = (notify_payload_t*)payload;
+ switch (notify_payload ->get_notify_type(notify_payload ))
+ {
+ case USE_TRANSPORT_MODE:
+ this->mode = MODE_TRANSPORT;
+ break;
+ case USE_BEET_MODE:
+ this->mode = MODE_BEET;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+}
+
+/**
+ * Implementation of task_t.build for initiator
+ */
+static status_t build_i(private_child_create_t *this, message_t *message)
+{
+ host_t *me, *other, *vip;
+
+ switch (message->get_exchange_type(message))
+ {
+ case IKE_SA_INIT:
+ return get_nonce(message, &this->my_nonce);
+ case CREATE_CHILD_SA:
+ if (generate_nonce(&this->my_nonce) != SUCCESS)
+ {
+ message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
+ return SUCCESS;
+ }
+ break;
+ case IKE_AUTH:
+ if (!message->get_payload(message, ID_INITIATOR))
+ {
+ /* send only in the first request, not in subsequent EAP */
+ return NEED_MORE;
+ }
+ break;
+ default:
+ break;
+ }
+
+ SIG(CHILD_UP_START, "establishing CHILD_SA");
+
+ me = this->ike_sa->get_my_host(this->ike_sa);
+ other = this->ike_sa->get_other_host(this->ike_sa);
+ vip = this->policy->get_virtual_ip(this->policy, NULL);
+
+ if (vip)
+ { /* propose a 0.0.0.0/0 subnet when we use virtual ip */
+ this->tsi = this->policy->get_my_traffic_selectors(this->policy, NULL);
+ vip->destroy(vip);
+ }
+ else
+ { /* but shorten a 0.0.0.0/0 subnet to the actual address if host2host */
+ this->tsi = this->policy->get_my_traffic_selectors(this->policy, me);
+ }
+ this->tsr = this->policy->get_other_traffic_selectors(this->policy, other);
+ this->proposals = this->policy->get_proposals(this->policy);
+ this->mode = this->policy->get_mode(this->policy);
+
+ this->child_sa = child_sa_create(me, other,
+ this->ike_sa->get_my_id(this->ike_sa),
+ this->ike_sa->get_other_id(this->ike_sa),
+ this->policy, this->reqid,
+ this->ike_sa->is_natt_enabled(this->ike_sa));
+
+ if (this->child_sa->alloc(this->child_sa, this->proposals) != SUCCESS)
+ {
+ SIG(CHILD_UP_FAILED, "unable to allocate SPIs from kernel");
+ return FAILED;
+ }
+
+ build_payloads(this, message);
+
+ this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
+ this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
+ this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
+ this->tsi = NULL;
+ this->tsr = NULL;
+ this->proposals = NULL;
+
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_r(private_child_create_t *this, message_t *message)
+{
+ switch (message->get_exchange_type(message))
+ {
+ case IKE_SA_INIT:
+ return get_nonce(message, &this->other_nonce);
+ case CREATE_CHILD_SA:
+ get_nonce(message, &this->other_nonce);
+ break;
+ case IKE_AUTH:
+ if (message->get_payload(message, ID_INITIATOR) == NULL)
+ {
+ /* wait until extensible authentication completed, if used */
+ return NEED_MORE;
+ }
+ default:
+ break;
+ }
+
+ process_payloads(this, message);
+
+ if (this->tsi == NULL || this->tsr == NULL)
+ {
+ DBG1(DBG_IKE, "TS payload missing in message");
+ return NEED_MORE;
+ }
+
+ this->policy = charon->policies->get_policy(charon->policies,
+ this->ike_sa->get_my_id(this->ike_sa),
+ this->ike_sa->get_other_id(this->ike_sa),
+ this->tsr, this->tsi,
+ this->ike_sa->get_my_host(this->ike_sa),
+ this->ike_sa->get_other_host(this->ike_sa));
+
+ if (this->policy && this->ike_sa->get_policy(this->ike_sa) == NULL)
+ {
+ this->ike_sa->set_policy(this->ike_sa, this->policy);
+ }
+
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.build for responder
+ */
+static status_t build_r(private_child_create_t *this, message_t *message)
+{
+ switch (message->get_exchange_type(message))
+ {
+ case IKE_SA_INIT:
+ return get_nonce(message, &this->my_nonce);
+ case CREATE_CHILD_SA:
+ if (generate_nonce(&this->my_nonce) != SUCCESS)
+ {
+ message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
+ return SUCCESS;
+ }
+ break;
+ case IKE_AUTH:
+ if (message->get_payload(message, EXTENSIBLE_AUTHENTICATION))
+ {
+ /* wait until extensible authentication completed, if used */
+ return NEED_MORE;
+ }
+ default:
+ break;
+ }
+
+ if (this->ike_sa->get_state(this->ike_sa) == IKE_REKEYING)
+ {
+ SIG(CHILD_UP_FAILED, "unable to create CHILD_SA while rekeying IKE_SA");
+ message->add_notify(message, TRUE, NO_ADDITIONAL_SAS, chunk_empty);
+ return SUCCESS;
+ }
+
+ if (this->policy == NULL)
+ {
+ SIG(CHILD_UP_FAILED, "no acceptable policy found");
+ message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
+ return SUCCESS;
+ }
+
+ this->child_sa = child_sa_create(this->ike_sa->get_my_host(this->ike_sa),
+ this->ike_sa->get_other_host(this->ike_sa),
+ this->ike_sa->get_my_id(this->ike_sa),
+ this->ike_sa->get_other_id(this->ike_sa),
+ this->policy, this->reqid,
+ this->ike_sa->is_natt_enabled(this->ike_sa));
+
+ if (select_and_install(this) != SUCCESS)
+ {
+ message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty);
+ return SUCCESS;
+ }
+
+ build_payloads(this, message);
+
+ SIG(CHILD_UP_SUCCESS, "established CHILD_SA successfully");
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_i(private_child_create_t *this, message_t *message)
+{
+ iterator_t *iterator;
+ payload_t *payload;
+
+ switch (message->get_exchange_type(message))
+ {
+ case IKE_SA_INIT:
+ return get_nonce(message, &this->other_nonce);
+ case CREATE_CHILD_SA:
+ get_nonce(message, &this->other_nonce);
+ break;
+ case IKE_AUTH:
+ if (message->get_payload(message, EXTENSIBLE_AUTHENTICATION))
+ {
+ /* wait until extensible authentication completed, if used */
+ return NEED_MORE;
+ }
+ default:
+ break;
+ }
+
+ /* check for erronous notifies */
+ iterator = message->get_payload_iterator(message);
+ while (iterator->iterate(iterator, (void**)&payload))
+ {
+ if (payload->get_type(payload) == NOTIFY)
+ {
+ notify_payload_t *notify = (notify_payload_t*)payload;
+ notify_type_t type = notify->get_notify_type(notify);
+
+ switch (type)
+ {
+ /* handle notify errors related to CHILD_SA only */
+ case NO_PROPOSAL_CHOSEN:
+ case SINGLE_PAIR_REQUIRED:
+ case NO_ADDITIONAL_SAS:
+ case INTERNAL_ADDRESS_FAILURE:
+ case FAILED_CP_REQUIRED:
+ case TS_UNACCEPTABLE:
+ case INVALID_SELECTORS:
+ {
+ SIG(CHILD_UP_FAILED, "received %N notify, no CHILD_SA built",
+ notify_type_names, type);
+ iterator->destroy(iterator);
+ /* an error in CHILD_SA creation is not critical */
+ return SUCCESS;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ iterator->destroy(iterator);
+
+ process_payloads(this, message);
+
+ if (select_and_install(this) == SUCCESS)
+ {
+ SIG(CHILD_UP_SUCCESS, "established CHILD_SA successfully");
+ }
+ return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.get_type
+ */
+static task_type_t get_type(private_child_create_t *this)
+{
+ return CHILD_CREATE;
+}
+
+/**
+ * Implementation of child_create_t.use_reqid
+ */
+static void use_reqid(private_child_create_t *this, u_int32_t reqid)
+{
+ this->reqid = reqid;
+}
+
+/**
+ * Implementation of child_create_t.get_child
+ */
+static child_sa_t* get_child(private_child_create_t *this)
+{
+ return this->child_sa;
+}
+
+/**
+ * Implementation of child_create_t.get_lower_nonce
+ */
+static chunk_t get_lower_nonce(private_child_create_t *this)
+{
+ if (memcmp(this->my_nonce.ptr, this->other_nonce.ptr,
+ min(this->my_nonce.len, this->other_nonce.len)) < 0)
+ {
+ return this->my_nonce;
+ }
+ else
+ {
+ return this->other_nonce;
+ }
+}
+
+/**
+ * Implementation of task_t.migrate
+ */
+static void migrate(private_child_create_t *this, ike_sa_t *ike_sa)
+{
+ chunk_free(&this->my_nonce);
+ chunk_free(&this->other_nonce);
+ if (this->tsi)
+ {
+ this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
+ }
+ if (this->tsr)
+ {
+ this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
+ }
+ DESTROY_IF(this->child_sa);
+ DESTROY_IF(this->proposal);
+ if (this->proposals)
+ {
+ this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
+ }
+
+ this->ike_sa = ike_sa;
+ this->proposals = NULL;
+ this->tsi = NULL;
+ this->tsr = NULL;
+ this->child_sa = NULL;
+ this->mode = MODE_TUNNEL;
+ this->reqid = 0;
+ this->established = FALSE;
+}
+
+/**
+ * Implementation of task_t.destroy
+ */
+static void destroy(private_child_create_t *this)
+{
+ chunk_free(&this->my_nonce);
+ chunk_free(&this->other_nonce);
+ if (this->tsi)
+ {
+ this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
+ }
+ if (this->tsr)
+ {
+ this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
+ }
+ if (!this->established)
+ {
+ DESTROY_IF(this->child_sa);
+ }
+ DESTROY_IF(this->proposal);
+ if (this->proposals)
+ {
+ this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
+ }
+
+ DESTROY_IF(this->policy);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+child_create_t *child_create_create(ike_sa_t *ike_sa, policy_t *policy)
+{
+ private_child_create_t *this = malloc_thing(private_child_create_t);
+
+ this->public.get_child = (child_sa_t*(*)(child_create_t*))get_child;
+ this->public.get_lower_nonce = (chunk_t(*)(child_create_t*))get_lower_nonce;
+ this->public.use_reqid = (void(*)(child_create_t*,u_int32_t))use_reqid;
+ this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
+ this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
+ this->public.task.destroy = (void(*)(task_t*))destroy;
+ if (policy)
+ {
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
+ this->initiator = TRUE;
+ policy->get_ref(policy);
+ }
+ else
+ {
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
+ this->initiator = FALSE;
+ }
+
+ this->ike_sa = ike_sa;
+ this->policy = policy;
+ this->my_nonce = chunk_empty;
+ this->other_nonce = chunk_empty;
+ this->proposals = NULL;
+ this->proposal = NULL;
+ this->tsi = NULL;
+ this->tsr = NULL;
+ this->child_sa = NULL;
+ this->mode = MODE_TUNNEL;
+ this->reqid = 0;
+ this->established = FALSE;
+
+ return &this->public;
+}
diff --git a/src/charon/sa/tasks/child_create.h b/src/charon/sa/tasks/child_create.h
new file mode 100644
index 000000000..200d37457
--- /dev/null
+++ b/src/charon/sa/tasks/child_create.h
@@ -0,0 +1,88 @@
+/**
+ * @file child_create.h
+ *
+ * @brief Interface child_create_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_CREATE_H_
+#define CHILD_CREATE_H_
+
+typedef struct child_create_t child_create_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <sa/tasks/task.h>
+#include <config/policies/policy.h>
+
+/**
+ * @brief Task of type CHILD_CREATE, established a new CHILD_SA.
+ *
+ * This task may be included in the IKE_AUTH message or in a separate
+ * CREATE_CHILD_SA exchange.
+ *
+ * @b Constructors:
+ * - child_create_create()
+ *
+ * @ingroup tasks
+ */
+struct child_create_t {
+
+ /**
+ * Implements the task_t interface
+ */
+ task_t task;
+
+ /**
+ * @brief Use a specific reqid for the CHILD_SA.
+ *
+ * When this task is used for rekeying, the same reqid is used
+ * for the new CHILD_SA.
+ *
+ * @param this calling object
+ * @param reqid reqid to use
+ */
+ void (*use_reqid) (child_create_t *this, u_int32_t reqid);
+
+ /**
+ * @brief Get the lower of the two nonces, used for rekey collisions.
+ *
+ * @param this calling object
+ * @return lower nonce
+ */
+ chunk_t (*get_lower_nonce) (child_create_t *this);
+
+ /**
+ * @brief Get the CHILD_SA established/establishing by this task.
+ *
+ * @param this calling object
+ * @return child_sa
+ */
+ child_sa_t* (*get_child) (child_create_t *this);
+};
+
+/**
+ * @brief Create a new child_create task.
+ *
+ * @param ike_sa IKE_SA this task works for
+ * @param policy policy if task initiator, NULL if responder
+ * @return child_create task to handle by the task_manager
+ */
+child_create_t *child_create_create(ike_sa_t *ike_sa, policy_t *policy);
+
+#endif /* CHILD_CREATE_H_ */
diff --git a/src/charon/sa/tasks/child_delete.c b/src/charon/sa/tasks/child_delete.c
new file mode 100644
index 000000000..23d509de5
--- /dev/null
+++ b/src/charon/sa/tasks/child_delete.c
@@ -0,0 +1,292 @@
+/**
+ * @file child_delete.c
+ *
+ * @brief Implementation of the child_delete task.
+ *
+ */
+
+/*
+ * Copyright (C) 2006-2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_delete.h"
+
+#include <daemon.h>
+#include <encoding/payloads/delete_payload.h>
+
+
+typedef struct private_child_delete_t private_child_delete_t;
+
+/**
+ * Private members of a child_delete_t task.
+ */
+struct private_child_delete_t {
+
+ /**
+ * Public methods and task_t interface.
+ */
+ child_delete_t public;
+
+ /**
+ * Assigned IKE_SA.
+ */
+ ike_sa_t *ike_sa;
+
+ /**
+ * Are we the initiator?
+ */
+ bool initiator;
+
+ /**
+ * CHILD_SAs which get deleted
+ */
+ linked_list_t *child_sas;
+};
+
+/**
+ * build the delete payloads from the listed child_sas
+ */
+static void build_payloads(private_child_delete_t *this, message_t *message)
+{
+ iterator_t *iterator;
+ delete_payload_t *ah = NULL, *esp = NULL;
+ u_int32_t spi;
+ child_sa_t *child_sa;
+
+ iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
+ while (iterator->iterate(iterator, (void**)&child_sa))
+ {
+ spi = child_sa->get_spi(child_sa, TRUE);
+ switch (child_sa->get_protocol(child_sa))
+ {
+ case PROTO_ESP:
+ if (esp == NULL)
+ {
+ esp = delete_payload_create(PROTO_ESP);
+ message->add_payload(message, (payload_t*)esp);
+ }
+ esp->add_spi(esp, spi);
+ break;
+ case PROTO_AH:
+ if (ah == NULL)
+ {
+ ah = delete_payload_create(PROTO_AH);
+ message->add_payload(message, (payload_t*)ah);
+ }
+ ah->add_spi(ah, spi);
+ break;
+ default:
+ break;
+ }
+ child_sa->set_state(child_sa, CHILD_DELETING);
+ }
+ iterator->destroy(iterator);
+}
+
+/**
+ * read in payloads and find the children to delete
+ */
+static void process_payloads(private_child_delete_t *this, message_t *message)
+{
+ iterator_t *payloads, *spis;
+ payload_t *payload;
+ delete_payload_t *delete_payload;
+ u_int32_t *spi;
+ protocol_id_t protocol;
+ child_sa_t *child_sa;
+
+ payloads = message->get_payload_iterator(message);
+ while (payloads->iterate(payloads, (void**)&payload))
+ {
+ if (payload->get_type(payload) == DELETE)
+ {
+ delete_payload = (delete_payload_t*)payload;
+ protocol = delete_payload->get_protocol_id(delete_payload);
+ if (protocol != PROTO_ESP && protocol != PROTO_AH)
+ {
+ continue;
+ }
+ spis = delete_payload->create_spi_iterator(delete_payload);
+ while (spis->iterate(spis, (void**)&spi))
+ {
+ child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
+ *spi, FALSE);
+ if (child_sa == NULL)
+ {
+ DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI 0x%x, "
+ "but no such SA", protocol_id_names, protocol, ntohl(*spi));
+ continue;
+ }
+ DBG2(DBG_IKE, "received DELETE for %N CHILD_SA with SPI 0x%x",
+ protocol_id_names, protocol, ntohl(*spi));
+
+ switch (child_sa->get_state(child_sa))
+ {
+ case CHILD_REKEYING:
+ /* we reply as usual, rekeying will fail */
+ break;
+ case CHILD_DELETING:
+ /* we don't send back a delete if we initiated ourself */
+ if (!this->initiator)
+ {
+ this->ike_sa->destroy_child_sa(this->ike_sa,
+ protocol, *spi);
+ continue;
+ }
+ default:
+ break;
+ }
+
+ this->child_sas->insert_last(this->child_sas, child_sa);
+ }
+ spis->destroy(spis);
+ }
+ }
+ payloads->destroy(payloads);
+}
+
+/**
+ * destroy the children listed in this->child_sas
+ */
+static void destroy_children(private_child_delete_t *this)
+{
+ iterator_t *iterator;
+ child_sa_t *child_sa;
+ protocol_id_t protocol;
+ u_int32_t spi;
+
+ iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
+ while (iterator->iterate(iterator, (void**)&child_sa))
+ {
+ spi = child_sa->get_spi(child_sa, TRUE);
+ protocol = child_sa->get_protocol(child_sa);
+ this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
+ }
+ iterator->destroy(iterator);
+}
+
+/**
+ * Implementation of task_t.build for initiator
+ */
+static status_t build_i(private_child_delete_t *this, message_t *message)
+{
+ build_payloads(this, message);
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_i(private_child_delete_t *this, message_t *message)
+{
+ /* flush the list before adding new SAs */
+ this->child_sas->destroy(this->child_sas);
+ this->child_sas = linked_list_create();
+
+ process_payloads(this, message);
+ destroy_children(this);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_r(private_child_delete_t *this, message_t *message)
+{
+ process_payloads(this, message);
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.build for responder
+ */
+static status_t build_r(private_child_delete_t *this, message_t *message)
+{
+ /* if we are rekeying, we send an empty informational */
+ if (this->ike_sa->get_state(this->ike_sa) != IKE_REKEYING)
+ {
+ build_payloads(this, message);
+ }
+ destroy_children(this);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.get_type
+ */
+static task_type_t get_type(private_child_delete_t *this)
+{
+ return CHILD_DELETE;
+}
+
+/**
+ * Implementation of child_delete_t.get_child
+ */
+static child_sa_t* get_child(private_child_delete_t *this)
+{
+ child_sa_t *child_sa = NULL;
+ this->child_sas->get_first(this->child_sas, (void**)&child_sa);
+ return child_sa;
+}
+
+/**
+ * Implementation of task_t.migrate
+ */
+static void migrate(private_child_delete_t *this, ike_sa_t *ike_sa)
+{
+ this->ike_sa = ike_sa;
+
+ this->child_sas->destroy(this->child_sas);
+ this->child_sas = linked_list_create();
+}
+
+/**
+ * Implementation of task_t.destroy
+ */
+static void destroy(private_child_delete_t *this)
+{
+ this->child_sas->destroy(this->child_sas);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+child_delete_t *child_delete_create(ike_sa_t *ike_sa, child_sa_t *child_sa)
+{
+ private_child_delete_t *this = malloc_thing(private_child_delete_t);
+
+ this->public.get_child = (child_sa_t*(*)(child_delete_t*))get_child;
+ this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
+ this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
+ this->public.task.destroy = (void(*)(task_t*))destroy;
+
+ this->ike_sa = ike_sa;
+ this->child_sas = linked_list_create();
+
+ if (child_sa != NULL)
+ {
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
+ this->initiator = TRUE;
+ this->child_sas->insert_last(this->child_sas, child_sa);
+ }
+ else
+ {
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
+ this->initiator = FALSE;
+ }
+ return &this->public;
+}
diff --git a/src/charon/sa/tasks/child_delete.h b/src/charon/sa/tasks/child_delete.h
new file mode 100644
index 000000000..a7e676a50
--- /dev/null
+++ b/src/charon/sa/tasks/child_delete.h
@@ -0,0 +1,66 @@
+/**
+ * @file child_delete.h
+ *
+ * @brief Interface child_delete_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_DELETE_H_
+#define CHILD_DELETE_H_
+
+typedef struct child_delete_t child_delete_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <sa/tasks/task.h>
+#include <sa/child_sa.h>
+
+/**
+ * @brief Task of type child_delete, delete a CHILD_SA.
+ *
+ * @b Constructors:
+ * - child_delete_create()
+ *
+ * @ingroup tasks
+ */
+struct child_delete_t {
+
+ /**
+ * Implements the task_t interface
+ */
+ task_t task;
+
+ /**
+ * @brief Get the CHILD_SA to delete by this task.
+ *
+ * @param this calling object
+ * @return child_sa
+ */
+ child_sa_t* (*get_child) (child_delete_t *this);
+};
+
+/**
+ * @brief Create a new child_delete task.
+ *
+ * @param ike_sa IKE_SA this task works for
+ * @param child_sa CHILD_SA to delete, or NULL as responder
+ * @return child_delete task to handle by the task_manager
+ */
+child_delete_t *child_delete_create(ike_sa_t *ike_sa, child_sa_t *child_sa);
+
+#endif /* CHILD_DELETE_H_ */
diff --git a/src/charon/sa/tasks/child_rekey.c b/src/charon/sa/tasks/child_rekey.c
new file mode 100644
index 000000000..745895dbb
--- /dev/null
+++ b/src/charon/sa/tasks/child_rekey.c
@@ -0,0 +1,346 @@
+/**
+ * @file child_rekey.c
+ *
+ * @brief Implementation of the child_rekey task.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2007 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_rekey.h"
+
+#include <daemon.h>
+#include <encoding/payloads/notify_payload.h>
+#include <sa/tasks/child_create.h>
+#include <sa/tasks/child_delete.h>
+#include <queues/jobs/rekey_child_sa_job.h>
+
+
+typedef struct private_child_rekey_t private_child_rekey_t;
+
+/**
+ * Private members of a child_rekey_t task.
+ */
+struct private_child_rekey_t {
+
+ /**
+ * Public methods and task_t interface.
+ */
+ child_rekey_t public;
+
+ /**
+ * Assigned IKE_SA.
+ */
+ ike_sa_t *ike_sa;
+
+ /**
+ * Are we the initiator?
+ */
+ bool initiator;
+
+ /**
+ * the CHILD_CREATE task which is reused to simplify rekeying
+ */
+ child_create_t *child_create;
+
+ /**
+ * CHILD_SA which gets rekeyed
+ */
+ child_sa_t *child_sa;
+
+ /**
+ * colliding task, may be delete or rekey
+ */
+ task_t *collision;
+};
+
+/**
+ * find a child using the REKEY_SA notify
+ */
+static void find_child(private_child_rekey_t *this, message_t *message)
+{
+ iterator_t *iterator;
+ payload_t *payload;
+
+ iterator = message->get_payload_iterator(message);
+ while (iterator->iterate(iterator, (void**)&payload))
+ {
+ notify_payload_t *notify;
+ u_int32_t spi;
+ protocol_id_t protocol;
+
+ if (payload->get_type(payload) != NOTIFY)
+ {
+ continue;
+ }
+
+ notify = (notify_payload_t*)payload;
+ protocol = notify->get_protocol_id(notify);
+ spi = notify->get_spi(notify);
+
+ if (protocol != PROTO_ESP && protocol != PROTO_AH)
+ {
+ continue;
+ }
+ this->child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
+ spi, FALSE);
+ break;
+
+ }
+ iterator->destroy(iterator);
+}
+
+/**
+ * Implementation of task_t.build for initiator
+ */
+static status_t build_i(private_child_rekey_t *this, message_t *message)
+{
+ notify_payload_t *notify;
+ protocol_id_t protocol;
+ u_int32_t spi, reqid;
+
+ /* we just need the rekey notify ... */
+ protocol = this->child_sa->get_protocol(this->child_sa);
+ spi = this->child_sa->get_spi(this->child_sa, TRUE);
+ notify = notify_payload_create_from_protocol_and_type(protocol, REKEY_SA);
+ notify->set_spi(notify, spi);
+ message->add_payload(message, (payload_t*)notify);
+
+ /* ... our CHILD_CREATE task does the hard work for us. */
+ reqid = this->child_sa->get_reqid(this->child_sa);
+ this->child_create->use_reqid(this->child_create, reqid);
+ this->child_create->task.build(&this->child_create->task, message);
+
+ this->child_sa->set_state(this->child_sa, CHILD_REKEYING);
+
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_r(private_child_rekey_t *this, message_t *message)
+{
+ /* let the CHILD_CREATE task process the message */
+ this->child_create->task.process(&this->child_create->task, message);
+
+ find_child(this, message);
+
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.build for responder
+ */
+static status_t build_r(private_child_rekey_t *this, message_t *message)
+{
+ u_int32_t reqid;
+
+ if (this->child_sa == NULL ||
+ this->child_sa->get_state(this->child_sa) == CHILD_DELETING)
+ {
+ DBG1(DBG_IKE, "unable to rekey, CHILD_SA not found");
+ message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
+ return SUCCESS;
+ }
+
+ /* let the CHILD_CREATE task build the response */
+ reqid = this->child_sa->get_reqid(this->child_sa);
+ this->child_create->use_reqid(this->child_create, reqid);
+ this->child_create->task.build(&this->child_create->task, message);
+
+ if (message->get_payload(message, SECURITY_ASSOCIATION) == NULL)
+ {
+ /* rekeying failed, reuse old child */
+ this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
+ return SUCCESS;
+ }
+
+ this->child_sa->set_state(this->child_sa, CHILD_REKEYING);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_i(private_child_rekey_t *this, message_t *message)
+{
+ protocol_id_t protocol;
+ u_int32_t spi;
+ child_sa_t *to_delete;
+
+ this->child_create->task.process(&this->child_create->task, message);
+ if (message->get_payload(message, SECURITY_ASSOCIATION) == NULL)
+ {
+ /* establishing new child failed, reuse old. but not when we
+ * recieved a delete in the meantime */
+ if (!(this->collision &&
+ this->collision->get_type(this->collision) == CHILD_DELETE))
+ {
+ job_t *job;
+ u_int32_t retry = charon->configuration->get_retry_interval(
+ charon->configuration);
+ job = (job_t*)rekey_child_sa_job_create(
+ this->child_sa->get_reqid(this->child_sa),
+ this->child_sa->get_protocol(this->child_sa),
+ this->child_sa->get_spi(this->child_sa, TRUE));
+ DBG1(DBG_IKE, "CHILD_SA rekeying failed, "
+ "trying again in %d seconds", retry);
+ this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
+ charon->event_queue->add_relative(charon->event_queue, job, retry * 1000);
+ }
+ return SUCCESS;
+ }
+
+ to_delete = this->child_sa;
+
+ /* check for rekey collisions */
+ if (this->collision &&
+ this->collision->get_type(this->collision) == CHILD_REKEY)
+ {
+ chunk_t this_nonce, other_nonce;
+ private_child_rekey_t *other = (private_child_rekey_t*)this->collision;
+
+ this_nonce = this->child_create->get_lower_nonce(this->child_create);
+ other_nonce = other->child_create->get_lower_nonce(other->child_create);
+
+ /* if we have the lower nonce, delete rekeyed SA. If not, delete
+ * the redundant. */
+ if (memcmp(this_nonce.ptr, other_nonce.ptr,
+ min(this_nonce.len, other_nonce.len)) < 0)
+ {
+ DBG1(DBG_IKE, "CHILD_SA rekey collision won, deleting rekeyed child");
+ }
+ else
+ {
+ DBG1(DBG_IKE, "CHILD_SA rekey collision lost, deleting redundant child");
+ to_delete = this->child_create->get_child(this->child_create);
+ if (to_delete == NULL)
+ {
+ /* ooops, should not happen, fallback */
+ to_delete = this->child_sa;
+ }
+ }
+ }
+
+ spi = to_delete->get_spi(to_delete, TRUE);
+ protocol = to_delete->get_protocol(to_delete);
+ if (this->ike_sa->delete_child_sa(this->ike_sa, protocol, spi) != SUCCESS)
+ {
+ return FAILED;
+ }
+ return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.get_type
+ */
+static task_type_t get_type(private_child_rekey_t *this)
+{
+ return CHILD_REKEY;
+}
+
+/**
+ * Implementation of child_rekey_t.collide
+ */
+static void collide(private_child_rekey_t *this, task_t *other)
+{
+ /* the task manager only detects exchange collision, but not if
+ * the collision is for the same child. we check it here. */
+ if (other->get_type(other) == CHILD_REKEY)
+ {
+ private_child_rekey_t *rekey = (private_child_rekey_t*)other;
+ if (rekey == NULL || rekey->child_sa != this->child_sa)
+ {
+ /* not the same child => no collision */
+ return;
+ }
+ }
+ else if (other->get_type(other) == CHILD_DELETE)
+ {
+ child_delete_t *del = (child_delete_t*)other;
+ if (del == NULL || del->get_child(del) != this->child_sa)
+ {
+ /* not the same child => no collision */
+ return;
+ }
+ }
+ else
+ {
+ /* any other task is not critical for collisisions, ignore */
+ return;
+ }
+ DESTROY_IF(this->collision);
+ this->collision = other;
+}
+
+/**
+ * Implementation of task_t.migrate
+ */
+static void migrate(private_child_rekey_t *this, ike_sa_t *ike_sa)
+{
+ this->child_create->task.migrate(&this->child_create->task, ike_sa);
+ DESTROY_IF(this->collision);
+
+ this->ike_sa = ike_sa;
+ this->collision = NULL;
+}
+
+/**
+ * Implementation of task_t.destroy
+ */
+static void destroy(private_child_rekey_t *this)
+{
+ this->child_create->task.destroy(&this->child_create->task);
+ DESTROY_IF(this->collision);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, child_sa_t *child_sa)
+{
+ private_child_rekey_t *this = malloc_thing(private_child_rekey_t);
+ policy_t *policy;
+
+ this->public.collide = (void (*)(child_rekey_t*,task_t*))collide;
+ this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
+ this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
+ this->public.task.destroy = (void(*)(task_t*))destroy;
+ if (child_sa != NULL)
+ {
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
+ this->initiator = TRUE;
+ policy = child_sa->get_policy(child_sa);
+ this->child_create = child_create_create(ike_sa, policy);
+ }
+ else
+ {
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
+ this->initiator = FALSE;
+ this->child_create = child_create_create(ike_sa, NULL);
+ }
+
+ this->ike_sa = ike_sa;
+ this->child_sa = child_sa;
+ this->collision = NULL;
+
+ return &this->public;
+}
diff --git a/src/charon/sa/tasks/child_rekey.h b/src/charon/sa/tasks/child_rekey.h
new file mode 100644
index 000000000..3515f0c3f
--- /dev/null
+++ b/src/charon/sa/tasks/child_rekey.h
@@ -0,0 +1,70 @@
+/**
+ * @file child_rekey.h
+ *
+ * @brief Interface child_rekey_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_REKEY_H_
+#define CHILD_REKEY_H_
+
+typedef struct child_rekey_t child_rekey_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <sa/child_sa.h>
+#include <sa/tasks/task.h>
+
+/**
+ * @brief Task of type CHILD_REKEY, rekey an established CHILD_SA.
+ *
+ * @b Constructors:
+ * - child_rekey_create()
+ *
+ * @ingroup tasks
+ */
+struct child_rekey_t {
+
+ /**
+ * Implements the task_t interface
+ */
+ task_t task;
+
+ /**
+ * @brief Register a rekeying task which collides with this one
+ *
+ * If two peers initiate rekeying at the same time, the collision must
+ * be handled gracefully. The task manager is aware of what exchanges
+ * are going on and notifies the outgoing task by passing the incoming.
+ *
+ * @param this task initated by us
+ * @param other incoming task
+ */
+ void (*collide)(child_rekey_t* this, task_t *other);
+};
+
+/**
+ * @brief Create a new CHILD_REKEY task.
+ *
+ * @param ike_sa IKE_SA this task works for
+ * @param child_sa child_sa to rekey, NULL if responder
+ * @return child_rekey task to handle by the task_manager
+ */
+child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, child_sa_t *child_sa);
+
+#endif /* CHILD_REKEY_H_ */
diff --git a/src/charon/sa/tasks/ike_auth.c b/src/charon/sa/tasks/ike_auth.c
new file mode 100644
index 000000000..541e1bb37
--- /dev/null
+++ b/src/charon/sa/tasks/ike_auth.c
@@ -0,0 +1,750 @@
+/**
+ * @file ike_auth.c
+ *
+ * @brief Implementation of the ike_auth task.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2007 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_auth.h"
+
+#include <string.h>
+
+#include <daemon.h>
+#include <crypto/diffie_hellman.h>
+#include <encoding/payloads/id_payload.h>
+#include <encoding/payloads/auth_payload.h>
+#include <encoding/payloads/eap_payload.h>
+#include <encoding/payloads/nonce_payload.h>
+#include <sa/authenticators/eap_authenticator.h>
+
+
+
+typedef struct private_ike_auth_t private_ike_auth_t;
+
+/**
+ * Private members of a ike_auth_t task.
+ */
+struct private_ike_auth_t {
+
+ /**
+ * Public methods and task_t interface.
+ */
+ ike_auth_t public;
+
+ /**
+ * Assigned IKE_SA.
+ */
+ ike_sa_t *ike_sa;
+
+ /**
+ * Are we the initiator?
+ */
+ bool initiator;
+
+ /**
+ * Nonce chosen by us in ike_init
+ */
+ chunk_t my_nonce;
+
+ /**
+ * Nonce chosen by peer in ike_init
+ */
+ chunk_t other_nonce;
+
+ /**
+ * IKE_SA_INIT message sent by us
+ */
+ packet_t *my_packet;
+
+ /**
+ * IKE_SA_INIT message sent by peer
+ */
+ packet_t *other_packet;
+
+ /**
+ * EAP authenticator when using EAP
+ */
+ eap_authenticator_t *eap_auth;
+
+ /**
+ * EAP payload received and ready to process
+ */
+ eap_payload_t *eap_payload;
+
+ /**
+ * has the peer been authenticated successfully?
+ */
+ bool peer_authenticated;
+};
+
+/**
+ * build the AUTH payload
+ */
+static status_t build_auth(private_ike_auth_t *this, message_t *message)
+{
+ authenticator_t *auth;
+ auth_payload_t *auth_payload;
+ policy_t *policy;
+ auth_method_t method;
+ status_t status;
+
+ /* create own authenticator and add auth payload */
+ policy = this->ike_sa->get_policy(this->ike_sa);
+ if (!policy)
+ {
+ SIG(IKE_UP_FAILED, "unable to authenticate, no policy found");
+ return FAILED;
+ }
+ method = policy->get_auth_method(policy);
+
+ auth = authenticator_create(this->ike_sa, method);
+ if (auth == NULL)
+ {
+ SIG(IKE_UP_FAILED, "configured authentication method %N not supported",
+ auth_method_names, method);
+ return FAILED;
+ }
+
+ status = auth->build(auth, this->my_packet->get_data(this->my_packet),
+ this->other_nonce, &auth_payload);
+ auth->destroy(auth);
+ if (status != SUCCESS)
+ {
+ SIG(IKE_UP_FAILED, "generating authentication data failed");
+ return FAILED;
+ }
+ message->add_payload(message, (payload_t*)auth_payload);
+ return SUCCESS;
+}
+
+/**
+ * build ID payload(s)
+ */
+static status_t build_id(private_ike_auth_t *this, message_t *message)
+{
+ identification_t *me, *other;
+ id_payload_t *id;
+ policy_t *policy;
+
+ me = this->ike_sa->get_my_id(this->ike_sa);
+ other = this->ike_sa->get_other_id(this->ike_sa);
+ policy = this->ike_sa->get_policy(this->ike_sa);
+
+ if (me->contains_wildcards(me))
+ {
+ me = policy->get_my_id(policy);
+ if (me->contains_wildcards(me))
+ {
+ SIG(IKE_UP_FAILED, "negotiation of own ID failed");
+ return FAILED;
+ }
+ this->ike_sa->set_my_id(this->ike_sa, me->clone(me));
+ }
+
+ id = id_payload_create_from_identification(this->initiator, me);
+ message->add_payload(message, (payload_t*)id);
+
+ /* as initiator, include other ID if it does not contain wildcards */
+ if (this->initiator && !other->contains_wildcards(other))
+ {
+ id = id_payload_create_from_identification(FALSE, other);
+ message->add_payload(message, (payload_t*)id);
+ }
+ return SUCCESS;
+}
+
+/**
+ * process AUTH payload
+ */
+static status_t process_auth(private_ike_auth_t *this, message_t *message)
+{
+ auth_payload_t *auth_payload;
+ authenticator_t *auth;
+ auth_method_t auth_method;
+ status_t status;
+
+ auth_payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION);
+
+ if (auth_payload == NULL)
+ {
+ /* AUTH payload is missing, client wants to use EAP authentication */
+ return NOT_FOUND;
+ }
+
+ auth_method = auth_payload->get_auth_method(auth_payload);
+ auth = authenticator_create(this->ike_sa, auth_method);
+
+ if (auth == NULL)
+ {
+ SIG(IKE_UP_FAILED, "authentication method %N used by %D not "
+ "supported", auth_method_names, auth_method,
+ this->ike_sa->get_other_id(this->ike_sa));
+ return NOT_SUPPORTED;
+ }
+ status = auth->verify(auth, this->other_packet->get_data(this->other_packet),
+ this->my_nonce, auth_payload);
+ auth->destroy(auth);
+ if (status != SUCCESS)
+ {
+ SIG(IKE_UP_FAILED, "authentication of %D using %N failed",
+ this->ike_sa->get_other_id(this->ike_sa),
+ auth_method_names, auth_method);
+ return FAILED;
+ }
+ return SUCCESS;
+}
+
+/**
+ * process ID payload(s)
+ */
+static status_t process_id(private_ike_auth_t *this, message_t *message)
+{
+ identification_t *id;
+ id_payload_t *idr, *idi;
+
+ idi = (id_payload_t*)message->get_payload(message, ID_INITIATOR);
+ idr = (id_payload_t*)message->get_payload(message, ID_RESPONDER);
+
+ if ((this->initiator && idr == NULL) || (!this->initiator && idi == NULL))
+ {
+ SIG(IKE_UP_FAILED, "ID payload missing in message");
+ return FAILED;
+ }
+
+ if (this->initiator)
+ {
+ id = idr->get_identification(idr);
+ this->ike_sa->set_other_id(this->ike_sa, id);
+ }
+ else
+ {
+ id = idi->get_identification(idi);
+ this->ike_sa->set_other_id(this->ike_sa, id);
+ if (idr)
+ {
+ id = idr->get_identification(idr);
+ this->ike_sa->set_my_id(this->ike_sa, id);
+ }
+ }
+ return SUCCESS;
+}
+
+/**
+ * collect the needed information in the IKE_SA_INIT exchange from our message
+ */
+static status_t collect_my_init_data(private_ike_auth_t *this, message_t *message)
+{
+ nonce_payload_t *nonce;
+
+ /* get the nonce that was generated in ike_init */
+ nonce = (nonce_payload_t*)message->get_payload(message, NONCE);
+ if (nonce == NULL)
+ {
+ return FAILED;
+ }
+ this->my_nonce = nonce->get_nonce(nonce);
+
+ /* pre-generate the message, so we can store it for us */
+ if (this->ike_sa->generate_message(this->ike_sa, message,
+ &this->my_packet) != SUCCESS)
+ {
+ return FAILED;
+ }
+ return NEED_MORE;
+}
+
+/**
+ * collect the needed information in the IKE_SA_INIT exchange from others message
+ */
+static status_t collect_other_init_data(private_ike_auth_t *this, message_t *message)
+{
+ /* we collect the needed information in the IKE_SA_INIT exchange */
+ nonce_payload_t *nonce;
+
+ /* get the nonce that was generated in ike_init */
+ nonce = (nonce_payload_t*)message->get_payload(message, NONCE);
+ if (nonce == NULL)
+ {
+ return FAILED;
+ }
+ this->other_nonce = nonce->get_nonce(nonce);
+
+ /* pre-generate the message, so we can store it for us */
+ this->other_packet = message->get_packet(message);
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.build to create AUTH payload from EAP data
+ */
+static status_t build_auth_eap(private_ike_auth_t *this, message_t *message)
+{
+ authenticator_t *auth;
+ auth_payload_t *auth_payload;
+
+ auth = (authenticator_t*)this->eap_auth;
+ if (auth->build(auth, this->my_packet->get_data(this->my_packet),
+ this->other_nonce, &auth_payload) != SUCCESS)
+ {
+ SIG(IKE_UP_FAILED, "generating authentication data failed");
+ if (!this->initiator)
+ {
+ message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty);
+ }
+ return FAILED;
+ }
+ message->add_payload(message, (payload_t*)auth_payload);
+ if (!this->initiator)
+ {
+ this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
+ SIG(IKE_UP_SUCCESS, "IKE_SA established between %D[%H]...[%H]%D",
+ this->ike_sa->get_my_id(this->ike_sa),
+ this->ike_sa->get_my_host(this->ike_sa),
+ this->ike_sa->get_other_host(this->ike_sa),
+ this->ike_sa->get_other_id(this->ike_sa));
+ return SUCCESS;
+ }
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.process to verify AUTH payload after EAP
+ */
+static status_t process_auth_eap(private_ike_auth_t *this, message_t *message)
+{
+ auth_payload_t *auth_payload;
+ authenticator_t *auth;
+
+ auth_payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION);
+ this->peer_authenticated = FALSE;
+
+ if (auth_payload)
+ {
+ auth = (authenticator_t*)this->eap_auth;
+ if (auth->verify(auth, this->other_packet->get_data(this->other_packet),
+ this->my_nonce, auth_payload) == SUCCESS)
+ {
+ this->peer_authenticated = TRUE;
+ }
+ }
+
+ if (!this->peer_authenticated)
+ {
+ SIG(IKE_UP_FAILED, "authentication of %D using %N failed",
+ this->ike_sa->get_other_id(this->ike_sa),
+ auth_method_names, AUTH_EAP);
+ if (this->initiator)
+ {
+ return FAILED;
+ }
+ return NEED_MORE;
+ }
+ if (this->initiator)
+ {
+ this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
+ SIG(IKE_UP_SUCCESS, "IKE_SA established between %D[%H]...[%H]%D",
+ this->ike_sa->get_my_id(this->ike_sa),
+ this->ike_sa->get_my_host(this->ike_sa),
+ this->ike_sa->get_other_host(this->ike_sa),
+ this->ike_sa->get_other_id(this->ike_sa));
+ return SUCCESS;
+ }
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.process for EAP exchanges
+ */
+static status_t process_eap_i(private_ike_auth_t *this, message_t *message)
+{
+ eap_payload_t *eap;
+
+ eap = (eap_payload_t*)message->get_payload(message, EXTENSIBLE_AUTHENTICATION);
+ if (eap == NULL)
+ {
+ SIG(IKE_UP_FAILED, "EAP payload missing");
+ return FAILED;
+ }
+ switch (this->eap_auth->process(this->eap_auth, eap, &eap))
+ {
+ case NEED_MORE:
+ this->eap_payload = eap;
+ return NEED_MORE;
+ case SUCCESS:
+ /* EAP exchange completed, now create and process AUTH */
+ this->eap_payload = NULL;
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_auth_eap;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_auth_eap;
+ return NEED_MORE;
+ default:
+ this->eap_payload = NULL;
+ SIG(IKE_UP_FAILED, "failed to authenticate against %D using EAP",
+ this->ike_sa->get_other_id(this->ike_sa));
+ return FAILED;
+ }
+}
+
+/**
+ * Implementation of task_t.process for EAP exchanges
+ */
+static status_t process_eap_r(private_ike_auth_t *this, message_t *message)
+{
+ this->eap_payload = (eap_payload_t*)message->get_payload(message,
+ EXTENSIBLE_AUTHENTICATION);
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.build for EAP exchanges
+ */
+static status_t build_eap_i(private_ike_auth_t *this, message_t *message)
+{
+ message->add_payload(message, (payload_t*)this->eap_payload);
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.build for EAP exchanges
+ */
+static status_t build_eap_r(private_ike_auth_t *this, message_t *message)
+{
+ status_t status = NEED_MORE;
+ eap_payload_t *eap;
+
+ if (this->eap_payload == NULL)
+ {
+ SIG(IKE_UP_FAILED, "EAP payload missing");
+ return FAILED;
+ }
+
+ switch (this->eap_auth->process(this->eap_auth, this->eap_payload, &eap))
+ {
+ case NEED_MORE:
+
+ break;
+ case SUCCESS:
+ /* EAP exchange completed, now create and process AUTH */
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_auth_eap;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_auth_eap;
+ break;
+ default:
+ SIG(IKE_UP_FAILED, "authentication of %D using %N failed",
+ this->ike_sa->get_other_id(this->ike_sa),
+ auth_method_names, AUTH_EAP);
+ status = FAILED;
+ break;
+ }
+ message->add_payload(message, (payload_t*)eap);
+ return status;
+}
+
+/**
+ * Implementation of task_t.build for initiator
+ */
+static status_t build_i(private_ike_auth_t *this, message_t *message)
+{
+ policy_t *policy;
+
+ if (message->get_exchange_type(message) == IKE_SA_INIT)
+ {
+ return collect_my_init_data(this, message);
+ }
+
+ if (build_id(this, message) != SUCCESS)
+ {
+ return FAILED;
+ }
+
+ policy = this->ike_sa->get_policy(this->ike_sa);
+ if (policy->get_auth_method(policy) == AUTH_EAP)
+ {
+ this->eap_auth = eap_authenticator_create(this->ike_sa);
+ }
+ else
+ {
+ if (build_auth(this, message) != SUCCESS)
+ {
+ return FAILED;
+ }
+ }
+
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_r(private_ike_auth_t *this, message_t *message)
+{
+ if (message->get_exchange_type(message) == IKE_SA_INIT)
+ {
+ return collect_other_init_data(this, message);
+ }
+
+ if (process_id(this, message) != SUCCESS)
+ {
+ return NEED_MORE;
+ }
+
+ switch (process_auth(this, message))
+ {
+ case SUCCESS:
+ this->peer_authenticated = TRUE;
+ break;
+ case NOT_FOUND:
+ /* use EAP if no AUTH payload found */
+ this->eap_auth = eap_authenticator_create(this->ike_sa);
+ break;
+ default:
+ break;
+ }
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.build for responder
+ */
+static status_t build_r(private_ike_auth_t *this, message_t *message)
+{
+ policy_t *policy;
+ eap_type_t eap_type;
+ eap_payload_t *eap_payload;
+ status_t status;
+
+ if (message->get_exchange_type(message) == IKE_SA_INIT)
+ {
+ return collect_my_init_data(this, message);
+ }
+
+ policy = this->ike_sa->get_policy(this->ike_sa);
+ if (policy == NULL)
+ {
+ SIG(IKE_UP_FAILED, "no acceptable policy found");
+ message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty);
+ return FAILED;
+ }
+
+ if (build_id(this, message) != SUCCESS ||
+ build_auth(this, message) != SUCCESS)
+ {
+ message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty);
+ return FAILED;
+ }
+
+ /* use "traditional" authentication if we could authenticate peer */
+ if (this->peer_authenticated)
+ {
+ this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
+ SIG(IKE_UP_SUCCESS, "IKE_SA established between %D[%H]...[%H]%D",
+ this->ike_sa->get_my_id(this->ike_sa),
+ this->ike_sa->get_my_host(this->ike_sa),
+ this->ike_sa->get_other_host(this->ike_sa),
+ this->ike_sa->get_other_id(this->ike_sa));
+ return SUCCESS;
+ }
+
+ if (this->eap_auth == NULL)
+ {
+ /* peer not authenticated, nor does it want to use EAP */
+ message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty);
+ return FAILED;
+ }
+
+ /* initiate EAP authenitcation */
+ eap_type = policy->get_eap_type(policy);
+ status = this->eap_auth->initiate(this->eap_auth, eap_type, &eap_payload);
+ message->add_payload(message, (payload_t*)eap_payload);
+ if (status != NEED_MORE)
+ {
+ SIG(IKE_UP_FAILED, "unable to initiate EAP authentication");
+ return FAILED;
+ }
+
+ /* switch to EAP methods */
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_eap_r;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_eap_r;
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_i(private_ike_auth_t *this, message_t *message)
+{
+ iterator_t *iterator;
+ payload_t *payload;
+
+ if (message->get_exchange_type(message) == IKE_SA_INIT)
+ {
+ return collect_other_init_data(this, message);
+ }
+
+ iterator = message->get_payload_iterator(message);
+ while (iterator->iterate(iterator, (void**)&payload))
+ {
+ if (payload->get_type(payload) == NOTIFY)
+ {
+ notify_payload_t *notify = (notify_payload_t*)payload;
+ notify_type_t type = notify->get_notify_type(notify);
+
+ switch (type)
+ {
+ case NO_PROPOSAL_CHOSEN:
+ case SINGLE_PAIR_REQUIRED:
+ case NO_ADDITIONAL_SAS:
+ case INTERNAL_ADDRESS_FAILURE:
+ case FAILED_CP_REQUIRED:
+ case TS_UNACCEPTABLE:
+ case INVALID_SELECTORS:
+ /* these are errors, but are not critical as only the
+ * CHILD_SA won't get build, but IKE_SA establishes anyway */
+ break;
+ default:
+ {
+ if (type < 16383)
+ {
+ SIG(IKE_UP_FAILED, "received %N notify error",
+ notify_type_names, type);
+ iterator->destroy(iterator);
+ return FAILED;
+ }
+ DBG1(DBG_IKE, "received %N notify",
+ notify_type_names, type);
+ break;
+ }
+ }
+ }
+ }
+ iterator->destroy(iterator);
+
+ if (process_id(this, message) != SUCCESS ||
+ process_auth(this, message) != SUCCESS)
+ {
+ return FAILED;
+ }
+
+ if (this->eap_auth)
+ {
+ /* switch to EAP authentication methods */
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_eap_i;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_eap_i;
+ return process_eap_i(this, message);
+ }
+
+ this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
+ SIG(IKE_UP_SUCCESS, "IKE_SA established between %D[%H]...[%H]%D",
+ this->ike_sa->get_my_id(this->ike_sa),
+ this->ike_sa->get_my_host(this->ike_sa),
+ this->ike_sa->get_other_host(this->ike_sa),
+ this->ike_sa->get_other_id(this->ike_sa));
+ return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.get_type
+ */
+static task_type_t get_type(private_ike_auth_t *this)
+{
+ return IKE_AUTHENTICATE;
+}
+
+/**
+ * Implementation of task_t.migrate
+ */
+static void migrate(private_ike_auth_t *this, ike_sa_t *ike_sa)
+{
+ chunk_free(&this->my_nonce);
+ chunk_free(&this->other_nonce);
+ DESTROY_IF(this->my_packet);
+ DESTROY_IF(this->other_packet);
+ if (this->eap_auth)
+ {
+ this->eap_auth->authenticator_interface.destroy(
+ &this->eap_auth->authenticator_interface);
+ }
+
+ this->my_packet = NULL;
+ this->other_packet = NULL;
+ this->peer_authenticated = FALSE;
+ this->eap_auth = NULL;
+ this->eap_payload = NULL;
+ this->ike_sa = ike_sa;
+ if (this->initiator)
+ {
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
+ }
+ else
+ {
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
+ }
+}
+
+/**
+ * Implementation of task_t.destroy
+ */
+static void destroy(private_ike_auth_t *this)
+{
+ chunk_free(&this->my_nonce);
+ chunk_free(&this->other_nonce);
+ DESTROY_IF(this->my_packet);
+ DESTROY_IF(this->other_packet);
+ if (this->eap_auth)
+ {
+ this->eap_auth->authenticator_interface.destroy(
+ &this->eap_auth->authenticator_interface);
+ }
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+ike_auth_t *ike_auth_create(ike_sa_t *ike_sa, bool initiator)
+{
+ private_ike_auth_t *this = malloc_thing(private_ike_auth_t);
+
+ this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
+ this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
+ this->public.task.destroy = (void(*)(task_t*))destroy;
+
+ if (initiator)
+ {
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
+ }
+ else
+ {
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
+ }
+
+ this->ike_sa = ike_sa;
+ this->initiator = initiator;
+ this->my_nonce = chunk_empty;
+ this->other_nonce = chunk_empty;
+ this->my_packet = NULL;
+ this->other_packet = NULL;
+ this->peer_authenticated = FALSE;
+ this->eap_auth = NULL;
+ this->eap_payload = NULL;
+
+ return &this->public;
+}
diff --git a/src/charon/sa/tasks/ike_auth.h b/src/charon/sa/tasks/ike_auth.h
new file mode 100644
index 000000000..d7326c988
--- /dev/null
+++ b/src/charon/sa/tasks/ike_auth.h
@@ -0,0 +1,64 @@
+/**
+ * @file ike_auth.h
+ *
+ * @brief Interface ike_auth_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_H_
+#define IKE_AUTH_H_
+
+typedef struct ike_auth_t ike_auth_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <sa/tasks/task.h>
+
+/**
+ * @brief Task of type ike_auth, authenticates an IKE_SA using authenticators.
+ *
+ * The ike_auth task authenticates the IKE_SA using the IKE_AUTH
+ * exchange. It processes and build IDi and IDr payloads and also
+ * handles AUTH payloads. The AUTH payloads are passed to authenticator_t's,
+ * which do the actual authentication process. If the ike_auth task is used
+ * with EAP authentication, it stays alive over multiple exchanges until
+ * EAP has completed.
+ *
+ * @b Constructors:
+ * - ike_auth_create()
+ *
+ * @ingroup tasks
+ */
+struct ike_auth_t {
+
+ /**
+ * Implements the task_t interface
+ */
+ task_t task;
+};
+
+/**
+ * @brief Create a new task of type IKE_AUTHENTICATE.
+ *
+ * @param ike_sa IKE_SA this task works for
+ * @param initiator TRUE if thask is the initator of an exchange
+ * @return ike_auth task to handle by the task_manager
+ */
+ike_auth_t *ike_auth_create(ike_sa_t *ike_sa, bool initiator);
+
+#endif /* IKE_AUTH_H_ */
diff --git a/src/charon/sa/tasks/ike_cert.c b/src/charon/sa/tasks/ike_cert.c
new file mode 100644
index 000000000..160600742
--- /dev/null
+++ b/src/charon/sa/tasks/ike_cert.c
@@ -0,0 +1,370 @@
+/**
+ * @file ike_cert.c
+ *
+ * @brief Implementation of the ike_cert task.
+ *
+ */
+
+/*
+ * Copyright (C) 2006-2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "ike_cert.h"
+
+#include <daemon.h>
+#include <sa/ike_sa.h>
+#include <crypto/hashers/hasher.h>
+#include <encoding/payloads/cert_payload.h>
+#include <encoding/payloads/certreq_payload.h>
+
+
+typedef struct private_ike_cert_t private_ike_cert_t;
+
+/**
+ * Private members of a ike_cert_t task.
+ */
+struct private_ike_cert_t {
+
+ /**
+ * Public methods and task_t interface.
+ */
+ ike_cert_t public;
+
+ /**
+ * Assigned IKE_SA.
+ */
+ ike_sa_t *ike_sa;
+
+ /**
+ * Are we the initiator?
+ */
+ bool initiator;
+
+ /**
+ * list of CA cert hashes requested, items point to 20 byte chunk
+ */
+ linked_list_t *cas;
+
+ /**
+ * have we seen a certificate request?
+ */
+ bool certreq_seen;
+};
+
+/**
+ * read certificate requests
+ */
+static void process_certreqs(private_ike_cert_t *this, message_t *message)
+{
+ iterator_t *iterator;
+ payload_t *payload;
+
+ iterator = message->get_payload_iterator(message);
+ while (iterator->iterate(iterator, (void**)&payload))
+ {
+ if (payload->get_type(payload) == CERTIFICATE_REQUEST)
+ {
+ certreq_payload_t *certreq = (certreq_payload_t*)payload;
+ cert_encoding_t encoding;
+ chunk_t keyids, keyid;
+
+ this->certreq_seen = TRUE;
+
+ encoding = certreq->get_cert_encoding(certreq);
+ if (encoding != CERT_X509_SIGNATURE)
+ {
+ DBG1(DBG_IKE, "certreq payload %N not supported, ignored",
+ cert_encoding_names, encoding);
+ continue;
+ }
+
+ keyids = certreq->get_data(certreq);
+
+ while (keyids.len >= HASH_SIZE_SHA1)
+ {
+ keyid = chunk_create(keyids.ptr, HASH_SIZE_SHA1);
+ keyid = chunk_clone(keyid);
+ this->cas->insert_last(this->cas, keyid.ptr);
+ keyids = chunk_skip(keyids, HASH_SIZE_SHA1);
+ }
+ }
+ }
+ iterator->destroy(iterator);
+}
+
+/**
+ * import certificates
+ */
+static void process_certs(private_ike_cert_t *this, message_t *message)
+{
+ iterator_t *iterator;
+ payload_t *payload;
+
+ iterator = message->get_payload_iterator(message);
+ while (iterator->iterate(iterator, (void**)&payload))
+ {
+ if (payload->get_type(payload) == CERTIFICATE)
+ {
+ cert_encoding_t encoding;
+ x509_t *cert;
+ chunk_t cert_data;
+ bool found;
+ cert_payload_t *cert_payload = (cert_payload_t*)payload;
+
+ encoding = cert_payload->get_cert_encoding(cert_payload);
+ if (encoding != CERT_X509_SIGNATURE)
+ {
+ DBG1(DBG_IKE, "certificate payload %N not supported, ignored",
+ cert_encoding_names, encoding);
+ continue;
+ }
+
+ cert_data = cert_payload->get_data_clone(cert_payload);
+ cert = x509_create_from_chunk(cert_data, 0);
+ if (cert)
+ {
+ if (charon->credentials->verify(charon->credentials,
+ cert, &found))
+ {
+ DBG2(DBG_IKE, "received end entity certificate is trusted, "
+ "added to store");
+ if (!found)
+ {
+ charon->credentials->add_end_certificate(
+ charon->credentials, cert);
+ }
+ else
+ {
+ cert->destroy(cert);
+ }
+ }
+ else
+ {
+ DBG1(DBG_IKE, "received end entity certificate is not "
+ "trusted, discarded");
+ cert->destroy(cert);
+ }
+ }
+ else
+ {
+ DBG1(DBG_IKE, "parsing of received certificate failed, discarded");
+ chunk_free(&cert_data);
+ }
+ }
+ }
+ iterator->destroy(iterator);
+}
+
+/**
+ * build certificate requests
+ */
+static void build_certreqs(private_ike_cert_t *this, message_t *message)
+{
+ connection_t *connection;
+ policy_t *policy;
+ identification_t *ca;
+ certreq_payload_t *certreq;
+
+ connection = this->ike_sa->get_connection(this->ike_sa);
+
+ if (connection->get_certreq_policy(connection) != CERT_NEVER_SEND)
+ {
+ policy = this->ike_sa->get_policy(this->ike_sa);
+
+ if (policy)
+ {
+ ca = policy->get_other_ca(policy);
+
+ if (ca && ca->get_type(ca) != ID_ANY)
+ {
+ certreq = certreq_payload_create_from_cacert(ca);
+ }
+ else
+ {
+ certreq = certreq_payload_create_from_cacerts();
+ }
+ }
+ else
+ {
+ certreq = certreq_payload_create_from_cacerts();
+ }
+
+ if (certreq)
+ {
+ message->add_payload(message, (payload_t*)certreq);
+ }
+ }
+}
+
+/**
+ * add certificates to message
+ */
+static void build_certs(private_ike_cert_t *this, message_t *message)
+{
+ policy_t *policy;
+ connection_t *connection;
+ x509_t *cert;
+ cert_payload_t *payload;
+
+ policy = this->ike_sa->get_policy(this->ike_sa);
+ connection = this->ike_sa->get_connection(this->ike_sa);
+
+ if (policy && policy->get_auth_method(policy) == AUTH_RSA)
+ {
+ switch (connection->get_cert_policy(connection))
+ {
+ case CERT_NEVER_SEND:
+ break;
+ case CERT_SEND_IF_ASKED:
+ if (!this->certreq_seen)
+ {
+ break;
+ }
+ /* FALL */
+ case CERT_ALWAYS_SEND:
+ {
+ /* TODO: respect CA cert request */
+ cert = charon->credentials->get_certificate(charon->credentials,
+ policy->get_my_id(policy));
+ if (cert)
+ {
+ payload = cert_payload_create_from_x509(cert);
+ message->add_payload(message, (payload_t*)payload);
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t build_i(private_ike_cert_t *this, message_t *message)
+{
+ if (message->get_exchange_type(message) == IKE_SA_INIT)
+ {
+ return NEED_MORE;
+ }
+
+ build_certreqs(this, message);
+ build_certs(this, message);
+
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.process for responder
+ */
+static status_t process_r(private_ike_cert_t *this, message_t *message)
+{
+ if (message->get_exchange_type(message) == IKE_SA_INIT)
+ {
+ return NEED_MORE;
+ }
+
+ process_certreqs(this, message);
+ process_certs(this, message);
+
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.build for responder
+ */
+static status_t build_r(private_ike_cert_t *this, message_t *message)
+{
+ if (message->get_exchange_type(message) == IKE_SA_INIT)
+ {
+ build_certreqs(this, message);
+ return NEED_MORE;
+ }
+
+ build_certs(this, message);
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_i(private_ike_cert_t *this, message_t *message)
+{
+ if (message->get_exchange_type(message) == IKE_SA_INIT)
+ {
+ process_certreqs(this, message);
+ return NEED_MORE;
+ }
+
+ process_certs(this, message);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.get_type
+ */
+static task_type_t get_type(private_ike_cert_t *this)
+{
+ return IKE_CERT;
+}
+
+/**
+ * Implementation of task_t.migrate
+ */
+static void migrate(private_ike_cert_t *this, ike_sa_t *ike_sa)
+{
+ this->ike_sa = ike_sa;
+
+ this->cas->destroy_function(this->cas, free);
+ this->cas = linked_list_create();
+ this->certreq_seen = FALSE;
+}
+
+/**
+ * Implementation of task_t.destroy
+ */
+static void destroy(private_ike_cert_t *this)
+{
+ this->cas->destroy_function(this->cas, free);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+ike_cert_t *ike_cert_create(ike_sa_t *ike_sa, bool initiator)
+{
+ private_ike_cert_t *this = malloc_thing(private_ike_cert_t);
+
+ this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
+ this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
+ this->public.task.destroy = (void(*)(task_t*))destroy;
+
+ if (initiator)
+ {
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
+ }
+ else
+ {
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
+ }
+
+ this->ike_sa = ike_sa;
+ this->initiator = initiator;
+ this->cas = linked_list_create();
+ this->certreq_seen = FALSE;
+
+ return &this->public;
+}
diff --git a/src/charon/sa/tasks/ike_cert.h b/src/charon/sa/tasks/ike_cert.h
new file mode 100644
index 000000000..ba0283953
--- /dev/null
+++ b/src/charon/sa/tasks/ike_cert.h
@@ -0,0 +1,61 @@
+/**
+ * @file ike_cert.h
+ *
+ * @brief Interface ike_cert_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef IKE_CERT_H_
+#define IKE_CERT_H_
+
+typedef struct ike_cert_t ike_cert_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <sa/tasks/task.h>
+
+/**
+ * @brief Task of type ike_cert, exchanges certificates and
+ * certificate requests.
+ *
+ * @b Constructors:
+ * - ike_cert_create()
+ *
+ * @ingroup tasks
+ */
+struct ike_cert_t {
+
+ /**
+ * Implements the task_t interface
+ */
+ task_t task;
+};
+
+/**
+ * @brief Create a new ike_cert task.
+ *
+ * The initiator parameter means the original initiator, not the initiator
+ * of the certificate request.
+ *
+ * @param ike_sa IKE_SA this task works for
+ * @param initiator TRUE if thask is the original initator
+ * @return ike_cert task to handle by the task_manager
+ */
+ike_cert_t *ike_cert_create(ike_sa_t *ike_sa, bool initiator);
+
+#endif /* IKE_CERT_H_ */
diff --git a/src/charon/sa/tasks/ike_config.c b/src/charon/sa/tasks/ike_config.c
new file mode 100644
index 000000000..ce29b9220
--- /dev/null
+++ b/src/charon/sa/tasks/ike_config.c
@@ -0,0 +1,428 @@
+/**
+ * @file ike_config.c
+ *
+ * @brief Implementation of the ike_config task.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_config.h"
+
+#include <daemon.h>
+#include <encoding/payloads/cp_payload.h>
+
+typedef struct private_ike_config_t private_ike_config_t;
+
+/**
+ * Private members of a ike_config_t task.
+ */
+struct private_ike_config_t {
+
+ /**
+ * Public methods and task_t interface.
+ */
+ ike_config_t public;
+
+ /**
+ * Assigned IKE_SA.
+ */
+ ike_sa_t *ike_sa;
+
+ /**
+ * Are we the initiator?
+ */
+ bool initiator;
+
+ /**
+ * associated policy with virtual IP configuration
+ */
+ policy_t *policy;
+
+ /**
+ * virtual ip
+ */
+ host_t *virtual_ip;
+
+ /**
+ * list of DNS servers
+ */
+ linked_list_t *dns;
+};
+
+/**
+ * build configuration payloads and attributes
+ */
+static void build_payloads(private_ike_config_t *this, message_t *message,
+ config_type_t type)
+{
+ cp_payload_t *cp;
+ configuration_attribute_t *ca;
+ chunk_t chunk, prefix;
+
+ if (!this->virtual_ip)
+ {
+ return;
+ }
+
+ cp = cp_payload_create();
+ cp->set_config_type(cp, type);
+
+ ca = configuration_attribute_create();
+
+ if (this->virtual_ip->get_family(this->virtual_ip) == AF_INET)
+ {
+ ca->set_type(ca, INTERNAL_IP4_ADDRESS);
+ if (this->virtual_ip->is_anyaddr(this->virtual_ip))
+ {
+ chunk = chunk_empty;
+ }
+ else
+ {
+ chunk = this->virtual_ip->get_address(this->virtual_ip);
+ }
+ }
+ else
+ {
+ ca->set_type(ca, INTERNAL_IP6_ADDRESS);
+ if (this->virtual_ip->is_anyaddr(this->virtual_ip))
+ {
+ chunk = chunk_empty;
+ }
+ else
+ {
+ prefix = chunk_alloca(1);
+ *prefix.ptr = 64;
+ chunk = this->virtual_ip->get_address(this->virtual_ip);
+ chunk = chunk_cata("cc", chunk, prefix);
+ }
+ }
+ ca->set_value(ca, chunk);
+ cp->add_configuration_attribute(cp, ca);
+
+ /* we currently always add a DNS request if we request an IP */
+ if (this->initiator)
+ {
+ ca = configuration_attribute_create();
+ if (this->virtual_ip->get_family(this->virtual_ip) == AF_INET)
+ {
+ ca->set_type(ca, INTERNAL_IP4_DNS);
+ }
+ else
+ {
+ ca->set_type(ca, INTERNAL_IP6_DNS);
+ }
+ cp->add_configuration_attribute(cp, ca);
+ }
+ else
+ {
+ host_t *ip;
+ iterator_t *iterator = this->dns->create_iterator(this->dns, TRUE);
+ while (iterator->iterate(iterator, (void**)&ip))
+ {
+ ca = configuration_attribute_create();
+ if (ip->get_family(ip) == AF_INET)
+ {
+ ca->set_type(ca, INTERNAL_IP4_DNS);
+ }
+ else
+ {
+ ca->set_type(ca, INTERNAL_IP6_DNS);
+ }
+ chunk = ip->get_address(ip);
+ ca->set_value(ca, chunk);
+ cp->add_configuration_attribute(cp, ca);
+ }
+ iterator->destroy(iterator);
+ }
+ message->add_payload(message, (payload_t*)cp);
+}
+
+/**
+ * process a single configuration attribute
+ */
+static void process_attribute(private_ike_config_t *this,
+ configuration_attribute_t *ca)
+{
+ host_t *ip;
+ chunk_t addr;
+ int family = AF_INET6;
+
+ switch (ca->get_type(ca))
+ {
+ case INTERNAL_IP4_ADDRESS:
+ family = AF_INET;
+ /* fall */
+ case INTERNAL_IP6_ADDRESS:
+ {
+ addr = ca->get_value(ca);
+ if (addr.len == 0)
+ {
+ ip = host_create_any(family);
+ }
+ else
+ {
+ /* skip prefix byte in IPv6 payload*/
+ if (family == AF_INET6)
+ {
+ addr.len--;
+ }
+ ip = host_create_from_chunk(family, addr, 0);
+ }
+ if (ip && !this->virtual_ip)
+ {
+ this->virtual_ip = ip;
+ }
+ break;
+ }
+ case INTERNAL_IP4_DNS:
+ family = AF_INET;
+ /* fall */
+ case INTERNAL_IP6_DNS:
+ {
+ addr = ca->get_value(ca);
+ if (addr.len == 0)
+ {
+ ip = host_create_any(family);
+ }
+ else
+ {
+ ip = host_create_from_chunk(family, addr, 0);
+ }
+ if (ip)
+ {
+ this->dns->insert_last(this->dns, ip);
+ }
+ break;
+ }
+ case INTERNAL_IP4_NBNS:
+ case INTERNAL_IP6_NBNS:
+ /* TODO */
+ default:
+ DBG1(DBG_IKE, "ignoring %N config attribute",
+ configuration_attribute_type_names,
+ ca->get_type(ca));
+ break;
+ }
+}
+
+/**
+ * Scan for configuration payloads and attributes
+ */
+static void process_payloads(private_ike_config_t *this, message_t *message)
+{
+ iterator_t *iterator, *attributes;
+ payload_t *payload;
+
+ iterator = message->get_payload_iterator(message);
+ while (iterator->iterate(iterator, (void**)&payload))
+ {
+ if (payload->get_type(payload) == CONFIGURATION)
+ {
+ cp_payload_t *cp = (cp_payload_t*)payload;
+ configuration_attribute_t *ca;
+ switch (cp->get_config_type(cp))
+ {
+ case CFG_REQUEST:
+ case CFG_REPLY:
+ {
+ attributes = cp->create_attribute_iterator(cp);
+ while (attributes->iterate(attributes, (void**)&ca))
+ {
+ process_attribute(this, ca);
+ }
+ attributes->destroy(attributes);
+ break;
+ }
+ default:
+ DBG1(DBG_IKE, "ignoring %N config payload",
+ config_type_names, cp->get_config_type(cp));
+ break;
+ }
+ }
+ }
+ iterator->destroy(iterator);
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t build_i(private_ike_config_t *this, message_t *message)
+{
+ if (message->get_exchange_type(message) == IKE_AUTH &&
+ message->get_payload(message, ID_INITIATOR))
+ {
+ this->virtual_ip = this->policy->get_virtual_ip(this->policy, NULL);
+
+ build_payloads(this, message, CFG_REQUEST);
+ }
+
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.process for responder
+ */
+static status_t process_r(private_ike_config_t *this, message_t *message)
+{
+ if (message->get_exchange_type(message) == IKE_AUTH &&
+ message->get_payload(message, ID_INITIATOR))
+ {
+ process_payloads(this, message);
+ }
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.build for responder
+ */
+static status_t build_r(private_ike_config_t *this, message_t *message)
+{
+ if (message->get_exchange_type(message) == IKE_AUTH &&
+ message->get_payload(message, EXTENSIBLE_AUTHENTICATION) == NULL)
+ {
+ this->policy = this->ike_sa->get_policy(this->ike_sa);
+
+ if (this->policy && this->virtual_ip)
+ {
+ host_t *ip;
+
+ DBG1(DBG_IKE, "peer requested virtual IP %H", this->virtual_ip);
+ ip = this->policy->get_virtual_ip(this->policy, this->virtual_ip);
+ if (ip == NULL || ip->is_anyaddr(ip))
+ {
+ DBG1(DBG_IKE, "not assigning a virtual IP to peer");
+ return SUCCESS;
+ }
+ DBG1(DBG_IKE, "assigning virtual IP %H to peer", ip);
+ this->ike_sa->set_virtual_ip(this->ike_sa, FALSE, ip);
+
+ this->virtual_ip->destroy(this->virtual_ip);
+ this->virtual_ip = ip;
+
+ /* DNS testing values
+ if (this->dns->remove_last(this->dns, (void**)&ip) == SUCCESS)
+ {
+ ip->destroy(ip);
+ ip = host_create_from_string("10.3.0.1", 0);
+ this->dns->insert_last(this->dns, ip);
+ ip = host_create_from_string("10.3.0.2", 0);
+ this->dns->insert_last(this->dns, ip);
+ } */
+
+ build_payloads(this, message, CFG_REPLY);
+ }
+ return SUCCESS;
+ }
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_i(private_ike_config_t *this, message_t *message)
+{
+ if (message->get_exchange_type(message) == IKE_AUTH &&
+ !message->get_payload(message, EXTENSIBLE_AUTHENTICATION))
+ {
+ host_t *ip;
+
+ DESTROY_IF(this->virtual_ip);
+ this->virtual_ip = NULL;
+
+ process_payloads(this, message);
+
+ if (this->virtual_ip)
+ {
+ this->ike_sa->set_virtual_ip(this->ike_sa, TRUE, this->virtual_ip);
+
+ while (this->dns->remove_last(this->dns, (void**)&ip) == SUCCESS)
+ {
+ if (!ip->is_anyaddr(ip))
+ {
+ this->ike_sa->add_dns_server(this->ike_sa, ip);
+ }
+ ip->destroy(ip);
+ }
+ }
+ return SUCCESS;
+ }
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.get_type
+ */
+static task_type_t get_type(private_ike_config_t *this)
+{
+ return IKE_CONFIG;
+}
+
+/**
+ * Implementation of task_t.migrate
+ */
+static void migrate(private_ike_config_t *this, ike_sa_t *ike_sa)
+{
+ DESTROY_IF(this->virtual_ip);
+ this->dns->destroy_offset(this->dns, offsetof(host_t, destroy));
+
+ this->ike_sa = ike_sa;
+ this->virtual_ip = NULL;
+ this->dns = linked_list_create();
+}
+
+/**
+ * Implementation of task_t.destroy
+ */
+static void destroy(private_ike_config_t *this)
+{
+ DESTROY_IF(this->virtual_ip);
+ this->dns->destroy_offset(this->dns, offsetof(host_t, destroy));
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+ike_config_t *ike_config_create(ike_sa_t *ike_sa, policy_t *policy)
+{
+ private_ike_config_t *this = malloc_thing(private_ike_config_t);
+
+ this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
+ this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
+ this->public.task.destroy = (void(*)(task_t*))destroy;
+
+ if (policy)
+ {
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
+ this->initiator = TRUE;
+ }
+ else
+ {
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
+ this->initiator = FALSE;
+ }
+
+ this->ike_sa = ike_sa;
+ this->policy = policy;
+ this->virtual_ip = NULL;
+ this->dns = linked_list_create();
+
+ return &this->public;
+}
diff --git a/src/charon/sa/tasks/ike_config.h b/src/charon/sa/tasks/ike_config.h
new file mode 100644
index 000000000..0c9b961b4
--- /dev/null
+++ b/src/charon/sa/tasks/ike_config.h
@@ -0,0 +1,59 @@
+/**
+ * @file ike_config.h
+ *
+ * @brief Interface ike_config_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_CONFIG_H_
+#define IKE_CONFIG_H_
+
+typedef struct ike_config_t ike_config_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <sa/tasks/task.h>
+#include <config/policies/policy.h>
+
+/**
+ * @brief Task of type IKE_CONFIG, sets up a virtual IP and other
+ * configurations for an IKE_SA.
+ *
+ * @b Constructors:
+ * - ike_config_create()
+ *
+ * @ingroup tasks
+ */
+struct ike_config_t {
+
+ /**
+ * Implements the task_t interface
+ */
+ task_t task;
+};
+
+/**
+ * @brief Create a new ike_config task.
+ *
+ * @param ike_sa IKE_SA this task works for
+ * @param policy policy for the initiator, NULL for the responder
+ * @return ike_config task to handle by the task_manager
+ */
+ike_config_t *ike_config_create(ike_sa_t *ike_sa, policy_t *policy);
+
+#endif /* IKE_CONFIG_H_ */
diff --git a/src/charon/sa/tasks/ike_delete.c b/src/charon/sa/tasks/ike_delete.c
new file mode 100644
index 000000000..9c4fdac0e
--- /dev/null
+++ b/src/charon/sa/tasks/ike_delete.c
@@ -0,0 +1,172 @@
+/**
+ * @file ike_delete.c
+ *
+ * @brief Implementation of the ike_delete task.
+ *
+ */
+
+/*
+ * Copyright (C) 2006-2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_delete.h"
+
+#include <daemon.h>
+#include <encoding/payloads/delete_payload.h>
+
+
+typedef struct private_ike_delete_t private_ike_delete_t;
+
+/**
+ * Private members of a ike_delete_t task.
+ */
+struct private_ike_delete_t {
+
+ /**
+ * Public methods and task_t interface.
+ */
+ ike_delete_t public;
+
+ /**
+ * Assigned IKE_SA.
+ */
+ ike_sa_t *ike_sa;
+
+ /**
+ * Are we the initiator?
+ */
+ bool initiator;
+
+ /**
+ * are we responding to a delete, but have initated our own?
+ */
+ bool simultaneous;
+};
+
+/**
+ * Implementation of task_t.build for initiator
+ */
+static status_t build_i(private_ike_delete_t *this, message_t *message)
+{
+ delete_payload_t *delete_payload;
+
+ delete_payload = delete_payload_create(PROTO_IKE);
+ message->add_payload(message, (payload_t*)delete_payload);
+
+ this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
+
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_i(private_ike_delete_t *this, message_t *message)
+{
+ /* completed, delete IKE_SA by returning FAILED */
+ return FAILED;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_r(private_ike_delete_t *this, message_t *message)
+{
+ /* we don't even scan the payloads, as the message wouldn't have
+ * come so far without being correct */
+ switch (this->ike_sa->get_state(this->ike_sa))
+ {
+ case IKE_DELETING:
+ this->simultaneous = TRUE;
+ break;
+ case IKE_ESTABLISHED:
+ DBG1(DBG_IKE, "deleting IKE_SA on request");
+ break;
+ case IKE_REKEYING:
+ DBG1(DBG_IKE, "initiated rekeying, but received delete for IKE_SA");
+ break;
+ default:
+ break;
+ }
+ this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.build for responder
+ */
+static status_t build_r(private_ike_delete_t *this, message_t *message)
+{
+ if (this->simultaneous)
+ {
+ /* wait for peers response for our delete request, but set a timeout */
+ return SUCCESS;
+ }
+ /* completed, delete IKE_SA by returning FAILED */
+ return FAILED;
+}
+
+/**
+ * Implementation of task_t.get_type
+ */
+static task_type_t get_type(private_ike_delete_t *this)
+{
+ return IKE_DELETE;
+}
+
+/**
+ * Implementation of task_t.migrate
+ */
+static void migrate(private_ike_delete_t *this, ike_sa_t *ike_sa)
+{
+ this->ike_sa = ike_sa;
+ this->simultaneous = FALSE;
+}
+
+/**
+ * Implementation of task_t.destroy
+ */
+static void destroy(private_ike_delete_t *this)
+{
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+ike_delete_t *ike_delete_create(ike_sa_t *ike_sa, bool initiator)
+{
+ private_ike_delete_t *this = malloc_thing(private_ike_delete_t);
+
+ this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
+ this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
+ this->public.task.destroy = (void(*)(task_t*))destroy;
+
+ if (initiator)
+ {
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
+ }
+ else
+ {
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
+ }
+
+ this->ike_sa = ike_sa;
+ this->initiator = initiator;
+ this->simultaneous = FALSE;
+
+ return &this->public;
+}
diff --git a/src/charon/sa/tasks/ike_delete.h b/src/charon/sa/tasks/ike_delete.h
new file mode 100644
index 000000000..e8ec5ebbe
--- /dev/null
+++ b/src/charon/sa/tasks/ike_delete.h
@@ -0,0 +1,57 @@
+/**
+ * @file ike_delete.h
+ *
+ * @brief Interface ike_delete_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_DELETE_H_
+#define IKE_DELETE_H_
+
+typedef struct ike_delete_t ike_delete_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <sa/tasks/task.h>
+
+/**
+ * @brief Task of type ike_delete, delete an IKE_SA.
+ *
+ * @b Constructors:
+ * - ike_delete_create()
+ *
+ * @ingroup tasks
+ */
+struct ike_delete_t {
+
+ /**
+ * Implements the task_t interface
+ */
+ task_t task;
+};
+
+/**
+ * @brief Create a new ike_delete task.
+ *
+ * @param ike_sa IKE_SA this task works for
+ * @param initiator TRUE if we initiate the delete
+ * @return ike_delete task to handle by the task_manager
+ */
+ike_delete_t *ike_delete_create(ike_sa_t *ike_sa, bool initiator);
+
+#endif /* IKE_DELETE_H_ */
diff --git a/src/charon/sa/tasks/ike_dpd.c b/src/charon/sa/tasks/ike_dpd.c
new file mode 100644
index 000000000..1cb05c45c
--- /dev/null
+++ b/src/charon/sa/tasks/ike_dpd.c
@@ -0,0 +1,106 @@
+/**
+ * @file ike_dpd.c
+ *
+ * @brief Implementation of the ike_dpd task.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_dpd.h"
+
+#include <daemon.h>
+
+
+typedef struct private_ike_dpd_t private_ike_dpd_t;
+
+/**
+ * Private members of a ike_dpd_t task.
+ */
+struct private_ike_dpd_t {
+
+ /**
+ * Public methods and task_t interface.
+ */
+ ike_dpd_t public;
+};
+
+/**
+ * Implementation of task_t.build for initiator
+ * Implementation of task_t.process for responder
+ */
+static status_t return_need_more(private_ike_dpd_t *this, message_t *message)
+{
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ * Implementation of task_t.build for responder
+ */
+static status_t return_success(private_ike_dpd_t *this, message_t *message)
+{
+ return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.get_type
+ */
+static task_type_t get_type(private_ike_dpd_t *this)
+{
+ return IKE_DEADPEER;
+}
+
+/**
+ * Implementation of task_t.migrate
+ */
+static void migrate(private_ike_dpd_t *this, ike_sa_t *ike_sa)
+{
+
+}
+
+/**
+ * Implementation of task_t.destroy
+ */
+static void destroy(private_ike_dpd_t *this)
+{
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+ike_dpd_t *ike_dpd_create(bool initiator)
+{
+ private_ike_dpd_t *this = malloc_thing(private_ike_dpd_t);
+
+ this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
+ this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
+ this->public.task.destroy = (void(*)(task_t*))destroy;
+
+ if (initiator)
+ {
+ this->public.task.build = (status_t(*)(task_t*,message_t*))return_need_more;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))return_success;
+ }
+ else
+ {
+ this->public.task.build = (status_t(*)(task_t*,message_t*))return_success;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))return_need_more;
+ }
+
+ return &this->public;
+}
diff --git a/src/charon/sa/tasks/ike_dpd.h b/src/charon/sa/tasks/ike_dpd.h
new file mode 100644
index 000000000..531b0502d
--- /dev/null
+++ b/src/charon/sa/tasks/ike_dpd.h
@@ -0,0 +1,58 @@
+/**
+ * @file ike_dpd.h
+ *
+ * @brief Interface ike_dpd_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_DPD_H_
+#define IKE_DPD_H_
+
+typedef struct ike_dpd_t ike_dpd_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <sa/tasks/task.h>
+
+/**
+ * @brief Task of type ike_dpd, detects dead peers.
+ *
+ * The DPD task actually does nothing, as a DPD has no associated payloads.
+ *
+ * @b Constructors:
+ * - ike_dpd_create()
+ *
+ * @ingroup tasks
+ */
+struct ike_dpd_t {
+
+ /**
+ * Implements the task_t interface
+ */
+ task_t task;
+};
+
+/**
+ * @brief Create a new ike_dpd task.
+ *
+ * @param initiator TRUE if thask is the original initator
+ * @return ike_dpd task to handle by the task_manager
+ */
+ike_dpd_t *ike_dpd_create(bool initiator);
+
+#endif /* IKE_DPD_H_ */
diff --git a/src/charon/sa/tasks/ike_init.c b/src/charon/sa/tasks/ike_init.c
new file mode 100644
index 000000000..0b493666a
--- /dev/null
+++ b/src/charon/sa/tasks/ike_init.c
@@ -0,0 +1,598 @@
+/**
+ * @file ike_init.c
+ *
+ * @brief Implementation of the ike_init task.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2007 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_init.h"
+
+#include <string.h>
+
+#include <daemon.h>
+#include <crypto/diffie_hellman.h>
+#include <encoding/payloads/sa_payload.h>
+#include <encoding/payloads/ke_payload.h>
+#include <encoding/payloads/nonce_payload.h>
+
+/** maximum retries to do with cookies/other dh groups */
+#define MAX_RETRIES 5
+
+typedef struct private_ike_init_t private_ike_init_t;
+
+/**
+ * Private members of a ike_init_t task.
+ */
+struct private_ike_init_t {
+
+ /**
+ * Public methods and task_t interface.
+ */
+ ike_init_t public;
+
+ /**
+ * Assigned IKE_SA.
+ */
+ ike_sa_t *ike_sa;
+
+ /**
+ * Are we the initiator?
+ */
+ bool initiator;
+
+ /**
+ * Connection established by this IKE_SA
+ */
+ connection_t *connection;
+
+ /**
+ * diffie hellman group to use
+ */
+ diffie_hellman_group_t dh_group;
+
+ /**
+ * Diffie hellman object used to generate public DH value.
+ */
+ diffie_hellman_t *diffie_hellman;
+
+ /**
+ * nonce chosen by us
+ */
+ chunk_t my_nonce;
+
+ /**
+ * nonce chosen by peer
+ */
+ chunk_t other_nonce;
+
+ /**
+ * Negotiated proposal used for IKE_SA
+ */
+ proposal_t *proposal;
+
+ /**
+ * Old IKE_SA which gets rekeyed
+ */
+ ike_sa_t *old_sa;
+
+ /**
+ * cookie received from responder
+ */
+ chunk_t cookie;
+
+ /**
+ * retries done so far after failure (cookie or bad dh group)
+ */
+ u_int retry;
+};
+
+/**
+ * build the payloads for the message
+ */
+static void build_payloads(private_ike_init_t *this, message_t *message)
+{
+ sa_payload_t *sa_payload;
+ ke_payload_t *ke_payload;
+ nonce_payload_t *nonce_payload;
+ linked_list_t *proposal_list;
+ ike_sa_id_t *id;
+ proposal_t *proposal;
+ iterator_t *iterator;
+
+ id = this->ike_sa->get_id(this->ike_sa);
+
+ this->connection = this->ike_sa->get_connection(this->ike_sa);
+
+ if (this->initiator)
+ {
+ proposal_list = this->connection->get_proposals(this->connection);
+ if (this->old_sa)
+ {
+ /* include SPI of new IKE_SA when we are rekeying */
+ iterator = proposal_list->create_iterator(proposal_list, TRUE);
+ while (iterator->iterate(iterator, (void**)&proposal))
+ {
+ proposal->set_spi(proposal, id->get_initiator_spi(id));
+ }
+ iterator->destroy(iterator);
+ }
+
+ sa_payload = sa_payload_create_from_proposal_list(proposal_list);
+ proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy));
+ }
+ else
+ {
+ if (this->old_sa)
+ {
+ /* include SPI of new IKE_SA when we are rekeying */
+ this->proposal->set_spi(this->proposal, id->get_responder_spi(id));
+ }
+ sa_payload = sa_payload_create_from_proposal(this->proposal);
+ }
+ message->add_payload(message, (payload_t*)sa_payload);
+
+ nonce_payload = nonce_payload_create();
+ nonce_payload->set_nonce(nonce_payload, this->my_nonce);
+ message->add_payload(message, (payload_t*)nonce_payload);
+
+ ke_payload = ke_payload_create_from_diffie_hellman(this->diffie_hellman);
+ message->add_payload(message, (payload_t*)ke_payload);
+}
+
+/**
+ * Read payloads from message
+ */
+static void process_payloads(private_ike_init_t *this, message_t *message)
+{
+ iterator_t *iterator;
+ payload_t *payload;
+
+ iterator = message->get_payload_iterator(message);
+ while (iterator->iterate(iterator, (void**)&payload))
+ {
+ switch (payload->get_type(payload))
+ {
+ case SECURITY_ASSOCIATION:
+ {
+ sa_payload_t *sa_payload = (sa_payload_t*)payload;
+ linked_list_t *proposal_list;
+
+ proposal_list = sa_payload->get_proposals(sa_payload);
+ this->proposal = this->connection->select_proposal(
+ this->connection, proposal_list);
+ proposal_list->destroy_offset(proposal_list,
+ offsetof(proposal_t, destroy));
+ break;
+ }
+ case KEY_EXCHANGE:
+ {
+ ke_payload_t *ke_payload = (ke_payload_t*)payload;
+ diffie_hellman_group_t dh_group;
+ chunk_t key_data;
+
+ dh_group = ke_payload->get_dh_group_number(ke_payload);
+
+ if (this->initiator)
+ {
+ if (dh_group != this->dh_group)
+ {
+ DBG1(DBG_IKE, "received a DH group not requested (%N)",
+ diffie_hellman_group_names, dh_group);
+ break;
+ }
+ }
+ else
+ {
+ this->dh_group = dh_group;
+ if (!this->connection->check_dh_group(this->connection,
+ dh_group))
+ {
+ break;
+ }
+ this->diffie_hellman = diffie_hellman_create(dh_group);
+ }
+ if (this->diffie_hellman)
+ {
+ key_data = ke_payload->get_key_exchange_data(ke_payload);
+ this->diffie_hellman->set_other_public_value(this->diffie_hellman, key_data);
+ }
+ break;
+ }
+ case NONCE:
+ {
+ nonce_payload_t *nonce_payload = (nonce_payload_t*)payload;
+ this->other_nonce = nonce_payload->get_nonce(nonce_payload);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t build_i(private_ike_init_t *this, message_t *message)
+{
+ randomizer_t *randomizer;
+ status_t status;
+
+ this->connection = this->ike_sa->get_connection(this->ike_sa);
+ SIG(IKE_UP_START, "initiating IKE_SA to %H",
+ this->connection->get_other_host(this->connection));
+ this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
+
+ if (this->retry++ >= MAX_RETRIES)
+ {
+ SIG(IKE_UP_FAILED, "giving up after %d retries", MAX_RETRIES);
+ return FAILED;
+ }
+
+ /* if the DH group is set via use_dh_group(), we already have a DH object */
+ if (!this->diffie_hellman)
+ {
+ this->dh_group = this->connection->get_dh_group(this->connection);
+ this->diffie_hellman = diffie_hellman_create(this->dh_group);
+ if (this->diffie_hellman == NULL)
+ {
+ SIG(IKE_UP_FAILED, "configured DH group %N not supported",
+ diffie_hellman_group_names, this->dh_group);
+ return FAILED;
+ }
+ }
+
+ /* generate nonce only when we are trying the first time */
+ if (this->my_nonce.ptr == NULL)
+ {
+ randomizer = randomizer_create();
+ status = randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE,
+ &this->my_nonce);
+ randomizer->destroy(randomizer);
+ if (status != SUCCESS)
+ {
+ SIG(IKE_UP_FAILED, "error generating random nonce value");
+ return FAILED;
+ }
+ }
+
+ if (this->cookie.ptr)
+ {
+ message->add_notify(message, FALSE, COOKIE, this->cookie);
+ }
+
+ build_payloads(this, message);
+
+
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_r(private_ike_init_t *this, message_t *message)
+{
+ randomizer_t *randomizer;
+
+ this->connection = this->ike_sa->get_connection(this->ike_sa);
+ SIG(IKE_UP_FAILED, "%H is initiating an IKE_SA",
+ message->get_source(message));
+ this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
+
+ randomizer = randomizer_create();
+ if (randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE,
+ &this->my_nonce) != SUCCESS)
+ {
+ DBG1(DBG_IKE, "error generating random nonce value");
+ }
+ randomizer->destroy(randomizer);
+
+ process_payloads(this, message);
+
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.build for responder
+ */
+static status_t build_r(private_ike_init_t *this, message_t *message)
+{
+ chunk_t secret;
+ status_t status;
+
+ /* check if we have everything we need */
+ if (this->proposal == NULL ||
+ this->other_nonce.len == 0 || this->my_nonce.len == 0)
+ {
+ SIG(IKE_UP_FAILED, "received proposals inacceptable");
+ message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
+ return FAILED;
+ }
+
+ if (this->diffie_hellman == NULL ||
+ this->diffie_hellman->get_shared_secret(this->diffie_hellman,
+ &secret) != SUCCESS)
+ {
+ chunk_t chunk;
+ u_int16_t dh_enc;
+
+ SIG(IKE_UP_FAILED, "received inacceptable DH group (%N)",
+ diffie_hellman_group_names, this->dh_group);
+ this->dh_group = this->connection->get_dh_group(this->connection);
+ dh_enc = htons(this->dh_group);
+ chunk.ptr = (u_int8_t*)&dh_enc;
+ chunk.len = sizeof(dh_enc);
+ message->add_notify(message, TRUE, INVALID_KE_PAYLOAD, chunk);
+ DBG1(DBG_IKE, "requesting DH group %N",
+ diffie_hellman_group_names, this->dh_group);
+ return FAILED;
+ }
+
+
+ if (this->old_sa)
+ {
+ ike_sa_id_t *id;
+ prf_t *prf, *child_prf;
+
+ /* Apply SPI if we are rekeying */
+ id = this->ike_sa->get_id(this->ike_sa);
+ id->set_initiator_spi(id, this->proposal->get_spi(this->proposal));
+
+ /* setup crypto keys for the rekeyed SA */
+ prf = this->old_sa->get_prf(this->old_sa);
+ child_prf = this->old_sa->get_child_prf(this->old_sa);
+ status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret,
+ this->other_nonce, this->my_nonce,
+ FALSE, child_prf, prf);
+ }
+ else
+ {
+ /* setup crypto keys */
+ status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret,
+ this->other_nonce, this->my_nonce,
+ FALSE, NULL, NULL);
+ }
+ if (status != SUCCESS)
+ {
+ SIG(IKE_UP_FAILED, "key derivation failed");
+ message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
+ return FAILED;
+ }
+
+ build_payloads(this, message);
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_i(private_ike_init_t *this, message_t *message)
+{
+ chunk_t secret;
+ status_t status;
+ iterator_t *iterator;
+ payload_t *payload;
+
+ /* check for erronous notifies */
+ iterator = message->get_payload_iterator(message);
+ while (iterator->iterate(iterator, (void**)&payload))
+ {
+ if (payload->get_type(payload) == NOTIFY)
+ {
+ notify_payload_t *notify = (notify_payload_t*)payload;
+ notify_type_t type = notify->get_notify_type(notify);
+
+ switch (type)
+ {
+ case INVALID_KE_PAYLOAD:
+ {
+ chunk_t data;
+ diffie_hellman_group_t old_dh_group;
+
+ old_dh_group = this->dh_group;
+ data = notify->get_notification_data(notify);
+ this->dh_group = ntohs(*((u_int16_t*)data.ptr));
+
+ DBG1(DBG_IKE, "peer didn't accept DH group %N, it requested"
+ " %N", diffie_hellman_group_names, old_dh_group,
+ diffie_hellman_group_names, this->dh_group);
+ if (!this->connection->check_dh_group(this->connection,
+ this->dh_group))
+ {
+ DBG1(DBG_IKE, "requested DH group %N not acceptable, "
+ "giving up", diffie_hellman_group_names,
+ this->dh_group);
+ iterator->destroy(iterator);
+ return FAILED;
+ }
+
+ this->ike_sa->reset(this->ike_sa);
+
+ iterator->destroy(iterator);
+ return NEED_MORE;
+ }
+ case NAT_DETECTION_SOURCE_IP:
+ case NAT_DETECTION_DESTINATION_IP:
+ /* skip, handled in ike_natd_t */
+ break;
+ case COOKIE:
+ {
+ chunk_free(&this->cookie);
+ this->cookie = chunk_clone(notify->get_notification_data(notify));
+ this->ike_sa->reset(this->ike_sa);
+ iterator->destroy(iterator);
+ DBG1(DBG_IKE, "received %N notify", notify_type_names, type);
+ return NEED_MORE;
+ }
+ default:
+ {
+ if (type < 16383)
+ {
+ SIG(IKE_UP_FAILED, "received %N notify error",
+ notify_type_names, type);
+ iterator->destroy(iterator);
+ return FAILED;
+ }
+ DBG1(DBG_IKE, "received %N notify",
+ notify_type_names, type);
+ break;
+ }
+ }
+ }
+ }
+ iterator->destroy(iterator);
+
+ process_payloads(this, message);
+
+ /* check if we have everything */
+ if (this->proposal == NULL ||
+ this->other_nonce.len == 0 || this->my_nonce.len == 0)
+ {
+ SIG(IKE_UP_FAILED, "peers proposal selection invalid");
+ return FAILED;
+ }
+
+ if (this->diffie_hellman == NULL ||
+ this->diffie_hellman->get_shared_secret(this->diffie_hellman,
+ &secret) != SUCCESS)
+ {
+ SIG(IKE_UP_FAILED, "peers DH group selection invalid");
+ return FAILED;
+ }
+
+ /* Apply SPI if we are rekeying */
+ if (this->old_sa)
+ {
+ ike_sa_id_t *id;
+ prf_t *prf, *child_prf;
+
+ id = this->ike_sa->get_id(this->ike_sa);
+ id->set_responder_spi(id, this->proposal->get_spi(this->proposal));
+
+ /* setup crypto keys for the rekeyed SA */
+ prf = this->old_sa->get_prf(this->old_sa);
+ child_prf = this->old_sa->get_child_prf(this->old_sa);
+ status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret,
+ this->my_nonce, this->other_nonce,
+ TRUE, child_prf, prf);
+ }
+ else
+ {
+ /* setup crypto keys for a new SA */
+ status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret,
+ this->my_nonce, this->other_nonce,
+ TRUE, NULL, NULL);
+ }
+ if (status != SUCCESS)
+ {
+ SIG(IKE_UP_FAILED, "key derivation failed");
+ return FAILED;
+ }
+ return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.get_type
+ */
+static task_type_t get_type(private_ike_init_t *this)
+{
+ return IKE_INIT;
+}
+
+/**
+ * Implementation of task_t.get_type
+ */
+static chunk_t get_lower_nonce(private_ike_init_t *this)
+{
+ if (memcmp(this->my_nonce.ptr, this->other_nonce.ptr,
+ min(this->my_nonce.len, this->other_nonce.len)) < 0)
+ {
+ return this->my_nonce;
+ }
+ else
+ {
+ return this->other_nonce;
+ }
+}
+
+/**
+ * Implementation of task_t.migrate
+ */
+static void migrate(private_ike_init_t *this, ike_sa_t *ike_sa)
+{
+ DESTROY_IF(this->proposal);
+ DESTROY_IF(this->diffie_hellman);
+ chunk_free(&this->other_nonce);
+
+ this->ike_sa = ike_sa;
+ this->proposal = NULL;
+ this->diffie_hellman = diffie_hellman_create(this->dh_group);
+}
+
+/**
+ * Implementation of task_t.destroy
+ */
+static void destroy(private_ike_init_t *this)
+{
+ DESTROY_IF(this->proposal);
+ DESTROY_IF(this->diffie_hellman);
+ chunk_free(&this->my_nonce);
+ chunk_free(&this->other_nonce);
+ chunk_free(&this->cookie);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa)
+{
+ private_ike_init_t *this = malloc_thing(private_ike_init_t);
+
+ this->public.get_lower_nonce = (chunk_t(*)(ike_init_t*))get_lower_nonce;
+ this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
+ this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
+ this->public.task.destroy = (void(*)(task_t*))destroy;
+ if (initiator)
+ {
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
+ }
+ else
+ {
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
+ }
+
+ this->ike_sa = ike_sa;
+ this->initiator = initiator;
+ this->dh_group = MODP_NONE;
+ this->diffie_hellman = NULL;
+ this->my_nonce = chunk_empty;
+ this->other_nonce = chunk_empty;
+ this->cookie = chunk_empty;
+ this->proposal = NULL;
+ this->connection = NULL;
+ this->old_sa = old_sa;
+ this->retry = 0;
+
+ return &this->public;
+}
diff --git a/src/charon/sa/tasks/ike_init.h b/src/charon/sa/tasks/ike_init.h
new file mode 100644
index 000000000..f60c096e8
--- /dev/null
+++ b/src/charon/sa/tasks/ike_init.h
@@ -0,0 +1,68 @@
+/**
+ * @file ike_init.h
+ *
+ * @brief Interface ike_init_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_INIT_H_
+#define IKE_INIT_H_
+
+typedef struct ike_init_t ike_init_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <sa/tasks/task.h>
+
+/**
+ * @brief Task of type IKE_INIT, creates an IKE_SA without authentication.
+ *
+ * The authentication of is handle in the ike_auth task.
+ *
+ * @b Constructors:
+ * - ike_init_create()
+ *
+ * @ingroup tasks
+ */
+struct ike_init_t {
+
+ /**
+ * Implements the task_t interface
+ */
+ task_t task;
+
+ /**
+ * @brief Get the lower of the two nonces, used for rekey collisions.
+ *
+ * @param this calling object
+ * @return lower nonce
+ */
+ chunk_t (*get_lower_nonce) (ike_init_t *this);
+};
+
+/**
+ * @brief Create a new IKE_INIT task.
+ *
+ * @param ike_sa IKE_SA this task works for (new one when rekeying)
+ * @param initiator TRUE if thask is the original initator
+ * @param old_sa old IKE_SA when we are rekeying
+ * @return ike_init task to handle by the task_manager
+ */
+ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa);
+
+#endif /* IKE_INIT_H_ */
diff --git a/src/charon/sa/tasks/ike_natd.c b/src/charon/sa/tasks/ike_natd.c
new file mode 100644
index 000000000..50b5d652b
--- /dev/null
+++ b/src/charon/sa/tasks/ike_natd.c
@@ -0,0 +1,371 @@
+/**
+ * @file ike_natd.c
+ *
+ * @brief Implementation of the ike_natd task.
+ *
+ */
+
+/*
+ * Copyright (C) 2006-2007 Martin Willi
+ * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_natd.h"
+
+#include <string.h>
+
+#include <daemon.h>
+#include <crypto/hashers/hasher.h>
+#include <encoding/payloads/notify_payload.h>
+
+
+typedef struct private_ike_natd_t private_ike_natd_t;
+
+/**
+ * Private members of a ike_natd_t task.
+ */
+struct private_ike_natd_t {
+
+ /**
+ * Public methods and task_t interface.
+ */
+ ike_natd_t public;
+
+ /**
+ * Assigned IKE_SA.
+ */
+ ike_sa_t *ike_sa;
+
+ /**
+ * Are we the initiator?
+ */
+ bool initiator;
+
+ /**
+ * Hasher used to build NAT detection hashes
+ */
+ hasher_t *hasher;
+
+ /**
+ * Did we process any NAT detection notifys for a source address?
+ */
+ bool src_seen;
+
+ /**
+ * Did we process any NAT detection notifys for a destination address?
+ */
+ bool dst_seen;
+
+ /**
+ * Have we found a matching source address NAT hash?
+ */
+ bool src_matched;
+
+ /**
+ * Have we found a matching destination address NAT hash?
+ */
+ bool dst_matched;
+};
+
+
+/**
+ * Build NAT detection hash for a host
+ */
+static chunk_t generate_natd_hash(private_ike_natd_t *this,
+ ike_sa_id_t *ike_sa_id, host_t *host)
+{
+ chunk_t natd_chunk, spi_i_chunk, spi_r_chunk, addr_chunk, port_chunk;
+ chunk_t natd_hash;
+ u_int64_t spi_i, spi_r;
+ u_int16_t port;
+
+ /* prepare all requred chunks */
+ spi_i = ike_sa_id->get_initiator_spi(ike_sa_id);
+ spi_r = ike_sa_id->get_responder_spi(ike_sa_id);
+ spi_i_chunk.ptr = (void*)&spi_i;
+ spi_i_chunk.len = sizeof(spi_i);
+ spi_r_chunk.ptr = (void*)&spi_r;
+ spi_r_chunk.len = sizeof(spi_r);
+ port = htons(host->get_port(host));
+ port_chunk.ptr = (void*)&port;
+ port_chunk.len = sizeof(port);
+ addr_chunk = host->get_address(host);
+
+ /* natd_hash = SHA1( spi_i | spi_r | address | port ) */
+ natd_chunk = chunk_cat("cccc", spi_i_chunk, spi_r_chunk, addr_chunk, port_chunk);
+ this->hasher->allocate_hash(this->hasher, natd_chunk, &natd_hash);
+ DBG3(DBG_IKE, "natd_chunk %B", &natd_chunk);
+ DBG3(DBG_IKE, "natd_hash %B", &natd_hash);
+
+ chunk_free(&natd_chunk);
+ return natd_hash;
+}
+
+/**
+ * Build a NAT detection notify payload.
+ */
+static notify_payload_t *build_natd_payload(private_ike_natd_t *this,
+ notify_type_t type, host_t *host)
+{
+ chunk_t hash;
+ notify_payload_t *notify;
+ ike_sa_id_t *ike_sa_id;
+
+ ike_sa_id = this->ike_sa->get_id(this->ike_sa);
+ notify = notify_payload_create();
+ notify->set_notify_type(notify, type);
+ hash = generate_natd_hash(this, ike_sa_id, host);
+ notify->set_notification_data(notify, hash);
+ chunk_free(&hash);
+
+ return notify;
+}
+
+/**
+ * read notifys from message and evaluate them
+ */
+static void process_payloads(private_ike_natd_t *this, message_t *message)
+{
+ iterator_t *iterator;
+ payload_t *payload;
+ notify_payload_t *notify;
+ chunk_t hash, src_hash, dst_hash;
+ ike_sa_id_t *ike_sa_id;
+ host_t *me, *other;
+
+ /* Precompute NAT-D hashes for incoming NAT notify comparison */
+ ike_sa_id = message->get_ike_sa_id(message);
+ me = this->ike_sa->get_my_host(this->ike_sa);
+ other = this->ike_sa->get_other_host(this->ike_sa);
+ dst_hash = generate_natd_hash(this, ike_sa_id, me);
+ src_hash = generate_natd_hash(this, ike_sa_id, other);
+
+ DBG3(DBG_IKE, "precalculated src_hash %B", &src_hash);
+ DBG3(DBG_IKE, "precalculated dst_hash %B", &dst_hash);
+
+ iterator = message->get_payload_iterator(message);
+ while (iterator->iterate(iterator, (void**)&payload))
+ {
+ if (payload->get_type(payload) != NOTIFY)
+ {
+ continue;
+ }
+ notify = (notify_payload_t*)payload;
+ switch (notify->get_notify_type(notify))
+ {
+ case NAT_DETECTION_DESTINATION_IP:
+ {
+ this->dst_seen = TRUE;
+ if (!this->dst_matched)
+ {
+ hash = notify->get_notification_data(notify);
+ DBG3(DBG_IKE, "received dst_hash %B", &hash);
+ if (chunk_equals(hash, dst_hash))
+ {
+ this->dst_matched = TRUE;
+ }
+ }
+ break;
+ }
+ case NAT_DETECTION_SOURCE_IP:
+ {
+ this->src_seen = TRUE;
+ if (!this->src_matched)
+ {
+ hash = notify->get_notification_data(notify);
+ DBG3(DBG_IKE, "received src_hash %B", &hash);
+ if (chunk_equals(hash, src_hash))
+ {
+ this->src_matched = TRUE;
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+
+ chunk_free(&src_hash);
+ chunk_free(&dst_hash);
+
+ if (this->src_seen && this->dst_seen)
+ {
+ if (!this->dst_matched)
+ {
+ this->ike_sa->enable_natt(this->ike_sa, TRUE);
+ }
+ if (!this->src_matched)
+ {
+ this->ike_sa->enable_natt(this->ike_sa, FALSE);
+ }
+ }
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_i(private_ike_natd_t *this, message_t *message)
+{
+ process_payloads(this, message);
+
+ if (this->ike_sa->is_natt_enabled(this->ike_sa))
+ {
+ host_t *me, *other;
+
+ me = this->ike_sa->get_my_host(this->ike_sa);
+ me->set_port(me, IKEV2_NATT_PORT);
+ other = this->ike_sa->get_other_host(this->ike_sa);
+ other->set_port(other, IKEV2_NATT_PORT);
+ }
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t build_i(private_ike_natd_t *this, message_t *message)
+{
+ notify_payload_t *notify;
+ linked_list_t *list;
+ host_t *host;
+
+ /* include one notify if our address is defined, all addresses otherwise */
+ host = this->ike_sa->get_my_host(this->ike_sa);
+ if (host->is_anyaddr(host))
+ {
+ /* TODO: we could get the src address from netlink!? */
+ list = charon->kernel_interface->create_address_list(charon->kernel_interface);
+ while (list->remove_first(list, (void**)&host) == SUCCESS)
+ {
+ notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host);
+ host->destroy(host);
+ message->add_payload(message, (payload_t*)notify);
+ }
+ list->destroy(list);
+ }
+ else
+ {
+ notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host);
+ message->add_payload(message, (payload_t*)notify);
+ }
+
+ host = this->ike_sa->get_other_host(this->ike_sa);
+ notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, host);
+ message->add_payload(message, (payload_t*)notify);
+
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.build for responder
+ */
+static status_t build_r(private_ike_natd_t *this, message_t *message)
+{
+ notify_payload_t *notify;
+ host_t *me, *other;
+
+ /* only add notifies on successfull responses. */
+ if (message->get_payload(message, SECURITY_ASSOCIATION) == NULL)
+ {
+ return SUCCESS;
+ }
+
+ if (this->src_seen && this->dst_seen)
+ {
+ /* initiator seems to support NAT detection, add response */
+ me = this->ike_sa->get_my_host(this->ike_sa);
+ notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, me);
+ message->add_payload(message, (payload_t*)notify);
+
+ other = this->ike_sa->get_other_host(this->ike_sa);
+ notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, other);
+ message->add_payload(message, (payload_t*)notify);
+ }
+ return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.process for responder
+ */
+static status_t process_r(private_ike_natd_t *this, message_t *message)
+{
+ process_payloads(this, message);
+
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.get_type
+ */
+static task_type_t get_type(private_ike_natd_t *this)
+{
+ return IKE_NATD;
+}
+
+/**
+ * Implementation of task_t.migrate
+ */
+static void migrate(private_ike_natd_t *this, ike_sa_t *ike_sa)
+{
+ this->ike_sa = ike_sa;
+ this->src_seen = FALSE;
+ this->dst_seen = FALSE;
+ this->src_matched = FALSE;
+ this->dst_matched = FALSE;
+}
+
+/**
+ * Implementation of task_t.destroy
+ */
+static void destroy(private_ike_natd_t *this)
+{
+ this->hasher->destroy(this->hasher);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+ike_natd_t *ike_natd_create(ike_sa_t *ike_sa, bool initiator)
+{
+ private_ike_natd_t *this = malloc_thing(private_ike_natd_t);
+
+ this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
+ this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
+ this->public.task.destroy = (void(*)(task_t*))destroy;
+
+ if (initiator)
+ {
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
+ }
+ else
+ {
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
+ }
+
+ this->ike_sa = ike_sa;
+ this->initiator = initiator;
+ this->hasher = hasher_create(HASH_SHA1);
+ this->src_seen = FALSE;
+ this->dst_seen = FALSE;
+ this->src_matched = FALSE;
+ this->dst_matched = FALSE;
+
+ return &this->public;
+}
diff --git a/src/charon/sa/tasks/ike_natd.h b/src/charon/sa/tasks/ike_natd.h
new file mode 100644
index 000000000..8d0cb58b4
--- /dev/null
+++ b/src/charon/sa/tasks/ike_natd.h
@@ -0,0 +1,57 @@
+/**
+ * @file ike_natd.h
+ *
+ * @brief Interface ike_natd_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_NATD_H_
+#define IKE_NATD_H_
+
+typedef struct ike_natd_t ike_natd_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <sa/tasks/task.h>
+
+/**
+ * @brief Task of type ike_natd, detects NAT situation in IKE_SA_INIT exchange.
+ *
+ * @b Constructors:
+ * - ike_natd_create()
+ *
+ * @ingroup tasks
+ */
+struct ike_natd_t {
+
+ /**
+ * Implements the task_t interface
+ */
+ task_t task;
+};
+
+/**
+ * @brief Create a new ike_natd task.
+ *
+ * @param ike_sa IKE_SA this task works for
+ * @param initiator TRUE if thask is the original initator
+ * @return ike_natd task to handle by the task_manager
+ */
+ike_natd_t *ike_natd_create(ike_sa_t *ike_sa, bool initiator);
+
+#endif /* IKE_NATD_H_ */
diff --git a/src/charon/sa/tasks/ike_rekey.c b/src/charon/sa/tasks/ike_rekey.c
new file mode 100644
index 000000000..a33e7ee34
--- /dev/null
+++ b/src/charon/sa/tasks/ike_rekey.c
@@ -0,0 +1,329 @@
+/**
+ * @file ike_rekey.c
+ *
+ * @brief Implementation of the ike_rekey task.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2007 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_rekey.h"
+
+#include <daemon.h>
+#include <encoding/payloads/notify_payload.h>
+#include <sa/tasks/ike_init.h>
+#include <queues/jobs/delete_ike_sa_job.h>
+#include <queues/jobs/rekey_ike_sa_job.h>
+
+
+typedef struct private_ike_rekey_t private_ike_rekey_t;
+
+/**
+ * Private members of a ike_rekey_t task.
+ */
+struct private_ike_rekey_t {
+
+ /**
+ * Public methods and task_t interface.
+ */
+ ike_rekey_t public;
+
+ /**
+ * Assigned IKE_SA.
+ */
+ ike_sa_t *ike_sa;
+
+ /**
+ * New IKE_SA which replaces the current one
+ */
+ ike_sa_t *new_sa;
+
+ /**
+ * Are we the initiator?
+ */
+ bool initiator;
+
+ /**
+ * the IKE_INIT task which is reused to simplify rekeying
+ */
+ ike_init_t *ike_init;
+
+ /**
+ * colliding task detected by the task manager
+ */
+ task_t *collision;
+};
+
+/**
+ * Implementation of task_t.build for initiator
+ */
+static status_t build_i(private_ike_rekey_t *this, message_t *message)
+{
+ connection_t *connection;
+ policy_t *policy;
+
+ this->new_sa = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager,
+ TRUE);
+
+ connection = this->ike_sa->get_connection(this->ike_sa);
+ policy = this->ike_sa->get_policy(this->ike_sa);
+ this->new_sa->set_connection(this->new_sa, connection);
+ this->new_sa->set_policy(this->new_sa, policy);
+
+ this->ike_init = ike_init_create(this->new_sa, TRUE, this->ike_sa);
+ this->ike_init->task.build(&this->ike_init->task, message);
+
+ this->ike_sa->set_state(this->ike_sa, IKE_REKEYING);
+
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_r(private_ike_rekey_t *this, message_t *message)
+{
+ connection_t *connection;
+ policy_t *policy;
+ iterator_t *iterator;
+ child_sa_t *child_sa;
+
+ if (this->ike_sa->get_state(this->ike_sa) == IKE_DELETING)
+ {
+ DBG1(DBG_IKE, "peer initiated rekeying, but we are deleting");
+ return NEED_MORE;
+ }
+
+ iterator = this->ike_sa->create_child_sa_iterator(this->ike_sa);
+ while (iterator->iterate(iterator, (void**)&child_sa))
+ {
+ switch (child_sa->get_state(child_sa))
+ {
+ case CHILD_CREATED:
+ case CHILD_REKEYING:
+ case CHILD_DELETING:
+ /* we do not allow rekeying while we have children in-progress */
+ DBG1(DBG_IKE, "peer initiated rekeying, but a child is half-open");
+ iterator->destroy(iterator);
+ return NEED_MORE;
+ default:
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+
+ this->new_sa = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager,
+ FALSE);
+
+ connection = this->ike_sa->get_connection(this->ike_sa);
+ policy = this->ike_sa->get_policy(this->ike_sa);
+ this->new_sa->set_connection(this->new_sa, connection);
+ this->new_sa->set_policy(this->new_sa, policy);
+
+ this->ike_init = ike_init_create(this->new_sa, FALSE, this->ike_sa);
+ this->ike_init->task.process(&this->ike_init->task, message);
+
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.build for responder
+ */
+static status_t build_r(private_ike_rekey_t *this, message_t *message)
+{
+ if (this->new_sa == NULL)
+ {
+ /* IKE_SA/a CHILD_SA is in an inacceptable state, deny rekeying */
+ message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
+ return SUCCESS;
+ }
+
+ if (this->ike_init->task.build(&this->ike_init->task, message) == FAILED)
+ {
+ return SUCCESS;
+ }
+
+ this->ike_sa->set_state(this->ike_sa, IKE_REKEYING);
+ this->new_sa->set_state(this->new_sa, IKE_ESTABLISHED);
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_i(private_ike_rekey_t *this, message_t *message)
+{
+ job_t *job;
+ ike_sa_id_t *to_delete;
+
+ if (this->ike_init->task.process(&this->ike_init->task, message) == FAILED)
+ {
+ /* rekeying failed, fallback to old SA */
+ if (!(this->collision &&
+ this->collision->get_type(this->collision) == IKE_DELETE))
+ {
+ job_t *job;
+ u_int32_t retry = charon->configuration->get_retry_interval(
+ charon->configuration);
+ job = (job_t*)rekey_ike_sa_job_create(
+ this->ike_sa->get_id(this->ike_sa), FALSE);
+ DBG1(DBG_IKE, "IKE_SA rekeying failed, "
+ "trying again in %d seconds", retry);
+ this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
+ charon->event_queue->add_relative(charon->event_queue, job, retry * 1000);
+ }
+ return SUCCESS;
+ }
+
+ this->new_sa->set_state(this->new_sa, IKE_ESTABLISHED);
+ to_delete = this->ike_sa->get_id(this->ike_sa);
+
+ /* check for collisions */
+ if (this->collision &&
+ this->collision->get_type(this->collision) == IKE_REKEY)
+ {
+ chunk_t this_nonce, other_nonce;
+ host_t *host;
+ private_ike_rekey_t *other = (private_ike_rekey_t*)this->collision;
+
+ this_nonce = this->ike_init->get_lower_nonce(this->ike_init);
+ other_nonce = other->ike_init->get_lower_nonce(other->ike_init);
+
+ /* if we have the lower nonce, delete rekeyed SA. If not, delete
+ * the redundant. */
+ if (memcmp(this_nonce.ptr, other_nonce.ptr,
+ min(this_nonce.len, other_nonce.len)) < 0)
+ {
+ DBG1(DBG_IKE, "IKE_SA rekey collision won, deleting rekeyed IKE_SA");
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, other->new_sa);
+ }
+ else
+ {
+ DBG1(DBG_IKE, "IKE_SA rekey collision lost, deleting redundant IKE_SA");
+ /* apply host for a proper delete */
+ host = this->ike_sa->get_my_host(this->ike_sa);
+ this->new_sa->set_my_host(this->new_sa, host->clone(host));
+ host = this->ike_sa->get_other_host(this->ike_sa);
+ this->new_sa->set_other_host(this->new_sa, host->clone(host));
+ this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
+ to_delete = this->new_sa->get_id(this->new_sa);
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, this->new_sa);
+ /* inherit to other->new_sa in destroy() */
+ this->new_sa = other->new_sa;
+ other->new_sa = NULL;
+ }
+ }
+
+ job = (job_t*)delete_ike_sa_job_create(to_delete, TRUE);
+ charon->job_queue->add(charon->job_queue, job);
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.get_type
+ */
+static task_type_t get_type(private_ike_rekey_t *this)
+{
+ return IKE_REKEY;
+}
+
+static void collide(private_ike_rekey_t* this, task_t *other)
+{
+ DESTROY_IF(this->collision);
+ this->collision = other;
+}
+
+/**
+ * Implementation of task_t.migrate
+ */
+static void migrate(private_ike_rekey_t *this, ike_sa_t *ike_sa)
+{
+ if (this->ike_init)
+ {
+ this->ike_init->task.destroy(&this->ike_init->task);
+ }
+ if (this->new_sa)
+ {
+ charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
+ this->new_sa);
+ }
+ DESTROY_IF(this->collision);
+
+ this->collision = NULL;
+ this->ike_sa = ike_sa;
+ this->new_sa = NULL;
+ this->ike_init = NULL;
+}
+
+/**
+ * Implementation of task_t.destroy
+ */
+static void destroy(private_ike_rekey_t *this)
+{
+ if (this->new_sa)
+ {
+ if (this->new_sa->get_state(this->new_sa) == IKE_ESTABLISHED &&
+ this->new_sa->inherit(this->new_sa, this->ike_sa) != DESTROY_ME)
+ {
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, this->new_sa);
+ }
+ else
+ {
+ charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
+ this->new_sa);
+ }
+ }
+ if (this->ike_init)
+ {
+ this->ike_init->task.destroy(&this->ike_init->task);
+ }
+ DESTROY_IF(this->collision);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+ike_rekey_t *ike_rekey_create(ike_sa_t *ike_sa, bool initiator)
+{
+ private_ike_rekey_t *this = malloc_thing(private_ike_rekey_t);
+
+ this->public.collide = (void(*)(ike_rekey_t*,task_t*))collide;
+ this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
+ this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
+ this->public.task.destroy = (void(*)(task_t*))destroy;
+ if (initiator)
+ {
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
+ }
+ else
+ {
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
+ }
+
+ this->ike_sa = ike_sa;
+ this->new_sa = NULL;
+ this->ike_init = NULL;
+ this->initiator = initiator;
+ this->collision = NULL;
+
+ return &this->public;
+}
diff --git a/src/charon/sa/tasks/ike_rekey.h b/src/charon/sa/tasks/ike_rekey.h
new file mode 100644
index 000000000..125422efd
--- /dev/null
+++ b/src/charon/sa/tasks/ike_rekey.h
@@ -0,0 +1,69 @@
+/**
+ * @file ike_rekey.h
+ *
+ * @brief Interface ike_rekey_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_REKEY_H_
+#define IKE_REKEY_H_
+
+typedef struct ike_rekey_t ike_rekey_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <sa/tasks/task.h>
+
+/**
+ * @brief Task of type IKE_REKEY, rekey an established IKE_SA.
+ *
+ * @b Constructors:
+ * - ike_rekey_create()
+ *
+ * @ingroup tasks
+ */
+struct ike_rekey_t {
+
+ /**
+ * Implements the task_t interface
+ */
+ task_t task;
+
+ /**
+ * @brief Register a rekeying task which collides with this one.
+ *
+ * If two peers initiate rekeying at the same time, the collision must
+ * be handled gracefully. The task manager is aware of what exchanges
+ * are going on and notifies the outgoing task by passing the incoming.
+ *
+ * @param this task initated by us
+ * @param other incoming task
+ */
+ void (*collide)(ike_rekey_t* this, task_t *other);
+};
+
+/**
+ * @brief Create a new IKE_REKEY task.
+ *
+ * @param ike_sa IKE_SA this task works for
+ * @param initiator TRUE for initiator, FALSE for responder
+ * @return IKE_REKEY task to handle by the task_manager
+ */
+ike_rekey_t *ike_rekey_create(ike_sa_t *ike_sa, bool initiator);
+
+#endif /* IKE_REKEY_H_ */
diff --git a/src/charon/sa/tasks/task.c b/src/charon/sa/tasks/task.c
new file mode 100644
index 000000000..68d8ebf0c
--- /dev/null
+++ b/src/charon/sa/tasks/task.c
@@ -0,0 +1,38 @@
+/**
+ * @file task.c
+ *
+ * @brief Enum values for task types
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 "task.h"
+
+ENUM(task_type_names, IKE_INIT, CHILD_REKEY,
+ "IKE_INIT",
+ "IKE_NATD",
+ "IKE_AUTHENTICATE",
+ "IKE_CERT",
+ "IKE_CONFIG",
+ "IKE_DPD",
+ "IKE_REKEY",
+ "IKE_DELETE",
+ "IKE_DEADPEER",
+ "CHILD_CREATE",
+ "CHILD_DELETE",
+ "CHILD_REKEY",
+);
diff --git a/src/charon/sa/tasks/task.h b/src/charon/sa/tasks/task.h
new file mode 100644
index 000000000..128d7db4a
--- /dev/null
+++ b/src/charon/sa/tasks/task.h
@@ -0,0 +1,151 @@
+/**
+ * @file task.h
+ *
+ * @brief Interface task_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 TASK_H_
+#define TASK_H_
+
+typedef enum task_type_t task_type_t;
+typedef struct task_t task_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <encoding/message.h>
+
+/**
+ * @brief Different kinds of tasks.
+ *
+ * @ingroup tasks
+ */
+enum task_type_t {
+ /** establish an unauthenticated IKE_SA */
+ IKE_INIT,
+ /** detect NAT situation */
+ IKE_NATD,
+ /** authenticate the initiated IKE_SA */
+ IKE_AUTHENTICATE,
+ /** exchange certificates and requests */
+ IKE_CERT,
+ /** Configuration payloads, virtual IP and such */
+ IKE_CONFIG,
+ /** DPD detection */
+ IKE_DEADPEER,
+ /** rekey an IKE_SA */
+ IKE_REKEY,
+ /** delete an IKE_SA */
+ IKE_DELETE,
+ /** liveness check */
+ IKE_DPD,
+ /** establish a CHILD_SA within an IKE_SA */
+ CHILD_CREATE,
+ /** delete an established CHILD_SA */
+ CHILD_DELETE,
+ /** rekey an CHILD_SA */
+ CHILD_REKEY,
+};
+
+/**
+ * enum names for task_type_t.
+ */
+extern enum_name_t *task_type_names;
+
+/**
+ * @brief Interface for a task, an operation handled within exchanges.
+ *
+ * A task is an elemantary operation. It may be handled by a single or by
+ * multiple exchanges. An exchange may even complete multiple tasks.
+ * A task has a build() and an process() operation. The build() operation
+ * creates payloads and adds it to the message. The process() operation
+ * inspects a message and handles its payloads. An initiator of an exchange
+ * first calls build() to build the request, and processes the response message
+ * with the process() method.
+ * A responder does the opposite; it calls process() first to handle an incoming
+ * request and secondly calls build() to build an appropriate response.
+ * Both methods return either SUCCESS, NEED_MORE or FAILED. A SUCCESS indicates
+ * that the task completed, even when the task completed unsuccesfully. The
+ * manager then removes the task from the list. A NEED_MORE is returned when
+ * the task needs further build()/process() calls to complete, the manager
+ * leaves the taks in the queue. A returned FAILED indicates a critical failure.
+ * The manager closes the IKE_SA whenever a task returns FAILED.
+ *
+ * @b Constructors:
+ * - None, use implementations specific constructors
+ *
+ * @ingroup tasks
+ */
+struct task_t {
+
+ /**
+ * @brief Build a request or response message for this task.
+ *
+ * @param this calling object
+ * @param message message to add payloads to
+ * @return
+ * - FAILED if a critical error occured
+ * - NEED_MORE if another call to build/process needed
+ * - SUCCESS if task completed
+ */
+ status_t (*build) (task_t *this, message_t *message);
+
+ /**
+ * @brief Process a request or response message for this task.
+ *
+ * @param this calling object
+ * @param message message to read payloads from
+ * @return
+ * - FAILED if a critical error occured
+ * - NEED_MORE if another call to build/process needed
+ * - SUCCESS if task completed
+ */
+ status_t (*process) (task_t *this, message_t *message);
+
+ /**
+ * @brief Get the type of the task implementation.
+ *
+ * @param this calling object
+ */
+ task_type_t (*get_type) (task_t *this);
+
+ /**
+ * @brief Migrate a task to a new IKE_SA.
+ *
+ * After migrating a task, it goes back to a state where it can be
+ * used again to initate an exchange. This is useful when a task
+ * has to get migrated to a new IKE_SA.
+ * A special usage is when a INVALID_KE_PAYLOAD is received. A call
+ * to reset resets the task, but uses another DH group for the next
+ * try.
+ * The ike_sa is the new IKE_SA this task belongs to and operates on.
+ *
+ * @param this calling object
+ * @param ike_sa new IKE_SA this task works for
+ */
+ void (*migrate) (task_t *this, ike_sa_t *ike_sa);
+
+ /**
+ * @brief Destroys a task_t object.
+ *
+ * @param this calling object
+ */
+ void (*destroy) (task_t *this);
+};
+
+#endif /* TASK_H_ */
diff --git a/src/charon/threads/kernel_interface.c b/src/charon/threads/kernel_interface.c
new file mode 100644
index 000000000..4a70d2ecf
--- /dev/null
+++ b/src/charon/threads/kernel_interface.c
@@ -0,0 +1,1964 @@
+/**
+ * @file kernel_interface.c
+ *
+ * @brief Implementation of kernel_interface_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2007 Martin Willi
+ * Copyright (C) 2006-2007 Tobias Brunner
+ * Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser
+ * Copyright (C) 2006 Daniel Roethlisberger
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2003 Herbert Xu.
+ *
+ * Based on xfrm 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 <sys/types.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/xfrm.h>
+#include <linux/udp.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+
+#include "kernel_interface.h"
+
+#include <daemon.h>
+#include <utils/linked_list.h>
+#include <queues/jobs/delete_child_sa_job.h>
+#include <queues/jobs/rekey_child_sa_job.h>
+#include <queues/jobs/acquire_job.h>
+
+/** kernel level protocol identifiers */
+#define KERNEL_ESP 50
+#define KERNEL_AH 51
+
+/** default priority of installed policies */
+#define PRIO_LOW 3000
+#define PRIO_HIGH 2000
+
+#define BUFFER_SIZE 1024
+
+/**
+ * returns a pointer to the first rtattr following the nlmsghdr *nlh and the
+ * 'usual' netlink data x like 'struct xfrm_usersa_info'
+ */
+#define XFRM_RTA(nlh, x) ((struct rtattr*)(NLMSG_DATA(nlh) + NLMSG_ALIGN(sizeof(x))))
+/**
+ * returns a pointer to the next rtattr following rta.
+ * !!! do not use this to parse messages. use RTA_NEXT and RTA_OK instead !!!
+ */
+#define XFRM_RTA_NEXT(rta) ((struct rtattr*)(((char*)(rta)) + RTA_ALIGN((rta)->rta_len)))
+/**
+ * returns the total size of attached rta data
+ * (after 'usual' netlink data x like 'struct xfrm_usersa_info')
+ */
+#define XFRM_PAYLOAD(nlh, x) NLMSG_PAYLOAD(nlh, sizeof(x))
+
+typedef struct kernel_algorithm_t kernel_algorithm_t;
+
+/**
+ * Mapping from the algorithms defined in IKEv2 to
+ * kernel level algorithm names and their key length
+ */
+struct kernel_algorithm_t {
+ /**
+ * Identifier specified in IKEv2
+ */
+ int ikev2_id;
+
+ /**
+ * Name of the algorithm, as used as kernel identifier
+ */
+ char *name;
+
+ /**
+ * Key length in bits, if fixed size
+ */
+ u_int key_size;
+};
+#define END_OF_LIST -1
+
+/**
+ * Algorithms for encryption
+ */
+kernel_algorithm_t encryption_algs[] = {
+/* {ENCR_DES_IV64, "***", 0}, */
+ {ENCR_DES, "des", 64},
+ {ENCR_3DES, "des3_ede", 192},
+/* {ENCR_RC5, "***", 0}, */
+/* {ENCR_IDEA, "***", 0}, */
+ {ENCR_CAST, "cast128", 0},
+ {ENCR_BLOWFISH, "blowfish", 0},
+/* {ENCR_3IDEA, "***", 0}, */
+/* {ENCR_DES_IV32, "***", 0}, */
+ {ENCR_NULL, "cipher_null", 0},
+ {ENCR_AES_CBC, "aes", 0},
+/* {ENCR_AES_CTR, "***", 0}, */
+ {END_OF_LIST, NULL, 0},
+};
+
+/**
+ * Algorithms for integrity protection
+ */
+kernel_algorithm_t integrity_algs[] = {
+ {AUTH_HMAC_MD5_96, "md5", 128},
+ {AUTH_HMAC_SHA1_96, "sha1", 160},
+ {AUTH_HMAC_SHA2_256_128, "sha256", 256},
+ {AUTH_HMAC_SHA2_384_192, "sha384", 384},
+ {AUTH_HMAC_SHA2_512_256, "sha512", 512},
+/* {AUTH_DES_MAC, "***", 0}, */
+/* {AUTH_KPDK_MD5, "***", 0}, */
+/* {AUTH_AES_XCBC_96, "***", 0}, */
+ {END_OF_LIST, NULL, 0},
+};
+
+/**
+ * Look up a kernel algorithm name and its key size
+ */
+char* lookup_algorithm(kernel_algorithm_t *kernel_algo,
+ algorithm_t *ikev2_algo, u_int *key_size)
+{
+ while (kernel_algo->ikev2_id != END_OF_LIST)
+ {
+ if (ikev2_algo->algorithm == kernel_algo->ikev2_id)
+ {
+ /* match, evaluate key length */
+ if (ikev2_algo->key_size)
+ { /* variable length */
+ *key_size = ikev2_algo->key_size;
+ }
+ else
+ { /* fixed length */
+ *key_size = kernel_algo->key_size;
+ }
+ return kernel_algo->name;
+ }
+ kernel_algo++;
+ }
+ return NULL;
+}
+
+typedef struct route_entry_t route_entry_t;
+
+/**
+ * installed routing entry
+ */
+struct route_entry_t {
+
+ /** Index of the interface the route is bound to */
+ int if_index;
+
+ /** Source ip of the route */
+ host_t *src_ip;
+
+ /** Destination net */
+ chunk_t dst_net;
+
+ /** Destination net prefixlen */
+ u_int8_t prefixlen;
+};
+
+/**
+ * destroy an route_entry_t object
+ */
+static void route_entry_destroy(route_entry_t *this)
+{
+ this->src_ip->destroy(this->src_ip);
+ chunk_free(&this->dst_net);
+ free(this);
+}
+
+typedef struct policy_entry_t policy_entry_t;
+
+/**
+ * installed kernel policy.
+ */
+struct policy_entry_t {
+
+ /** direction of this policy: in, out, forward */
+ u_int8_t direction;
+
+ /** reqid of the policy */
+ u_int32_t reqid;
+
+ /** parameters of installed policy */
+ struct xfrm_selector sel;
+
+ /** associated route installed for this policy */
+ route_entry_t *route;
+
+ /** by how many CHILD_SA's this policy is used */
+ u_int refcount;
+};
+
+typedef struct vip_entry_t vip_entry_t;
+
+/**
+ * Installed virtual ip
+ */
+struct vip_entry_t {
+ /** Index of the interface the ip is bound to */
+ u_int8_t if_index;
+
+ /** The ip address */
+ host_t *ip;
+
+ /** Number of times this IP is used */
+ u_int refcount;
+};
+
+/**
+ * destroy a vip_entry_t object
+ */
+static void vip_entry_destroy(vip_entry_t *this)
+{
+ this->ip->destroy(this->ip);
+ free(this);
+}
+
+typedef struct address_entry_t address_entry_t;
+
+/**
+ * an address found on the system, containg address and interface info
+ */
+struct address_entry_t {
+
+ /** address of this entry */
+ host_t *host;
+
+ /** interface index */
+ int ifindex;
+
+ /** name of the index */
+ char ifname[IFNAMSIZ];
+};
+
+/**
+ * destroy an address entry
+ */
+static void address_entry_destroy(address_entry_t *this)
+{
+ this->host->destroy(this->host);
+ free(this);
+}
+
+typedef struct private_kernel_interface_t private_kernel_interface_t;
+
+/**
+ * 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;
+
+ /**
+ * List of installed policies (kernel_entry_t)
+ */
+ linked_list_t *policies;
+
+ /**
+ * Mutex locks access to policies
+ */
+ pthread_mutex_t policies_mutex;
+
+ /**
+ * List of installed virtual IPs. (vip_entry_t)
+ */
+ linked_list_t *vips;
+
+ /**
+ * Mutex to lock access to vips.
+ */
+ pthread_mutex_t vips_mutex;
+
+ /**
+ * netlink xfrm socket to receive acquire and expire events
+ */
+ int socket_xfrm_events;
+
+ /**
+ * Netlink xfrm socket (IPsec)
+ */
+ int socket_xfrm;
+
+ /**
+ * Netlink rt socket (routing)
+ */
+ int socket_rt;
+
+ /**
+ * Thread receiving events from kernel
+ */
+ pthread_t event_thread;
+};
+
+/**
+ * convert a host_t to a struct xfrm_address
+ */
+static void host2xfrm(host_t *host, xfrm_address_t *xfrm)
+{
+ chunk_t chunk = host->get_address(host);
+ memcpy(xfrm, chunk.ptr, min(chunk.len, sizeof(xfrm_address_t)));
+}
+
+/**
+ * convert a traffic selector address range to subnet and its mask.
+ */
+static void ts2subnet(traffic_selector_t* ts,
+ xfrm_address_t *net, u_int8_t *mask)
+{
+ /* there is no way to do this cleanly, as the address range may
+ * be anything else but a subnet. We use from_addr as subnet
+ * and try to calculate a usable subnet mask.
+ */
+ int byte, bit;
+ bool found = FALSE;
+ chunk_t from, to;
+ size_t size = (ts->get_type(ts) == TS_IPV4_ADDR_RANGE) ? 4 : 16;
+
+ from = ts->get_from_address(ts);
+ to = ts->get_to_address(ts);
+
+ *mask = (size * 8);
+ /* go trough all bits of the addresses, beginning in the front.
+ * as long as they are equal, the subnet gets larger
+ */
+ for (byte = 0; byte < size; byte++)
+ {
+ for (bit = 7; bit >= 0; bit--)
+ {
+ if ((1<<bit & from.ptr[byte]) != (1<<bit & to.ptr[byte]))
+ {
+ *mask = ((7 - bit) + (byte * 8));
+ found = TRUE;
+ break;
+ }
+ }
+ if (found)
+ {
+ break;
+ }
+ }
+ memcpy(net, from.ptr, from.len);
+ chunk_free(&from);
+ chunk_free(&to);
+}
+
+/**
+ * convert a traffic selector port range to port/portmask
+ */
+static void ts2ports(traffic_selector_t* ts,
+ u_int16_t *port, u_int16_t *mask)
+{
+ /* linux does not seem to accept complex portmasks. Only
+ * any or a specific port is allowed. We set to any, if we have
+ * a port range, or to a specific, if we have one port only.
+ */
+ u_int16_t from, to;
+
+ from = ts->get_from_port(ts);
+ to = ts->get_to_port(ts);
+
+ if (from == to)
+ {
+ *port = htons(from);
+ *mask = ~0;
+ }
+ else
+ {
+ *port = 0;
+ *mask = 0;
+ }
+}
+
+/**
+ * convert a pair of traffic_selectors to a xfrm_selector
+ */
+static struct xfrm_selector ts2selector(traffic_selector_t *src,
+ traffic_selector_t *dst)
+{
+ struct xfrm_selector sel;
+
+ memset(&sel, 0, sizeof(sel));
+ sel.family = src->get_type(src) == TS_IPV4_ADDR_RANGE ? AF_INET : AF_INET6;
+ /* src or dest proto may be "any" (0), use more restrictive one */
+ sel.proto = max(src->get_protocol(src), dst->get_protocol(dst));
+ ts2subnet(dst, &sel.daddr, &sel.prefixlen_d);
+ ts2subnet(src, &sel.saddr, &sel.prefixlen_s);
+ ts2ports(dst, &sel.dport, &sel.dport_mask);
+ ts2ports(src, &sel.sport, &sel.sport_mask);
+ sel.ifindex = 0;
+ sel.user = 0;
+
+ return sel;
+}
+
+/**
+ * Creates an rtattr and adds it to the netlink message
+ */
+static void add_attribute(struct nlmsghdr *hdr, int rta_type, chunk_t data,
+ size_t buflen)
+{
+ struct rtattr *rta;
+
+ if (NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(data.len) > buflen)
+ {
+ DBG1(DBG_KNL, "unable to add attribute, buffer too small");
+ return;
+ }
+
+ rta = (struct rtattr*)(((char*)hdr) + NLMSG_ALIGN(hdr->nlmsg_len));
+ rta->rta_type = rta_type;
+ rta->rta_len = RTA_LENGTH(data.len);
+ memcpy(RTA_DATA(rta), data.ptr, data.len);
+ hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + rta->rta_len;
+}
+
+/**
+ * Receives events from kernel
+ */
+static void receive_events(private_kernel_interface_t *this)
+{
+ while(TRUE)
+ {
+ unsigned char response[512];
+ struct nlmsghdr *hdr;
+ struct sockaddr_nl addr;
+ socklen_t addr_len = sizeof(addr);
+ int len;
+
+ hdr = (struct nlmsghdr*)response;
+ len = recvfrom(this->socket_xfrm_events, response, sizeof(response),
+ 0, (struct sockaddr*)&addr, &addr_len);
+ if (len < 0)
+ {
+ if (errno == EINTR)
+ {
+ /* interrupted, try again */
+ continue;
+ }
+ charon->kill(charon, "unable to receive netlink events");
+ }
+
+ if (!NLMSG_OK(hdr, len))
+ {
+ /* bad netlink message */
+ continue;
+ }
+
+ if (addr.nl_pid != 0)
+ {
+ /* not from kernel. not interested, try another one */
+ continue;
+ }
+
+ /* we handle ACQUIRE and EXPIRE messages directly */
+ if (hdr->nlmsg_type == XFRM_MSG_ACQUIRE)
+ {
+ u_int32_t reqid = 0;
+ job_t *job;
+ struct rtattr *rtattr = XFRM_RTA(hdr, struct xfrm_user_acquire);
+ size_t rtsize = XFRM_PAYLOAD(hdr, struct xfrm_user_tmpl);
+ if (RTA_OK(rtattr, rtsize))
+ {
+ if (rtattr->rta_type == XFRMA_TMPL)
+ {
+ struct xfrm_user_tmpl* tmpl = (struct xfrm_user_tmpl*)RTA_DATA(rtattr);
+ reqid = tmpl->reqid;
+ }
+ }
+ if (reqid == 0)
+ {
+ DBG1(DBG_KNL, "received a XFRM_MSG_ACQUIRE, but no reqid found");
+ }
+ else
+ {
+ DBG2(DBG_KNL, "received a XFRM_MSG_ACQUIRE");
+ DBG1(DBG_KNL, "creating acquire job for CHILD_SA with reqid %d",
+ reqid);
+ job = (job_t*)acquire_job_create(reqid);
+ charon->job_queue->add(charon->job_queue, job);
+ }
+ }
+ else if (hdr->nlmsg_type == XFRM_MSG_EXPIRE)
+ {
+ job_t *job;
+ protocol_id_t protocol;
+ u_int32_t spi, reqid;
+ struct xfrm_user_expire *expire;
+
+ expire = (struct xfrm_user_expire*)NLMSG_DATA(hdr);
+ protocol = expire->state.id.proto == KERNEL_ESP ?
+ PROTO_ESP : PROTO_AH;
+ spi = expire->state.id.spi;
+ reqid = expire->state.reqid;
+
+ DBG2(DBG_KNL, "received a XFRM_MSG_EXPIRE");
+ DBG1(DBG_KNL, "creating %s job for %N CHILD_SA 0x%x (reqid %d)",
+ expire->hard ? "delete" : "rekey", protocol_id_names,
+ protocol, ntohl(spi), reqid);
+ if (expire->hard)
+ {
+ job = (job_t*)delete_child_sa_job_create(reqid, protocol, spi);
+ }
+ else
+ {
+ job = (job_t*)rekey_child_sa_job_create(reqid, protocol, spi);
+ }
+ charon->job_queue->add(charon->job_queue, job);
+ }
+ }
+}
+
+/**
+ * send a netlink message and wait for a reply
+ */
+static status_t netlink_send(int socket, struct nlmsghdr *in,
+ struct nlmsghdr **out, size_t *out_len)
+{
+ int len, addr_len;
+ struct sockaddr_nl addr;
+ chunk_t result = chunk_empty, tmp;
+ struct nlmsghdr *msg, peek;
+
+ static int seq = 200;
+ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+
+ pthread_mutex_lock(&mutex);
+
+ in->nlmsg_seq = ++seq;
+ in->nlmsg_pid = getpid();
+
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ addr.nl_pid = 0;
+ addr.nl_groups = 0;
+
+ while (TRUE)
+ {
+ len = sendto(socket, in, in->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+
+ if (len != in->nlmsg_len)
+ {
+ if (errno == EINTR)
+ {
+ /* interrupted, try again */
+ continue;
+ }
+ pthread_mutex_unlock(&mutex);
+ DBG1(DBG_KNL, "error sending to netlink socket: %m");
+ return FAILED;
+ }
+ break;
+ }
+
+ while (TRUE)
+ {
+ char buf[1024];
+ tmp.len = sizeof(buf);
+ tmp.ptr = buf;
+ msg = (struct nlmsghdr*)tmp.ptr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ addr.nl_pid = getpid();
+ addr.nl_groups = 0;
+ addr_len = sizeof(addr);
+
+ len = recvfrom(socket, tmp.ptr, tmp.len, 0,
+ (struct sockaddr*)&addr, &addr_len);
+
+ if (len < 0)
+ {
+ if (errno == EINTR)
+ {
+ DBG1(DBG_IKE, "got interrupted");
+ /* interrupted, try again */
+ continue;
+ }
+ DBG1(DBG_IKE, "error reading from netlink socket: %m");
+ pthread_mutex_unlock(&mutex);
+ return FAILED;
+ }
+ if (!NLMSG_OK(msg, len))
+ {
+ DBG1(DBG_IKE, "received corrupted netlink message");
+ pthread_mutex_unlock(&mutex);
+ return FAILED;
+ }
+ if (msg->nlmsg_seq != seq)
+ {
+ DBG1(DBG_IKE, "received invalid netlink sequence number");
+ if (msg->nlmsg_seq < seq)
+ {
+ continue;
+ }
+ pthread_mutex_unlock(&mutex);
+ return FAILED;
+ }
+
+ tmp.len = len;
+ result = chunk_cata("cc", result, tmp);
+
+ /* NLM_F_MULTI flag does not seem to be set correctly, we use sequence
+ * numbers to detect multi header messages */
+ len = recvfrom(socket, &peek, sizeof(peek), MSG_PEEK | MSG_DONTWAIT,
+ (struct sockaddr*)&addr, &addr_len);
+
+ if (len == sizeof(peek) && peek.nlmsg_seq == seq)
+ {
+ /* seems to be multipart */
+ continue;
+ }
+ break;
+ }
+
+ *out_len = result.len;
+ *out = (struct nlmsghdr*)clalloc(result.ptr, result.len);
+
+ pthread_mutex_unlock(&mutex);
+
+ return SUCCESS;
+}
+
+/**
+ * send a netlink message and wait for its acknowlegde
+ */
+static status_t netlink_send_ack(int socket, struct nlmsghdr *in)
+{
+ struct nlmsghdr *out, *hdr;
+ size_t len;
+
+ if (netlink_send(socket, in, &out, &len) != SUCCESS)
+ {
+ return FAILED;
+ }
+ hdr = out;
+ while (NLMSG_OK(hdr, len))
+ {
+ switch (hdr->nlmsg_type)
+ {
+ case NLMSG_ERROR:
+ {
+ struct nlmsgerr* err = (struct nlmsgerr*)NLMSG_DATA(hdr);
+
+ if (err->error)
+ {
+ DBG1(DBG_KNL, "received netlink error: %s (%d)",
+ strerror(-err->error), -err->error);
+ free(out);
+ return FAILED;
+ }
+ free(out);
+ return SUCCESS;
+ }
+ default:
+ hdr = NLMSG_NEXT(hdr, len);
+ continue;
+ case NLMSG_DONE:
+ break;
+ }
+ break;
+ }
+ DBG1(DBG_KNL, "netlink request not acknowlegded");
+ free(out);
+ return FAILED;
+}
+
+/**
+ * Create a list of local addresses.
+ */
+static linked_list_t *create_address_list(private_kernel_interface_t *this)
+{
+ char request[BUFFER_SIZE];
+ struct nlmsghdr *out, *hdr;
+ struct rtgenmsg *msg;
+ size_t len;
+ linked_list_t *list;
+
+ DBG2(DBG_IKE, "getting local address list");
+
+ list = linked_list_create();
+
+ memset(&request, 0, sizeof(request));
+
+ hdr = (struct nlmsghdr*)&request;
+ hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
+ hdr->nlmsg_type = RTM_GETADDR;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH | NLM_F_ROOT;
+ msg = (struct rtgenmsg*)NLMSG_DATA(hdr);
+ msg->rtgen_family = AF_UNSPEC;
+
+ if (netlink_send(this->socket_rt, hdr, &out, &len) == SUCCESS)
+ {
+ hdr = out;
+ while (NLMSG_OK(hdr, len))
+ {
+ switch (hdr->nlmsg_type)
+ {
+ case RTM_NEWADDR:
+ {
+ struct ifaddrmsg* msg = (struct ifaddrmsg*)(NLMSG_DATA(hdr));
+ struct rtattr *rta = IFA_RTA(msg);
+ size_t rtasize = IFA_PAYLOAD (hdr);
+ host_t *host = NULL;
+ char *name = NULL;
+ chunk_t local = chunk_empty, address = chunk_empty;
+
+ while(RTA_OK(rta, rtasize))
+ {
+ switch (rta->rta_type)
+ {
+ case IFA_LOCAL:
+ local.ptr = RTA_DATA(rta);
+ local.len = RTA_PAYLOAD(rta);
+ break;
+ case IFA_ADDRESS:
+ address.ptr = RTA_DATA(rta);
+ address.len = RTA_PAYLOAD(rta);
+ break;
+ case IFA_LABEL:
+ name = RTA_DATA(rta);
+ break;
+ }
+ rta = RTA_NEXT(rta, rtasize);
+ }
+
+ /* For PPP interfaces, we need the IFA_LOCAL address,
+ * IFA_ADDRESS is the peers address. But IFA_LOCAL is
+ * not included in all cases, so fallback to IFA_ADDRESS. */
+ if (local.ptr)
+ {
+ host = host_create_from_chunk(msg->ifa_family, local, 0);
+ }
+ else if (address.ptr)
+ {
+ host = host_create_from_chunk(msg->ifa_family, address, 0);
+ }
+
+ if (host)
+ {
+ address_entry_t *entry;
+
+ entry = malloc_thing(address_entry_t);
+ entry->host = host;
+ entry->ifindex = msg->ifa_index;
+ if (name)
+ {
+ memcpy(entry->ifname, name, IFNAMSIZ);
+ }
+ else
+ {
+ strcpy(entry->ifname, "(unknown)");
+ }
+ list->insert_last(list, entry);
+ }
+ hdr = NLMSG_NEXT(hdr, len);
+ continue;
+ }
+ default:
+ hdr = NLMSG_NEXT(hdr, len);
+ continue;
+ case NLMSG_DONE:
+ break;
+ }
+ break;
+ }
+ free(out);
+ }
+ else
+ {
+ DBG1(DBG_IKE, "unable to get local address list");
+ }
+
+ return list;
+}
+
+/**
+ * Implements kernel_interface_t.create_address_list.
+ */
+static linked_list_t *create_address_list_public(private_kernel_interface_t *this)
+{
+ linked_list_t *result, *list;
+ address_entry_t *entry;
+
+ result = linked_list_create();
+ list = create_address_list(this);
+ while (list->remove_last(list, (void**)&entry) == SUCCESS)
+ {
+ result->insert_last(result, entry->host);
+ free(entry);
+ }
+ list->destroy(list);
+
+ return result;
+}
+
+/**
+ * implementation of kernel_interface_t.get_interface_name
+ */
+static char *get_interface_name(private_kernel_interface_t *this, host_t* ip)
+{
+ linked_list_t *list;
+ address_entry_t *entry;
+ char *name = NULL;
+
+ DBG2(DBG_IKE, "getting interface name for %H", ip);
+
+ list = create_address_list(this);
+ while (!name && list->remove_last(list, (void**)&entry) == SUCCESS)
+ {
+ if (ip->ip_equals(ip, entry->host))
+ {
+ name = strdup(entry->ifname);
+ }
+ address_entry_destroy(entry);
+ }
+ list->destroy_function(list, (void*)address_entry_destroy);
+
+ if (name)
+ {
+ DBG2(DBG_IKE, "%H is on interface %s", ip, name);
+ }
+ else
+ {
+ DBG2(DBG_IKE, "%H is not a local address", ip);
+ }
+ return name;
+}
+
+/**
+ * Tries to find an ip address of a local interface that is included in the
+ * supplied traffic selector.
+ */
+static status_t get_address_by_ts(private_kernel_interface_t *this,
+ traffic_selector_t *ts, host_t **ip)
+{
+ address_entry_t *entry;
+ host_t *host;
+ int family;
+ linked_list_t *list;
+ bool found = FALSE;
+
+ DBG2(DBG_IKE, "getting a local address in traffic selector %R", ts);
+
+ /* if we have a family which includes localhost, we do not
+ * search for an IP, we use the default */
+ family = ts->get_type(ts) == TS_IPV4_ADDR_RANGE ? AF_INET : AF_INET6;
+
+ if (family == AF_INET)
+ {
+ host = host_create_from_string("127.0.0.1", 0);
+ }
+ else
+ {
+ host = host_create_from_string("::1", 0);
+ }
+
+ if (ts->includes(ts, host))
+ {
+ *ip = host_create_any(family);
+ host->destroy(host);
+ DBG2(DBG_IKE, "using host %H", *ip);
+ return SUCCESS;
+ }
+ host->destroy(host);
+
+ list = create_address_list(this);
+ while (!found && list->remove_last(list, (void**)&entry) == SUCCESS)
+ {
+ if (ts->includes(ts, entry->host))
+ {
+ found = TRUE;
+ *ip = entry->host->clone(entry->host);
+ }
+ address_entry_destroy(entry);
+ }
+ list->destroy_function(list, (void*)address_entry_destroy);
+
+ if (!found)
+ {
+ DBG1(DBG_IKE, "no local address found in traffic selector %R", ts);
+ return FAILED;
+ }
+ DBG2(DBG_IKE, "using host %H", *ip);
+ return SUCCESS;
+}
+
+/**
+ * get the interface of a local address
+ */
+static int get_interface_index(private_kernel_interface_t *this, host_t* ip)
+{
+ linked_list_t *list;
+ address_entry_t *entry;
+ int ifindex = 0;
+
+ DBG2(DBG_IKE, "getting iface for %H", ip);
+
+ list = create_address_list(this);
+ while (!ifindex && list->remove_last(list, (void**)&entry) == SUCCESS)
+ {
+ if (ip->ip_equals(ip, entry->host))
+ {
+ ifindex = entry->ifindex;
+ }
+ address_entry_destroy(entry);
+ }
+ list->destroy_function(list, (void*)address_entry_destroy);
+
+ if (ifindex == 0)
+ {
+ DBG1(DBG_IKE, "unable to get interface for %H", ip);
+ }
+ return ifindex;
+}
+
+/**
+ * Manages the creation and deletion of ip addresses on an interface.
+ * By setting the appropriate nlmsg_type, the ip will be set or unset.
+ */
+static status_t manage_ipaddr(private_kernel_interface_t *this, int nlmsg_type,
+ int flags, int if_index, host_t *ip)
+{
+ unsigned char request[BUFFER_SIZE];
+ struct nlmsghdr *hdr;
+ struct ifaddrmsg *msg;
+ chunk_t chunk;
+
+ memset(&request, 0, sizeof(request));
+
+ chunk = ip->get_address(ip);
+
+ hdr = (struct nlmsghdr*)request;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ hdr->nlmsg_type = nlmsg_type;
+ hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+
+ msg = (struct ifaddrmsg*)NLMSG_DATA(hdr);
+ msg->ifa_family = ip->get_family(ip);
+ msg->ifa_flags = 0;
+ msg->ifa_prefixlen = 8 * chunk.len;
+ msg->ifa_scope = RT_SCOPE_UNIVERSE;
+ msg->ifa_index = if_index;
+
+ add_attribute(hdr, IFA_LOCAL, chunk, sizeof(request));
+
+ return netlink_send_ack(this->socket_rt, hdr);
+}
+
+/**
+ * Manages source routes in the routing table.
+ * By setting the appropriate nlmsg_type, the route added or r.
+ */
+static status_t manage_srcroute(private_kernel_interface_t *this, int nlmsg_type,
+ int flags, route_entry_t *route)
+{
+ unsigned char request[BUFFER_SIZE];
+ struct nlmsghdr *hdr;
+ struct rtmsg *msg;
+ chunk_t chunk;
+
+ /* if route is 0.0.0.0/0, we can't install it, as it would
+ * overwrite the default route. Instead, we add two routes:
+ * 0.0.0.0/1 and 128.0.0.0/1
+ * TODO: use metrics instead */
+ if (route->prefixlen == 0)
+ {
+ route_entry_t half;
+ status_t status;
+
+ half.dst_net = chunk_alloca(route->dst_net.len);
+ memset(half.dst_net.ptr, 0, half.dst_net.len);
+ half.src_ip = route->src_ip;
+ half.if_index = route->if_index;
+ half.prefixlen = 1;
+
+ status = manage_srcroute(this, nlmsg_type, flags, &half);
+ half.dst_net.ptr[0] |= 0x80;
+ status = manage_srcroute(this, nlmsg_type, flags, &half);
+ return status;
+ }
+
+ memset(&request, 0, sizeof(request));
+
+ hdr = (struct nlmsghdr*)request;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+ hdr->nlmsg_type = nlmsg_type;
+ hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+
+ msg = (struct rtmsg*)NLMSG_DATA(hdr);
+ msg->rtm_family = route->src_ip->get_family(route->src_ip);
+ msg->rtm_dst_len = route->prefixlen;
+ msg->rtm_table = RT_TABLE_MAIN;
+ msg->rtm_protocol = RTPROT_STATIC;
+ msg->rtm_type = RTN_UNICAST;
+ msg->rtm_scope = RT_SCOPE_UNIVERSE;
+
+ add_attribute(hdr, RTA_DST, route->dst_net, sizeof(request));
+ chunk = route->src_ip->get_address(route->src_ip);
+ add_attribute(hdr, RTA_PREFSRC, chunk, sizeof(request));
+ chunk.ptr = (char*)&route->if_index;
+ chunk.len = sizeof(route->if_index);
+ add_attribute(hdr, RTA_OIF, chunk, sizeof(request));
+
+ return netlink_send_ack(this->socket_rt, hdr);
+}
+
+
+/**
+ * Implementation of kernel_interface_t.add_ip.
+ */
+static status_t add_ip(private_kernel_interface_t *this,
+ host_t *virtual_ip, host_t *iface_ip)
+{
+ int targetif;
+ vip_entry_t *listed;
+ iterator_t *iterator;
+
+ DBG2(DBG_KNL, "adding virtual IP %H", virtual_ip);
+
+ targetif = get_interface_index(this, iface_ip);
+ if (targetif == 0)
+ {
+ DBG1(DBG_KNL, "unable to add virtual IP %H, no iface found for %H",
+ virtual_ip, iface_ip);
+ return FAILED;
+ }
+
+ /* beware of deadlocks (e.g. send/receive packets while holding the lock) */
+ iterator = this->vips->create_iterator_locked(this->vips, &(this->vips_mutex));
+ while (iterator->iterate(iterator, (void**)&listed))
+ {
+ if (listed->if_index == targetif &&
+ virtual_ip->ip_equals(virtual_ip, listed->ip))
+ {
+ listed->refcount++;
+ iterator->destroy(iterator);
+ DBG2(DBG_KNL, "virtual IP %H already added to iface %d reusing it",
+ virtual_ip, targetif);
+ return SUCCESS;
+ }
+ }
+ iterator->destroy(iterator);
+
+ if (manage_ipaddr(this, RTM_NEWADDR, NLM_F_CREATE | NLM_F_EXCL,
+ targetif, virtual_ip) == SUCCESS)
+ {
+ listed = malloc_thing(vip_entry_t);
+ listed->ip = virtual_ip->clone(virtual_ip);
+ listed->if_index = targetif;
+ listed->refcount = 1;
+ this->vips->insert_last(this->vips, listed);
+ DBG2(DBG_KNL, "virtual IP %H added to iface %d",
+ virtual_ip, targetif);
+ return SUCCESS;
+ }
+
+ DBG2(DBG_KNL, "unable to add virtual IP %H to iface %d",
+ virtual_ip, targetif);
+ return FAILED;
+}
+
+/**
+ * Implementation of kernel_interface_t.del_ip.
+ */
+static status_t del_ip(private_kernel_interface_t *this,
+ host_t *virtual_ip, host_t *iface_ip)
+{
+ int targetif;
+ vip_entry_t *listed;
+ iterator_t *iterator;
+
+ DBG2(DBG_KNL, "deleting virtual IP %H", virtual_ip);
+
+ targetif = get_interface_index(this, iface_ip);
+ if (targetif == 0)
+ {
+ DBG1(DBG_KNL, "unable to delete virtual IP %H, no iface found for %H",
+ virtual_ip, iface_ip);
+ return FAILED;
+ }
+
+ /* beware of deadlocks (e.g. send/receive packets while holding the lock) */
+ iterator = this->vips->create_iterator_locked(this->vips, &(this->vips_mutex));
+ while (iterator->iterate(iterator, (void**)&listed))
+ {
+ if (listed->if_index == targetif &&
+ virtual_ip->ip_equals(virtual_ip, listed->ip))
+ {
+ listed->refcount--;
+ if (listed->refcount == 0)
+ {
+ iterator->remove(iterator);
+ vip_entry_destroy(listed);
+ iterator->destroy(iterator);
+ return manage_ipaddr(this, RTM_DELADDR, 0, targetif, virtual_ip);
+ }
+ iterator->destroy(iterator);
+ DBG2(DBG_KNL, "virtual IP %H used by other SAs, not deleting",
+ virtual_ip);
+ return SUCCESS;
+ }
+ }
+ iterator->destroy(iterator);
+
+ DBG2(DBG_KNL, "virtual IP %H not cached, unable to delete", virtual_ip);
+ return FAILED;
+}
+
+/**
+ * Implementation of kernel_interface_t.get_spi.
+ */
+static status_t get_spi(private_kernel_interface_t *this,
+ host_t *src, host_t *dst,
+ protocol_id_t protocol, u_int32_t reqid,
+ u_int32_t *spi)
+{
+ unsigned char request[BUFFER_SIZE];
+ struct nlmsghdr *hdr, *out;
+ struct xfrm_userspi_info *userspi;
+ u_int32_t received_spi = 0;
+ size_t len;
+
+ memset(&request, 0, sizeof(request));
+
+ DBG2(DBG_KNL, "getting SPI for reqid %d", reqid);
+
+ hdr = (struct nlmsghdr*)request;
+ hdr->nlmsg_flags = NLM_F_REQUEST;
+ hdr->nlmsg_type = XFRM_MSG_ALLOCSPI;
+ hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_userspi_info));
+
+ userspi = (struct xfrm_userspi_info*)NLMSG_DATA(hdr);
+ host2xfrm(src, &userspi->info.saddr);
+ host2xfrm(dst, &userspi->info.id.daddr);
+ userspi->info.id.proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH;
+ userspi->info.mode = TRUE; /* tunnel mode */
+ userspi->info.reqid = reqid;
+ userspi->info.family = src->get_family(src);
+ userspi->min = 0xc0000000;
+ userspi->max = 0xcFFFFFFF;
+
+ if (netlink_send(this->socket_xfrm, hdr, &out, &len) == SUCCESS)
+ {
+ hdr = out;
+ while (NLMSG_OK(hdr, len))
+ {
+ switch (hdr->nlmsg_type)
+ {
+ case XFRM_MSG_NEWSA:
+ {
+ struct xfrm_usersa_info* usersa = NLMSG_DATA(hdr);
+ received_spi = usersa->id.spi;
+ break;
+ }
+ case NLMSG_ERROR:
+ {
+ struct nlmsgerr *err = NLMSG_DATA(hdr);
+
+ DBG1(DBG_KNL, "allocating SPI failed: %s (%d)",
+ strerror(-err->error), -err->error);
+ break;
+ }
+ default:
+ hdr = NLMSG_NEXT(hdr, len);
+ continue;
+ case NLMSG_DONE:
+ break;
+ }
+ break;
+ }
+ free(out);
+ }
+
+ if (received_spi == 0)
+ {
+ DBG1(DBG_KNL, "unable to get SPI for reqid %d", reqid);
+ return FAILED;
+ }
+
+ DBG2(DBG_KNL, "got SPI 0x%x for reqid %d", received_spi, reqid);
+
+ *spi = received_spi;
+ return SUCCESS;
+}
+
+/**
+ * Implementation of kernel_interface_t.add_sa.
+ */
+static status_t add_sa(private_kernel_interface_t *this,
+ host_t *src, host_t *dst, u_int32_t spi,
+ protocol_id_t protocol, u_int32_t reqid,
+ u_int64_t expire_soft, u_int64_t expire_hard,
+ algorithm_t *enc_alg, algorithm_t *int_alg,
+ prf_plus_t *prf_plus, natt_conf_t *natt, mode_t mode,
+ bool replace)
+{
+ unsigned char request[BUFFER_SIZE];
+ char *alg_name;
+ u_int key_size;
+ struct nlmsghdr *hdr;
+ struct xfrm_usersa_info *sa;
+
+ memset(&request, 0, sizeof(request));
+
+ DBG2(DBG_KNL, "adding SAD entry with SPI 0x%x", spi);
+
+ hdr = (struct nlmsghdr*)request;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ hdr->nlmsg_type = replace ? XFRM_MSG_UPDSA : XFRM_MSG_NEWSA;
+ hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info));
+
+ sa = (struct xfrm_usersa_info*)NLMSG_DATA(hdr);
+ host2xfrm(src, &sa->saddr);
+ host2xfrm(dst, &sa->id.daddr);
+ sa->id.spi = spi;
+ sa->id.proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH;
+ sa->family = src->get_family(src);
+ sa->mode = mode;
+ sa->replay_window = 32;
+ sa->reqid = reqid;
+ /* we currently do not expire SAs by volume/packet count */
+ sa->lft.soft_byte_limit = XFRM_INF;
+ sa->lft.hard_byte_limit = XFRM_INF;
+ sa->lft.soft_packet_limit = XFRM_INF;
+ sa->lft.hard_packet_limit = XFRM_INF;
+ /* we use lifetimes since added, not since used */
+ sa->lft.soft_add_expires_seconds = expire_soft;
+ sa->lft.hard_add_expires_seconds = expire_hard;
+ sa->lft.soft_use_expires_seconds = 0;
+ sa->lft.hard_use_expires_seconds = 0;
+
+ struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_usersa_info);
+
+ if (enc_alg->algorithm != ENCR_UNDEFINED)
+ {
+ rthdr->rta_type = XFRMA_ALG_CRYPT;
+ alg_name = lookup_algorithm(encryption_algs, enc_alg, &key_size);
+ if (alg_name == NULL)
+ {
+ DBG1(DBG_KNL, "algorithm %N not supported by kernel!",
+ encryption_algorithm_names, enc_alg->algorithm);
+ return FAILED;
+ }
+ DBG2(DBG_KNL, " using encryption algorithm %N with key size %d",
+ encryption_algorithm_names, enc_alg->algorithm, key_size);
+
+ rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + key_size);
+ hdr->nlmsg_len += rthdr->rta_len;
+ if (hdr->nlmsg_len > sizeof(request))
+ {
+ return FAILED;
+ }
+
+ struct xfrm_algo* algo = (struct xfrm_algo*)RTA_DATA(rthdr);
+ algo->alg_key_len = key_size;
+ strcpy(algo->alg_name, alg_name);
+ prf_plus->get_bytes(prf_plus, key_size / 8, algo->alg_key);
+
+ rthdr = XFRM_RTA_NEXT(rthdr);
+ }
+
+ if (int_alg->algorithm != AUTH_UNDEFINED)
+ {
+ rthdr->rta_type = XFRMA_ALG_AUTH;
+ alg_name = lookup_algorithm(integrity_algs, int_alg, &key_size);
+ if (alg_name == NULL)
+ {
+ DBG1(DBG_KNL, "algorithm %N not supported by kernel!",
+ integrity_algorithm_names, int_alg->algorithm);
+ return FAILED;
+ }
+ DBG2(DBG_KNL, " using integrity algorithm %N with key size %d",
+ integrity_algorithm_names, int_alg->algorithm, key_size);
+
+ rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + key_size);
+ hdr->nlmsg_len += rthdr->rta_len;
+ if (hdr->nlmsg_len > sizeof(request))
+ {
+ return FAILED;
+ }
+
+ struct xfrm_algo* algo = (struct xfrm_algo*)RTA_DATA(rthdr);
+ algo->alg_key_len = key_size;
+ strcpy(algo->alg_name, alg_name);
+ prf_plus->get_bytes(prf_plus, key_size / 8, algo->alg_key);
+
+ rthdr = XFRM_RTA_NEXT(rthdr);
+ }
+
+ /* TODO: add IPComp here */
+
+ if (natt)
+ {
+ rthdr->rta_type = XFRMA_ENCAP;
+ rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_encap_tmpl));
+
+ hdr->nlmsg_len += rthdr->rta_len;
+ if (hdr->nlmsg_len > sizeof(request))
+ {
+ return FAILED;
+ }
+
+ struct xfrm_encap_tmpl* encap = (struct xfrm_encap_tmpl*)RTA_DATA(rthdr);
+ encap->encap_type = UDP_ENCAP_ESPINUDP;
+ encap->encap_sport = htons(natt->sport);
+ encap->encap_dport = htons(natt->dport);
+ memset(&encap->encap_oa, 0, sizeof (xfrm_address_t));
+ /* encap_oa could probably be derived from the
+ * traffic selectors [rfc4306, p39]. In the netlink kernel implementation
+ * pluto does the same as we do here but it uses encap_oa in the
+ * pfkey implementation. BUT as /usr/src/linux/net/key/af_key.c indicates
+ * the kernel ignores it anyway
+ * -> does that mean that NAT-T encap doesn't work in transport mode?
+ * No. The reason the kernel ignores NAT-OA is that it recomputes
+ * (or, rather, just ignores) the checksum. If packets pass
+ * the IPsec checks it marks them "checksum ok" so OA isn't needed. */
+ rthdr = XFRM_RTA_NEXT(rthdr);
+ }
+
+ if (netlink_send_ack(this->socket_xfrm, hdr) != SUCCESS)
+ {
+ DBG1(DBG_KNL, "unalbe to add SAD entry with SPI 0x%x", spi);
+ return FAILED;
+ }
+ return SUCCESS;
+}
+
+/**
+ * Implementation of kernel_interface_t.update_sa.
+ */
+static status_t update_sa(private_kernel_interface_t *this,
+ host_t *src, host_t *dst,
+ host_t *new_src, host_t *new_dst,
+ host_diff_t src_changes, host_diff_t dst_changes,
+ u_int32_t spi, protocol_id_t protocol)
+{
+ unsigned char request[BUFFER_SIZE];
+ struct nlmsghdr *hdr, *out = NULL;
+ struct xfrm_usersa_id *sa_id;
+ struct xfrm_usersa_info *sa = NULL;
+ size_t len;
+
+ memset(&request, 0, sizeof(request));
+
+ DBG2(DBG_KNL, "querying SAD entry with SPI 0x%x", spi);
+
+ hdr = (struct nlmsghdr*)request;
+ hdr->nlmsg_flags = NLM_F_REQUEST;
+ hdr->nlmsg_type = XFRM_MSG_GETSA;
+ hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_id));
+
+ sa_id = (struct xfrm_usersa_id*)NLMSG_DATA(hdr);
+ host2xfrm(dst, &sa_id->daddr);
+ sa_id->spi = spi;
+ sa_id->proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH;
+ sa_id->family = dst->get_family(dst);
+
+ if (netlink_send(this->socket_xfrm, hdr, &out, &len) == SUCCESS)
+ {
+ hdr = out;
+ while (NLMSG_OK(hdr, len))
+ {
+ switch (hdr->nlmsg_type)
+ {
+ case XFRM_MSG_NEWSA:
+ {
+ sa = NLMSG_DATA(hdr);
+ break;
+ }
+ case NLMSG_ERROR:
+ {
+ struct nlmsgerr *err = NLMSG_DATA(hdr);
+ DBG1(DBG_KNL, "querying SAD entry failed: %s (%d)",
+ strerror(-err->error), -err->error);
+ break;
+ }
+ default:
+ hdr = NLMSG_NEXT(hdr, len);
+ continue;
+ case NLMSG_DONE:
+ break;
+ }
+ break;
+ }
+ }
+ if (sa == NULL)
+ {
+ DBG1(DBG_KNL, "unable to update SAD entry with SPI 0x%x", spi);
+ free(out);
+ return FAILED;
+ }
+
+ DBG2(DBG_KNL, "updating SAD entry with SPI 0x%x", spi);
+
+ hdr = out;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ hdr->nlmsg_type = XFRM_MSG_UPDSA;
+
+ if (src_changes & HOST_DIFF_ADDR)
+ {
+ host2xfrm(new_src, &sa->saddr);
+ }
+
+ if (dst_changes & HOST_DIFF_ADDR)
+ {
+ hdr->nlmsg_type = XFRM_MSG_NEWSA;
+ host2xfrm(new_dst, &sa->id.daddr);
+ }
+
+ if (src_changes & HOST_DIFF_PORT || dst_changes & HOST_DIFF_PORT)
+ {
+ struct rtattr *rtattr = XFRM_RTA(hdr, struct xfrm_usersa_info);
+ size_t rtsize = XFRM_PAYLOAD(hdr, struct xfrm_usersa_info);
+ while (RTA_OK(rtattr, rtsize))
+ {
+ if (rtattr->rta_type == XFRMA_ENCAP)
+ {
+ struct xfrm_encap_tmpl* encap;
+ encap = (struct xfrm_encap_tmpl*)RTA_DATA(rtattr);
+ encap->encap_sport = ntohs(new_src->get_port(new_src));
+ encap->encap_dport = ntohs(new_dst->get_port(new_dst));
+ break;
+ }
+ rtattr = RTA_NEXT(rtattr, rtsize);
+ }
+ }
+ if (netlink_send_ack(this->socket_xfrm, hdr) != SUCCESS)
+ {
+ DBG1(DBG_KNL, "unalbe to update SAD entry with SPI 0x%x", spi);
+ free(out);
+ return FAILED;
+ }
+ free(out);
+
+ if (dst_changes & HOST_DIFF_ADDR)
+ {
+ return this->public.del_sa(&this->public, dst, spi, protocol);
+ }
+ return SUCCESS;
+}
+
+/**
+ * Implementation of kernel_interface_t.query_sa.
+ */
+static status_t query_sa(private_kernel_interface_t *this, host_t *dst,
+ u_int32_t spi, protocol_id_t protocol,
+ u_int32_t *use_time)
+{
+ unsigned char request[BUFFER_SIZE];
+ struct nlmsghdr *out = NULL, *hdr;
+ struct xfrm_usersa_id *sa_id;
+ struct xfrm_usersa_info *sa = NULL;
+ size_t len;
+
+ DBG2(DBG_KNL, "querying SAD entry with SPI 0x%x", spi);
+ memset(&request, 0, sizeof(request));
+
+ hdr = (struct nlmsghdr*)request;
+ hdr->nlmsg_flags = NLM_F_REQUEST;
+ hdr->nlmsg_type = XFRM_MSG_GETSA;
+ hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info));
+
+ sa_id = (struct xfrm_usersa_id*)NLMSG_DATA(hdr);
+ host2xfrm(dst, &sa_id->daddr);
+ sa_id->spi = spi;
+ sa_id->proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH;
+ sa_id->family = dst->get_family(dst);
+
+ if (netlink_send(this->socket_xfrm, hdr, &out, &len) == SUCCESS)
+ {
+ hdr = out;
+ while (NLMSG_OK(hdr, len))
+ {
+ switch (hdr->nlmsg_type)
+ {
+ case XFRM_MSG_NEWSA:
+ {
+ sa = NLMSG_DATA(hdr);
+ break;
+ }
+ case NLMSG_ERROR:
+ {
+ struct nlmsgerr *err = NLMSG_DATA(hdr);
+ DBG1(DBG_KNL, "querying SAD entry failed: %s (%d)",
+ strerror(-err->error), -err->error);
+ break;
+ }
+ default:
+ hdr = NLMSG_NEXT(hdr, len);
+ continue;
+ case NLMSG_DONE:
+ break;
+ }
+ break;
+ }
+ }
+
+ if (sa == NULL)
+ {
+ DBG1(DBG_KNL, "unable to query SAD entry with SPI 0x%x", spi);
+ free(out);
+ return FAILED;
+ }
+
+ *use_time = sa->curlft.use_time;
+ free (out);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of kernel_interface_t.del_sa.
+ */
+static status_t del_sa(private_kernel_interface_t *this, host_t *dst,
+ u_int32_t spi, protocol_id_t protocol)
+{
+ unsigned char request[BUFFER_SIZE];
+ struct nlmsghdr *hdr;
+ struct xfrm_usersa_id *sa_id;
+
+ memset(&request, 0, sizeof(request));
+
+ DBG2(DBG_KNL, "deleting SAD entry with SPI 0x%x", spi);
+
+ hdr = (struct nlmsghdr*)request;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ hdr->nlmsg_type = XFRM_MSG_DELSA;
+ hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_id));
+
+ sa_id = (struct xfrm_usersa_id*)NLMSG_DATA(hdr);
+ host2xfrm(dst, &sa_id->daddr);
+ sa_id->spi = spi;
+ sa_id->proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH;
+ sa_id->family = dst->get_family(dst);
+
+ if (netlink_send_ack(this->socket_xfrm, hdr) != SUCCESS)
+ {
+ DBG1(DBG_KNL, "unalbe to delete SAD entry with SPI 0x%x", spi);
+ return FAILED;
+ }
+ DBG2(DBG_KNL, "deleted SAD entry with SPI 0x%x", spi);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of kernel_interface_t.add_policy.
+ */
+static status_t add_policy(private_kernel_interface_t *this,
+ host_t *src, host_t *dst,
+ traffic_selector_t *src_ts,
+ traffic_selector_t *dst_ts,
+ policy_dir_t direction, protocol_id_t protocol,
+ u_int32_t reqid, bool high_prio, mode_t mode,
+ bool update)
+{
+ iterator_t *iterator;
+ policy_entry_t *current, *policy;
+ bool found = FALSE;
+ unsigned char request[BUFFER_SIZE];
+ struct xfrm_userpolicy_info *policy_info;
+ struct nlmsghdr *hdr;
+
+ /* create a policy */
+ policy = malloc_thing(policy_entry_t);
+ memset(policy, 0, sizeof(policy_entry_t));
+ policy->sel = ts2selector(src_ts, dst_ts);
+ policy->direction = direction;
+
+ /* find the policy, which matches EXACTLY */
+ pthread_mutex_lock(&this->policies_mutex);
+ iterator = this->policies->create_iterator(this->policies, TRUE);
+ while (iterator->iterate(iterator, (void**)&current))
+ {
+ if (memcmp(&current->sel, &policy->sel, sizeof(struct xfrm_selector)) == 0 &&
+ policy->direction == current->direction)
+ {
+ /* use existing policy */
+ if (!update)
+ {
+ current->refcount++;
+ DBG2(DBG_KNL, "policy %R===%R already exists, increasing ",
+ "refcount", src_ts, dst_ts);
+ }
+ free(policy);
+ policy = current;
+ found = TRUE;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ if (!found)
+ { /* apply the new one, if we have no such policy */
+ this->policies->insert_last(this->policies, policy);
+ policy->refcount = 1;
+ }
+
+ DBG2(DBG_KNL, "adding policy %R===%R", src_ts, dst_ts);
+
+ memset(&request, 0, sizeof(request));
+ hdr = (struct nlmsghdr*)request;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ hdr->nlmsg_type = XFRM_MSG_UPDPOLICY;
+ hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_info));
+
+ policy_info = (struct xfrm_userpolicy_info*)NLMSG_DATA(hdr);
+ policy_info->sel = policy->sel;
+ policy_info->dir = policy->direction;
+ /* calculate priority based on source selector size, small size = high prio */
+ policy_info->priority = high_prio ? PRIO_HIGH : PRIO_LOW;
+ policy_info->priority -= policy->sel.prefixlen_s * 10;
+ policy_info->priority -= policy->sel.proto ? 2 : 0;
+ policy_info->priority -= policy->sel.sport_mask ? 1 : 0;
+ policy_info->action = XFRM_POLICY_ALLOW;
+ policy_info->share = XFRM_SHARE_ANY;
+ pthread_mutex_unlock(&this->policies_mutex);
+
+ /* policies don't expire */
+ policy_info->lft.soft_byte_limit = XFRM_INF;
+ policy_info->lft.soft_packet_limit = XFRM_INF;
+ policy_info->lft.hard_byte_limit = XFRM_INF;
+ policy_info->lft.hard_packet_limit = XFRM_INF;
+ policy_info->lft.soft_add_expires_seconds = 0;
+ policy_info->lft.hard_add_expires_seconds = 0;
+ policy_info->lft.soft_use_expires_seconds = 0;
+ policy_info->lft.hard_use_expires_seconds = 0;
+
+ struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_userpolicy_info);
+ rthdr->rta_type = XFRMA_TMPL;
+
+ rthdr->rta_len = sizeof(struct xfrm_user_tmpl);
+ rthdr->rta_len = RTA_LENGTH(rthdr->rta_len);
+
+ hdr->nlmsg_len += rthdr->rta_len;
+ if (hdr->nlmsg_len > sizeof(request))
+ {
+ return FAILED;
+ }
+
+ struct xfrm_user_tmpl *tmpl = (struct xfrm_user_tmpl*)RTA_DATA(rthdr);
+ tmpl->reqid = reqid;
+ tmpl->id.proto = (protocol == PROTO_AH) ? KERNEL_AH : KERNEL_ESP;
+ tmpl->aalgos = tmpl->ealgos = tmpl->calgos = ~0;
+ tmpl->mode = mode;
+ tmpl->family = src->get_family(src);
+
+ host2xfrm(src, &tmpl->saddr);
+ host2xfrm(dst, &tmpl->id.daddr);
+
+ if (netlink_send_ack(this->socket_xfrm, hdr) != SUCCESS)
+ {
+ DBG1(DBG_KNL, "unable to add policy %R===%R", src_ts, dst_ts);
+ return FAILED;
+ }
+
+ /* install a route, if:
+ * - we are NOT updating a policy
+ * - this is a forward policy (to just get one for each child)
+ * - we are in tunnel mode
+ * - we are not using IPv6 (does not work correctly yet!)
+ */
+ if (policy->route == NULL && direction == POLICY_FWD &&
+ mode != MODE_TRANSPORT && src->get_family(src) != AF_INET6)
+ {
+ policy->route = malloc_thing(route_entry_t);
+ if (get_address_by_ts(this, dst_ts, &policy->route->src_ip) == SUCCESS)
+ {
+ policy->route->if_index = get_interface_index(this, dst);
+ policy->route->dst_net = chunk_alloc(policy->sel.family == AF_INET ? 4 : 16);
+ memcpy(policy->route->dst_net.ptr, &policy->sel.saddr, policy->route->dst_net.len);
+ policy->route->prefixlen = policy->sel.prefixlen_s;
+
+ if (manage_srcroute(this, RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL,
+ policy->route) != SUCCESS)
+ {
+ DBG1(DBG_KNL, "unable to install source route for %H",
+ policy->route->src_ip);
+ route_entry_destroy(policy->route);
+ policy->route = NULL;
+ }
+ }
+ else
+ {
+ free(policy->route);
+ policy->route = NULL;
+ }
+ }
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of kernel_interface_t.query_policy.
+ */
+static status_t query_policy(private_kernel_interface_t *this,
+ traffic_selector_t *src_ts,
+ traffic_selector_t *dst_ts,
+ policy_dir_t direction, u_int32_t *use_time)
+{
+ unsigned char request[BUFFER_SIZE];
+ struct nlmsghdr *out = NULL, *hdr;
+ struct xfrm_userpolicy_id *policy_id;
+ struct xfrm_userpolicy_info *policy = NULL;
+ size_t len;
+
+ memset(&request, 0, sizeof(request));
+
+ DBG2(DBG_KNL, "querying policy %R===%R", src_ts, dst_ts);
+
+ hdr = (struct nlmsghdr*)request;
+ hdr->nlmsg_flags = NLM_F_REQUEST;
+ hdr->nlmsg_type = XFRM_MSG_GETPOLICY;
+ hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_id));
+
+ policy_id = (struct xfrm_userpolicy_id*)NLMSG_DATA(hdr);
+ policy_id->sel = ts2selector(src_ts, dst_ts);
+ policy_id->dir = direction;
+
+ if (netlink_send(this->socket_xfrm, hdr, &out, &len) == SUCCESS)
+ {
+ hdr = out;
+ while (NLMSG_OK(hdr, len))
+ {
+ switch (hdr->nlmsg_type)
+ {
+ case XFRM_MSG_NEWPOLICY:
+ {
+ policy = (struct xfrm_userpolicy_info*)NLMSG_DATA(hdr);
+ break;
+ }
+ case NLMSG_ERROR:
+ {
+ struct nlmsgerr *err = NLMSG_DATA(hdr);
+ DBG1(DBG_KNL, "querying policy failed: %s (%d)",
+ strerror(-err->error), -err->error);
+ break;
+ }
+ default:
+ hdr = NLMSG_NEXT(hdr, len);
+ continue;
+ case NLMSG_DONE:
+ break;
+ }
+ break;
+ }
+ }
+
+ if (policy == NULL)
+ {
+ DBG2(DBG_KNL, "unable to query policy %R===%R", src_ts, dst_ts);
+ free(out);
+ return FAILED;
+ }
+ *use_time = (time_t)policy->curlft.use_time;
+
+ free(out);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of kernel_interface_t.del_policy.
+ */
+static status_t del_policy(private_kernel_interface_t *this,
+ traffic_selector_t *src_ts,
+ traffic_selector_t *dst_ts,
+ policy_dir_t direction)
+{
+ policy_entry_t *current, policy, *to_delete = NULL;
+ route_entry_t *route;
+ unsigned char request[BUFFER_SIZE];
+ struct nlmsghdr *hdr;
+ struct xfrm_userpolicy_id *policy_id;
+ iterator_t *iterator;
+
+ DBG2(DBG_KNL, "deleting policy %R===%R", src_ts, dst_ts);
+
+ /* create a policy */
+ memset(&policy, 0, sizeof(policy_entry_t));
+ policy.sel = ts2selector(src_ts, dst_ts);
+ policy.direction = direction;
+
+ /* find the policy */
+ pthread_mutex_lock(&this->policies_mutex);
+ iterator = this->policies->create_iterator(this->policies, TRUE);
+ while (iterator->iterate(iterator, (void**)&current))
+ {
+ if (memcmp(&current->sel, &policy.sel, sizeof(struct xfrm_selector)) == 0 &&
+ policy.direction == current->direction)
+ {
+ to_delete = current;
+ if (--to_delete->refcount > 0)
+ {
+ /* is used by more SAs, keep in kernel */
+ DBG2(DBG_KNL, "policy still used by another CHILD_SA, not removed");
+ iterator->destroy(iterator);
+ pthread_mutex_unlock(&this->policies_mutex);
+ return SUCCESS;
+ }
+ /* remove if last reference */
+ iterator->remove(iterator);
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ pthread_mutex_unlock(&this->policies_mutex);
+ if (!to_delete)
+ {
+ DBG1(DBG_KNL, "deleting policy %R===%R failed, not found", src_ts, dst_ts);
+ return NOT_FOUND;
+ }
+
+ memset(&request, 0, sizeof(request));
+
+ hdr = (struct nlmsghdr*)request;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ hdr->nlmsg_type = XFRM_MSG_DELPOLICY;
+ hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_id));
+
+ policy_id = (struct xfrm_userpolicy_id*)NLMSG_DATA(hdr);
+ policy_id->sel = to_delete->sel;
+ policy_id->dir = direction;
+
+ route = to_delete->route;
+ free(to_delete);
+
+ if (netlink_send_ack(this->socket_xfrm, hdr) != SUCCESS)
+ {
+ DBG1(DBG_KNL, "unable to delete policy %R===%R", src_ts, dst_ts);
+ return FAILED;
+ }
+
+ if (route)
+ {
+ if (manage_srcroute(this, RTM_DELROUTE, 0, route) != SUCCESS)
+ {
+ DBG1(DBG_KNL, "error uninstalling route installed with "
+ "policy %R===%R", src_ts, dst_ts);
+ }
+ route_entry_destroy(route);
+ }
+ return SUCCESS;
+}
+
+/**
+ * Implementation of kernel_interface_t.destroy.
+ */
+static void destroy(private_kernel_interface_t *this)
+{
+ pthread_cancel(this->event_thread);
+ pthread_join(this->event_thread, NULL);
+ close(this->socket_xfrm_events);
+ close(this->socket_xfrm);
+ close(this->socket_rt);
+ this->vips->destroy(this->vips);
+ this->policies->destroy(this->policies);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+kernel_interface_t *kernel_interface_create()
+{
+ private_kernel_interface_t *this = malloc_thing(private_kernel_interface_t);
+ struct sockaddr_nl addr;
+
+ /* 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,u_int64_t,u_int64_t,algorithm_t*,algorithm_t*,prf_plus_t*,natt_conf_t*,mode_t,bool))add_sa;
+ this->public.update_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t,host_t*,host_t*,host_diff_t,host_diff_t))update_sa;
+ this->public.query_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t*))query_sa;
+ this->public.del_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t))del_sa;
+ this->public.add_policy = (status_t(*)(kernel_interface_t*,host_t*,host_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,protocol_id_t,u_int32_t,bool,mode_t,bool))add_policy;
+ this->public.query_policy = (status_t(*)(kernel_interface_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,u_int32_t*))query_policy;
+ this->public.del_policy = (status_t(*)(kernel_interface_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t))del_policy;
+
+ this->public.get_interface = (char*(*)(kernel_interface_t*,host_t*))get_interface_name;
+ this->public.create_address_list = (linked_list_t*(*)(kernel_interface_t*))create_address_list_public;
+ this->public.add_ip = (status_t(*)(kernel_interface_t*,host_t*,host_t*)) add_ip;
+ this->public.del_ip = (status_t(*)(kernel_interface_t*,host_t*,host_t*)) del_ip;
+ this->public.destroy = (void(*)(kernel_interface_t*)) destroy;
+
+ /* private members */
+ this->vips = linked_list_create();
+ this->policies = linked_list_create();
+ pthread_mutex_init(&this->policies_mutex,NULL);
+ pthread_mutex_init(&this->vips_mutex,NULL);
+
+ addr.nl_family = AF_NETLINK;
+ addr.nl_pid = 0;
+ addr.nl_groups = 0;
+
+ /* create and bind XFRM socket */
+ this->socket_xfrm = socket(AF_NETLINK, SOCK_RAW, NETLINK_XFRM);
+ if (this->socket_xfrm <= 0)
+ {
+ charon->kill(charon, "unable to create XFRM netlink socket");
+ }
+
+ if (bind(this->socket_xfrm, (struct sockaddr*)&addr, sizeof(addr)))
+ {
+ charon->kill(charon, "unable to bind XFRM netlink socket");
+ }
+
+ /* create and bind RT socket */
+ this->socket_rt = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (this->socket_rt <= 0)
+ {
+ charon->kill(charon, "unable to create RT netlink socket");
+ }
+
+ if (bind(this->socket_rt, (struct sockaddr*)&addr, sizeof(addr)))
+ {
+ charon->kill(charon, "unable to bind RT netlink socket");
+ }
+
+ /* create and bind XFRM socket for ACQUIRE & EXPIRE */
+ addr.nl_groups = XFRMGRP_ACQUIRE | XFRMGRP_EXPIRE;
+ this->socket_xfrm_events = socket(AF_NETLINK, SOCK_RAW, NETLINK_XFRM);
+ if (this->socket_xfrm_events <= 0)
+ {
+ charon->kill(charon, "unable to create XFRM event socket");
+ }
+
+ if (bind(this->socket_xfrm_events, (struct sockaddr*)&addr, sizeof(addr)))
+ {
+ charon->kill(charon, "unable to bind XFRM event socket");
+ }
+
+ /* create a thread receiving ACQUIRE & EXPIRE events */
+ if (pthread_create(&this->event_thread, NULL,
+ (void*(*)(void*))receive_events, this))
+ {
+ charon->kill(charon, "unable to create xfrm event dispatcher thread");
+ }
+
+ return &this->public;
+}
+
+/* vim: set ts=4 sw=4 noet: */
diff --git a/src/charon/threads/kernel_interface.h b/src/charon/threads/kernel_interface.h
new file mode 100644
index 000000000..34b06f594
--- /dev/null
+++ b/src/charon/threads/kernel_interface.h
@@ -0,0 +1,331 @@
+/**
+ * @file kernel_interface.h
+ *
+ * @brief Interface of kernel_interface_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct natt_conf_t natt_conf_t;
+typedef enum policy_dir_t policy_dir_t;
+typedef struct kernel_interface_t kernel_interface_t;
+
+#include <utils/host.h>
+#include <crypto/prf_plus.h>
+#include <encoding/payloads/proposal_substructure.h>
+
+/**
+ * Configuration for NAT-T
+ */
+struct natt_conf_t {
+ /** source port to use for UDP-encapsulated packets */
+ u_int16_t sport;
+ /** dest port to use for UDP-encapsulated packets */
+ u_int16_t dport;
+};
+
+/**
+ * Direction of a policy. These are equal to those
+ * defined in xfrm.h, but we want to stay implementation
+ * neutral here.
+ */
+enum policy_dir_t {
+ /** Policy for inbound traffic */
+ POLICY_IN = 0,
+ /** Policy for outbound traffic */
+ POLICY_OUT = 1,
+ /** Policy for forwarded traffic */
+ POLICY_FWD = 2,
+};
+
+/**
+ * @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.
+ * Policy information are cached in the interface. This is necessary to do
+ * reference counting. The Linux kernel does not allow the same policy
+ * installed twice, but we need this as CHILD_SA exist multiple times
+ * when rekeying. Thats why we do reference counting of policies.
+ *
+ * @b Constructors:
+ * - kernel_interface_create()
+ *
+ * @ingroup threads
+ */
+struct kernel_interface_t {
+
+ /**
+ * @brief Get a SPI from the kernel.
+ *
+ * @warning get_spi() implicitely creates an SA with
+ * the allocated SPI, therefore the replace flag
+ * in add_sa() must be set when installing this SA.
+ *
+ * @param this calling object
+ * @param src source address of SA
+ * @param dst destination address of SA
+ * @param protocol protocol for SA (ESP/AH)
+ * @param reqid unique ID for this SA
+ * @param[out] spi allocated spi
+ * @return
+ * - SUCCESS
+ * - FAILED if kernel comm failed
+ */
+ 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. The kernel-interface
+ * gets the keys itself from the PRF, as we don't know
+ * his algorithms and key sizes.
+ *
+ * @param this calling object
+ * @param src source address for this SA
+ * @param dst destination address for this SA
+ * @param spi SPI allocated by us or remote peer
+ * @param protocol protocol for this SA (ESP/AH)
+ * @param reqid unique ID for this SA
+ * @param expire_soft lifetime in seconds before rekeying
+ * @param expire_hard lieftime in seconds before delete
+ * @param enc_alg Algorithm to use for encryption (ESP only)
+ * @param int_alg Algorithm to use for integrity protection
+ * @param prf_plus PRF to derive keys from
+ * @param natt NAT-T Configuration, or NULL of no NAT-T used
+ * @param mode mode of the SA (tunnel, transport)
+ * @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,
+ u_int64_t expire_soft, u_int64_t expire_hard,
+ algorithm_t *enc_alg, algorithm_t *int_alg,
+ prf_plus_t *prf_plus, natt_conf_t *natt,
+ mode_t mode, bool update);
+
+ /**
+ * @brief Update the hosts on an installed SA.
+ *
+ * We cannot directly update the destination address as the kernel
+ * requires the spi, the protocol AND the destination address (and family)
+ * to identify SAs. Therefore if the destination address changed we
+ * create a new SA and delete the old one.
+ *
+ * @param this calling object
+ * @param dst destination address for this SA
+ * @param spi SPI of the SA
+ * @param protocol protocol for this SA (ESP/AH)
+ * @param new_src new source address for this SA
+ * @param new_dst new destination address for this SA
+ * @param src_changes changes in src
+ * @param dst_changes changes in dst
+ * @return
+ * - SUCCESS
+ * - FAILED if kernel comm failed
+ */
+ status_t (*update_sa)(kernel_interface_t *this, host_t *dst, u_int32_t spi,
+ protocol_id_t protocol,
+ host_t *new_src, host_t *new_dst,
+ host_diff_t src_changes, host_diff_t dst_changes);
+
+ /**
+ * @brief Query the use time of an SA.
+ *
+ * The use time of an SA is not the time of the last usage, but
+ * the time of the first usage of the SA.
+ *
+ * @param this calling object
+ * @param dst destination address for this SA
+ * @param spi SPI allocated by us or remote peer
+ * @param protocol protocol for this SA (ESP/AH)
+ * @param[out] use_time the time of this SA's last use
+ * @return
+ * - SUCCESS
+ * - FAILED if kernel comm failed
+ */
+ status_t (*query_sa) (kernel_interface_t *this, host_t *dst, u_int32_t spi,
+ protocol_id_t protocol, u_int32_t *use_time);
+
+ /**
+ * @brief Delete a previusly installed SA from the SAD.
+ *
+ * @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. Traffic which matches a
+ * policy is handled by the SA with the same reqid.
+ * If the update flag is set, the policy is updated with the new
+ * src/dst addresses.
+ * If the update flag is not set, but a such policy is already in the
+ * kernel, the reference count to this policy is increased.
+ *
+ * @param this calling object
+ * @param src source address of SA
+ * @param dst dest address of SA
+ * @param src_ts traffic selector to match traffic source
+ * @param dst_ts traffic selector to match traffic dest
+ * @param direction direction of traffic, POLICY_IN, POLICY_OUT, POLICY_FWD
+ * @param protocol protocol to use to protect traffic (AH/ESP)
+ * @param reqid uniqe ID of an SA to use to enforce policy
+ * @param high_prio if TRUE, uses a higher priority than any with FALSE
+ * @param mode mode of SA (tunnel, transport)
+ * @param update update an existing policy, if TRUE
+ * @return
+ * - SUCCESS
+ * - FAILED if kernel comm failed
+ */
+ status_t (*add_policy) (kernel_interface_t *this,
+ host_t *src, host_t *dst,
+ traffic_selector_t *src_ts,
+ traffic_selector_t *dst_ts,
+ policy_dir_t direction, protocol_id_t protocol,
+ u_int32_t reqid, bool high_prio,
+ mode_t mode, bool update);
+
+ /**
+ * @brief Query the use time of a policy.
+ *
+ * The use time of a policy is the time the policy was used
+ * for the last time.
+ *
+ * @param this calling object
+ * @param src_ts traffic selector to match traffic source
+ * @param dst_ts traffic selector to match traffic dest
+ * @param direction direction of traffic, POLICY_IN, POLICY_OUT, POLICY_FWD
+ * @param[out] use_time the time of this SA's last use
+ * @return
+ * - SUCCESS
+ * - FAILED if kernel comm failed
+ */
+ status_t (*query_policy) (kernel_interface_t *this,
+ traffic_selector_t *src_ts,
+ traffic_selector_t *dst_ts,
+ policy_dir_t direction, u_int32_t *use_time);
+
+ /**
+ * @brief Remove a policy from the SPD.
+ *
+ * The kernel interface implements reference counting for policies.
+ * If the same policy is installed multiple times (in the case of rekeying),
+ * the reference counter is increased. del_policy() decreases the ref counter
+ * and removes the policy only when no more references are available.
+ *
+ * @param this calling object
+ * @param src_ts traffic selector to match traffic source
+ * @param dst_ts traffic selector to match traffic dest
+ * @param direction direction of traffic, POLICY_IN, POLICY_OUT, POLICY_FWD
+ * @return
+ * - SUCCESS
+ * - FAILED if kernel comm failed
+ */
+ status_t (*del_policy) (kernel_interface_t *this,
+ traffic_selector_t *src_ts,
+ traffic_selector_t *dst_ts,
+ policy_dir_t direction);
+
+ /**
+ * @brief Get the interface name of a local address.
+ *
+ * @param this calling object
+ * @param host address to get interface name from
+ * @return allocated interface name, or NULL if not found
+ */
+ char* (*get_interface) (kernel_interface_t *this, host_t *host);
+
+ /**
+ * @brief Creates a list of all local addresses.
+ *
+ * @param this calling object
+ * @return allocated list with host_t objects
+ */
+ linked_list_t *(*create_address_list) (kernel_interface_t *this);
+
+ /**
+ * @brief Add a virtual IP to an interface.
+ *
+ * Virtual IPs are attached to an interface. If an IP is added multiple
+ * times, the IP is refcounted and not removed until del_ip() was called
+ * as many times as add_ip().
+ * The virtual IP is attached to the interface where the iface_ip is found.
+ *
+ * @param this calling object
+ * @param virtual_ip virtual ip address to assign
+ * @param iface_ip IP of an interface to attach virtual IP
+ * @return
+ * - SUCCESS
+ * - FAILED if kernel comm failed
+ */
+ status_t (*add_ip) (kernel_interface_t *this, host_t *virtual_ip,
+ host_t *iface_ip);
+
+ /**
+ * @brief Remove a virtual IP from an interface.
+ *
+ * The kernel interface uses refcounting, see add_ip().
+ *
+ * @param this calling object
+ * @param virtual_ip virtual ip address to assign
+ * @param iface_ip IP of an interface to remove virtual IP from
+ * @return
+ * - SUCCESS
+ * - FAILED if kernel comm failed
+ */
+ status_t (*del_ip) (kernel_interface_t *this, host_t *virtual_ip,
+ host_t *iface_ip);
+
+ /**
+ * @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(void);
+
+#endif /*KERNEL_INTERFACE_H_*/
diff --git a/src/charon/threads/receiver.c b/src/charon/threads/receiver.c
new file mode 100644
index 000000000..7195c162d
--- /dev/null
+++ b/src/charon/threads/receiver.c
@@ -0,0 +1,372 @@
+/**
+ * @file receiver.c
+ *
+ * @brief Implementation of receiver_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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/process_message_job.h>
+
+/** length of the full cookie, including time (u_int32_t + SHA1()) */
+#define COOKIE_LENGTH 24
+/** lifetime of a cookie, in seconds */
+#define COOKIE_LIFETIME 10
+/** how many times to reuse the secret */
+#define COOKIE_REUSE 10000
+/** require cookies after half open IKE_SAs */
+#define COOKIE_TRESHOLD 10
+/** how many half open IKE_SAs per peer before blocking */
+#define BLOCK_TRESHOLD 5
+/** length of the secret to use for cookie calculation */
+#define SECRET_LENGTH 16
+
+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;
+
+ /**
+ * Assigned thread.
+ */
+ pthread_t assigned_thread;
+
+ /**
+ * current secret to use for cookie calculation
+ */
+ char secret[SECRET_LENGTH];
+
+ /**
+ * previous secret used to verify older cookies
+ */
+ char secret_old[SECRET_LENGTH];
+
+ /**
+ * how many times we have used "secret" so far
+ */
+ u_int32_t secret_used;
+
+ /**
+ * time we did the cookie switch
+ */
+ u_int32_t secret_switch;
+
+ /**
+ * time offset to use, hides our system time
+ */
+ u_int32_t secret_offset;
+
+ /**
+ * the randomizer to use for secret generation
+ */
+ randomizer_t *randomizer;
+
+ /**
+ * hasher to use for cookie calculation
+ */
+ hasher_t *hasher;
+};
+
+/**
+ * send a notify back to the sender
+ */
+static void send_notify(message_t *request, notify_type_t type, chunk_t data)
+{
+ if (request->get_request(request) &&
+ request->get_exchange_type(request) == IKE_SA_INIT)
+ {
+ message_t *response;
+ host_t *src, *dst;
+ packet_t *packet;
+ ike_sa_id_t *ike_sa_id;
+
+ response = message_create();
+ dst = request->get_source(request);
+ src = request->get_destination(request);
+ response->set_source(response, src->clone(src));
+ response->set_destination(response, dst->clone(dst));
+ response->set_exchange_type(response, request->get_exchange_type(request));
+ response->set_request(response, FALSE);
+ response->set_message_id(response, 0);
+ ike_sa_id = request->get_ike_sa_id(request);
+ ike_sa_id->switch_initiator(ike_sa_id);
+ response->set_ike_sa_id(response, ike_sa_id);
+ response->add_notify(response, FALSE, type, data);
+ if (response->generate(response, NULL, NULL, &packet) == SUCCESS)
+ {
+ charon->sender->send(charon->sender, packet);
+ response->destroy(response);
+ }
+ }
+}
+
+/**
+ * build a cookie
+ */
+static chunk_t cookie_build(private_receiver_t *this, message_t *message,
+ u_int32_t t, chunk_t secret)
+{
+ u_int64_t spi = message->get_initiator_spi(message);
+ host_t *ip = message->get_source(message);
+ chunk_t input, hash = chunk_alloca(this->hasher->get_hash_size(this->hasher));
+
+ /* COOKIE = t | sha1( IPi | SPIi | t | secret ) */
+ input = chunk_cata("cccc", ip->get_address(ip), chunk_from_thing(spi),
+ chunk_from_thing(t), secret);
+ this->hasher->get_hash(this->hasher, input, hash.ptr);
+ return chunk_cat("cc", chunk_from_thing(t), hash);
+}
+
+/**
+ * verify a received cookie
+ */
+static bool cookie_verify(private_receiver_t *this, message_t *message,
+ chunk_t cookie)
+{
+ u_int32_t t, now;
+ chunk_t reference;
+ chunk_t secret;
+
+ now = time(NULL);
+ t = *(u_int32_t*)cookie.ptr;
+
+ if (cookie.len != COOKIE_LENGTH ||
+ t < now - this->secret_offset - COOKIE_LIFETIME)
+ {
+ DBG2(DBG_NET, "received cookie lifetime expired, rejecting");
+ return FALSE;
+ }
+
+ /* check if cookie is derived from old_secret */
+ if (t + this->secret_offset > this->secret_switch)
+ {
+ secret = chunk_from_thing(this->secret);
+ }
+ else
+ {
+ secret = chunk_from_thing(this->secret_old);
+ }
+
+ /* compare own calculation against received */
+ reference = cookie_build(this, message, t, secret);
+ if (chunk_equals(reference, cookie))
+ {
+ chunk_free(&reference);
+ return TRUE;
+ }
+ chunk_free(&reference);
+ return FALSE;
+}
+
+/**
+ * check if cookies are required, and if so, a valid cookie is included
+ */
+static bool cookie_required(private_receiver_t *this, message_t *message)
+{
+ bool failed = FALSE;
+
+ if (charon->ike_sa_manager->get_half_open_count(charon->ike_sa_manager,
+ NULL) >= COOKIE_TRESHOLD)
+ {
+ /* check for a cookie. We don't use our parser here and do it
+ * quick and dirty for performance reasons.
+ * we assume to cookie is the first payload (which is a MUST), and
+ * the cookies SPI length is zero. */
+ packet_t *packet = message->get_packet(message);
+ chunk_t data = packet->get_data(packet);
+ if (data.len <
+ IKE_HEADER_LENGTH + NOTIFY_PAYLOAD_HEADER_LENGTH + COOKIE_LENGTH ||
+ *(data.ptr + 16) != NOTIFY ||
+ *(u_int16_t*)(data.ptr + IKE_HEADER_LENGTH + 6) != htons(COOKIE))
+ {
+ /* no cookie found */
+ failed = TRUE;
+ }
+ else
+ {
+ data.ptr += IKE_HEADER_LENGTH + NOTIFY_PAYLOAD_HEADER_LENGTH;
+ data.len = COOKIE_LENGTH;
+ if (!cookie_verify(this, message, data))
+ {
+ DBG2(DBG_NET, "found cookie, but content invalid");
+ failed = TRUE;
+ }
+ }
+ packet->destroy(packet);
+ }
+ return failed;
+}
+
+/**
+ * check if peer has to many half open IKE_SAs
+ */
+static bool peer_to_aggressive(private_receiver_t *this, message_t *message)
+{
+ if (charon->ike_sa_manager->get_half_open_count(charon->ike_sa_manager,
+ message->get_source(message)) >= BLOCK_TRESHOLD)
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * Implementation of receiver_t.receive_packets.
+ */
+static void receive_packets(private_receiver_t *this)
+{
+ packet_t *packet;
+ message_t *message;
+ job_t *job;
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+ DBG1(DBG_NET, "receiver thread running, thread_ID: %06u",
+ (int)pthread_self());
+
+ while (TRUE)
+ {
+ /* read in a packet */
+ if (charon->socket->receive(charon->socket, &packet) != SUCCESS)
+ {
+ DBG1(DBG_NET, "receiving from socket failed!");
+ continue;
+ }
+
+ /* parse message header */
+ message = message_create_from_packet(packet);
+ if (message->parse_header(message) != SUCCESS)
+ {
+ DBG1(DBG_NET, "received invalid IKE header from %H, ignored",
+ packet->get_source(packet));
+ message->destroy(message);
+ continue;
+ }
+
+ /* check IKE major version */
+ if (message->get_major_version(message) != IKE_MAJOR_VERSION)
+ {
+ DBG1(DBG_NET, "received unsupported IKE version %d.%d from %H, "
+ "sending INVALID_MAJOR_VERSION", message->get_major_version(message),
+ message->get_minor_version(message), packet->get_source(packet));
+ send_notify(message, INVALID_MAJOR_VERSION, chunk_empty);
+ message->destroy(message);
+ continue;
+ }
+
+ if (message->get_request(message) &&
+ message->get_exchange_type(message) == IKE_SA_INIT)
+ {
+ /* check for cookies */
+ if (cookie_required(this, message))
+ {
+ u_int32_t now = time(NULL);
+ chunk_t cookie = cookie_build(this, message, now - this->secret_offset,
+ chunk_from_thing(this->secret));
+
+ DBG2(DBG_NET, "received packet from: %#H to %#H",
+ message->get_source(message),
+ message->get_destination(message));
+ DBG2(DBG_NET, "sending COOKIE notify to %H",
+ message->get_source(message));
+ send_notify(message, COOKIE, cookie);
+ chunk_free(&cookie);
+ if (++this->secret_used > COOKIE_REUSE)
+ {
+ /* create new cookie */
+ DBG1(DBG_NET, "generating new cookie secret after %d uses",
+ this->secret_used);
+ memcpy(this->secret_old, this->secret, SECRET_LENGTH);
+ this->randomizer->get_pseudo_random_bytes(this->randomizer,
+ SECRET_LENGTH, this->secret);
+ this->secret_switch = now;
+ this->secret_used = 0;
+ }
+ message->destroy(message);
+ continue;
+ }
+
+ /* check if peer has not too many IKE_SAs half open */
+ if (peer_to_aggressive(this, message))
+ {
+ DBG1(DBG_NET, "ignoring IKE_SA setup from %H, "
+ "peer to aggressive", message->get_source(message));
+ message->destroy(message);
+ continue;
+ }
+ }
+ job = (job_t *)process_message_job_create(message);
+ charon->job_queue->add(charon->job_queue, job);
+ }
+}
+
+/**
+ * Implementation of receiver_t.destroy.
+ */
+static void destroy(private_receiver_t *this)
+{
+ pthread_cancel(this->assigned_thread);
+ pthread_join(this->assigned_thread, NULL);
+ this->randomizer->destroy(this->randomizer);
+ this->hasher->destroy(this->hasher);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+receiver_t *receiver_create()
+{
+ private_receiver_t *this = malloc_thing(private_receiver_t);
+ u_int32_t now = time(NULL);
+
+ this->public.destroy = (void(*)(receiver_t*)) destroy;
+
+ this->randomizer = randomizer_create();
+ this->hasher = hasher_create(HASH_SHA1);
+ this->secret_switch = now;
+ this->secret_offset = random() % now;
+ this->secret_used = 0;
+ this->randomizer->get_pseudo_random_bytes(this->randomizer, SECRET_LENGTH,
+ this->secret);
+ memcpy(this->secret_old, this->secret, SECRET_LENGTH);
+
+ if (pthread_create(&this->assigned_thread, NULL,
+ (void*)receive_packets, this) != 0)
+ {
+ free(this);
+ charon->kill(charon, "unable to create receiver thread");
+ }
+
+ return &this->public;
+}
diff --git a/src/charon/threads/receiver.h b/src/charon/threads/receiver.h
new file mode 100644
index 000000000..68d9136c0
--- /dev/null
+++ b/src/charon/threads/receiver.h
@@ -0,0 +1,81 @@
+/**
+ * @file receiver.h
+ *
+ * @brief Interface of receiver_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2007 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct receiver_t receiver_t;
+
+#include <library.h>
+#include <utils/host.h>
+
+/**
+ * @brief Receives packets from the socket and adds them to the job queue.
+ *
+ * The receiver starts a thread, wich reads on the blocking socket. A received
+ * packet is preparsed and a process_message_job is queued in the job queue.
+ *
+ * To endure DoS attacks, cookies are enabled when to many IKE_SAs are half
+ * open. The calculation of cookies is slightly different from the proposed
+ * method in RFC4306. We do not include a nonce, because we think the advantage
+ * we gain does not justify the overhead to parse the whole message.
+ * Instead of VersionIdOfSecret, we include a timestamp. This allows us to
+ * find out wich key was used for cookie creation. Further, we can set a
+ * lifetime for the cookie, which allows us to reuse the secret for a longer
+ * time.
+ * COOKIE = time | sha1( IPi | SPIi | time | secret )
+ *
+ * The secret is changed after a certain amount of cookies sent. The old
+ * secret is stored to allow a clean migration between secret changes.
+ *
+ * Further, the number of half-initiated IKE_SAs is limited per peer. This
+ * mades it impossible for a peer to flood the server with its real IP address.
+ *
+ * @b Constructors:
+ * - receiver_create()
+ *
+ * @ingroup 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
+ *
+ * @ingroup threads
+ */
+receiver_t * receiver_create(void);
+
+#endif /*RECEIVER_H_*/
diff --git a/src/charon/threads/scheduler.c b/src/charon/threads/scheduler.c
new file mode 100644
index 000000000..74091e3a3
--- /dev/null
+++ b/src/charon/threads/scheduler.c
@@ -0,0 +1,102 @@
+/**
+ * @file scheduler.c
+ *
+ * @brief Implementation of scheduler_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <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;
+
+ /**
+ * Assigned thread.
+ */
+ pthread_t assigned_thread;
+};
+
+/**
+ * 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);
+
+ DBG1(DBG_JOB, "scheduler thread running, thread_ID: %06u",
+ (int)pthread_self());
+
+ while (TRUE)
+ {
+ DBG2(DBG_JOB, "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 */
+ DBG2(DBG_JOB, "got event, adding job %N to job-queue",
+ job_type_names, current_job->get_type(current_job));
+ charon->job_queue->add(charon->job_queue, current_job);
+ }
+}
+
+/**
+ * Implementation of scheduler_t.destroy.
+ */
+static void destroy(private_scheduler_t *this)
+{
+ pthread_cancel(this->assigned_thread);
+ pthread_join(this->assigned_thread, NULL);
+ 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;
+
+ if (pthread_create(&(this->assigned_thread), NULL, (void*(*)(void*))get_events, this) != 0)
+ {
+ /* thread could not be created */
+ free(this);
+ charon->kill(charon, "unable to create scheduler thread");
+ }
+
+ return &(this->public);
+}
diff --git a/src/charon/threads/scheduler.h b/src/charon/threads/scheduler.h
new file mode 100644
index 000000000..daecce3c6
--- /dev/null
+++ b/src/charon/threads/scheduler.h
@@ -0,0 +1,68 @@
+/**
+ * @file scheduler.h
+ *
+ * @brief Interface of scheduler_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct scheduler_t scheduler_t;
+
+#include <library.h>
+
+/**
+ * @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(void);
+
+#endif /*SCHEDULER_H_*/
diff --git a/src/charon/threads/sender.c b/src/charon/threads/sender.c
new file mode 100644
index 000000000..c1cd0a68c
--- /dev/null
+++ b/src/charon/threads/sender.c
@@ -0,0 +1,149 @@
+/**
+ * @file sender.c
+ *
+ * @brief Implementation of sender_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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>
+
+
+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;
+
+ /**
+ * The packets are stored in a linked list
+ */
+ linked_list_t *list;
+
+ /**
+ * mutex to synchronize access to list
+ */
+ pthread_mutex_t mutex;
+
+ /**
+ * condvar to signal for packets in list
+ */
+ pthread_cond_t condvar;
+};
+
+/**
+ * implements sender_t.send
+ */
+static void send_(private_sender_t *this, packet_t *packet)
+{
+ host_t *src, *dst;
+
+ src = packet->get_source(packet);
+ dst = packet->get_destination(packet);
+ DBG1(DBG_NET, "sending packet: from %#H to %#H", src, dst);
+
+ pthread_mutex_lock(&this->mutex);
+ this->list->insert_last(this->list, packet);
+ pthread_mutex_unlock(&this->mutex);
+ pthread_cond_signal(&this->condvar);
+}
+
+/**
+ * Implementation of private_sender_t.send_packets.
+ */
+static void send_packets(private_sender_t * this)
+{
+
+ /* cancellation disabled by default */
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+ DBG1(DBG_NET, "sender thread running, thread_ID: %06u", (int)pthread_self());
+
+ while (TRUE)
+ {
+ packet_t *packet;
+ int oldstate;
+
+ pthread_mutex_lock(&this->mutex);
+ /* go to wait while no packets available */
+ while (this->list->get_count(this->list) == 0)
+ {
+ /* add cleanup handler, wait for packet, remove cleanup handler */
+ pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock, (void*)&this->mutex);
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
+ pthread_cond_wait(&this->condvar, &this->mutex);
+
+ pthread_setcancelstate(oldstate, NULL);
+ pthread_cleanup_pop(0);
+ }
+ this->list->remove_first(this->list, (void**)&packet);
+ pthread_mutex_unlock(&this->mutex);
+
+ charon->socket->send(charon->socket, packet);
+ packet->destroy(packet);
+ }
+}
+
+/**
+ * Implementation of sender_t.destroy.
+ */
+static void destroy(private_sender_t *this)
+{
+ pthread_cancel(this->assigned_thread);
+ pthread_join(this->assigned_thread, NULL);
+ this->list->destroy_offset(this->list, offsetof(packet_t, destroy));
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+sender_t * sender_create()
+{
+ private_sender_t *this = malloc_thing(private_sender_t);
+
+ this->public.send = (void(*)(sender_t*,packet_t*))send_;
+ this->public.destroy = (void(*)(sender_t*)) destroy;
+
+ this->list = linked_list_create();
+ pthread_mutex_init(&this->mutex, NULL);
+ pthread_cond_init(&this->condvar, NULL);
+
+ if (pthread_create(&this->assigned_thread, NULL,
+ (void*)send_packets, this) != 0)
+ {
+ charon->kill(charon, "unable to create sender thread");
+ }
+
+ return &(this->public);
+}
diff --git a/src/charon/threads/sender.h b/src/charon/threads/sender.h
new file mode 100644
index 000000000..4f42f6f9e
--- /dev/null
+++ b/src/charon/threads/sender.h
@@ -0,0 +1,74 @@
+/**
+ * @file sender.h
+ *
+ * @brief Interface of sender_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2007 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct sender_t sender_t;
+
+#include <library.h>
+#include <network/packet.h>
+
+/**
+ * @brief Thread responsible for sending packets over the socket.
+ *
+ * @b Constructors:
+ * - sender_create()
+ *
+ * @ingroup threads
+ */
+struct sender_t {
+
+ /**
+ * @brief Send a packet over the network.
+ *
+ * This function is non blocking and adds the packet to a queue.
+ * Whenever the sender thread things it's good to send the packet,
+ * it'll do so.
+ *
+ * @param this calling object
+ * @param packet packet to send
+ */
+ void (*send) (sender_t *this, packet_t *packet);
+
+ /**
+ * @brief Destroys a sender object.
+ *
+ * @param this calling object
+ */
+ void (*destroy) (sender_t *this);
+};
+
+/**
+ * @brief Create the sender thread.
+ *
+ * The thread will start to work, getting packets
+ * from its queue and sends them out.
+ *
+ * @return created sender object
+ *
+ * @ingroup threads
+ */
+sender_t * sender_create(void);
+
+#endif /*SENDER_H_*/
diff --git a/src/charon/threads/stroke_interface.c b/src/charon/threads/stroke_interface.c
new file mode 100755
index 000000000..a9074debb
--- /dev/null
+++ b/src/charon/threads/stroke_interface.c
@@ -0,0 +1,1456 @@
+/**
+ * @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 <signal.h>
+
+#include "stroke_interface.h"
+
+#include <library.h>
+#include <stroke.h>
+#include <daemon.h>
+#include <crypto/x509.h>
+#include <crypto/ca.h>
+#include <crypto/crl.h>
+#include <queues/jobs/initiate_job.h>
+#include <queues/jobs/route_job.h>
+#include <utils/leak_detective.h>
+
+#define IKE_PORT 500
+#define PATH_BUF 256
+
+
+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;
+
+ /**
+ * Output stream (stroke console)
+ */
+ FILE *out;
+
+ /**
+ * Unix socket to listen for strokes
+ */
+ int socket;
+
+ /**
+ * Thread which reads from the Socket
+ */
+ pthread_t assigned_thread;
+};
+
+/**
+ * Helper function which corrects the string pointers
+ * in a stroke_msg_t. Strings in a stroke_msg sent over "wire"
+ * contains RELATIVE addresses (relative to the beginning of the
+ * stroke_msg). They must be corrected if they reach our address
+ * space...
+ */
+static void pop_string(stroke_msg_t *msg, char **string)
+{
+ if (*string == NULL)
+ return;
+
+ /* check for sanity of string pointer and string */
+ if (string < (char**)msg
+ || string > (char**)msg + sizeof(stroke_msg_t)
+ || (unsigned long)*string < (unsigned long)((char*)msg->buffer - (char*)msg)
+ || (unsigned long)*string > msg->length)
+ {
+ *string = "(invalid pointer in stroke msg)";
+ }
+ else
+ {
+ *string = (char*)msg + (unsigned long)*string;
+ }
+}
+
+/**
+ * Load end entitity certificate
+ */
+static x509_t* load_end_certificate(const char *filename, identification_t **idp)
+{
+ char path[PATH_BUF];
+ x509_t *cert;
+
+ if (*filename == '/')
+ {
+ /* absolute path name */
+ snprintf(path, sizeof(path), "%s", filename);
+ }
+ else
+ {
+ /* relative path name */
+ snprintf(path, sizeof(path), "%s/%s", CERTIFICATE_DIR, filename);
+ }
+
+ cert = x509_create_from_file(path, "end entity");
+
+ if (cert)
+ {
+ identification_t *id = *idp;
+ identification_t *subject = cert->get_subject(cert);
+
+ err_t ugh = cert->is_valid(cert, NULL);
+
+ if (ugh != NULL)
+ {
+ DBG1(DBG_CFG, "warning: certificate %s", ugh);
+ }
+ if (!id->equals(id, subject) && !cert->equals_subjectAltName(cert, id))
+ {
+ id->destroy(id);
+ id = subject;
+ *idp = id->clone(id);
+ }
+ return charon->credentials->add_end_certificate(charon->credentials, cert);
+ }
+ return NULL;
+}
+
+/**
+ * Load ca certificate
+ */
+static x509_t* load_ca_certificate(const char *filename)
+{
+ char path[PATH_BUF];
+ x509_t *cert;
+
+ if (*filename == '/')
+ {
+ /* absolute path name */
+ snprintf(path, sizeof(path), "%s", filename);
+ }
+ else
+ {
+ /* relative path name */
+ snprintf(path, sizeof(path), "%s/%s", CA_CERTIFICATE_DIR, filename);
+ }
+
+ cert = x509_create_from_file(path, "ca");
+
+ if (cert)
+ {
+ if (cert->is_ca(cert))
+ {
+ return charon->credentials->add_auth_certificate(charon->credentials, cert, AUTH_CA);
+ }
+ else
+ {
+ DBG1(DBG_CFG, " CA basic constraints flag not set, cert discarded");
+ cert->destroy(cert);
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Add a connection to the configuration list
+ */
+static void stroke_add_conn(stroke_msg_t *msg, FILE *out)
+{
+ connection_t *connection;
+ policy_t *policy;
+ identification_t *my_id, *other_id;
+ identification_t *my_ca = NULL;
+ identification_t *other_ca = NULL;
+ bool my_ca_same = FALSE;
+ bool other_ca_same =FALSE;
+ host_t *my_host, *other_host, *my_subnet, *other_subnet;
+ host_t *my_vip = NULL, *other_vip = NULL;
+ proposal_t *proposal;
+ traffic_selector_t *my_ts, *other_ts;
+ char *interface;
+
+ 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.subnet);
+ pop_string(msg, &msg->add_conn.other.subnet);
+ pop_string(msg, &msg->add_conn.me.sourceip);
+ pop_string(msg, &msg->add_conn.other.sourceip);
+ 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.ca);
+ pop_string(msg, &msg->add_conn.other.ca);
+ pop_string(msg, &msg->add_conn.me.updown);
+ pop_string(msg, &msg->add_conn.other.updown);
+ pop_string(msg, &msg->add_conn.algorithms.ike);
+ pop_string(msg, &msg->add_conn.algorithms.esp);
+
+ DBG1(DBG_CFG, "received stroke: add connection '%s'", msg->add_conn.name);
+
+ DBG2(DBG_CFG, "conn %s", msg->add_conn.name);
+ DBG2(DBG_CFG, " left=%s", msg->add_conn.me.address);
+ DBG2(DBG_CFG, " right=%s", msg->add_conn.other.address);
+ DBG2(DBG_CFG, " leftsubnet=%s", msg->add_conn.me.subnet);
+ DBG2(DBG_CFG, " rightsubnet=%s", msg->add_conn.other.subnet);
+ DBG2(DBG_CFG, " leftsourceip=%s", msg->add_conn.me.sourceip);
+ DBG2(DBG_CFG, " rightsourceip=%s", msg->add_conn.other.sourceip);
+ DBG2(DBG_CFG, " leftid=%s", msg->add_conn.me.id);
+ DBG2(DBG_CFG, " rightid=%s", msg->add_conn.other.id);
+ DBG2(DBG_CFG, " leftcert=%s", msg->add_conn.me.cert);
+ DBG2(DBG_CFG, " rightcert=%s", msg->add_conn.other.cert);
+ DBG2(DBG_CFG, " leftca=%s", msg->add_conn.me.ca);
+ DBG2(DBG_CFG, " rightca=%s", msg->add_conn.other.ca);
+ DBG2(DBG_CFG, " ike=%s", msg->add_conn.algorithms.ike);
+ DBG2(DBG_CFG, " esp=%s", msg->add_conn.algorithms.esp);
+
+ my_host = msg->add_conn.me.address?
+ host_create_from_string(msg->add_conn.me.address, IKE_PORT) : NULL;
+ if (my_host == NULL)
+ {
+ DBG1(DBG_CFG, "invalid host: %s\n", msg->add_conn.me.address);
+ return;
+ }
+
+ other_host = msg->add_conn.other.address ?
+ host_create_from_string(msg->add_conn.other.address, IKE_PORT) : NULL;
+ if (other_host == NULL)
+ {
+ DBG1(DBG_CFG, "invalid host: %s\n", msg->add_conn.other.address);
+ my_host->destroy(my_host);
+ return;
+ }
+
+ interface = charon->kernel_interface->get_interface(charon->kernel_interface,
+ other_host);
+ if (interface)
+ {
+ stroke_end_t tmp_end;
+ host_t *tmp_host;
+
+ DBG2(DBG_CFG, "left is other host, swapping ends\n");
+
+ tmp_host = my_host;
+ my_host = other_host;
+ other_host = tmp_host;
+
+ tmp_end = msg->add_conn.me;
+ msg->add_conn.me = msg->add_conn.other;
+ msg->add_conn.other = tmp_end;
+ free(interface);
+ }
+ if (!interface)
+ {
+ interface = charon->kernel_interface->get_interface(
+ charon->kernel_interface, my_host);
+ if (!interface)
+ {
+ DBG1(DBG_CFG, "left nor right host is our side, aborting\n");
+ goto destroy_hosts;
+ }
+ free(interface);
+ }
+
+ my_id = identification_create_from_string(msg->add_conn.me.id ?
+ msg->add_conn.me.id : msg->add_conn.me.address);
+ if (my_id == NULL)
+ {
+ DBG1(DBG_CFG, "invalid ID: %s\n", msg->add_conn.me.id);
+ goto destroy_hosts;
+ }
+
+ other_id = identification_create_from_string(msg->add_conn.other.id ?
+ msg->add_conn.other.id : msg->add_conn.other.address);
+ if (other_id == NULL)
+ {
+ DBG1(DBG_CFG, "invalid ID: %s\n", msg->add_conn.other.id);
+ my_id->destroy(my_id);
+ goto destroy_hosts;
+ }
+
+ my_subnet = host_create_from_string(msg->add_conn.me.subnet ?
+ msg->add_conn.me.subnet : msg->add_conn.me.address, IKE_PORT);
+ if (my_subnet == NULL)
+ {
+ DBG1(DBG_CFG, "invalid subnet: %s\n", msg->add_conn.me.subnet);
+ goto destroy_ids;
+ }
+
+ other_subnet = host_create_from_string(msg->add_conn.other.subnet ?
+ msg->add_conn.other.subnet : msg->add_conn.other.address, IKE_PORT);
+ if (other_subnet == NULL)
+ {
+ DBG1(DBG_CFG, "invalid subnet: %s\n", msg->add_conn.me.subnet);
+ my_subnet->destroy(my_subnet);
+ goto destroy_ids;
+ }
+
+ if (msg->add_conn.me.virtual_ip)
+ {
+ my_vip = host_create_from_string(msg->add_conn.me.sourceip, 0);
+ }
+ other_vip = host_create_from_string(msg->add_conn.other.sourceip, 0);
+
+ if (msg->add_conn.me.tohost)
+ {
+ my_ts = traffic_selector_create_dynamic(msg->add_conn.me.protocol,
+ my_host->get_family(my_host) == AF_INET ?
+ TS_IPV4_ADDR_RANGE : TS_IPV6_ADDR_RANGE,
+ msg->add_conn.me.port ? msg->add_conn.me.port : 0,
+ msg->add_conn.me.port ? msg->add_conn.me.port : 65535);
+ }
+ else
+ {
+ my_ts = traffic_selector_create_from_subnet(my_subnet,
+ msg->add_conn.me.subnet ? msg->add_conn.me.subnet_mask : 0,
+ msg->add_conn.me.protocol, msg->add_conn.me.port);
+ }
+ my_subnet->destroy(my_subnet);
+
+ if (msg->add_conn.other.tohost)
+ {
+ other_ts = traffic_selector_create_dynamic(msg->add_conn.other.protocol,
+ other_host->get_family(other_host) == AF_INET ?
+ TS_IPV4_ADDR_RANGE : TS_IPV6_ADDR_RANGE,
+ msg->add_conn.other.port ? msg->add_conn.other.port : 0,
+ msg->add_conn.other.port ? msg->add_conn.other.port : 65535);
+ }
+ else
+ {
+ other_ts = traffic_selector_create_from_subnet(other_subnet,
+ msg->add_conn.other.subnet ? msg->add_conn.other.subnet_mask : 0,
+ msg->add_conn.other.protocol, msg->add_conn.other.port);
+ }
+ other_subnet->destroy(other_subnet);
+
+ if (msg->add_conn.me.ca)
+ {
+ if (streq(msg->add_conn.me.ca, "%same"))
+ {
+ my_ca_same = TRUE;
+ }
+ else
+ {
+ my_ca = identification_create_from_string(msg->add_conn.me.ca);
+ }
+ }
+ if (msg->add_conn.other.ca)
+ {
+ if (streq(msg->add_conn.other.ca, "%same"))
+ {
+ other_ca_same = TRUE;
+ }
+ else
+ {
+ other_ca = identification_create_from_string(msg->add_conn.other.ca);
+ }
+ }
+ if (msg->add_conn.me.cert)
+ {
+ x509_t *cert = load_end_certificate(msg->add_conn.me.cert, &my_id);
+
+ if (my_ca == NULL && !my_ca_same && cert)
+ {
+ identification_t *issuer = cert->get_issuer(cert);
+
+ my_ca = issuer->clone(issuer);
+ }
+ }
+ if (msg->add_conn.other.cert)
+ {
+ x509_t *cert = load_end_certificate(msg->add_conn.other.cert, &other_id);
+
+ if (other_ca == NULL && !other_ca_same && cert)
+ {
+ identification_t *issuer = cert->get_issuer(cert);
+
+ other_ca = issuer->clone(issuer);
+ }
+ }
+ if (other_ca_same && my_ca)
+ {
+ other_ca = my_ca->clone(my_ca);
+ }
+ else if (my_ca_same && other_ca)
+ {
+ my_ca = other_ca->clone(other_ca);
+ }
+ if (my_ca == NULL)
+ {
+ my_ca = identification_create_from_string("%any");
+ }
+ if (other_ca == NULL)
+ {
+ other_ca = identification_create_from_string("%any");
+ }
+ DBG2(DBG_CFG, " my ca: '%D'", my_ca);
+ DBG2(DBG_CFG, " other ca:'%D'", other_ca);
+ DBG2(DBG_CFG, " updown: '%s'", msg->add_conn.me.updown);
+
+ connection = connection_create(msg->add_conn.name,
+ msg->add_conn.ikev2,
+ msg->add_conn.me.sendcert,
+ msg->add_conn.other.sendcert,
+ my_host, other_host,
+ msg->add_conn.dpd.delay,
+ msg->add_conn.rekey.reauth,
+ msg->add_conn.rekey.tries,
+ msg->add_conn.rekey.ike_lifetime,
+ msg->add_conn.rekey.ike_lifetime - msg->add_conn.rekey.margin,
+ msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100);
+
+ if (msg->add_conn.algorithms.ike)
+ {
+ char *proposal_string;
+ char *strict = msg->add_conn.algorithms.ike + strlen(msg->add_conn.algorithms.ike) - 1;
+
+ if (*strict == '!')
+ *strict = '\0';
+ else
+ strict = NULL;
+
+ while ((proposal_string = strsep(&msg->add_conn.algorithms.ike, ",")))
+ {
+ proposal = proposal_create_from_string(PROTO_IKE, proposal_string);
+ if (proposal == NULL)
+ {
+ DBG1(DBG_CFG, "invalid IKE proposal string: %s", proposal_string);
+ my_id->destroy(my_id);
+ other_id->destroy(other_id);
+ my_ts->destroy(my_ts);
+ other_ts->destroy(other_ts);
+ my_ca->destroy(my_ca);
+ other_ca->destroy(other_ca);
+ connection->destroy(connection);
+ return;
+ }
+ connection->add_proposal(connection, proposal);
+ }
+ if (!strict)
+ {
+ proposal = proposal_create_default(PROTO_IKE);
+ connection->add_proposal(connection, proposal);
+ }
+ }
+ else
+ {
+ proposal = proposal_create_default(PROTO_IKE);
+ connection->add_proposal(connection, proposal);
+ }
+
+ policy = policy_create(msg->add_conn.name, my_id, other_id, my_vip, other_vip,
+ msg->add_conn.auth_method, msg->add_conn.eap_type,
+ msg->add_conn.rekey.ipsec_lifetime,
+ msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin,
+ msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100,
+ msg->add_conn.me.updown, msg->add_conn.me.hostaccess,
+ msg->add_conn.mode, msg->add_conn.dpd.action);
+ policy->add_my_traffic_selector(policy, my_ts);
+ policy->add_other_traffic_selector(policy, other_ts);
+ policy->add_authorities(policy, my_ca, other_ca);
+
+ if (msg->add_conn.algorithms.esp)
+ {
+ char *proposal_string;
+ char *strict = msg->add_conn.algorithms.esp + strlen(msg->add_conn.algorithms.esp) - 1;
+
+ if (*strict == '!')
+ *strict = '\0';
+ else
+ strict = NULL;
+
+ while ((proposal_string = strsep(&msg->add_conn.algorithms.esp, ",")))
+ {
+ proposal = proposal_create_from_string(PROTO_ESP, proposal_string);
+ if (proposal == NULL)
+ {
+ DBG1(DBG_CFG, "invalid ESP proposal string: %s", proposal_string);
+ policy->destroy(policy);
+ connection->destroy(connection);
+ return;
+ }
+ policy->add_proposal(policy, proposal);
+ }
+ if (!strict)
+ {
+ proposal = proposal_create_default(PROTO_ESP);
+ policy->add_proposal(policy, proposal);
+ }
+ }
+ else
+ {
+ proposal = proposal_create_default(PROTO_ESP);
+ policy->add_proposal(policy, proposal);
+ }
+
+ /* add to global connection list */
+ charon->connections->add_connection(charon->connections, connection);
+ DBG1(DBG_CFG, "added connection '%s': %H[%D]...%H[%D]",
+ msg->add_conn.name, my_host, my_id, other_host, other_id);
+ /* add to global policy list */
+ charon->policies->add_policy(charon->policies, policy);
+
+ return;
+
+ /* mopping up after parsing errors */
+
+destroy_ids:
+ my_id->destroy(my_id);
+ other_id->destroy(other_id);
+
+destroy_hosts:
+ my_host->destroy(my_host);
+ other_host->destroy(other_host);
+}
+
+/**
+ * Delete a connection from the list
+ */
+static void stroke_del_conn(stroke_msg_t *msg, FILE *out)
+{
+ status_t status;
+
+ pop_string(msg, &(msg->del_conn.name));
+ DBG1(DBG_CFG, "received stroke: delete connection '%s'", msg->del_conn.name);
+
+ status = charon->connections->delete_connection(charon->connections,
+ msg->del_conn.name);
+ charon->policies->delete_policy(charon->policies, msg->del_conn.name);
+ if (status == SUCCESS)
+ {
+ fprintf(out, "deleted connection '%s'\n", msg->del_conn.name);
+ }
+ else
+ {
+ fprintf(out, "no connection named '%s'\n", msg->del_conn.name);
+ }
+}
+
+/**
+ * initiate a connection by name
+ */
+static void stroke_initiate(stroke_msg_t *msg, FILE *out)
+{
+ initiate_job_t *job;
+ connection_t *connection;
+ policy_t *policy;
+ ike_sa_t *init_ike_sa = NULL;
+ signal_t signal;
+
+ pop_string(msg, &(msg->initiate.name));
+ DBG1(DBG_CFG, "received stroke: initiate '%s'", msg->initiate.name);
+
+ connection = charon->connections->get_connection_by_name(charon->connections,
+ msg->initiate.name);
+ if (connection == NULL)
+ {
+ if (msg->output_verbosity >= 0)
+ {
+ fprintf(out, "no connection named '%s'\n", msg->initiate.name);
+ }
+ return;
+ }
+ if (!connection->is_ikev2(connection))
+ {
+ connection->destroy(connection);
+ return;
+ }
+
+ policy = charon->policies->get_policy_by_name(charon->policies,
+ msg->initiate.name);
+ if (policy == NULL)
+ {
+ if (msg->output_verbosity >= 0)
+ {
+ fprintf(out, "no policy named '%s'\n", msg->initiate.name);
+ }
+ connection->destroy(connection);
+ return;
+ }
+
+ job = initiate_job_create(connection, policy);
+ charon->bus->set_listen_state(charon->bus, TRUE);
+ charon->job_queue->add(charon->job_queue, (job_t*)job);
+ while (TRUE)
+ {
+ level_t level;
+ int thread;
+ ike_sa_t *ike_sa;
+ char* format;
+ va_list args;
+
+ signal = charon->bus->listen(charon->bus, &level, &thread, &ike_sa, &format, &args);
+
+ if ((init_ike_sa == NULL || ike_sa == init_ike_sa) &&
+ level <= msg->output_verbosity)
+ {
+ if (vfprintf(out, format, args) < 0 ||
+ fprintf(out, "\n") < 0 ||
+ fflush(out))
+ {
+ charon->bus->set_listen_state(charon->bus, FALSE);
+ break;
+ }
+ }
+
+ switch (signal)
+ {
+ case CHILD_UP_SUCCESS:
+ case CHILD_UP_FAILED:
+ case IKE_UP_FAILED:
+ if (ike_sa == init_ike_sa)
+ {
+ charon->bus->set_listen_state(charon->bus, FALSE);
+ return;
+ }
+ continue;
+ case CHILD_UP_START:
+ case IKE_UP_START:
+ if (init_ike_sa == NULL)
+ {
+ init_ike_sa = ike_sa;
+ }
+ continue;
+ default:
+ continue;
+ }
+ }
+}
+
+/**
+ * route/unroute a policy (install SPD entries)
+ */
+static void stroke_route(stroke_msg_t *msg, FILE *out, bool route)
+{
+ route_job_t *job;
+ connection_t *connection;
+ policy_t *policy;
+
+ pop_string(msg, &(msg->route.name));
+ DBG1(DBG_CFG, "received stroke: %s '%s'",
+ route ? "route" : "unroute", msg->route.name);
+
+ /* we wouldn't need a connection, but we only want to route policies
+ * whose connections are keyexchange=ikev2. */
+ connection = charon->connections->get_connection_by_name(charon->connections,
+ msg->route.name);
+ if (connection == NULL)
+ {
+ fprintf(out, "no connection named '%s'\n", msg->route.name);
+ return;
+ }
+ if (!connection->is_ikev2(connection))
+ {
+ connection->destroy(connection);
+ return;
+ }
+
+ policy = charon->policies->get_policy_by_name(charon->policies,
+ msg->route.name);
+ if (policy == NULL)
+ {
+ fprintf(out, "no policy named '%s'\n", msg->route.name);
+ connection->destroy(connection);
+ return;
+ }
+ fprintf(out, "%s policy '%s'\n",
+ route ? "routing" : "unrouting", msg->route.name);
+ job = route_job_create(connection, policy, route);
+ charon->job_queue->add(charon->job_queue, (job_t*)job);
+}
+
+/**
+ * terminate a connection by name
+ */
+static void stroke_terminate(stroke_msg_t *msg, FILE *out)
+{
+ char *string, *pos = NULL, *name = NULL;
+ u_int32_t id = 0;
+ bool child;
+ int len;
+ status_t status = SUCCESS;;
+ ike_sa_t *ike_sa;
+
+ pop_string(msg, &(msg->terminate.name));
+ string = msg->terminate.name;
+ DBG1(DBG_CFG, "received stroke: terminate '%s'", string);
+
+ len = strlen(string);
+ if (len < 1)
+ {
+ DBG1(DBG_CFG, "error parsing string");
+ return;
+ }
+ switch (string[len-1])
+ {
+ case '}':
+ child = TRUE;
+ pos = strchr(string, '{');
+ break;
+ case ']':
+ child = FALSE;
+ pos = strchr(string, '[');
+ break;
+ default:
+ name = string;
+ child = FALSE;
+ break;
+ }
+
+ if (name)
+ { /* must be a single name */
+ DBG1(DBG_CFG, "check out by single name '%s'", name);
+ ike_sa = charon->ike_sa_manager->checkout_by_name(charon->ike_sa_manager,
+ name, child);
+ }
+ else if (pos == string + len - 2)
+ { /* must be name[] or name{} */
+ string[len-2] = '\0';
+ DBG1(DBG_CFG, "check out by name '%s'", string);
+ ike_sa = charon->ike_sa_manager->checkout_by_name(charon->ike_sa_manager,
+ string, child);
+ }
+ else
+ { /* must be name[123] or name{23} */
+ string[len-1] = '\0';
+ id = atoi(pos + 1);
+ if (id == 0)
+ {
+ DBG1(DBG_CFG, "error parsing string");
+ return;
+ }
+ DBG1(DBG_CFG, "check out by id '%d'", id);
+ ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
+ id, child);
+ }
+ if (ike_sa == NULL)
+ {
+ DBG1(DBG_CFG, "no such IKE_SA found");
+ return;
+ }
+
+ if (!child)
+ {
+ status = ike_sa->delete(ike_sa);
+ }
+ else
+ {
+ child_sa_t *child_sa;
+ iterator_t *iterator = ike_sa->create_child_sa_iterator(ike_sa);
+ while (iterator->iterate(iterator, (void**)&child_sa))
+ {
+ if ((id && id == child_sa->get_reqid(child_sa)) ||
+ (string && streq(string, child_sa->get_name(child_sa))))
+ {
+ u_int32_t spi = child_sa->get_spi(child_sa, TRUE);
+ protocol_id_t proto = child_sa->get_protocol(child_sa);
+
+ status = ike_sa->delete_child_sa(ike_sa, proto, spi);
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ }
+ if (status == DESTROY_ME)
+ {
+ charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
+ ike_sa);
+ return;
+ }
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+}
+
+/**
+ * Add a ca information record to the cainfo list
+ */
+static void stroke_add_ca(stroke_msg_t *msg, FILE *out)
+{
+ x509_t *cacert;
+ ca_info_t *ca_info;
+
+ pop_string(msg, &msg->add_ca.name);
+ pop_string(msg, &msg->add_ca.cacert);
+ pop_string(msg, &msg->add_ca.crluri);
+ pop_string(msg, &msg->add_ca.crluri2);
+ pop_string(msg, &msg->add_ca.ocspuri);
+ pop_string(msg, &msg->add_ca.ocspuri2);
+
+ DBG1(DBG_CFG, "received stroke: add ca '%s'", msg->add_ca.name);
+
+ DBG2(DBG_CFG, "ca %s", msg->add_ca.name);
+ DBG2(DBG_CFG, " cacert=%s", msg->add_ca.cacert);
+ DBG2(DBG_CFG, " crluri=%s", msg->add_ca.crluri);
+ DBG2(DBG_CFG, " crluri2=%s", msg->add_ca.crluri2);
+ DBG2(DBG_CFG, " ocspuri=%s", msg->add_ca.ocspuri);
+ DBG2(DBG_CFG, " ocspuri2=%s", msg->add_ca.ocspuri2);
+
+ if (msg->add_ca.cacert == NULL)
+ {
+ DBG1(DBG_CFG, "missing cacert parameter\n");
+ return;
+ }
+
+ cacert = load_ca_certificate(msg->add_ca.cacert);
+
+ if (cacert == NULL)
+ {
+ return;
+ }
+ ca_info = ca_info_create(msg->add_ca.name, cacert);
+
+ if (msg->add_ca.crluri)
+ {
+ chunk_t uri = { msg->add_ca.crluri, strlen(msg->add_ca.crluri) };
+
+ ca_info->add_crluri(ca_info, uri);
+ }
+ if (msg->add_ca.crluri2)
+ {
+ chunk_t uri = { msg->add_ca.crluri2, strlen(msg->add_ca.crluri2) };
+
+ ca_info->add_crluri(ca_info, uri);
+ }
+ if (msg->add_ca.ocspuri)
+ {
+ chunk_t uri = { msg->add_ca.ocspuri, strlen(msg->add_ca.ocspuri) };
+
+ ca_info->add_ocspuri(ca_info, uri);
+ }
+ if (msg->add_ca.ocspuri2)
+ {
+ chunk_t uri = { msg->add_ca.ocspuri2, strlen(msg->add_ca.ocspuri2) };
+
+ ca_info->add_ocspuri(ca_info, uri);
+ }
+ charon->credentials->add_ca_info(charon->credentials, ca_info);
+ DBG1(DBG_CFG, "added ca '%s'", msg->add_ca.name);
+
+}
+
+/**
+ * Delete a ca information record from the cainfo list
+ */
+static void stroke_del_ca(stroke_msg_t *msg, FILE *out)
+{
+ status_t status;
+
+ pop_string(msg, &(msg->del_ca.name));
+ DBG1(DBG_CFG, "received stroke: delete ca '%s'", msg->del_ca.name);
+
+ status = charon->credentials->release_ca_info(charon->credentials,
+ msg->del_ca.name);
+
+ if (status == SUCCESS)
+ {
+ fprintf(out, "deleted ca '%s'\n", msg->del_ca.name);
+ }
+ else
+ {
+ fprintf(out, "no ca named '%s'\n", msg->del_ca.name);
+ }
+}
+
+/**
+ * show status of daemon
+ */
+static void stroke_statusall(stroke_msg_t *msg, FILE *out)
+{
+ iterator_t *iterator;
+ linked_list_t *list;
+ host_t *host;
+ connection_t *connection;
+ policy_t *policy;
+ ike_sa_t *ike_sa;
+ char *name = NULL;
+
+ leak_detective_status(out);
+
+ fprintf(out, "Performance:\n");
+ fprintf(out, " worker threads: %d idle of %d,",
+ charon->thread_pool->get_idle_threads(charon->thread_pool),
+ charon->thread_pool->get_pool_size(charon->thread_pool));
+ fprintf(out, " job queue load: %d,",
+ charon->job_queue->get_count(charon->job_queue));
+ fprintf(out, " scheduled events: %d\n",
+ charon->event_queue->get_count(charon->event_queue));
+ list = charon->kernel_interface->create_address_list(charon->kernel_interface);
+
+ fprintf(out, "Listening on %d IP addresses:\n", list->get_count(list));
+ while (list->remove_first(list, (void**)&host) == SUCCESS)
+ {
+ fprintf(out, " %H\n", host);
+ host->destroy(host);
+ }
+ list->destroy(list);
+
+ if (msg->status.name)
+ {
+ pop_string(msg, &(msg->status.name));
+ name = msg->status.name;
+ }
+
+ iterator = charon->connections->create_iterator(charon->connections);
+ if (iterator->get_count(iterator) > 0)
+ {
+ fprintf(out, "Connections:\n");
+ }
+ while (iterator->iterate(iterator, (void**)&connection))
+ {
+ if (connection->is_ikev2(connection)
+ && (name == NULL || streq(name, connection->get_name(connection))))
+ {
+ fprintf(out, "%12s: %H...%H\n",
+ connection->get_name(connection),
+ connection->get_my_host(connection),
+ connection->get_other_host(connection));
+ }
+ }
+ iterator->destroy(iterator);
+
+ iterator = charon->policies->create_iterator(charon->policies);
+ if (iterator->get_count(iterator) > 0)
+ {
+ fprintf(out, "Policies:\n");
+ }
+ while (iterator->iterate(iterator, (void**)&policy))
+ {
+ if (name == NULL || streq(name, policy->get_name(policy)))
+ {
+ fprintf(out, "%12s: '%D'...'%D'\n",
+ policy->get_name(policy),
+ policy->get_my_id(policy),
+ policy->get_other_id(policy));
+ }
+ }
+ iterator->destroy(iterator);
+
+ iterator = charon->ike_sa_manager->create_iterator(charon->ike_sa_manager);
+ if (iterator->get_count(iterator) > 0)
+ {
+ fprintf(out, "Security Associations:\n");
+ }
+ while (iterator->iterate(iterator, (void**)&ike_sa))
+ {
+ bool ike_sa_printed = FALSE;
+ child_sa_t *child_sa;
+ iterator_t *children = ike_sa->create_child_sa_iterator(ike_sa);
+
+ /* print IKE_SA */
+ if (name == NULL || strncmp(name, ike_sa->get_name(ike_sa), strlen(name)) == 0)
+ {
+ fprintf(out, "%#K\n", ike_sa);
+ ike_sa_printed = TRUE;
+ }
+
+ while (children->iterate(children, (void**)&child_sa))
+ {
+ bool child_sa_match = name == NULL ||
+ strncmp(name, child_sa->get_name(child_sa), strlen(name)) == 0;
+
+ /* print IKE_SA if its name differs from the CHILD_SA's name */
+ if (!ike_sa_printed && child_sa_match)
+ {
+ fprintf(out, "%#K\n", ike_sa);
+ ike_sa_printed = TRUE;
+ }
+
+ /* print CHILD_SA */
+ if (child_sa_match)
+ {
+ fprintf(out, "%#P\n", child_sa);
+ }
+ }
+ children->destroy(children);
+ }
+ iterator->destroy(iterator);
+}
+
+/**
+ * show status of daemon
+ */
+static void stroke_status(stroke_msg_t *msg, FILE *out)
+{
+ iterator_t *iterator;
+ ike_sa_t *ike_sa;
+ char *name = NULL;
+
+ if (msg->status.name)
+ {
+ pop_string(msg, &(msg->status.name));
+ name = msg->status.name;
+ }
+
+ iterator = charon->ike_sa_manager->create_iterator(charon->ike_sa_manager);
+ while (iterator->iterate(iterator, (void**)&ike_sa))
+ {
+ bool ike_sa_printed = FALSE;
+ child_sa_t *child_sa;
+ iterator_t *children = ike_sa->create_child_sa_iterator(ike_sa);
+
+ /* print IKE_SA */
+ if (name == NULL || strncmp(name, ike_sa->get_name(ike_sa), strlen(name)) == 0)
+ {
+ fprintf(out, "%K\n", ike_sa);
+ ike_sa_printed = TRUE;
+ }
+
+ while (children->iterate(children, (void**)&child_sa))
+ {
+ bool child_sa_match = name == NULL ||
+ strncmp(name, child_sa->get_name(child_sa), strlen(name)) == 0;
+
+ /* print IKE_SA if its name differs from the CHILD_SA's name */
+ if (!ike_sa_printed && child_sa_match)
+ {
+ fprintf(out, "%K\n", ike_sa);
+ ike_sa_printed = TRUE;
+ }
+
+ /* print CHILD_SA */
+ if (child_sa_match)
+ {
+ fprintf(out, "%P\n", child_sa);
+ }
+ }
+ children->destroy(children);
+ }
+ iterator->destroy(iterator);
+}
+
+/**
+ * list all authority certificates matching a specified flag
+ */
+static void list_auth_certificates(u_int flag, const char *label, bool utc, FILE *out)
+{
+ bool first = TRUE;
+ x509_t *cert;
+
+ iterator_t *iterator = charon->credentials->create_auth_cert_iterator(charon->credentials);
+
+ while (iterator->iterate(iterator, (void**)&cert))
+ {
+ if (cert->has_authority_flag(cert, flag))
+ {
+ if (first)
+ {
+ fprintf(out, "\n");
+ fprintf(out, "List of X.509 %s Certificates:\n", label);
+ fprintf(out, "\n");
+ first = FALSE;
+ }
+ fprintf(out, "%#Q\n", cert, utc);
+ }
+ }
+ iterator->destroy(iterator);
+}
+
+/**
+ * list various information
+ */
+static void stroke_list(stroke_msg_t *msg, FILE *out)
+{
+ iterator_t *iterator;
+
+ if (msg->list.flags & LIST_CERTS)
+ {
+ x509_t *cert;
+
+ iterator = charon->credentials->create_cert_iterator(charon->credentials);
+ if (iterator->get_count(iterator))
+ {
+ fprintf(out, "\n");
+ fprintf(out, "List of X.509 End Entity Certificates:\n");
+ fprintf(out, "\n");
+ }
+ while (iterator->iterate(iterator, (void**)&cert))
+ {
+ fprintf(out, "%#Q", cert, msg->list.utc);
+ if (charon->credentials->has_rsa_private_key(
+ charon->credentials, cert->get_public_key(cert)))
+ {
+ fprintf(out, ", has private key");
+ }
+ fprintf(out, "\n");
+
+ }
+ iterator->destroy(iterator);
+ }
+ if (msg->list.flags & LIST_CACERTS)
+ {
+ list_auth_certificates(AUTH_CA, "CA", msg->list.utc, out);
+ }
+ if (msg->list.flags & LIST_CAINFOS)
+ {
+ ca_info_t *ca_info;
+
+ iterator = charon->credentials->create_cainfo_iterator(charon->credentials);
+ if (iterator->get_count(iterator))
+ {
+ fprintf(out, "\n");
+ fprintf(out, "List of X.509 CA Information Records:\n");
+ fprintf(out, "\n");
+ }
+ while (iterator->iterate(iterator, (void**)&ca_info))
+ {
+ fprintf(out, "%#W", ca_info, msg->list.utc);
+ }
+ iterator->destroy(iterator);
+ }
+ if (msg->list.flags & LIST_CRLS)
+ {
+ ca_info_t *ca_info;
+ bool first = TRUE;
+
+ iterator = charon->credentials->create_cainfo_iterator(charon->credentials);
+
+ while (iterator->iterate(iterator, (void **)&ca_info))
+ {
+ if (ca_info->has_crl(ca_info))
+ {
+ if (first)
+ {
+ fprintf(out, "\n");
+ fprintf(out, "List of X.509 CRLs:\n");
+ fprintf(out, "\n");
+ first = FALSE;
+ }
+ ca_info->list_crl(ca_info, out, msg->list.utc);
+ }
+ }
+ iterator->destroy(iterator);
+ }
+ if (msg->list.flags & LIST_OCSPCERTS)
+ {
+ list_auth_certificates(AUTH_OCSP, "OCSP", msg->list.utc, out);
+ }
+ if (msg->list.flags & LIST_OCSP)
+ {
+ ca_info_t *ca_info;
+ bool first = TRUE;
+
+ iterator = charon->credentials->create_cainfo_iterator(charon->credentials);
+
+ while (iterator->iterate(iterator, (void **)&ca_info))
+ {
+ if (ca_info->has_certinfos(ca_info))
+ {
+ if (first)
+ {
+ fprintf(out, "\n");
+ fprintf(out, "List of OCSP responses:\n");
+ first = FALSE;
+ }
+ fprintf(out, "\n");
+ ca_info->list_certinfos(ca_info, out, msg->list.utc);
+ }
+ }
+ iterator->destroy(iterator);
+ }
+}
+
+/**
+ * reread various information
+ */
+static void stroke_reread(stroke_msg_t *msg, FILE *out)
+{
+ if (msg->reread.flags & REREAD_CACERTS)
+ {
+ charon->credentials->load_ca_certificates(charon->credentials);
+ }
+ if (msg->reread.flags & REREAD_OCSPCERTS)
+ {
+ charon->credentials->load_ocsp_certificates(charon->credentials);
+ }
+ if (msg->reread.flags & REREAD_CRLS)
+ {
+ charon->credentials->load_crls(charon->credentials);
+ }
+}
+
+/**
+ * purge various information
+ */
+static void stroke_purge(stroke_msg_t *msg, FILE *out)
+{
+ if (msg->purge.flags & PURGE_OCSP)
+ {
+ iterator_t *iterator = charon->credentials->create_cainfo_iterator(charon->credentials);
+ ca_info_t *ca_info;
+
+ while (iterator->iterate(iterator, (void**)&ca_info))
+ {
+ ca_info->purge_ocsp(ca_info);
+ }
+ iterator->destroy(iterator);
+ }
+}
+
+signal_t get_signal_from_logtype(char *type)
+{
+ if (strcasecmp(type, "any") == 0) return SIG_ANY;
+ else if (strcasecmp(type, "mgr") == 0) return DBG_MGR;
+ else if (strcasecmp(type, "ike") == 0) return DBG_IKE;
+ else if (strcasecmp(type, "chd") == 0) return DBG_CHD;
+ else if (strcasecmp(type, "job") == 0) return DBG_JOB;
+ else if (strcasecmp(type, "cfg") == 0) return DBG_CFG;
+ else if (strcasecmp(type, "knl") == 0) return DBG_KNL;
+ else if (strcasecmp(type, "net") == 0) return DBG_NET;
+ else if (strcasecmp(type, "enc") == 0) return DBG_ENC;
+ else if (strcasecmp(type, "lib") == 0) return DBG_LIB;
+ else return -1;
+}
+
+/**
+ * set the verbosity debug output
+ */
+static void stroke_loglevel(stroke_msg_t *msg, FILE *out)
+{
+ signal_t signal;
+
+ pop_string(msg, &(msg->loglevel.type));
+ DBG1(DBG_CFG, "received stroke: loglevel %d for %s",
+ msg->loglevel.level, msg->loglevel.type);
+
+ signal = get_signal_from_logtype(msg->loglevel.type);
+ if (signal < 0)
+ {
+ fprintf(out, "invalid type (%s)!\n", msg->loglevel.type);
+ return;
+ }
+
+ charon->outlog->set_level(charon->outlog, signal, msg->loglevel.level);
+ charon->syslog->set_level(charon->syslog, signal, msg->loglevel.level);
+}
+
+/**
+ * process a stroke request from the socket pointed by "fd"
+ */
+static void stroke_process(int *fd)
+{
+ stroke_msg_t *msg;
+ u_int16_t msg_length;
+ ssize_t bytes_read;
+ FILE *out;
+ int strokefd = *fd;
+
+ /* peek the length */
+ bytes_read = recv(strokefd, &msg_length, sizeof(msg_length), MSG_PEEK);
+ if (bytes_read != sizeof(msg_length))
+ {
+ DBG1(DBG_CFG, "reading length of stroke message failed");
+ close(strokefd);
+ return;
+ }
+
+ /* read message */
+ msg = malloc(msg_length);
+ bytes_read = recv(strokefd, msg, msg_length, 0);
+ if (bytes_read != msg_length)
+ {
+ DBG1(DBG_CFG, "reading stroke message failed: %m");
+ close(strokefd);
+ return;
+ }
+
+ out = fdopen(dup(strokefd), "w");
+ if (out == NULL)
+ {
+ DBG1(DBG_CFG, "opening stroke output channel failed: %m");
+ close(strokefd);
+ free(msg);
+ return;
+ }
+
+ DBG3(DBG_CFG, "stroke message %b", (void*)msg, msg_length);
+
+ switch (msg->type)
+ {
+ case STR_INITIATE:
+ stroke_initiate(msg, out);
+ break;
+ case STR_ROUTE:
+ stroke_route(msg, out, TRUE);
+ break;
+ case STR_UNROUTE:
+ stroke_route(msg, out, FALSE);
+ break;
+ case STR_TERMINATE:
+ stroke_terminate(msg, out);
+ break;
+ case STR_STATUS:
+ stroke_status(msg, out);
+ break;
+ case STR_STATUS_ALL:
+ stroke_statusall(msg, out);
+ break;
+ case STR_ADD_CONN:
+ stroke_add_conn(msg, out);
+ break;
+ case STR_DEL_CONN:
+ stroke_del_conn(msg, out);
+ break;
+ case STR_ADD_CA:
+ stroke_add_ca(msg, out);
+ break;
+ case STR_DEL_CA:
+ stroke_del_ca(msg, out);
+ break;
+ case STR_LOGLEVEL:
+ stroke_loglevel(msg, out);
+ break;
+ case STR_LIST:
+ stroke_list(msg, out);
+ break;
+ case STR_REREAD:
+ stroke_reread(msg, out);
+ break;
+ case STR_PURGE:
+ stroke_purge(msg, out);
+ break;
+ default:
+ DBG1(DBG_CFG, "received unknown stroke");
+ }
+ fclose(out);
+ close(strokefd);
+ free(msg);
+}
+
+/**
+ * Implementation of private_stroke_t.stroke_receive.
+ */
+static void stroke_receive(private_stroke_t *this)
+{
+ struct sockaddr_un strokeaddr;
+ int strokeaddrlen = sizeof(strokeaddr);
+ int strokefd;
+ int oldstate;
+ pthread_t thread;
+
+ /* ignore sigpipe. writing over the pipe back to the console
+ * only fails if SIGPIPE is ignored. */
+ signal(SIGPIPE, SIG_IGN);
+
+ /* disable cancellation by default */
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+
+ while (TRUE)
+ {
+ /* 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)
+ {
+ DBG1(DBG_CFG, "accepting stroke connection failed: %m");
+ continue;
+ }
+
+ /* handle request asynchronously */
+ if (pthread_create(&thread, NULL, (void*(*)(void*))stroke_process, (void*)&strokefd) != 0)
+ {
+ DBG1(DBG_CFG, "failed to spawn stroke thread: %m");
+ }
+ /* detach so the thread terminates cleanly */
+ pthread_detach(thread);
+ }
+}
+
+/**
+ * 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;
+
+ /* set up unix socket */
+ this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (this->socket == -1)
+ {
+ DBG1(DBG_CFG, "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)
+ {
+ DBG1(DBG_CFG, "could not bind stroke socket: %m");
+ close(this->socket);
+ free(this);
+ return NULL;
+ }
+ umask(old);
+
+ if (listen(this->socket, 0) < 0)
+ {
+ DBG1(DBG_CFG, "could not listen on stroke socket: %m");
+ 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*))stroke_receive, this) != 0)
+ {
+ DBG1(DBG_CFG, "could not spawn stroke thread");
+ close(this->socket);
+ unlink(socket_addr.sun_path);
+ free(this);
+ return NULL;
+ }
+
+ return (&this->public);
+}
diff --git a/src/charon/threads/stroke_interface.h b/src/charon/threads/stroke_interface.h
new file mode 100644
index 000000000..0def5167e
--- /dev/null
+++ b/src/charon/threads/stroke_interface.h
@@ -0,0 +1,61 @@
+/**
+ * @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_
+
+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).
+ *
+ * @b Constructors:
+ * - stroke_create()
+ *
+ * @ingroup threads
+ */
+struct stroke_t {
+
+ /**
+ * @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(void);
+
+#endif /* STROKE_INTERFACE_H_ */
diff --git a/src/charon/threads/thread_pool.c b/src/charon/threads/thread_pool.c
new file mode 100644
index 000000000..052b5aab9
--- /dev/null
+++ b/src/charon/threads/thread_pool.c
@@ -0,0 +1,181 @@
+/**
+ * @file thread_pool.c
+ *
+ * @brief Implementation of thread_pool_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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>
+
+
+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;
+
+ /**
+ * Number of running threads.
+ */
+ u_int pool_size;
+
+ /**
+ * Number of threads waiting for work
+ */
+ u_int idle_threads;
+
+ /**
+ * Array of thread ids.
+ */
+ pthread_t *threads;
+} ;
+
+/**
+ * Implementation of private_thread_pool_t.process_jobs.
+ */
+static void process_jobs(private_thread_pool_t *this)
+{
+ job_t *job;
+ status_t status;
+
+ /* cancellation disabled by default */
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+
+ DBG1(DBG_JOB, "worker thread running, thread_ID: %06u",
+ (int)pthread_self());
+
+ while (TRUE)
+ {
+ /* TODO: should be atomic, but is not mission critical */
+ this->idle_threads++;
+ job = charon->job_queue->get(charon->job_queue);
+ this->idle_threads--;
+
+ status = job->execute(job);
+
+ if (status == DESTROY_ME)
+ {
+ job->destroy(job);
+ }
+ }
+}
+
+/**
+ * Implementation of thread_pool_t.get_pool_size.
+ */
+static u_int get_pool_size(private_thread_pool_t *this)
+{
+ return this->pool_size;
+}
+
+/**
+ * Implementation of thread_pool_t.get_idle_threads.
+ */
+static u_int get_idle_threads(private_thread_pool_t *this)
+{
+ return this->idle_threads;
+}
+
+/**
+ * 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++)
+ {
+ DBG1(DBG_JOB, "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)
+ {
+ DBG1(DBG_JOB, "worker thread #%d terminated", current+1);
+ }
+ else
+ {
+ DBG1(DBG_JOB, "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 = (u_int(*)(thread_pool_t*))get_pool_size;
+ this->public.get_idle_threads = (u_int(*)(thread_pool_t*))get_idle_threads;
+
+ /* initialize member */
+ this->pool_size = pool_size;
+ this->idle_threads = 0;
+ this->threads = malloc(sizeof(pthread_t) * pool_size);
+
+ /* try to create as many threads as possible, up to pool_size */
+ for (current = 0; current < pool_size; current++)
+ {
+ if (pthread_create(&(this->threads[current]), NULL,
+ (void*(*)(void*))process_jobs, this) == 0)
+ {
+ DBG1(DBG_JOB, "created worker thread #%d", current+1);
+ }
+ else
+ {
+ /* creation failed, is it the first one? */
+ if (current == 0)
+ {
+ free(this->threads);
+ free(this);
+ charon->kill(charon, "could not create any worker threads");
+ }
+ /* not all threads could be created, but at least one :-/ */
+ DBG1(DBG_JOB, "could only create %d from requested %d threads!",
+ current, pool_size);
+ this->pool_size = current;
+ break;
+ }
+ }
+ return (thread_pool_t*)this;
+}
diff --git a/src/charon/threads/thread_pool.h b/src/charon/threads/thread_pool.h
new file mode 100644
index 000000000..8e1989bda
--- /dev/null
+++ b/src/charon/threads/thread_pool.h
@@ -0,0 +1,87 @@
+/**
+ * @file thread_pool.h
+ *
+ * @brief Interface of thread_pool_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct thread_pool_t thread_pool_t;
+
+#include <stdlib.h>
+
+#include <library.h>
+
+/**
+ * @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
+ */
+ u_int (*get_pool_size) (thread_pool_t *thread_pool);
+
+ /**
+ * @brief Get the number of threads currently waiting for work.
+ *
+ * @param thread_pool calling object
+ * @return number of idle threads
+ */
+ u_int (*get_idle_threads) (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/src/ipsec/Makefile.am b/src/ipsec/Makefile.am
new file mode 100644
index 000000000..44964e041
--- /dev/null
+++ b/src/ipsec/Makefile.am
@@ -0,0 +1,16 @@
+sbin_SCRIPTS = ipsec
+CLEANFILES = ipsec
+dist_man8_MANS = ipsec.8
+EXTRA_DIST = ipsec.in
+
+ipsec : ipsec.in
+ sed \
+ -e "s:@IPSEC_VERSION@:$(PACKAGE_VERSION):" \
+ -e "s:@IPSEC_NAME@:$(PACKAGE_NAME):" \
+ -e "s:@IPSEC_DISTRO@::" \
+ -e "s:@IPSEC_DIR@:$(ipsecdir):" \
+ -e "s:@IPSEC_SBINDIR@:$(sbindir):" \
+ -e "s:@IPSEC_CONFDIR@:$(confdir):" \
+ -e "s:@IPSEC_PIDDIR@:$(piddir):" \
+ $< > $@
+ chmod +x $@
diff --git a/src/ipsec/Makefile.in b/src/ipsec/Makefile.in
new file mode 100644
index 000000000..eaf0e9d79
--- /dev/null
+++ b/src/ipsec/Makefile.in
@@ -0,0 +1,434 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/ipsec
+DIST_COMMON = $(dist_man8_MANS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_CLEAN_FILES =
+am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man8dir)"
+sbinSCRIPT_INSTALL = $(INSTALL_SCRIPT)
+SCRIPTS = $(sbin_SCRIPTS)
+SOURCES =
+DIST_SOURCES =
+man8dir = $(mandir)/man8
+NROFF = nroff
+MANS = $(dist_man8_MANS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_EAP_SIM_FALSE = @BUILD_EAP_SIM_FALSE@
+BUILD_EAP_SIM_TRUE = @BUILD_EAP_SIM_TRUE@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GPERF = @GPERF@
+GREP = @GREP@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+USE_CISCO_QUIRKS_FALSE = @USE_CISCO_QUIRKS_FALSE@
+USE_CISCO_QUIRKS_TRUE = @USE_CISCO_QUIRKS_TRUE@
+USE_LEAK_DETECTIVE_FALSE = @USE_LEAK_DETECTIVE_FALSE@
+USE_LEAK_DETECTIVE_TRUE = @USE_LEAK_DETECTIVE_TRUE@
+USE_LIBCURL_FALSE = @USE_LIBCURL_FALSE@
+USE_LIBCURL_TRUE = @USE_LIBCURL_TRUE@
+USE_LIBLDAP_FALSE = @USE_LIBLDAP_FALSE@
+USE_LIBLDAP_TRUE = @USE_LIBLDAP_TRUE@
+USE_NAT_TRANSPORT_FALSE = @USE_NAT_TRANSPORT_FALSE@
+USE_NAT_TRANSPORT_TRUE = @USE_NAT_TRANSPORT_TRUE@
+USE_SMARTCARD_FALSE = @USE_SMARTCARD_FALSE@
+USE_SMARTCARD_TRUE = @USE_SMARTCARD_TRUE@
+USE_VENDORID_FALSE = @USE_VENDORID_FALSE@
+USE_VENDORID_TRUE = @USE_VENDORID_TRUE@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+confdir = @confdir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+eapdir = @eapdir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+ipsecdir = @ipsecdir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+piddir = @piddir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+sbin_SCRIPTS = ipsec
+CLEANFILES = ipsec
+dist_man8_MANS = ipsec.8
+EXTRA_DIST = ipsec.in
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/ipsec/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/ipsec/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-sbinSCRIPTS: $(sbin_SCRIPTS)
+ @$(NORMAL_INSTALL)
+ test -z "$(sbindir)" || $(mkdir_p) "$(DESTDIR)$(sbindir)"
+ @list='$(sbin_SCRIPTS)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ if test -f $$d$$p; then \
+ f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
+ echo " $(sbinSCRIPT_INSTALL) '$$d$$p' '$(DESTDIR)$(sbindir)/$$f'"; \
+ $(sbinSCRIPT_INSTALL) "$$d$$p" "$(DESTDIR)$(sbindir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-sbinSCRIPTS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(sbin_SCRIPTS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
+ echo " rm -f '$(DESTDIR)$(sbindir)/$$f'"; \
+ rm -f "$(DESTDIR)$(sbindir)/$$f"; \
+ done
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+install-man8: $(man8_MANS) $(man_MANS)
+ @$(NORMAL_INSTALL)
+ test -z "$(man8dir)" || $(mkdir_p) "$(DESTDIR)$(man8dir)"
+ @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 8*) ;; \
+ *) ext='8' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst"; \
+ done
+uninstall-man8:
+ @$(NORMAL_UNINSTALL)
+ @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 8*) ;; \
+ *) ext='8' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f '$(DESTDIR)$(man8dir)/$$inst'"; \
+ rm -f "$(DESTDIR)$(man8dir)/$$inst"; \
+ done
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(SCRIPTS) $(MANS)
+installdirs:
+ for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man8dir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-libtool
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-man
+
+install-exec-am: install-sbinSCRIPTS
+
+install-info: install-info-am
+
+install-man: install-man8
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-man uninstall-sbinSCRIPTS
+
+uninstall-man: uninstall-man8
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ distclean distclean-generic distclean-libtool distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-exec install-exec-am \
+ install-info install-info-am install-man install-man8 \
+ install-sbinSCRIPTS install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am uninstall uninstall-am uninstall-info-am \
+ uninstall-man uninstall-man8 uninstall-sbinSCRIPTS
+
+
+ipsec : ipsec.in
+ sed \
+ -e "s:@IPSEC_VERSION@:$(PACKAGE_VERSION):" \
+ -e "s:@IPSEC_NAME@:$(PACKAGE_NAME):" \
+ -e "s:@IPSEC_DISTRO@::" \
+ -e "s:@IPSEC_DIR@:$(ipsecdir):" \
+ -e "s:@IPSEC_SBINDIR@:$(sbindir):" \
+ -e "s:@IPSEC_CONFDIR@:$(confdir):" \
+ -e "s:@IPSEC_PIDDIR@:$(piddir):" \
+ $< > $@
+ chmod +x $@
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/ipsec/ipsec.8 b/src/ipsec/ipsec.8
new file mode 100644
index 000000000..b37ac2c3a
--- /dev/null
+++ b/src/ipsec/ipsec.8
@@ -0,0 +1,342 @@
+.TH IPSEC 8 "9 February 2006"
+.\" RCSID $Id: ipsec.8,v 1.3 2006/02/09 19:47:38 as Exp $
+.SH NAME
+ipsec \- invoke IPsec utilities
+.SH SYNOPSIS
+.B ipsec
+command [ argument ...]
+.sp
+.B ipsec start|update|reload|restart|stop
+.sp
+.B ipsec up|down|route|unroute
+\fIconnectionname\fP
+.sp
+.B ipsec status|statusall
+[
+\fIconnectionname\fP
+]
+.sp
+.B ipsec listalgs|listpubkeys|listcerts
+[
+.B \-\-utc
+]
+.br
+.B ipsec listcacerts|listaacerts|listocspcerts
+[
+.B \-\-utc
+]
+.br
+.B ipsec listacerts|listgroups|listcainfos
+[
+.B \-\-utc
+]
+.br
+.B ipsec listcrls|listocsp|listcards|listall
+[
+.B \-\-utc
+]
+.sp
+.B ipsec rereadsecrets|rereadgroups
+.br
+.B ipsec rereadcacerts|rereadaacerts|rereadocspcerts
+.br
+.B ipsec rereadacerts|rereadcrls|rereadall
+.sp
+.B ipsec purgeocsp
+.sp
+.B ipsec
+[
+.B \-\-help
+] [
+.B \-\-version
+] [
+.B \-\-versioncode
+] [
+.B \-\-copyright
+]
+.br
+.B ipsec
+[
+.B \-\-directory
+] [
+.B \-\-confdir
+]
+.SH DESCRIPTION
+.I Ipsec
+invokes any of several utilities involved in controlling the IPsec
+encryption/authentication system,
+running the specified
+.I command
+with the specified
+.IR argument s
+as if it had been invoked directly.
+This largely eliminates possible name collisions with other software,
+and also permits some centralized services.
+.PP
+The commands
+.BR start ,
+.BR update ,
+.BR reload ,
+.BR restart ,
+and
+.BR stop
+are built-in and are used to control the
+.BR "ipsec starter"
+utility, an extremely fast replacement for the traditional
+.BR ipsec
+.BR setup
+script.
+.PP
+The commands
+.BR up,
+.BR down,
+.BR route,
+.BR unroute,
+.BR status,
+.BR statusall,
+.BR listalgs,
+.BR listpubkeys,
+.BR listcerts,
+.BR listcacerts,
+.BR listaacerts,
+.BR listocspcerts,
+.BR listacerts,
+.BR listgroups,
+.BR listcainfos,
+.BR listcrls,
+.BR listocsp,
+.BR listcards,
+.BR listall,
+.BR rereadsecrets,
+.BR rereadgroups,
+.BR rereadcacerts,
+.BR rereadaacerts,
+.BR rereadocspcerts,
+.BR rereadacerts,
+.BR rereadcrls,
+and
+.BR rereadall
+are also built-in and completely replace the corresponding
+.BR "ipsec auto"
+\-\-\fIoperation\fP"
+commands. Communication with the pluto daemon happens via the
+.BR "ipsec whack"
+socket interface.
+.PP
+In particular,
+.I ipsec
+supplies the invoked
+.I command
+with a suitable PATH environment variable,
+and also provides IPSEC_DIR,
+IPSEC_CONFS, and IPSEC_VERSION environment variables,
+containing respectively
+the full pathname of the directory where the IPsec utilities are stored,
+the full pathname of the directory where the configuration files live,
+and the IPsec version number.
+.PP
+.B "ipsec start"
+calls
+.BR "ipsec starter"
+which in turn starts \fIpluto\fR.
+.PP
+.B "ipsec update"
+sends a \fIHUP\fR signal to
+.BR "ipsec starter"
+which in turn determines any changes in \fIipsec.conf\fR
+and updates the configuration on the running \fIpluto\fR daemon, correspondingly.
+.PP
+.B "ipsec reload"
+sends a \fIUSR1\fR signal to
+.BR "ipsec starter"
+which in turn reloads the whole configuration on the running \fIpluto\fR daemon
+based on the actual \fIipsec.conf\fR.
+.PP
+.B "ipsec restart"
+executes
+.B "ipsec stop"
+followed by
+.BR "ipsec start".
+.PP
+.B "ipsec stop"
+stops \fIipsec\fR by sending a \fITERM\fR signal to
+.BR "ipsec starter".
+.PP
+.B "ipsec up"
+\fIname\fP tells the \fIpluto\fP daemon to start up connection \fIname\fP.
+.PP
+.B "ipsec down"
+\fIname\fP tells the \fIpluto\fP daemon to take down connection \fIname\fP.
+.PP
+.B "ipsec route"
+\fIname\fP tells the \fIpluto\fP daemon to install a route for connection
+\fIname\fP.
+.PP
+.B "ipsec unroute"
+\fIname\fP tells the \fIpluto\fP daemon to take down the route for connection
+\fIname\fP.
+.PP
+.B "ipsec status"
+[ \fIname\fP ] gives concise status information either on connection
+\fIname\fP or if the \fIname\fP argument is lacking, on all connections.
+.PP
+.B "ipsec statusall"
+[ \fIname\fP ] gives detailed status information either on connection
+\fIname\fP or if the \fIname\fP argument is lacking, on all connections.
+.PP
+.B "ipsec listalgs"
+returns a list all supported IKE encryption and hash algorithms, the available
+Diffie-Hellman groups, as well as all supported ESP encryption and authentication
+algorithms.
+.PP
+.B "ipsec listpubkeys"
+returns a list of RSA public keys that were either loaded in raw key format
+or extracted from X.509 and|or OpenPGP certificates.
+.PP
+.B "ipsec listcerts"
+returns a list of X.509 and|or OpenPGP certificates that were loaded locally
+by the \fIpluto\fP daemon.
+.PP
+.B "ipsec listcacerts"
+returns a list of X.509 Certification Authority (CA) certificates that were
+loaded locally by the \fIpluto\fP daemon from the \fI/etc/ipsec.d/cacerts/\fP
+directory or received in PKCS#7-wrapped certificate payloads via the IKE
+protocol.
+.PP
+.B "ipsec listaacerts"
+returns a list of X.509 Authorization Authority (AA) certificates that were
+loaded locally by the \fIpluto\fP daemon from the \fI/etc/ipsec.d/aacerts/\fP
+directory.
+.PP
+.B "ipsec listocspcerts"
+returns a list of X.509 OCSP Signer certificates that were either loaded
+locally by the \fIpluto\fP daemon from the \fI/etc/ipsec.d/ocspcerts/\fP
+directory or were sent by an OCSP server.
+.PP
+.B "ipsec listacerts"
+returns a list of X.509 Attribute certificates that were loaded locally by
+the \fIpluto\fP daemon from the \fI/etc/ipsec.d/acerts/\fP directory.
+.PP
+.B "ipsec listgroups"
+returns a list of groups that are used to define user authorization profiles.
+.PP
+.B "ipsec listcainfos"
+returns certification authority information (CRL distribution points, OCSP URIs,
+LDAP servers) that were defined by
+.BR ca
+sections in \fIipsec.conf\fP.
+.PP
+.B "ipsec listcrls"
+returns a list of Certificate Revocation Lists (CRLs).
+.PP
+.B "ipsec listocsp"
+returns revocation information fetched from OCSP servers.
+.PP
+.B "ipsec listcards"
+returns a list of certificates residing on smartcards.
+.PP
+.B "ipsec listall"
+returns all information generated by the list commands above. Each list command
+can be called with the
+\-\-url
+option which displays all dates in UTC instead of local time.
+.PP
+.B "ipsec rereadsecrets"
+flushes and rereads all secrets defined in \fIipsec.conf\fP.
+.PP
+.B "ipsec rereadcacerts"
+reads all certificate files contained in the \fI/etc/ipsec.d/cacerts\fP
+directory and adds them to \fIpluto\fP's list of Certification Authority (CA) certificates.
+.PP
+.B "ipsec rereadaacerts"
+reads all certificate files contained in the \fI/etc/ipsec.d/aacerts\fP
+directory and adds them to \fIpluto\fP's list of Authorization Authority (AA) certificates.
+.PP
+.B "ipsec rereadocspcerts"
+reads all certificate files contained in the \fI/etc/ipsec.d/ocspcerts/\fP
+directory and adds them to \fIpluto\fP's list of OCSP signer certificates.
+.PP
+.B "ipsec rereadacerts"
+operation reads all certificate files contained in the \fI/etc/ipsec.d/acerts/\fP
+directory and adds them to \fIpluto\fP's list of attribute certificates.
+.PP
+.B "ipsec rereadcrls"
+reads all Certificate Revocation Lists (CRLs) contained in the
+\fI/etc/ipsec.d/crls/\fP directory and adds them to \fIpluto\fP's list of CRLs.
+.PP
+.B "ipsec rereadall"
+is equivalent to the execution of \fBrereadsecrets\fP,
+\fBrereadcacerts\fP, \fBrereadaacerts\fP, \fBrereadocspcerts\fP,
+\fBrereadacerts\fP, and \fBrereadcrls\fP.
+.PP
+.B "ipsec \-\-help"
+lists the available commands.
+Most have their own manual pages, e.g.
+.IR ipsec_auto (8)
+for
+.IR auto .
+.PP
+.B "ipsec \-\-version"
+outputs version information about Linux strongSwan.
+A version code of the form ``U\fIxxx\fR/K\fIyyy\fR''
+indicates that the user-level utilities are version \fIxxx\fR
+but the kernel portion appears to be version \fIyyy\fR
+(this form is used only if the two disagree).
+.PP
+.B "ipsec \-\-versioncode"
+outputs \fIjust\fR the version code,
+with none of
+.BR \-\-version 's
+supporting information,
+for use by scripts.
+.PP
+.B "ipsec \-\-copyright"
+supplies boring copyright details.
+.PP
+.B "ipsec \-\-directory"
+reports where
+.I ipsec
+thinks the IPsec utilities are stored.
+.PP
+.B "ipsec \-\-confdir"
+reports where
+.I ipsec
+thinks the IPsec configuration files are stored.
+.SH FILES
+/usr/local/lib/ipsec usual utilities directory
+.SH ENVIRONMENT
+.PP
+The following environment variables control where strongSwan finds its
+components.
+The
+.B ipsec
+command sets them if they are not already set.
+.nf
+.na
+
+IPSEC_DIR directory containing ipsec programs and utilities
+IPSEC_SBINDIR directory containing \fBipsec\fP command
+IPSEC_CONFDIR directory containing configuration files
+IPSEC_PIDDIR directory containing PID files
+IPSEC_NAME name of ipsec distribution
+IPSEC_VERSION version numer of ipsec userland and kernel
+IPSEC_STARTER_PID PID file for ipsec starter
+IPSEC_PLUTO_PID PID file for IKEv1 keying daemon
+IPSEC_CHARON_PID PID file for IKEv2 keying daemon
+.ad
+.fi
+.SH SEE ALSO
+.hy 0
+.na
+ipsec.conf(5), ipsec.secrets(5),
+ipsec_barf(8),
+.ad
+.hy
+.PP
+.SH HISTORY
+Written for Linux FreeS/WAN
+<http://www.freeswan.org>
+by Henry Spencer.
+Updated and extended for Linux strongSwan
+<http://www.strongswan.org>
+by Andreas Steffen.
diff --git a/src/ipsec/ipsec.in b/src/ipsec/ipsec.in
new file mode 100755
index 000000000..bd74b6f16
--- /dev/null
+++ b/src/ipsec/ipsec.in
@@ -0,0 +1,294 @@
+#! /bin/sh
+# prefix command to run stuff from our programs directory
+# Copyright (C) 1998-2002 Henry Spencer.
+# Copyright (C) 2006 Andreas Steffen
+# Copyright (C) 2006 Martin Willi
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT 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: ipsec.in,v 1.13 2006/03/09 20:09:33 as Exp $
+
+# name and version of the ipsec implementation
+IPSEC_NAME="@IPSEC_NAME@"
+IPSEC_VERSION="U@IPSEC_VERSION@/K`uname -r`"
+
+# where the private directory and the config files are
+IPSEC_DIR="@IPSEC_DIR@"
+IPSEC_SBINDIR="@IPSEC_SBINDIR@"
+IPSEC_CONFDIR="@IPSEC_CONFDIR@"
+IPSEC_PIDDIR="@IPSEC_PIDDIR@"
+
+IPSEC_STARTER_PID="${IPSEC_PIDDIR}/starter.pid"
+IPSEC_PLUTO_PID="${IPSEC_PIDDIR}/pluto.pid"
+IPSEC_CHARON_PID="${IPSEC_PIDDIR}/charon.pid"
+
+IPSEC_WHACK="${IPSEC_DIR}/whack"
+IPSEC_STROKE="${IPSEC_DIR}/stroke"
+IPSEC_STARTER="${IPSEC_DIR}/starter"
+
+export IPSEC_DIR IPSEC_SBINDIR IPSEC_CONFDIR IPSEC_PIDDIR IPSEC_VERSION IPSEC_NAME IPSEC_STARTER_PID IPSEC_PLUTO_PID IPSEC_CHARON_PID
+
+IPSEC_DISTRO="Institute for Internet Technologies and Applications\n
+ University of Applied Sciences Rapperswil, Switzerland"
+
+case "$1" in
+'')
+ echo "Usage: ipsec command argument ..."
+ echo "Use --help for list of commands, or see ipsec(8) manual page"
+ echo "or the $IPSEC_NAME documentation for names of the common ones."
+ echo "Most have their own manual pages, e.g. ipsec_auto(8)."
+ echo "See <http://www.strongswan.org> for more general info."
+ exit 0
+ ;;
+--help)
+ echo "Usage: ipsec command argument ..."
+ echo "where command is one of:"
+ echo " start|restart arguments..."
+ echo " update|reload|stop"
+ echo " up|down|route|unroute <connectionname>"
+ echo " status|statusall [<connectionname>]"
+ echo " ready"
+ echo " listalgs|listpubkeys|listcerts [--utc]"
+ echo " listcacerts|listaacerts|listocspcerts [--utc]"
+ echo " listacerts|listgroups|listcainfos [--utc]"
+ echo " listcrls|listocsp|listcards|listall [--utc]"
+ echo " rereadsecrets|rereadgroups"
+ echo " rereadcacerts|rereadaacerts|rereadocspcerts"
+ echo " rereadacerts|rereadcrls|rereadall"
+ echo " purgeocsp"
+ echo " scencrypt|scdecrypt <value> [--inbase <base>] [--outbase <base>] [--keyid <id>]"
+ echo " barf"
+ echo " openac"
+ echo " pluto"
+ echo " scepclient"
+ echo " secrets"
+ echo " starter"
+ echo " version"
+ echo " whack"
+ echo " stoke"
+ echo
+ echo "Some of these functions have their own manual pages, e.g. ipsec_scepclient(8)."
+ exit 0
+ ;;
+--versioncode)
+ echo "$IPSEC_VERSION"
+ exit 0
+ ;;
+--copyright)
+ set _copyright
+ # and fall through, invoking "ipsec _copyright"
+ ;;
+--directory)
+ echo "$IPSEC_DIR"
+ exit 0
+ ;;
+--confdir)
+ echo "$IPSEC_CONFDIR"
+ exit 0
+ ;;
+down)
+ shift
+ if [ "$#" -ne 1 ]
+ then
+ echo "Usage: ipsec down <connection name>"
+ exit 1
+ fi
+ if test -e $IPSEC_PLUTO_PID
+ then
+ $IPSEC_WHACK --name "$1" --terminate
+ fi
+ if test -e $IPSEC_CHARON_PID
+ then
+ $IPSEC_STROKE down "$1"
+ fi
+ exit 0
+ ;;
+listalgs|listpubkeys|listaacerts|\
+listacerts|listgroups|\listcards|\
+rereadsecrets|rereadgroups|\
+rereadaacerts|rereadacerts)
+ op="$1"
+ shift
+ if test -e $IPSEC_PLUTO_PID
+ then
+ $IPSEC_WHACK "$@" "--$op"
+ fi
+ exit 0
+ ;;
+listcerts|listcacerts|listocspcerts|\
+listcainfos|listcrls|listocsp|listall|\
+rereadcacerts|rereadocspcerts|rereadcrls|\
+rereadall|purgeocsp)
+ op="$1"
+ shift
+ if test -e $IPSEC_PLUTO_PID
+ then
+ $IPSEC_WHACK "$@" "--$op"
+ fi
+ if test -e $IPSEC_CHARON_PID
+ then
+ $IPSEC_STROKE "$op" "$@"
+ fi
+ exit 0
+ ;;
+ready)
+ shift
+ if test -e $IPSEC_PLUTO_PID
+ then
+ $IPSEC_WHACK --listen
+ fi
+ exit 0
+ ;;
+reload)
+ if test -e $IPSEC_STARTER_PID
+ then
+ echo "Reloading strongSwan IPsec configuration..." >&2
+ kill -s USR1 `cat $IPSEC_STARTER_PID`
+ else
+ echo "ipsec starter is not running" >&2
+ fi
+ exit 0
+ ;;
+restart)
+ $IPSEC_SBINDIR/ipsec stop
+ sleep 2
+ shift
+ $IPSEC_SBINDIR/ipsec start "$@"
+ exit 0
+ ;;
+route|unroute)
+ op="$1"
+ shift
+ if [ "$#" -ne 1 ]
+ then
+ echo "Usage: ipsec $op <connection name>"
+ exit 1
+ fi
+ if test -e $IPSEC_PLUTO_PID
+ then
+ $IPSEC_WHACK --name "$1" "--$op"
+ fi
+ if test -e $IPSEC_CHARON_PID
+ then
+ $IPSEC_STROKE "$op" "$1"
+ fi
+ exit 0
+ ;;
+scencrypt|scdecrypt)
+ op="$1"
+ shift
+ if test -e $IPSEC_PLUTO_PID
+ then
+ $IPSEC_WHACK "--$op" "$@"
+ fi
+ exit 0
+ ;;
+secrets)
+ if test -e $IPSEC_PLUTO_PID
+ then
+ $IPSEC_WHACK --rereadsecrets
+ fi
+ exit 0
+ ;;
+start)
+ shift
+ exec $IPSEC_STARTER "$@"
+ ;;
+status|statusall)
+ op="$1"
+ shift
+ if test $# -eq 0
+ then
+ if test -e $IPSEC_PLUTO_PID
+ then
+ $IPSEC_WHACK "--$op"
+ fi
+ if test -e $IPSEC_CHARON_PID
+ then
+ $IPSEC_STROKE "$op"
+ fi
+ else
+ if test -e $IPSEC_PLUTO_PID
+ then
+ $IPSEC_WHACK --name "$1" "--$op"
+ fi
+ if test -e $IPSEC_CHARON_PID
+ then
+ $IPSEC_STROKE "$op" "$1"
+ fi
+ fi
+ exit 0
+ ;;
+stop)
+ if test -e $IPSEC_STARTER_PID
+ then
+ echo "Stopping strongSwan IPsec..." >&2
+ kill `cat $IPSEC_STARTER_PID`
+ else
+ echo "ipsec starter is not running" >&2
+ fi
+ exit 0
+ ;;
+up)
+ shift
+ if [ "$#" -ne 1 ]
+ then
+ echo "Usage: ipsec up <connection name>"
+ exit 1
+ fi
+ if test -e $IPSEC_PLUTO_PID
+ then
+ $IPSEC_WHACK --name "$1" --initiate
+ fi
+ if test -e $IPSEC_CHARON_PID
+ then
+ $IPSEC_STROKE up "$1"
+ fi
+ exit 0
+ ;;
+update)
+ if test -e $IPSEC_STARTER_PID
+ then
+ echo "Updating strongSwan IPsec configuration..." >&2
+ kill -s HUP `cat $IPSEC_STARTER_PID`
+ else
+ echo "ipsec starter is not running" >&2
+ fi
+ exit 0
+ ;;
+version|--version)
+ echo "Linux $IPSEC_NAME $IPSEC_VERSION"
+ echo "See \`ipsec --copyright' for copyright information."
+ echo $IPSEC_DISTRO
+ exit 0
+ ;;
+--*)
+ echo "$0: unknown option \`$1' (perhaps command name was omitted?)" >&2
+ exit 1
+ ;;
+esac
+
+cmd="$1"
+shift
+
+path="$IPSEC_DIR/$cmd"
+
+if test ! -x "$path"
+then
+ path="$IPSEC_DIR/$cmd"
+ if test ! -x "$path"
+ then
+ echo "$0: unknown IPsec command \`$cmd' (\`ipsec --help' for list)" >&2
+ exit 1
+ fi
+fi
+
+exec $path "$@"
diff --git a/src/libcrypto/Makefile.am b/src/libcrypto/Makefile.am
new file mode 100644
index 000000000..23066033d
--- /dev/null
+++ b/src/libcrypto/Makefile.am
@@ -0,0 +1,11 @@
+noinst_LIBRARIES = libcrypto.a
+libcrypto_a_SOURCES = \
+libaes/aes_xcbc_mac.c libaes/aes_cbc.c libaes/aes_xcbc_mac.h libaes/aes_cbc.h libaes/aes.c libaes/aes.h \
+include/md32_common.h include/cbc_generic.h include/hmac_generic.h libblowfish/bf_skey.c libblowfish/blowfish.h \
+libblowfish/bf_pi.h libblowfish/bf_locl.h libblowfish/bf_enc.c libsha2/hmac_sha2.c libsha2/sha2.h libsha2/hmac_sha2.h \
+libsha2/sha2.c libserpent/serpent_cbc.c libserpent/serpent_cbc.h libserpent/serpent.c libserpent/serpent.h \
+libtwofish/twofish_cbc.h libtwofish/twofish_cbc.c libtwofish/twofish.c libtwofish/twofish.h libdes/des_enc.c \
+libdes/podd.h libdes/sk.h libdes/set_key.c libdes/speed.c libdes/fcrypt_b.c libdes/fcrypt.c libdes/destest.c \
+libdes/spr.h libdes/cbc_enc.c libdes/ecb_enc.c libdes/des_opts.c libdes/des_locl.h libdes/des_ver.h libdes/des.h
+
+INCLUDES = -I$(top_srcdir)/src/libcrypto/include
diff --git a/src/libcrypto/Makefile.in b/src/libcrypto/Makefile.in
new file mode 100644
index 000000000..63b7d4907
--- /dev/null
+++ b/src/libcrypto/Makefile.in
@@ -0,0 +1,761 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/libcrypto
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+ARFLAGS = cru
+libcrypto_a_AR = $(AR) $(ARFLAGS)
+libcrypto_a_LIBADD =
+am_libcrypto_a_OBJECTS = aes_xcbc_mac.$(OBJEXT) aes_cbc.$(OBJEXT) \
+ aes.$(OBJEXT) bf_skey.$(OBJEXT) bf_enc.$(OBJEXT) \
+ hmac_sha2.$(OBJEXT) sha2.$(OBJEXT) serpent_cbc.$(OBJEXT) \
+ serpent.$(OBJEXT) twofish_cbc.$(OBJEXT) twofish.$(OBJEXT) \
+ des_enc.$(OBJEXT) set_key.$(OBJEXT) speed.$(OBJEXT) \
+ fcrypt_b.$(OBJEXT) fcrypt.$(OBJEXT) destest.$(OBJEXT) \
+ cbc_enc.$(OBJEXT) ecb_enc.$(OBJEXT) des_opts.$(OBJEXT)
+libcrypto_a_OBJECTS = $(am_libcrypto_a_OBJECTS)
+DEFAULT_INCLUDES = -I. -I$(srcdir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libcrypto_a_SOURCES)
+DIST_SOURCES = $(libcrypto_a_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_EAP_SIM_FALSE = @BUILD_EAP_SIM_FALSE@
+BUILD_EAP_SIM_TRUE = @BUILD_EAP_SIM_TRUE@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GPERF = @GPERF@
+GREP = @GREP@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+USE_CISCO_QUIRKS_FALSE = @USE_CISCO_QUIRKS_FALSE@
+USE_CISCO_QUIRKS_TRUE = @USE_CISCO_QUIRKS_TRUE@
+USE_LEAK_DETECTIVE_FALSE = @USE_LEAK_DETECTIVE_FALSE@
+USE_LEAK_DETECTIVE_TRUE = @USE_LEAK_DETECTIVE_TRUE@
+USE_LIBCURL_FALSE = @USE_LIBCURL_FALSE@
+USE_LIBCURL_TRUE = @USE_LIBCURL_TRUE@
+USE_LIBLDAP_FALSE = @USE_LIBLDAP_FALSE@
+USE_LIBLDAP_TRUE = @USE_LIBLDAP_TRUE@
+USE_NAT_TRANSPORT_FALSE = @USE_NAT_TRANSPORT_FALSE@
+USE_NAT_TRANSPORT_TRUE = @USE_NAT_TRANSPORT_TRUE@
+USE_SMARTCARD_FALSE = @USE_SMARTCARD_FALSE@
+USE_SMARTCARD_TRUE = @USE_SMARTCARD_TRUE@
+USE_VENDORID_FALSE = @USE_VENDORID_FALSE@
+USE_VENDORID_TRUE = @USE_VENDORID_TRUE@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+confdir = @confdir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+eapdir = @eapdir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+ipsecdir = @ipsecdir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+piddir = @piddir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+noinst_LIBRARIES = libcrypto.a
+libcrypto_a_SOURCES = \
+libaes/aes_xcbc_mac.c libaes/aes_cbc.c libaes/aes_xcbc_mac.h libaes/aes_cbc.h libaes/aes.c libaes/aes.h \
+include/md32_common.h include/cbc_generic.h include/hmac_generic.h libblowfish/bf_skey.c libblowfish/blowfish.h \
+libblowfish/bf_pi.h libblowfish/bf_locl.h libblowfish/bf_enc.c libsha2/hmac_sha2.c libsha2/sha2.h libsha2/hmac_sha2.h \
+libsha2/sha2.c libserpent/serpent_cbc.c libserpent/serpent_cbc.h libserpent/serpent.c libserpent/serpent.h \
+libtwofish/twofish_cbc.h libtwofish/twofish_cbc.c libtwofish/twofish.c libtwofish/twofish.h libdes/des_enc.c \
+libdes/podd.h libdes/sk.h libdes/set_key.c libdes/speed.c libdes/fcrypt_b.c libdes/fcrypt.c libdes/destest.c \
+libdes/spr.h libdes/cbc_enc.c libdes/ecb_enc.c libdes/des_opts.c libdes/des_locl.h libdes/des_ver.h libdes/des.h
+
+INCLUDES = -I$(top_srcdir)/src/libcrypto/include
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libcrypto/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/libcrypto/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+libcrypto.a: $(libcrypto_a_OBJECTS) $(libcrypto_a_DEPENDENCIES)
+ -rm -f libcrypto.a
+ $(libcrypto_a_AR) libcrypto.a $(libcrypto_a_OBJECTS) $(libcrypto_a_LIBADD)
+ $(RANLIB) libcrypto.a
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aes.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aes_cbc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aes_xcbc_mac.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bf_enc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bf_skey.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cbc_enc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/des_enc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/des_opts.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/destest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ecb_enc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fcrypt.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fcrypt_b.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hmac_sha2.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/serpent.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/serpent_cbc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/set_key.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha2.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/speed.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/twofish.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/twofish_cbc.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+aes_xcbc_mac.o: libaes/aes_xcbc_mac.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT aes_xcbc_mac.o -MD -MP -MF "$(DEPDIR)/aes_xcbc_mac.Tpo" -c -o aes_xcbc_mac.o `test -f 'libaes/aes_xcbc_mac.c' || echo '$(srcdir)/'`libaes/aes_xcbc_mac.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/aes_xcbc_mac.Tpo" "$(DEPDIR)/aes_xcbc_mac.Po"; else rm -f "$(DEPDIR)/aes_xcbc_mac.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libaes/aes_xcbc_mac.c' object='aes_xcbc_mac.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o aes_xcbc_mac.o `test -f 'libaes/aes_xcbc_mac.c' || echo '$(srcdir)/'`libaes/aes_xcbc_mac.c
+
+aes_xcbc_mac.obj: libaes/aes_xcbc_mac.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT aes_xcbc_mac.obj -MD -MP -MF "$(DEPDIR)/aes_xcbc_mac.Tpo" -c -o aes_xcbc_mac.obj `if test -f 'libaes/aes_xcbc_mac.c'; then $(CYGPATH_W) 'libaes/aes_xcbc_mac.c'; else $(CYGPATH_W) '$(srcdir)/libaes/aes_xcbc_mac.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/aes_xcbc_mac.Tpo" "$(DEPDIR)/aes_xcbc_mac.Po"; else rm -f "$(DEPDIR)/aes_xcbc_mac.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libaes/aes_xcbc_mac.c' object='aes_xcbc_mac.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o aes_xcbc_mac.obj `if test -f 'libaes/aes_xcbc_mac.c'; then $(CYGPATH_W) 'libaes/aes_xcbc_mac.c'; else $(CYGPATH_W) '$(srcdir)/libaes/aes_xcbc_mac.c'; fi`
+
+aes_cbc.o: libaes/aes_cbc.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT aes_cbc.o -MD -MP -MF "$(DEPDIR)/aes_cbc.Tpo" -c -o aes_cbc.o `test -f 'libaes/aes_cbc.c' || echo '$(srcdir)/'`libaes/aes_cbc.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/aes_cbc.Tpo" "$(DEPDIR)/aes_cbc.Po"; else rm -f "$(DEPDIR)/aes_cbc.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libaes/aes_cbc.c' object='aes_cbc.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o aes_cbc.o `test -f 'libaes/aes_cbc.c' || echo '$(srcdir)/'`libaes/aes_cbc.c
+
+aes_cbc.obj: libaes/aes_cbc.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT aes_cbc.obj -MD -MP -MF "$(DEPDIR)/aes_cbc.Tpo" -c -o aes_cbc.obj `if test -f 'libaes/aes_cbc.c'; then $(CYGPATH_W) 'libaes/aes_cbc.c'; else $(CYGPATH_W) '$(srcdir)/libaes/aes_cbc.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/aes_cbc.Tpo" "$(DEPDIR)/aes_cbc.Po"; else rm -f "$(DEPDIR)/aes_cbc.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libaes/aes_cbc.c' object='aes_cbc.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o aes_cbc.obj `if test -f 'libaes/aes_cbc.c'; then $(CYGPATH_W) 'libaes/aes_cbc.c'; else $(CYGPATH_W) '$(srcdir)/libaes/aes_cbc.c'; fi`
+
+aes.o: libaes/aes.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT aes.o -MD -MP -MF "$(DEPDIR)/aes.Tpo" -c -o aes.o `test -f 'libaes/aes.c' || echo '$(srcdir)/'`libaes/aes.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/aes.Tpo" "$(DEPDIR)/aes.Po"; else rm -f "$(DEPDIR)/aes.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libaes/aes.c' object='aes.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o aes.o `test -f 'libaes/aes.c' || echo '$(srcdir)/'`libaes/aes.c
+
+aes.obj: libaes/aes.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT aes.obj -MD -MP -MF "$(DEPDIR)/aes.Tpo" -c -o aes.obj `if test -f 'libaes/aes.c'; then $(CYGPATH_W) 'libaes/aes.c'; else $(CYGPATH_W) '$(srcdir)/libaes/aes.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/aes.Tpo" "$(DEPDIR)/aes.Po"; else rm -f "$(DEPDIR)/aes.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libaes/aes.c' object='aes.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o aes.obj `if test -f 'libaes/aes.c'; then $(CYGPATH_W) 'libaes/aes.c'; else $(CYGPATH_W) '$(srcdir)/libaes/aes.c'; fi`
+
+bf_skey.o: libblowfish/bf_skey.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT bf_skey.o -MD -MP -MF "$(DEPDIR)/bf_skey.Tpo" -c -o bf_skey.o `test -f 'libblowfish/bf_skey.c' || echo '$(srcdir)/'`libblowfish/bf_skey.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/bf_skey.Tpo" "$(DEPDIR)/bf_skey.Po"; else rm -f "$(DEPDIR)/bf_skey.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libblowfish/bf_skey.c' object='bf_skey.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o bf_skey.o `test -f 'libblowfish/bf_skey.c' || echo '$(srcdir)/'`libblowfish/bf_skey.c
+
+bf_skey.obj: libblowfish/bf_skey.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT bf_skey.obj -MD -MP -MF "$(DEPDIR)/bf_skey.Tpo" -c -o bf_skey.obj `if test -f 'libblowfish/bf_skey.c'; then $(CYGPATH_W) 'libblowfish/bf_skey.c'; else $(CYGPATH_W) '$(srcdir)/libblowfish/bf_skey.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/bf_skey.Tpo" "$(DEPDIR)/bf_skey.Po"; else rm -f "$(DEPDIR)/bf_skey.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libblowfish/bf_skey.c' object='bf_skey.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o bf_skey.obj `if test -f 'libblowfish/bf_skey.c'; then $(CYGPATH_W) 'libblowfish/bf_skey.c'; else $(CYGPATH_W) '$(srcdir)/libblowfish/bf_skey.c'; fi`
+
+bf_enc.o: libblowfish/bf_enc.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT bf_enc.o -MD -MP -MF "$(DEPDIR)/bf_enc.Tpo" -c -o bf_enc.o `test -f 'libblowfish/bf_enc.c' || echo '$(srcdir)/'`libblowfish/bf_enc.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/bf_enc.Tpo" "$(DEPDIR)/bf_enc.Po"; else rm -f "$(DEPDIR)/bf_enc.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libblowfish/bf_enc.c' object='bf_enc.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o bf_enc.o `test -f 'libblowfish/bf_enc.c' || echo '$(srcdir)/'`libblowfish/bf_enc.c
+
+bf_enc.obj: libblowfish/bf_enc.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT bf_enc.obj -MD -MP -MF "$(DEPDIR)/bf_enc.Tpo" -c -o bf_enc.obj `if test -f 'libblowfish/bf_enc.c'; then $(CYGPATH_W) 'libblowfish/bf_enc.c'; else $(CYGPATH_W) '$(srcdir)/libblowfish/bf_enc.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/bf_enc.Tpo" "$(DEPDIR)/bf_enc.Po"; else rm -f "$(DEPDIR)/bf_enc.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libblowfish/bf_enc.c' object='bf_enc.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o bf_enc.obj `if test -f 'libblowfish/bf_enc.c'; then $(CYGPATH_W) 'libblowfish/bf_enc.c'; else $(CYGPATH_W) '$(srcdir)/libblowfish/bf_enc.c'; fi`
+
+hmac_sha2.o: libsha2/hmac_sha2.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT hmac_sha2.o -MD -MP -MF "$(DEPDIR)/hmac_sha2.Tpo" -c -o hmac_sha2.o `test -f 'libsha2/hmac_sha2.c' || echo '$(srcdir)/'`libsha2/hmac_sha2.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/hmac_sha2.Tpo" "$(DEPDIR)/hmac_sha2.Po"; else rm -f "$(DEPDIR)/hmac_sha2.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libsha2/hmac_sha2.c' object='hmac_sha2.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o hmac_sha2.o `test -f 'libsha2/hmac_sha2.c' || echo '$(srcdir)/'`libsha2/hmac_sha2.c
+
+hmac_sha2.obj: libsha2/hmac_sha2.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT hmac_sha2.obj -MD -MP -MF "$(DEPDIR)/hmac_sha2.Tpo" -c -o hmac_sha2.obj `if test -f 'libsha2/hmac_sha2.c'; then $(CYGPATH_W) 'libsha2/hmac_sha2.c'; else $(CYGPATH_W) '$(srcdir)/libsha2/hmac_sha2.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/hmac_sha2.Tpo" "$(DEPDIR)/hmac_sha2.Po"; else rm -f "$(DEPDIR)/hmac_sha2.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libsha2/hmac_sha2.c' object='hmac_sha2.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o hmac_sha2.obj `if test -f 'libsha2/hmac_sha2.c'; then $(CYGPATH_W) 'libsha2/hmac_sha2.c'; else $(CYGPATH_W) '$(srcdir)/libsha2/hmac_sha2.c'; fi`
+
+sha2.o: libsha2/sha2.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sha2.o -MD -MP -MF "$(DEPDIR)/sha2.Tpo" -c -o sha2.o `test -f 'libsha2/sha2.c' || echo '$(srcdir)/'`libsha2/sha2.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/sha2.Tpo" "$(DEPDIR)/sha2.Po"; else rm -f "$(DEPDIR)/sha2.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libsha2/sha2.c' object='sha2.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sha2.o `test -f 'libsha2/sha2.c' || echo '$(srcdir)/'`libsha2/sha2.c
+
+sha2.obj: libsha2/sha2.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sha2.obj -MD -MP -MF "$(DEPDIR)/sha2.Tpo" -c -o sha2.obj `if test -f 'libsha2/sha2.c'; then $(CYGPATH_W) 'libsha2/sha2.c'; else $(CYGPATH_W) '$(srcdir)/libsha2/sha2.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/sha2.Tpo" "$(DEPDIR)/sha2.Po"; else rm -f "$(DEPDIR)/sha2.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libsha2/sha2.c' object='sha2.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sha2.obj `if test -f 'libsha2/sha2.c'; then $(CYGPATH_W) 'libsha2/sha2.c'; else $(CYGPATH_W) '$(srcdir)/libsha2/sha2.c'; fi`
+
+serpent_cbc.o: libserpent/serpent_cbc.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT serpent_cbc.o -MD -MP -MF "$(DEPDIR)/serpent_cbc.Tpo" -c -o serpent_cbc.o `test -f 'libserpent/serpent_cbc.c' || echo '$(srcdir)/'`libserpent/serpent_cbc.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/serpent_cbc.Tpo" "$(DEPDIR)/serpent_cbc.Po"; else rm -f "$(DEPDIR)/serpent_cbc.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libserpent/serpent_cbc.c' object='serpent_cbc.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o serpent_cbc.o `test -f 'libserpent/serpent_cbc.c' || echo '$(srcdir)/'`libserpent/serpent_cbc.c
+
+serpent_cbc.obj: libserpent/serpent_cbc.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT serpent_cbc.obj -MD -MP -MF "$(DEPDIR)/serpent_cbc.Tpo" -c -o serpent_cbc.obj `if test -f 'libserpent/serpent_cbc.c'; then $(CYGPATH_W) 'libserpent/serpent_cbc.c'; else $(CYGPATH_W) '$(srcdir)/libserpent/serpent_cbc.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/serpent_cbc.Tpo" "$(DEPDIR)/serpent_cbc.Po"; else rm -f "$(DEPDIR)/serpent_cbc.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libserpent/serpent_cbc.c' object='serpent_cbc.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o serpent_cbc.obj `if test -f 'libserpent/serpent_cbc.c'; then $(CYGPATH_W) 'libserpent/serpent_cbc.c'; else $(CYGPATH_W) '$(srcdir)/libserpent/serpent_cbc.c'; fi`
+
+serpent.o: libserpent/serpent.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT serpent.o -MD -MP -MF "$(DEPDIR)/serpent.Tpo" -c -o serpent.o `test -f 'libserpent/serpent.c' || echo '$(srcdir)/'`libserpent/serpent.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/serpent.Tpo" "$(DEPDIR)/serpent.Po"; else rm -f "$(DEPDIR)/serpent.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libserpent/serpent.c' object='serpent.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o serpent.o `test -f 'libserpent/serpent.c' || echo '$(srcdir)/'`libserpent/serpent.c
+
+serpent.obj: libserpent/serpent.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT serpent.obj -MD -MP -MF "$(DEPDIR)/serpent.Tpo" -c -o serpent.obj `if test -f 'libserpent/serpent.c'; then $(CYGPATH_W) 'libserpent/serpent.c'; else $(CYGPATH_W) '$(srcdir)/libserpent/serpent.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/serpent.Tpo" "$(DEPDIR)/serpent.Po"; else rm -f "$(DEPDIR)/serpent.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libserpent/serpent.c' object='serpent.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o serpent.obj `if test -f 'libserpent/serpent.c'; then $(CYGPATH_W) 'libserpent/serpent.c'; else $(CYGPATH_W) '$(srcdir)/libserpent/serpent.c'; fi`
+
+twofish_cbc.o: libtwofish/twofish_cbc.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT twofish_cbc.o -MD -MP -MF "$(DEPDIR)/twofish_cbc.Tpo" -c -o twofish_cbc.o `test -f 'libtwofish/twofish_cbc.c' || echo '$(srcdir)/'`libtwofish/twofish_cbc.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/twofish_cbc.Tpo" "$(DEPDIR)/twofish_cbc.Po"; else rm -f "$(DEPDIR)/twofish_cbc.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libtwofish/twofish_cbc.c' object='twofish_cbc.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o twofish_cbc.o `test -f 'libtwofish/twofish_cbc.c' || echo '$(srcdir)/'`libtwofish/twofish_cbc.c
+
+twofish_cbc.obj: libtwofish/twofish_cbc.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT twofish_cbc.obj -MD -MP -MF "$(DEPDIR)/twofish_cbc.Tpo" -c -o twofish_cbc.obj `if test -f 'libtwofish/twofish_cbc.c'; then $(CYGPATH_W) 'libtwofish/twofish_cbc.c'; else $(CYGPATH_W) '$(srcdir)/libtwofish/twofish_cbc.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/twofish_cbc.Tpo" "$(DEPDIR)/twofish_cbc.Po"; else rm -f "$(DEPDIR)/twofish_cbc.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libtwofish/twofish_cbc.c' object='twofish_cbc.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o twofish_cbc.obj `if test -f 'libtwofish/twofish_cbc.c'; then $(CYGPATH_W) 'libtwofish/twofish_cbc.c'; else $(CYGPATH_W) '$(srcdir)/libtwofish/twofish_cbc.c'; fi`
+
+twofish.o: libtwofish/twofish.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT twofish.o -MD -MP -MF "$(DEPDIR)/twofish.Tpo" -c -o twofish.o `test -f 'libtwofish/twofish.c' || echo '$(srcdir)/'`libtwofish/twofish.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/twofish.Tpo" "$(DEPDIR)/twofish.Po"; else rm -f "$(DEPDIR)/twofish.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libtwofish/twofish.c' object='twofish.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o twofish.o `test -f 'libtwofish/twofish.c' || echo '$(srcdir)/'`libtwofish/twofish.c
+
+twofish.obj: libtwofish/twofish.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT twofish.obj -MD -MP -MF "$(DEPDIR)/twofish.Tpo" -c -o twofish.obj `if test -f 'libtwofish/twofish.c'; then $(CYGPATH_W) 'libtwofish/twofish.c'; else $(CYGPATH_W) '$(srcdir)/libtwofish/twofish.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/twofish.Tpo" "$(DEPDIR)/twofish.Po"; else rm -f "$(DEPDIR)/twofish.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libtwofish/twofish.c' object='twofish.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o twofish.obj `if test -f 'libtwofish/twofish.c'; then $(CYGPATH_W) 'libtwofish/twofish.c'; else $(CYGPATH_W) '$(srcdir)/libtwofish/twofish.c'; fi`
+
+des_enc.o: libdes/des_enc.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT des_enc.o -MD -MP -MF "$(DEPDIR)/des_enc.Tpo" -c -o des_enc.o `test -f 'libdes/des_enc.c' || echo '$(srcdir)/'`libdes/des_enc.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/des_enc.Tpo" "$(DEPDIR)/des_enc.Po"; else rm -f "$(DEPDIR)/des_enc.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libdes/des_enc.c' object='des_enc.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o des_enc.o `test -f 'libdes/des_enc.c' || echo '$(srcdir)/'`libdes/des_enc.c
+
+des_enc.obj: libdes/des_enc.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT des_enc.obj -MD -MP -MF "$(DEPDIR)/des_enc.Tpo" -c -o des_enc.obj `if test -f 'libdes/des_enc.c'; then $(CYGPATH_W) 'libdes/des_enc.c'; else $(CYGPATH_W) '$(srcdir)/libdes/des_enc.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/des_enc.Tpo" "$(DEPDIR)/des_enc.Po"; else rm -f "$(DEPDIR)/des_enc.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libdes/des_enc.c' object='des_enc.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o des_enc.obj `if test -f 'libdes/des_enc.c'; then $(CYGPATH_W) 'libdes/des_enc.c'; else $(CYGPATH_W) '$(srcdir)/libdes/des_enc.c'; fi`
+
+set_key.o: libdes/set_key.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT set_key.o -MD -MP -MF "$(DEPDIR)/set_key.Tpo" -c -o set_key.o `test -f 'libdes/set_key.c' || echo '$(srcdir)/'`libdes/set_key.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/set_key.Tpo" "$(DEPDIR)/set_key.Po"; else rm -f "$(DEPDIR)/set_key.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libdes/set_key.c' object='set_key.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o set_key.o `test -f 'libdes/set_key.c' || echo '$(srcdir)/'`libdes/set_key.c
+
+set_key.obj: libdes/set_key.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT set_key.obj -MD -MP -MF "$(DEPDIR)/set_key.Tpo" -c -o set_key.obj `if test -f 'libdes/set_key.c'; then $(CYGPATH_W) 'libdes/set_key.c'; else $(CYGPATH_W) '$(srcdir)/libdes/set_key.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/set_key.Tpo" "$(DEPDIR)/set_key.Po"; else rm -f "$(DEPDIR)/set_key.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libdes/set_key.c' object='set_key.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o set_key.obj `if test -f 'libdes/set_key.c'; then $(CYGPATH_W) 'libdes/set_key.c'; else $(CYGPATH_W) '$(srcdir)/libdes/set_key.c'; fi`
+
+speed.o: libdes/speed.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT speed.o -MD -MP -MF "$(DEPDIR)/speed.Tpo" -c -o speed.o `test -f 'libdes/speed.c' || echo '$(srcdir)/'`libdes/speed.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/speed.Tpo" "$(DEPDIR)/speed.Po"; else rm -f "$(DEPDIR)/speed.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libdes/speed.c' object='speed.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o speed.o `test -f 'libdes/speed.c' || echo '$(srcdir)/'`libdes/speed.c
+
+speed.obj: libdes/speed.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT speed.obj -MD -MP -MF "$(DEPDIR)/speed.Tpo" -c -o speed.obj `if test -f 'libdes/speed.c'; then $(CYGPATH_W) 'libdes/speed.c'; else $(CYGPATH_W) '$(srcdir)/libdes/speed.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/speed.Tpo" "$(DEPDIR)/speed.Po"; else rm -f "$(DEPDIR)/speed.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libdes/speed.c' object='speed.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o speed.obj `if test -f 'libdes/speed.c'; then $(CYGPATH_W) 'libdes/speed.c'; else $(CYGPATH_W) '$(srcdir)/libdes/speed.c'; fi`
+
+fcrypt_b.o: libdes/fcrypt_b.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fcrypt_b.o -MD -MP -MF "$(DEPDIR)/fcrypt_b.Tpo" -c -o fcrypt_b.o `test -f 'libdes/fcrypt_b.c' || echo '$(srcdir)/'`libdes/fcrypt_b.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/fcrypt_b.Tpo" "$(DEPDIR)/fcrypt_b.Po"; else rm -f "$(DEPDIR)/fcrypt_b.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libdes/fcrypt_b.c' object='fcrypt_b.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fcrypt_b.o `test -f 'libdes/fcrypt_b.c' || echo '$(srcdir)/'`libdes/fcrypt_b.c
+
+fcrypt_b.obj: libdes/fcrypt_b.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fcrypt_b.obj -MD -MP -MF "$(DEPDIR)/fcrypt_b.Tpo" -c -o fcrypt_b.obj `if test -f 'libdes/fcrypt_b.c'; then $(CYGPATH_W) 'libdes/fcrypt_b.c'; else $(CYGPATH_W) '$(srcdir)/libdes/fcrypt_b.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/fcrypt_b.Tpo" "$(DEPDIR)/fcrypt_b.Po"; else rm -f "$(DEPDIR)/fcrypt_b.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libdes/fcrypt_b.c' object='fcrypt_b.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fcrypt_b.obj `if test -f 'libdes/fcrypt_b.c'; then $(CYGPATH_W) 'libdes/fcrypt_b.c'; else $(CYGPATH_W) '$(srcdir)/libdes/fcrypt_b.c'; fi`
+
+fcrypt.o: libdes/fcrypt.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fcrypt.o -MD -MP -MF "$(DEPDIR)/fcrypt.Tpo" -c -o fcrypt.o `test -f 'libdes/fcrypt.c' || echo '$(srcdir)/'`libdes/fcrypt.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/fcrypt.Tpo" "$(DEPDIR)/fcrypt.Po"; else rm -f "$(DEPDIR)/fcrypt.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libdes/fcrypt.c' object='fcrypt.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fcrypt.o `test -f 'libdes/fcrypt.c' || echo '$(srcdir)/'`libdes/fcrypt.c
+
+fcrypt.obj: libdes/fcrypt.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fcrypt.obj -MD -MP -MF "$(DEPDIR)/fcrypt.Tpo" -c -o fcrypt.obj `if test -f 'libdes/fcrypt.c'; then $(CYGPATH_W) 'libdes/fcrypt.c'; else $(CYGPATH_W) '$(srcdir)/libdes/fcrypt.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/fcrypt.Tpo" "$(DEPDIR)/fcrypt.Po"; else rm -f "$(DEPDIR)/fcrypt.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libdes/fcrypt.c' object='fcrypt.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fcrypt.obj `if test -f 'libdes/fcrypt.c'; then $(CYGPATH_W) 'libdes/fcrypt.c'; else $(CYGPATH_W) '$(srcdir)/libdes/fcrypt.c'; fi`
+
+destest.o: libdes/destest.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT destest.o -MD -MP -MF "$(DEPDIR)/destest.Tpo" -c -o destest.o `test -f 'libdes/destest.c' || echo '$(srcdir)/'`libdes/destest.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/destest.Tpo" "$(DEPDIR)/destest.Po"; else rm -f "$(DEPDIR)/destest.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libdes/destest.c' object='destest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o destest.o `test -f 'libdes/destest.c' || echo '$(srcdir)/'`libdes/destest.c
+
+destest.obj: libdes/destest.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT destest.obj -MD -MP -MF "$(DEPDIR)/destest.Tpo" -c -o destest.obj `if test -f 'libdes/destest.c'; then $(CYGPATH_W) 'libdes/destest.c'; else $(CYGPATH_W) '$(srcdir)/libdes/destest.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/destest.Tpo" "$(DEPDIR)/destest.Po"; else rm -f "$(DEPDIR)/destest.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libdes/destest.c' object='destest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o destest.obj `if test -f 'libdes/destest.c'; then $(CYGPATH_W) 'libdes/destest.c'; else $(CYGPATH_W) '$(srcdir)/libdes/destest.c'; fi`
+
+cbc_enc.o: libdes/cbc_enc.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cbc_enc.o -MD -MP -MF "$(DEPDIR)/cbc_enc.Tpo" -c -o cbc_enc.o `test -f 'libdes/cbc_enc.c' || echo '$(srcdir)/'`libdes/cbc_enc.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/cbc_enc.Tpo" "$(DEPDIR)/cbc_enc.Po"; else rm -f "$(DEPDIR)/cbc_enc.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libdes/cbc_enc.c' object='cbc_enc.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cbc_enc.o `test -f 'libdes/cbc_enc.c' || echo '$(srcdir)/'`libdes/cbc_enc.c
+
+cbc_enc.obj: libdes/cbc_enc.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cbc_enc.obj -MD -MP -MF "$(DEPDIR)/cbc_enc.Tpo" -c -o cbc_enc.obj `if test -f 'libdes/cbc_enc.c'; then $(CYGPATH_W) 'libdes/cbc_enc.c'; else $(CYGPATH_W) '$(srcdir)/libdes/cbc_enc.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/cbc_enc.Tpo" "$(DEPDIR)/cbc_enc.Po"; else rm -f "$(DEPDIR)/cbc_enc.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libdes/cbc_enc.c' object='cbc_enc.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cbc_enc.obj `if test -f 'libdes/cbc_enc.c'; then $(CYGPATH_W) 'libdes/cbc_enc.c'; else $(CYGPATH_W) '$(srcdir)/libdes/cbc_enc.c'; fi`
+
+ecb_enc.o: libdes/ecb_enc.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ecb_enc.o -MD -MP -MF "$(DEPDIR)/ecb_enc.Tpo" -c -o ecb_enc.o `test -f 'libdes/ecb_enc.c' || echo '$(srcdir)/'`libdes/ecb_enc.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ecb_enc.Tpo" "$(DEPDIR)/ecb_enc.Po"; else rm -f "$(DEPDIR)/ecb_enc.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libdes/ecb_enc.c' object='ecb_enc.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ecb_enc.o `test -f 'libdes/ecb_enc.c' || echo '$(srcdir)/'`libdes/ecb_enc.c
+
+ecb_enc.obj: libdes/ecb_enc.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ecb_enc.obj -MD -MP -MF "$(DEPDIR)/ecb_enc.Tpo" -c -o ecb_enc.obj `if test -f 'libdes/ecb_enc.c'; then $(CYGPATH_W) 'libdes/ecb_enc.c'; else $(CYGPATH_W) '$(srcdir)/libdes/ecb_enc.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ecb_enc.Tpo" "$(DEPDIR)/ecb_enc.Po"; else rm -f "$(DEPDIR)/ecb_enc.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libdes/ecb_enc.c' object='ecb_enc.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ecb_enc.obj `if test -f 'libdes/ecb_enc.c'; then $(CYGPATH_W) 'libdes/ecb_enc.c'; else $(CYGPATH_W) '$(srcdir)/libdes/ecb_enc.c'; fi`
+
+des_opts.o: libdes/des_opts.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT des_opts.o -MD -MP -MF "$(DEPDIR)/des_opts.Tpo" -c -o des_opts.o `test -f 'libdes/des_opts.c' || echo '$(srcdir)/'`libdes/des_opts.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/des_opts.Tpo" "$(DEPDIR)/des_opts.Po"; else rm -f "$(DEPDIR)/des_opts.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libdes/des_opts.c' object='des_opts.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o des_opts.o `test -f 'libdes/des_opts.c' || echo '$(srcdir)/'`libdes/des_opts.c
+
+des_opts.obj: libdes/des_opts.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT des_opts.obj -MD -MP -MF "$(DEPDIR)/des_opts.Tpo" -c -o des_opts.obj `if test -f 'libdes/des_opts.c'; then $(CYGPATH_W) 'libdes/des_opts.c'; else $(CYGPATH_W) '$(srcdir)/libdes/des_opts.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/des_opts.Tpo" "$(DEPDIR)/des_opts.Po"; else rm -f "$(DEPDIR)/des_opts.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libdes/des_opts.c' object='des_opts.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o des_opts.obj `if test -f 'libdes/des_opts.c'; then $(CYGPATH_W) 'libdes/des_opts.c'; else $(CYGPATH_W) '$(srcdir)/libdes/des_opts.c'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am install-man \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am \
+ uninstall-info-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/libcrypto/include/cbc_generic.h b/src/libcrypto/include/cbc_generic.h
new file mode 100644
index 000000000..0dd3a77d6
--- /dev/null
+++ b/src/libcrypto/include/cbc_generic.h
@@ -0,0 +1,110 @@
+#ifndef _CBC_GENERIC_H
+#define _CBC_GENERIC_H
+/*
+ * CBC macro helpers
+ *
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ */
+
+/*
+ * Heavily inspired in loop_AES
+ */
+#define CBC_IMPL_BLK16(name, ctx_type, addr_type, enc_func, dec_func) \
+int name(ctx_type *ctx, const u_int8_t * in, u_int8_t * out, int ilen, const u_int8_t * iv, int encrypt) { \
+ int ret=ilen, pos; \
+ const u_int32_t *iv_i; \
+ if ((ilen) % 16) return 0; \
+ if (encrypt) { \
+ pos=0; \
+ while(pos<ilen) { \
+ if (pos==0) \
+ iv_i=(const u_int32_t*) iv; \
+ 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])); \
+ enc_func(ctx, (addr_type) out, (addr_type) out); \
+ in+=16; \
+ out+=16; \
+ pos+=16; \
+ } \
+ } else { \
+ pos=ilen-16; \
+ in+=pos; \
+ out+=pos; \
+ while(pos>=0) { \
+ dec_func(ctx, (const addr_type) in, (addr_type) out); \
+ if (pos==0) \
+ iv_i=(const u_int32_t*) (iv); \
+ 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 ret; \
+}
+#define CBC_IMPL_BLK8(name, ctx_type, addr_type, enc_func, dec_func) \
+int name(ctx_type *ctx, u_int8_t * in, u_int8_t * out, int ilen, const u_int8_t * iv, int encrypt) { \
+ int ret=ilen, pos; \
+ const u_int32_t *iv_i; \
+ if ((ilen) % 8) return 0; \
+ if (encrypt) { \
+ pos=0; \
+ while(pos<ilen) { \
+ if (pos==0) \
+ iv_i=(const u_int32_t*) iv; \
+ else \
+ iv_i=(const u_int32_t*) (out-8); \
+ *((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])); \
+ enc_func(ctx, (addr_type)out, (addr_type)out); \
+ in+=8; \
+ out+=8; \
+ pos+=8; \
+ } \
+ } else { \
+ pos=ilen-8; \
+ in+=pos; \
+ out+=pos; \
+ while(pos>=0) { \
+ dec_func(ctx, (const addr_type)in, (addr_type)out); \
+ if (pos==0) \
+ iv_i=(const u_int32_t*) (iv); \
+ else \
+ iv_i=(const u_int32_t*) (in-8); \
+ *((u_int32_t *)(&out[ 0])) ^= iv_i[0]; \
+ *((u_int32_t *)(&out[ 4])) ^= iv_i[1]; \
+ in-=8; \
+ out-=8; \
+ pos-=8; \
+ } \
+ } \
+ return ret; \
+}
+#define CBC_DECL(name, ctx_type) \
+int name(ctx_type *ctx, u_int8_t * in, u_int8_t * out, int ilen, const u_int8_t * iv, int encrypt)
+/*
+Eg.:
+CBC_IMPL_BLK16(AES_cbc_encrypt, aes_context, u_int8_t *, aes_encrypt, aes_decrypt);
+CBC_DECL(AES_cbc_encrypt, aes_context);
+*/
+#endif /* _CBC_GENERIC_H */
diff --git a/src/libcrypto/include/hmac_generic.h b/src/libcrypto/include/hmac_generic.h
new file mode 100644
index 000000000..a749228e3
--- /dev/null
+++ b/src/libcrypto/include/hmac_generic.h
@@ -0,0 +1,60 @@
+#ifndef _HMAC_GENERIC_H
+#define _HMAC_GENERIC_H
+/*
+ * HMAC macro helpers
+ *
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 DIVUP
+#define DIVUP(x,y) ((x + y -1) / y) /* divide, rounding upwards */
+#endif
+#ifndef HMAC_IPAD
+#define HMAC_IPAD 0x36
+#define HMAC_OPAD 0x5C
+#endif
+#define HMAC_SET_KEY_IMPL(func_name, hctx_t, blocksize, func_init, func_update) \
+void func_name(hctx_t *hctx, const u_int8_t * key, int keylen) { \
+ int i;\
+ u_int8_t kb[blocksize]; \
+ for (i = 0; i < DIVUP(keylen*8, 8); i++) { \
+ kb[i] = key[i] ^ HMAC_IPAD; \
+ } \
+ for (; i < blocksize; i++) { \
+ kb[i] = HMAC_IPAD; \
+ } \
+ func_init(&hctx->ictx); \
+ func_update(&hctx->ictx, kb, blocksize); \
+ for (i = 0; i < blocksize; i++) { \
+ kb[i] ^= (HMAC_IPAD ^ HMAC_OPAD); \
+ } \
+ func_init(&hctx->octx); \
+ func_update(&hctx->octx, kb, blocksize); \
+}
+#define HMAC_HASH_IMPL(func_name, hctx_t, ctx_t, ahlen, func_update, func_result ) \
+void func_name(hctx_t *hctx, const u_int8_t * dat, int len, u_int8_t * hash, int hashlen) { \
+ ctx_t ctx; \
+ ctx=hctx->ictx; \
+ if (dat) func_update(&ctx, dat, len); \
+ if (hash) { \
+ u_int8_t hash_buf[ahlen]; \
+ func_result(&ctx, hash_buf, ahlen); \
+ ctx=hctx->octx; \
+ func_update(&ctx, hash_buf, ahlen); \
+ func_result(&ctx, hash, hashlen); \
+ memset(&ctx, 0, sizeof (ctx)); \
+ memset(&hash_buf, 0, sizeof (hash_buf));\
+ } \
+}
+#endif /* _HMAC_GENERIC_H */
diff --git a/src/libcrypto/include/md32_common.h b/src/libcrypto/include/md32_common.h
new file mode 100644
index 000000000..1a404a458
--- /dev/null
+++ b/src/libcrypto/include/md32_common.h
@@ -0,0 +1,607 @@
+/* crypto/md32_common.h */
+/* ====================================================================
+ * Copyright (c) 1999 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+/*
+ * This is a generic 32 bit "collector" for message digest algorithms.
+ * Whenever needed it collects input character stream into chunks of
+ * 32 bit values and invokes a block function that performs actual hash
+ * calculations.
+ *
+ * Porting guide.
+ *
+ * Obligatory macros:
+ *
+ * DATA_ORDER_IS_BIG_ENDIAN or DATA_ORDER_IS_LITTLE_ENDIAN
+ * this macro defines byte order of input stream.
+ * HASH_CBLOCK
+ * size of a unit chunk HASH_BLOCK operates on.
+ * HASH_LONG
+ * has to be at lest 32 bit wide, if it's wider, then
+ * HASH_LONG_LOG2 *has to* be defined along
+ * HASH_CTX
+ * context structure that at least contains following
+ * members:
+ * typedef struct {
+ * ...
+ * HASH_LONG Nl,Nh;
+ * HASH_LONG data[HASH_LBLOCK];
+ * int num;
+ * ...
+ * } HASH_CTX;
+ * HASH_UPDATE
+ * name of "Update" function, implemented here.
+ * HASH_TRANSFORM
+ * name of "Transform" function, implemented here.
+ * HASH_FINAL
+ * name of "Final" function, implemented here.
+ * HASH_BLOCK_HOST_ORDER
+ * name of "block" function treating *aligned* input message
+ * in host byte order, implemented externally.
+ * HASH_BLOCK_DATA_ORDER
+ * name of "block" function treating *unaligned* input message
+ * in original (data) byte order, implemented externally (it
+ * actually is optional if data and host are of the same
+ * "endianess").
+ * HASH_MAKE_STRING
+ * macro convering context variables to an ASCII hash string.
+ *
+ * Optional macros:
+ *
+ * B_ENDIAN or L_ENDIAN
+ * defines host byte-order.
+ * HASH_LONG_LOG2
+ * defaults to 2 if not states otherwise.
+ * HASH_LBLOCK
+ * assumed to be HASH_CBLOCK/4 if not stated otherwise.
+ * HASH_BLOCK_DATA_ORDER_ALIGNED
+ * alternative "block" function capable of treating
+ * aligned input message in original (data) order,
+ * implemented externally.
+ *
+ * MD5 example:
+ *
+ * #define DATA_ORDER_IS_LITTLE_ENDIAN
+ *
+ * #define HASH_LONG MD5_LONG
+ * #define HASH_LONG_LOG2 MD5_LONG_LOG2
+ * #define HASH_CTX MD5_CTX
+ * #define HASH_CBLOCK MD5_CBLOCK
+ * #define HASH_LBLOCK MD5_LBLOCK
+ * #define HASH_UPDATE MD5_Update
+ * #define HASH_TRANSFORM MD5_Transform
+ * #define HASH_FINAL MD5_Final
+ * #define HASH_BLOCK_HOST_ORDER md5_block_host_order
+ * #define HASH_BLOCK_DATA_ORDER md5_block_data_order
+ *
+ * <appro@fy.chalmers.se>
+ */
+
+#if !defined(DATA_ORDER_IS_BIG_ENDIAN) && !defined(DATA_ORDER_IS_LITTLE_ENDIAN)
+#error "DATA_ORDER must be defined!"
+#endif
+
+#ifndef HASH_CBLOCK
+#error "HASH_CBLOCK must be defined!"
+#endif
+#ifndef HASH_LONG
+#error "HASH_LONG must be defined!"
+#endif
+#ifndef HASH_CTX
+#error "HASH_CTX must be defined!"
+#endif
+
+#ifndef HASH_UPDATE
+#error "HASH_UPDATE must be defined!"
+#endif
+#ifndef HASH_TRANSFORM
+#error "HASH_TRANSFORM must be defined!"
+#endif
+#ifndef HASH_FINAL
+#error "HASH_FINAL must be defined!"
+#endif
+
+#ifndef HASH_BLOCK_HOST_ORDER
+#error "HASH_BLOCK_HOST_ORDER must be defined!"
+#endif
+
+#if 0
+/*
+ * Moved below as it's required only if HASH_BLOCK_DATA_ORDER_ALIGNED
+ * isn't defined.
+ */
+#ifndef HASH_BLOCK_DATA_ORDER
+#error "HASH_BLOCK_DATA_ORDER must be defined!"
+#endif
+#endif
+
+#ifndef HASH_LBLOCK
+#define HASH_LBLOCK (HASH_CBLOCK/4)
+#endif
+
+#ifndef HASH_LONG_LOG2
+#define HASH_LONG_LOG2 2
+#endif
+
+/*
+ * Engage compiler specific rotate intrinsic function if available.
+ */
+#undef ROTATE
+#ifndef PEDANTIC
+# if defined(_MSC_VER)
+# define ROTATE(a,n) _lrotl(a,n)
+# elif defined(__MWERKS__)
+# if defined(__POWERPC__)
+# define ROTATE(a,n) __rlwinm(a,n,0,31)
+# elif defined(__MC68K__)
+ /* Motorola specific tweak. <appro@fy.chalmers.se> */
+# define ROTATE(a,n) ( n<24 ? __rol(a,n) : __ror(a,32-n) )
+# else
+# define ROTATE(a,n) __rol(a,n)
+# endif
+# elif defined(__GNUC__) && __GNUC__>=2 && !defined(NO_ASM) && !defined(NO_INLINE_ASM)
+ /*
+ * Some GNU C inline assembler templates. Note that these are
+ * rotates by *constant* number of bits! But that's exactly
+ * what we need here...
+ *
+ * <appro@fy.chalmers.se>
+ */
+# if defined(__i386)
+# define ROTATE(a,n) ({ register unsigned int ret; \
+ asm ( \
+ "roll %1,%0" \
+ : "=r"(ret) \
+ : "I"(n), "0"(a) \
+ : "cc"); \
+ ret; \
+ })
+# elif defined(__powerpc) || defined(__ppc)
+# define ROTATE(a,n) ({ register unsigned int ret; \
+ asm ( \
+ "rlwinm %0,%1,%2,0,31" \
+ : "=r"(ret) \
+ : "r"(a), "I"(n)); \
+ ret; \
+ })
+# endif
+# endif
+
+/*
+ * Engage compiler specific "fetch in reverse byte order"
+ * intrinsic function if available.
+ */
+# if defined(__GNUC__) && __GNUC__>=2 && !defined(NO_ASM) && !defined(NO_INLINE_ASM)
+ /* some GNU C inline assembler templates by <appro@fy.chalmers.se> */
+# if defined(__i386) && !defined(I386_ONLY)
+# define BE_FETCH32(a) ({ register unsigned int l=(a);\
+ asm ( \
+ "bswapl %0" \
+ : "=r"(l) : "0"(l)); \
+ l; \
+ })
+# elif defined(__powerpc)
+# define LE_FETCH32(a) ({ register unsigned int l; \
+ asm ( \
+ "lwbrx %0,0,%1" \
+ : "=r"(l) \
+ : "r"(a)); \
+ l; \
+ })
+
+# elif defined(__sparc) && defined(ULTRASPARC)
+# define LE_FETCH32(a) ({ register unsigned int l; \
+ asm ( \
+ "lda [%1]#ASI_PRIMARY_LITTLE,%0"\
+ : "=r"(l) \
+ : "r"(a)); \
+ l; \
+ })
+# endif
+# endif
+#endif /* PEDANTIC */
+
+#if HASH_LONG_LOG2==2 /* Engage only if sizeof(HASH_LONG)== 4 */
+/* A nice byte order reversal from Wei Dai <weidai@eskimo.com> */
+#ifdef ROTATE
+/* 5 instructions with rotate instruction, else 9 */
+#define REVERSE_FETCH32(a,l) ( \
+ l=*(const HASH_LONG *)(a), \
+ ((ROTATE(l,8)&0x00FF00FF)|(ROTATE((l&0x00FF00FF),24))) \
+ )
+#else
+/* 6 instructions with rotate instruction, else 8 */
+#define REVERSE_FETCH32(a,l) ( \
+ l=*(const HASH_LONG *)(a), \
+ l=(((l>>8)&0x00FF00FF)|((l&0x00FF00FF)<<8)), \
+ ROTATE(l,16) \
+ )
+/*
+ * Originally the middle line started with l=(((l&0xFF00FF00)>>8)|...
+ * It's rewritten as above for two reasons:
+ * - RISCs aren't good at long constants and have to explicitely
+ * compose 'em with several (well, usually 2) instructions in a
+ * register before performing the actual operation and (as you
+ * already realized:-) having same constant should inspire the
+ * compiler to permanently allocate the only register for it;
+ * - most modern CPUs have two ALUs, but usually only one has
+ * circuitry for shifts:-( this minor tweak inspires compiler
+ * to schedule shift instructions in a better way...
+ *
+ * <appro@fy.chalmers.se>
+ */
+#endif
+#endif
+
+#ifndef ROTATE
+#define ROTATE(a,n) (((a)<<(n))|(((a)&0xffffffff)>>(32-(n))))
+#endif
+
+/*
+ * Make some obvious choices. E.g., HASH_BLOCK_DATA_ORDER_ALIGNED
+ * and HASH_BLOCK_HOST_ORDER ought to be the same if input data
+ * and host are of the same "endianess". It's possible to mask
+ * this with blank #define HASH_BLOCK_DATA_ORDER though...
+ *
+ * <appro@fy.chalmers.se>
+ */
+#if defined(B_ENDIAN)
+# if defined(DATA_ORDER_IS_BIG_ENDIAN)
+# if !defined(HASH_BLOCK_DATA_ORDER_ALIGNED) && HASH_LONG_LOG2==2
+# define HASH_BLOCK_DATA_ORDER_ALIGNED HASH_BLOCK_HOST_ORDER
+# endif
+# elif defined(DATA_ORDER_IS_LITTLE_ENDIAN)
+# ifndef HOST_FETCH32
+# ifdef LE_FETCH32
+# define HOST_FETCH32(p,l) LE_FETCH32(p)
+# elif defined(REVERSE_FETCH32)
+# define HOST_FETCH32(p,l) REVERSE_FETCH32(p,l)
+# endif
+# endif
+# endif
+#elif defined(L_ENDIAN)
+# if defined(DATA_ORDER_IS_LITTLE_ENDIAN)
+# if !defined(HASH_BLOCK_DATA_ORDER_ALIGNED) && HASH_LONG_LOG2==2
+# define HASH_BLOCK_DATA_ORDER_ALIGNED HASH_BLOCK_HOST_ORDER
+# endif
+# elif defined(DATA_ORDER_IS_BIG_ENDIAN)
+# ifndef HOST_FETCH32
+# ifdef BE_FETCH32
+# define HOST_FETCH32(p,l) BE_FETCH32(p)
+# elif defined(REVERSE_FETCH32)
+# define HOST_FETCH32(p,l) REVERSE_FETCH32(p,l)
+# endif
+# endif
+# endif
+#endif
+
+#if !defined(HASH_BLOCK_DATA_ORDER_ALIGNED)
+#ifndef HASH_BLOCK_DATA_ORDER
+#error "HASH_BLOCK_DATA_ORDER must be defined!"
+#endif
+#endif
+
+#if defined(DATA_ORDER_IS_BIG_ENDIAN)
+
+#define HOST_c2l(c,l) (l =(((unsigned long)(*((c)++)))<<24), \
+ l|=(((unsigned long)(*((c)++)))<<16), \
+ l|=(((unsigned long)(*((c)++)))<< 8), \
+ l|=(((unsigned long)(*((c)++))) ), \
+ l)
+#define HOST_p_c2l(c,l,n) { \
+ switch (n) { \
+ case 0: l =((unsigned long)(*((c)++)))<<24; \
+ case 1: l|=((unsigned long)(*((c)++)))<<16; \
+ case 2: l|=((unsigned long)(*((c)++)))<< 8; \
+ case 3: l|=((unsigned long)(*((c)++))); \
+ } }
+#define HOST_p_c2l_p(c,l,sc,len) { \
+ switch (sc) { \
+ case 0: l =((unsigned long)(*((c)++)))<<24; \
+ if (--len == 0) break; \
+ case 1: l|=((unsigned long)(*((c)++)))<<16; \
+ if (--len == 0) break; \
+ case 2: l|=((unsigned long)(*((c)++)))<< 8; \
+ } }
+/* NOTE the pointer is not incremented at the end of this */
+#define HOST_c2l_p(c,l,n) { \
+ l=0; (c)+=n; \
+ switch (n) { \
+ case 3: l =((unsigned long)(*(--(c))))<< 8; \
+ case 2: l|=((unsigned long)(*(--(c))))<<16; \
+ case 1: l|=((unsigned long)(*(--(c))))<<24; \
+ } }
+#define HOST_l2c(l,c) (*((c)++)=(unsigned char)(((l)>>24)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>16)&0xff), \
+ *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
+ *((c)++)=(unsigned char)(((l) )&0xff), \
+ l)
+
+#elif defined(DATA_ORDER_IS_LITTLE_ENDIAN)
+
+#define HOST_c2l(c,l) (l =(((unsigned long)(*((c)++))) ), \
+ l|=(((unsigned long)(*((c)++)))<< 8), \
+ l|=(((unsigned long)(*((c)++)))<<16), \
+ l|=(((unsigned long)(*((c)++)))<<24), \
+ l)
+#define HOST_p_c2l(c,l,n) { \
+ switch (n) { \
+ case 0: l =((unsigned long)(*((c)++))); \
+ case 1: l|=((unsigned long)(*((c)++)))<< 8; \
+ case 2: l|=((unsigned long)(*((c)++)))<<16; \
+ case 3: l|=((unsigned long)(*((c)++)))<<24; \
+ } }
+#define HOST_p_c2l_p(c,l,sc,len) { \
+ switch (sc) { \
+ case 0: l =((unsigned long)(*((c)++))); \
+ if (--len == 0) break; \
+ case 1: l|=((unsigned long)(*((c)++)))<< 8; \
+ if (--len == 0) break; \
+ case 2: l|=((unsigned long)(*((c)++)))<<16; \
+ } }
+/* NOTE the pointer is not incremented at the end of this */
+#define HOST_c2l_p(c,l,n) { \
+ l=0; (c)+=n; \
+ switch (n) { \
+ case 3: l =((unsigned long)(*(--(c))))<<16; \
+ case 2: l|=((unsigned long)(*(--(c))))<< 8; \
+ case 1: l|=((unsigned long)(*(--(c)))); \
+ } }
+#define HOST_l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \
+ *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>16)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>24)&0xff), \
+ l)
+
+#endif
+
+/*
+ * Time for some action:-)
+ */
+
+void HASH_UPDATE (HASH_CTX *c, const void *data_, unsigned long len)
+ {
+ const unsigned char *data=data_;
+ register HASH_LONG * p;
+ register unsigned long l;
+ int sw,sc,ew,ec;
+
+ if (len==0) return;
+
+ l=(c->Nl+(len<<3))&0xffffffffL;
+ /* 95-05-24 eay Fixed a bug with the overflow handling, thanks to
+ * Wei Dai <weidai@eskimo.com> for pointing it out. */
+ if (l < c->Nl) /* overflow */
+ c->Nh++;
+ c->Nh+=(len>>29);
+ c->Nl=l;
+
+ if (c->num != 0)
+ {
+ p=c->data;
+ sw=c->num>>2;
+ sc=c->num&0x03;
+
+ if ((c->num+len) >= HASH_CBLOCK)
+ {
+ l=p[sw]; HOST_p_c2l(data,l,sc); p[sw++]=l;
+ for (; sw<HASH_LBLOCK; sw++)
+ {
+ HOST_c2l(data,l); p[sw]=l;
+ }
+ HASH_BLOCK_HOST_ORDER (c,p,1);
+ len-=(HASH_CBLOCK-c->num);
+ c->num=0;
+ /* drop through and do the rest */
+ }
+ else
+ {
+ c->num+=len;
+ if ((sc+len) < 4) /* ugly, add char's to a word */
+ {
+ l=p[sw]; HOST_p_c2l_p(data,l,sc,len); p[sw]=l;
+ }
+ else
+ {
+ ew=(c->num>>2);
+ ec=(c->num&0x03);
+ l=p[sw]; HOST_p_c2l(data,l,sc); p[sw++]=l;
+ for (; sw < ew; sw++)
+ {
+ HOST_c2l(data,l); p[sw]=l;
+ }
+ if (ec)
+ {
+ HOST_c2l_p(data,l,ec); p[sw]=l;
+ }
+ }
+ return;
+ }
+ }
+
+ sw=len/HASH_CBLOCK;
+ if (sw > 0)
+ {
+#if defined(HASH_BLOCK_DATA_ORDER_ALIGNED)
+ /*
+ * Note that HASH_BLOCK_DATA_ORDER_ALIGNED gets defined
+ * only if sizeof(HASH_LONG)==4.
+ */
+ if ((((unsigned long)data)%4) == 0)
+ {
+ /* data is properly aligned so that we can cast it: */
+ HASH_BLOCK_DATA_ORDER_ALIGNED (c,(HASH_LONG *)data,sw);
+ sw*=HASH_CBLOCK;
+ data+=sw;
+ len-=sw;
+ }
+ else
+#if !defined(HASH_BLOCK_DATA_ORDER)
+ while (sw--)
+ {
+ memcpy (p=c->data,data,HASH_CBLOCK);
+ HASH_BLOCK_DATA_ORDER_ALIGNED(c,p,1);
+ data+=HASH_CBLOCK;
+ len-=HASH_CBLOCK;
+ }
+#endif
+#endif
+#if defined(HASH_BLOCK_DATA_ORDER)
+ {
+ HASH_BLOCK_DATA_ORDER(c,data,sw);
+ sw*=HASH_CBLOCK;
+ data+=sw;
+ len-=sw;
+ }
+#endif
+ }
+
+ if (len!=0)
+ {
+ p = c->data;
+ c->num = len;
+ ew=len>>2; /* words to copy */
+ ec=len&0x03;
+ for (; ew; ew--,p++)
+ {
+ HOST_c2l(data,l); *p=l;
+ }
+ HOST_c2l_p(data,l,ec);
+ *p=l;
+ }
+ }
+
+
+void HASH_TRANSFORM (HASH_CTX *c, const unsigned char *data)
+ {
+#if defined(HASH_BLOCK_DATA_ORDER_ALIGNED)
+ if ((((unsigned long)data)%4) == 0)
+ /* data is properly aligned so that we can cast it: */
+ HASH_BLOCK_DATA_ORDER_ALIGNED (c,(HASH_LONG *)data,1);
+ else
+#if !defined(HASH_BLOCK_DATA_ORDER)
+ {
+ memcpy (c->data,data,HASH_CBLOCK);
+ HASH_BLOCK_DATA_ORDER_ALIGNED (c,c->data,1);
+ }
+#endif
+#endif
+#if defined(HASH_BLOCK_DATA_ORDER)
+ HASH_BLOCK_DATA_ORDER (c,data,1);
+#endif
+ }
+
+
+void HASH_FINAL (unsigned char *md, HASH_CTX *c)
+ {
+ register HASH_LONG *p;
+ register unsigned long l;
+ register int i,j;
+ static const unsigned char end[4]={0x80,0x00,0x00,0x00};
+ const unsigned char *cp=end;
+
+ /* c->num should definitly have room for at least one more byte. */
+ p=c->data;
+ i=c->num>>2;
+ j=c->num&0x03;
+
+#if 0
+ /* purify often complains about the following line as an
+ * Uninitialized Memory Read. While this can be true, the
+ * following p_c2l macro will reset l when that case is true.
+ * This is because j&0x03 contains the number of 'valid' bytes
+ * already in p[i]. If and only if j&0x03 == 0, the UMR will
+ * occur but this is also the only time p_c2l will do
+ * l= *(cp++) instead of l|= *(cp++)
+ * Many thanks to Alex Tang <altitude@cic.net> for pickup this
+ * 'potential bug' */
+#ifdef PURIFY
+ if (j==0) p[i]=0; /* Yeah, but that's not the way to fix it:-) */
+#endif
+ l=p[i];
+#else
+ l = (j==0) ? 0 : p[i];
+#endif
+ HOST_p_c2l(cp,l,j); p[i++]=l; /* i is the next 'undefined word' */
+
+ if (i>(HASH_LBLOCK-2)) /* save room for Nl and Nh */
+ {
+ if (i<HASH_LBLOCK) p[i]=0;
+ HASH_BLOCK_HOST_ORDER (c,p,1);
+ i=0;
+ }
+ for (; i<(HASH_LBLOCK-2); i++)
+ p[i]=0;
+
+#if defined(DATA_ORDER_IS_BIG_ENDIAN)
+ p[HASH_LBLOCK-2]=c->Nh;
+ p[HASH_LBLOCK-1]=c->Nl;
+#elif defined(DATA_ORDER_IS_LITTLE_ENDIAN)
+ p[HASH_LBLOCK-2]=c->Nl;
+ p[HASH_LBLOCK-1]=c->Nh;
+#endif
+ HASH_BLOCK_HOST_ORDER (c,p,1);
+
+#ifndef HASH_MAKE_STRING
+#error "HASH_MAKE_STRING must be defined!"
+#else
+ HASH_MAKE_STRING(c,md);
+#endif
+
+ c->num=0;
+ /* clear stuff, HASH_BLOCK may be leaving some stuff on the stack
+ * but I'm not worried :-)
+ memset((void *)c,0,sizeof(HASH_CTX));
+ */
+ }
diff --git a/src/libcrypto/libaes/aes.c b/src/libcrypto/libaes/aes.c
new file mode 100644
index 000000000..1748119ac
--- /dev/null
+++ b/src/libcrypto/libaes/aes.c
@@ -0,0 +1,1415 @@
+// I retain copyright in this code but I encourage its free use provided
+// that I don't carry any responsibility for the results. I am especially
+// happy to see it used in free and open source software. If you do use
+// it I would appreciate an acknowledgement of its origin in the code or
+// the product that results and I would also appreciate knowing a little
+// about the use to which it is being put. I am grateful to Frank Yellin
+// for some ideas that are used in this implementation.
+//
+// Dr B. R. Gladman <brg@gladman.uk.net> 6th April 2001.
+//
+// This is an implementation of the AES encryption algorithm (Rijndael)
+// designed by Joan Daemen and Vincent Rijmen. This version is designed
+// to provide both fixed and dynamic block and key lengths and can also
+// run with either big or little endian internal byte order (see aes.h).
+// It inputs block and key lengths in bytes with the legal values being
+// 16, 24 and 32.
+
+/*
+ * Modified by Jari Ruusu, May 1 2001
+ * - Fixed some compile warnings, code was ok but gcc warned anyway.
+ * - Changed basic types: byte -> unsigned char, word -> u_int32_t
+ * - Major name space cleanup: Names visible to outside now begin
+ * with "aes_" or "AES_". A lot of stuff moved from aes.h to aes.c
+ * - Removed C++ and DLL support as part of name space cleanup.
+ * - Eliminated unnecessary recomputation of tables. (actual bug fix)
+ * - Merged precomputed constant tables to aes.c file.
+ * - Removed data alignment restrictions for portability reasons.
+ * - Made block and key lengths accept bit count (128/192/256)
+ * as well byte count (16/24/32).
+ * - Removed all error checks. This change also eliminated the need
+ * to preinitialize the context struct to zero.
+ * - Removed some totally unused constants.
+ */
+
+#include "aes.h"
+
+// CONFIGURATION OPTIONS (see also aes.h)
+//
+// 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
+
+// upr(x,n): rotates bytes within words by n positions, moving bytes
+// to higher index positions with wrap around into low positions
+// ups(x,n): moves bytes by n positions to higher index positions in
+// words but without wrap around
+// bval(x,n): extracts a byte from a word
+
+#define upr(x,n) (((x) << 8 * (n)) | ((x) >> (32 - 8 * (n))))
+#define ups(x,n) ((x) << 8 * (n))
+#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
+
+// Subroutine to set the block size (if variable) in bytes, legal
+// values being 16, 24 and 32.
+
+#if defined(AES_BLOCK_SIZE)
+#define nc (AES_BLOCK_SIZE / 4)
+#else
+#define nc (cx->aes_Ncol)
+
+void aes_set_blk(aes_context *cx, int n_bytes)
+{
+#if !defined(FIXED_TABLES)
+ if(!tab_gen) { gen_tabs(); tab_gen = 1; }
+#endif
+
+ switch(n_bytes) {
+ case 32: /* bytes */
+ case 256: /* bits */
+ nc = 8;
+ break;
+ case 24: /* bytes */
+ case 192: /* bits */
+ nc = 6;
+ break;
+ case 16: /* bytes */
+ case 128: /* bits */
+ default:
+ nc = 4;
+ break;
+ }
+}
+
+#endif
+
+// 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
+
+void aes_set_key(aes_context *cx, const unsigned char in_key[], int n_bytes, const int f)
+{ u_int32_t *kf, *kt, rci;
+
+#if !defined(FIXED_TABLES)
+ if(!tab_gen) { gen_tabs(); tab_gen = 1; }
+#endif
+
+ switch(n_bytes) {
+ case 32: /* bytes */
+ case 256: /* bits */
+ cx->aes_Nkey = 8;
+ break;
+ case 24: /* bytes */
+ case 192: /* bits */
+ cx->aes_Nkey = 6;
+ break;
+ case 16: /* bytes */
+ case 128: /* bits */
+ default:
+ cx->aes_Nkey = 4;
+ break;
+ }
+
+ cx->aes_Nrnd = (cx->aes_Nkey > nc ? cx->aes_Nkey : nc) + 6;
+
+ cx->aes_e_key[0] = const_word_in(in_key );
+ cx->aes_e_key[1] = const_word_in(in_key + 4);
+ cx->aes_e_key[2] = const_word_in(in_key + 8);
+ cx->aes_e_key[3] = const_word_in(in_key + 12);
+
+ kf = cx->aes_e_key;
+ kt = kf + nc * (cx->aes_Nrnd + 1) - cx->aes_Nkey;
+ rci = 0;
+
+ switch(cx->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: cx->aes_e_key[4] = const_word_in(in_key + 16);
+ cx->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: cx->aes_e_key[4] = const_word_in(in_key + 16);
+ cx->aes_e_key[5] = const_word_in(in_key + 20);
+ cx->aes_e_key[6] = const_word_in(in_key + 24);
+ cx->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 = cx->aes_d_key + nc * cx->aes_Nrnd;
+ kf = cx->aes_e_key;
+
+ cpy(kt, kf); kt -= 2 * nc;
+
+ for(i = 1; i < cx->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);
+ }
+}
+
+// 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
+
+void aes_encrypt(const aes_context *cx, const unsigned char in_blk[], unsigned char out_blk[])
+{ u_int32_t locals(b0, b1);
+ const u_int32_t *kp = cx->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(cx->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 < (cx->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 < cx->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);
+}
+
+void aes_decrypt(const aes_context *cx, const unsigned char in_blk[], unsigned char out_blk[])
+{ u_int32_t locals(b0, b1);
+ const u_int32_t *kp = cx->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(cx->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 < (cx->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 < cx->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);
+}
diff --git a/src/libcrypto/libaes/aes.h b/src/libcrypto/libaes/aes.h
new file mode 100644
index 000000000..4f1e3b335
--- /dev/null
+++ b/src/libcrypto/libaes/aes.h
@@ -0,0 +1,97 @@
+// I retain copyright in this code but I encourage its free use provided
+// that I don't carry any responsibility for the results. I am especially
+// happy to see it used in free and open source software. If you do use
+// it I would appreciate an acknowledgement of its origin in the code or
+// the product that results and I would also appreciate knowing a little
+// about the use to which it is being put. I am grateful to Frank Yellin
+// for some ideas that are used in this implementation.
+//
+// Dr B. R. Gladman <brg@gladman.uk.net> 6th April 2001.
+//
+// This is an implementation of the AES encryption algorithm (Rijndael)
+// designed by Joan Daemen and Vincent Rijmen. This version is designed
+// to provide both fixed and dynamic block and key lengths and can also
+// run with either big or little endian internal byte order (see aes.h).
+// It inputs block and key lengths in bytes with the legal values being
+// 16, 24 and 32.
+
+/*
+ * Modified by Jari Ruusu, May 1 2001
+ * - Fixed some compile warnings, code was ok but gcc warned anyway.
+ * - Changed basic types: byte -> unsigned char, word -> u_int32_t
+ * - Major name space cleanup: Names visible to outside now begin
+ * with "aes_" or "AES_". A lot of stuff moved from aes.h to aes.c
+ * - Removed C++ and DLL support as part of name space cleanup.
+ * - Eliminated unnecessary recomputation of tables. (actual bug fix)
+ * - Merged precomputed constant tables to aes.c file.
+ * - Removed data alignment restrictions for portability reasons.
+ * - Made block and key lengths accept bit count (128/192/256)
+ * as well byte count (16/24/32).
+ * - Removed all error checks. This change also eliminated the need
+ * to preinitialize the context struct to zero.
+ * - Removed some totally unused constants.
+ */
+
+#ifndef _AES_H
+#define _AES_H
+
+#if defined(__linux__) && defined(__KERNEL__)
+# include <linux/types.h>
+#else
+# include <sys/types.h>
+#endif
+
+// CONFIGURATION OPTIONS (see also aes.c)
+//
+// Define AES_BLOCK_SIZE to set the cipher block size (16, 24 or 32) or
+// leave this undefined for dynamically variable block size (this will
+// result in much slower code).
+// IMPORTANT NOTE: AES_BLOCK_SIZE is in BYTES (16, 24, 32 or undefined). If
+// left undefined a slower version providing variable block length is compiled
+
+#define AES_BLOCK_SIZE 16
+
+// 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
+//
+// Nk = 4 6 8
+// -------------
+// Nb = 4 | 60 60 64
+// 6 | 96 90 96
+// 8 | 120 120 120
+
+#if !defined(AES_BLOCK_SIZE) || (AES_BLOCK_SIZE == 32)
+#define AES_KS_LENGTH 120
+#define AES_RC_LENGTH 29
+#else
+#define AES_KS_LENGTH 4 * AES_BLOCK_SIZE
+#define AES_RC_LENGTH (9 * AES_BLOCK_SIZE) / 8 - 8
+#endif
+
+typedef struct
+{
+ u_int32_t aes_Nkey; // the number of words in the key input block
+ u_int32_t aes_Nrnd; // the number of cipher rounds
+ u_int32_t aes_e_key[AES_KS_LENGTH]; // the encryption key schedule
+ u_int32_t aes_d_key[AES_KS_LENGTH]; // the decryption key schedule
+#if !defined(AES_BLOCK_SIZE)
+ u_int32_t aes_Ncol; // the number of columns in the cipher state
+#endif
+} aes_context;
+
+// THE CIPHER INTERFACE
+
+#if !defined(AES_BLOCK_SIZE)
+extern void aes_set_blk(aes_context *, const int);
+#endif
+extern void aes_set_key(aes_context *, const unsigned char [], const int, const int);
+extern void aes_encrypt(const aes_context *, const unsigned char [], unsigned char []);
+extern void aes_decrypt(const aes_context *, const unsigned char [], unsigned char []);
+
+// The block length inputs to aes_set_block and aes_set_key are in numbers
+// of bytes or bits. The calls to subroutines must be made in the above
+// order but multiple calls can be made without repeating earlier calls
+// if their parameters have not changed.
+
+#endif // _AES_H
diff --git a/src/libcrypto/libaes/aes_cbc.c b/src/libcrypto/libaes/aes_cbc.c
new file mode 100644
index 000000000..962dd1a35
--- /dev/null
+++ b/src/libcrypto/libaes/aes_cbc.c
@@ -0,0 +1,13 @@
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <sys/types.h>
+#endif
+#include "aes_cbc.h"
+#include "cbc_generic.h"
+/* returns bool success */
+int AES_set_key(aes_context *aes_ctx, const u_int8_t *key, int keysize) {
+ aes_set_key(aes_ctx, key, keysize, 0);
+ return 1;
+}
+CBC_IMPL_BLK16(AES_cbc_encrypt, aes_context, u_int8_t *, aes_encrypt, aes_decrypt);
diff --git a/src/libcrypto/libaes/aes_cbc.h b/src/libcrypto/libaes/aes_cbc.h
new file mode 100644
index 000000000..92f5d77f5
--- /dev/null
+++ b/src/libcrypto/libaes/aes_cbc.h
@@ -0,0 +1,4 @@
+/* Glue header */
+#include "aes.h"
+int AES_set_key(aes_context *aes_ctx, const u_int8_t * key, int keysize);
+int AES_cbc_encrypt(aes_context *ctx, const u_int8_t * in, u_int8_t * out, int ilen, const u_int8_t * iv, int encrypt);
diff --git a/src/libcrypto/libaes/aes_xcbc_mac.c b/src/libcrypto/libaes/aes_xcbc_mac.c
new file mode 100644
index 000000000..89d7bc067
--- /dev/null
+++ b/src/libcrypto/libaes/aes_xcbc_mac.c
@@ -0,0 +1,67 @@
+#ifdef __KERNEL__
+#include <linux/types.h>
+#include <linux/kernel.h>
+#define DEBUG(x)
+#else
+#include <stdio.h>
+#include <sys/types.h>
+#define DEBUG(x) x
+#endif
+
+#include "aes.h"
+#include "aes_xcbc_mac.h"
+
+int AES_xcbc_mac_set_key(aes_context_mac *ctxm, const u_int8_t *key, int keylen)
+{
+ int ret=1;
+ aes_block kn[3] = {
+ { 0x01010101, 0x01010101, 0x01010101, 0x01010101 },
+ { 0x02020202, 0x02020202, 0x02020202, 0x02020202 },
+ { 0x03030303, 0x03030303, 0x03030303, 0x03030303 },
+ };
+ aes_set_key(&ctxm->ctx_k1, key, keylen, 0);
+ aes_encrypt(&ctxm->ctx_k1, (u_int8_t *) kn[0], (u_int8_t *) kn[0]);
+ aes_encrypt(&ctxm->ctx_k1, (u_int8_t *) kn[1], (u_int8_t *) ctxm->k2);
+ aes_encrypt(&ctxm->ctx_k1, (u_int8_t *) kn[2], (u_int8_t *) ctxm->k3);
+ aes_set_key(&ctxm->ctx_k1, (u_int8_t *) kn[0], 16, 0);
+ return ret;
+}
+static void do_pad_xor(u_int8_t *out, const u_int8_t *in, int len) {
+ int pos=0;
+ for (pos=1; pos <= 16; pos++, in++, out++) {
+ if (pos <= len)
+ *out ^= *in;
+ if (pos > len) {
+ DEBUG(printf("put 0x80 at pos=%d\n", pos));
+ *out ^= 0x80;
+ break;
+ }
+ }
+}
+static void xor_block(aes_block res, const aes_block op) {
+ res[0] ^= op[0];
+ res[1] ^= op[1];
+ res[2] ^= op[2];
+ res[3] ^= op[3];
+}
+int AES_xcbc_mac_hash(const aes_context_mac *ctxm, const u_int8_t * in, int ilen, u_int8_t hash[16]) {
+ int ret=ilen;
+ u_int32_t out[4] = { 0, 0, 0, 0 };
+ for (; ilen > 16 ; ilen-=16) {
+ xor_block(out, (const u_int32_t*) &in[0]);
+ aes_encrypt(&ctxm->ctx_k1, in, (u_int8_t *)&out[0]);
+ in+=16;
+ }
+ do_pad_xor((u_int8_t *)&out, in, ilen);
+ if (ilen==16) {
+ DEBUG(printf("using k3\n"));
+ xor_block(out, ctxm->k3);
+ }
+ else
+ {
+ DEBUG(printf("using k2\n"));
+ xor_block(out, ctxm->k2);
+ }
+ aes_encrypt(&ctxm->ctx_k1, (u_int8_t *)out, hash);
+ return ret;
+}
diff --git a/src/libcrypto/libaes/aes_xcbc_mac.h b/src/libcrypto/libaes/aes_xcbc_mac.h
new file mode 100644
index 000000000..baf438cd4
--- /dev/null
+++ b/src/libcrypto/libaes/aes_xcbc_mac.h
@@ -0,0 +1,12 @@
+#ifndef _AES_XCBC_MAC_H
+#define _AES_XCBC_MAC_H
+
+typedef u_int32_t aes_block[4];
+typedef struct {
+ aes_context ctx_k1;
+ aes_block k2;
+ aes_block k3;
+} aes_context_mac;
+int AES_xcbc_mac_set_key(aes_context_mac *ctxm, const u_int8_t *key, int keylen);
+int AES_xcbc_mac_hash(const aes_context_mac *ctxm, const u_int8_t * in, int ilen, u_int8_t hash[16]);
+#endif /* _AES_XCBC_MAC_H */
diff --git a/src/libcrypto/libblowfish/bf_enc.c b/src/libcrypto/libblowfish/bf_enc.c
new file mode 100644
index 000000000..aa6c79812
--- /dev/null
+++ b/src/libcrypto/libblowfish/bf_enc.c
@@ -0,0 +1,306 @@
+/* crypto/bf/bf_enc.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include "blowfish.h"
+#include "bf_locl.h"
+
+/* Blowfish as implemented from 'Blowfish: Springer-Verlag paper'
+ * (From LECTURE NOTES IN COMPUTER SCIENCE 809, FAST SOFTWARE ENCRYPTION,
+ * CAMBRIDGE SECURITY WORKSHOP, CAMBRIDGE, U.K., DECEMBER 9-11, 1993)
+ */
+
+#if (BF_ROUNDS != 16) && (BF_ROUNDS != 20)
+#error If you set BF_ROUNDS to some value other than 16 or 20, you will have \
+to modify the code.
+#endif
+
+void BF_encrypt(BF_LONG *data, const BF_KEY *key)
+ {
+#ifndef BF_PTR2
+ const BF_LONG *p,*s;
+ BF_LONG l,r;
+
+ p=key->P;
+ s= &(key->S[0]);
+ l=data[0];
+ r=data[1];
+
+ l^=p[0];
+ BF_ENC(r,l,s,p[ 1]);
+ BF_ENC(l,r,s,p[ 2]);
+ BF_ENC(r,l,s,p[ 3]);
+ BF_ENC(l,r,s,p[ 4]);
+ BF_ENC(r,l,s,p[ 5]);
+ BF_ENC(l,r,s,p[ 6]);
+ BF_ENC(r,l,s,p[ 7]);
+ BF_ENC(l,r,s,p[ 8]);
+ BF_ENC(r,l,s,p[ 9]);
+ BF_ENC(l,r,s,p[10]);
+ BF_ENC(r,l,s,p[11]);
+ BF_ENC(l,r,s,p[12]);
+ BF_ENC(r,l,s,p[13]);
+ BF_ENC(l,r,s,p[14]);
+ BF_ENC(r,l,s,p[15]);
+ BF_ENC(l,r,s,p[16]);
+#if BF_ROUNDS == 20
+ BF_ENC(r,l,s,p[17]);
+ BF_ENC(l,r,s,p[18]);
+ BF_ENC(r,l,s,p[19]);
+ BF_ENC(l,r,s,p[20]);
+#endif
+ r^=p[BF_ROUNDS+1];
+
+ data[1]=l&0xffffffffL;
+ data[0]=r&0xffffffffL;
+#else
+ BF_LONG l,r,t,*k;
+
+ l=data[0];
+ r=data[1];
+ k=(BF_LONG*)key;
+
+ l^=k[0];
+ BF_ENC(r,l,k, 1);
+ BF_ENC(l,r,k, 2);
+ BF_ENC(r,l,k, 3);
+ BF_ENC(l,r,k, 4);
+ BF_ENC(r,l,k, 5);
+ BF_ENC(l,r,k, 6);
+ BF_ENC(r,l,k, 7);
+ BF_ENC(l,r,k, 8);
+ BF_ENC(r,l,k, 9);
+ BF_ENC(l,r,k,10);
+ BF_ENC(r,l,k,11);
+ BF_ENC(l,r,k,12);
+ BF_ENC(r,l,k,13);
+ BF_ENC(l,r,k,14);
+ BF_ENC(r,l,k,15);
+ BF_ENC(l,r,k,16);
+#if BF_ROUNDS == 20
+ BF_ENC(r,l,k,17);
+ BF_ENC(l,r,k,18);
+ BF_ENC(r,l,k,19);
+ BF_ENC(l,r,k,20);
+#endif
+ r^=k[BF_ROUNDS+1];
+
+ data[1]=l&0xffffffffL;
+ data[0]=r&0xffffffffL;
+#endif
+ }
+
+#ifndef BF_DEFAULT_OPTIONS
+
+void BF_decrypt(BF_LONG *data, const BF_KEY *key)
+ {
+#ifndef BF_PTR2
+ const BF_LONG *p,*s;
+ BF_LONG l,r;
+
+ p=key->P;
+ s= &(key->S[0]);
+ l=data[0];
+ r=data[1];
+
+ l^=p[BF_ROUNDS+1];
+#if BF_ROUNDS == 20
+ BF_ENC(r,l,s,p[20]);
+ BF_ENC(l,r,s,p[19]);
+ BF_ENC(r,l,s,p[18]);
+ BF_ENC(l,r,s,p[17]);
+#endif
+ BF_ENC(r,l,s,p[16]);
+ BF_ENC(l,r,s,p[15]);
+ BF_ENC(r,l,s,p[14]);
+ BF_ENC(l,r,s,p[13]);
+ BF_ENC(r,l,s,p[12]);
+ BF_ENC(l,r,s,p[11]);
+ BF_ENC(r,l,s,p[10]);
+ BF_ENC(l,r,s,p[ 9]);
+ BF_ENC(r,l,s,p[ 8]);
+ BF_ENC(l,r,s,p[ 7]);
+ BF_ENC(r,l,s,p[ 6]);
+ BF_ENC(l,r,s,p[ 5]);
+ BF_ENC(r,l,s,p[ 4]);
+ BF_ENC(l,r,s,p[ 3]);
+ BF_ENC(r,l,s,p[ 2]);
+ BF_ENC(l,r,s,p[ 1]);
+ r^=p[0];
+
+ data[1]=l&0xffffffffL;
+ data[0]=r&0xffffffffL;
+#else
+ BF_LONG l,r,t,*k;
+
+ l=data[0];
+ r=data[1];
+ k=(BF_LONG *)key;
+
+ l^=k[BF_ROUNDS+1];
+#if BF_ROUNDS == 20
+ BF_ENC(r,l,k,20);
+ BF_ENC(l,r,k,19);
+ BF_ENC(r,l,k,18);
+ BF_ENC(l,r,k,17);
+#endif
+ BF_ENC(r,l,k,16);
+ BF_ENC(l,r,k,15);
+ BF_ENC(r,l,k,14);
+ BF_ENC(l,r,k,13);
+ BF_ENC(r,l,k,12);
+ BF_ENC(l,r,k,11);
+ BF_ENC(r,l,k,10);
+ BF_ENC(l,r,k, 9);
+ BF_ENC(r,l,k, 8);
+ BF_ENC(l,r,k, 7);
+ BF_ENC(r,l,k, 6);
+ BF_ENC(l,r,k, 5);
+ BF_ENC(r,l,k, 4);
+ BF_ENC(l,r,k, 3);
+ BF_ENC(r,l,k, 2);
+ BF_ENC(l,r,k, 1);
+ r^=k[0];
+
+ data[1]=l&0xffffffffL;
+ data[0]=r&0xffffffffL;
+#endif
+ }
+
+void BF_cbc_encrypt(const unsigned char *in, unsigned char *out, long length,
+ const BF_KEY *schedule, unsigned char *ivec, int encrypt)
+ {
+ BF_LONG tin0,tin1;
+ BF_LONG tout0,tout1,xor0,xor1;
+ long l=length;
+ BF_LONG tin[2];
+
+ if (encrypt)
+ {
+ n2l(ivec,tout0);
+ n2l(ivec,tout1);
+ ivec-=8;
+ for (l-=8; l>=0; l-=8)
+ {
+ n2l(in,tin0);
+ n2l(in,tin1);
+ tin0^=tout0;
+ tin1^=tout1;
+ tin[0]=tin0;
+ tin[1]=tin1;
+ BF_encrypt(tin,schedule);
+ tout0=tin[0];
+ tout1=tin[1];
+ l2n(tout0,out);
+ l2n(tout1,out);
+ }
+ if (l != -8)
+ {
+ n2ln(in,tin0,tin1,l+8);
+ tin0^=tout0;
+ tin1^=tout1;
+ tin[0]=tin0;
+ tin[1]=tin1;
+ BF_encrypt(tin,schedule);
+ tout0=tin[0];
+ tout1=tin[1];
+ l2n(tout0,out);
+ l2n(tout1,out);
+ }
+ l2n(tout0,ivec);
+ l2n(tout1,ivec);
+ }
+ else
+ {
+ n2l(ivec,xor0);
+ n2l(ivec,xor1);
+ ivec-=8;
+ for (l-=8; l>=0; l-=8)
+ {
+ n2l(in,tin0);
+ n2l(in,tin1);
+ tin[0]=tin0;
+ tin[1]=tin1;
+ BF_decrypt(tin,schedule);
+ tout0=tin[0]^xor0;
+ tout1=tin[1]^xor1;
+ l2n(tout0,out);
+ l2n(tout1,out);
+ xor0=tin0;
+ xor1=tin1;
+ }
+ if (l != -8)
+ {
+ n2l(in,tin0);
+ n2l(in,tin1);
+ tin[0]=tin0;
+ tin[1]=tin1;
+ BF_decrypt(tin,schedule);
+ tout0=tin[0]^xor0;
+ tout1=tin[1]^xor1;
+ l2nn(tout0,tout1,out,l+8);
+ xor0=tin0;
+ xor1=tin1;
+ }
+ l2n(xor0,ivec);
+ l2n(xor1,ivec);
+ }
+ tin0=tin1=tout0=tout1=xor0=xor1=0;
+ tin[0]=tin[1]=0;
+ }
+
+#endif
diff --git a/src/libcrypto/libblowfish/bf_locl.h b/src/libcrypto/libblowfish/bf_locl.h
new file mode 100644
index 000000000..283bf4c43
--- /dev/null
+++ b/src/libcrypto/libblowfish/bf_locl.h
@@ -0,0 +1,218 @@
+/* crypto/bf/bf_locl.h */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_BF_LOCL_H
+#define HEADER_BF_LOCL_H
+
+#undef c2l
+#define c2l(c,l) (l =((unsigned long)(*((c)++))) , \
+ l|=((unsigned long)(*((c)++)))<< 8L, \
+ l|=((unsigned long)(*((c)++)))<<16L, \
+ l|=((unsigned long)(*((c)++)))<<24L)
+
+/* NOTE - c is not incremented as per c2l */
+#undef c2ln
+#define c2ln(c,l1,l2,n) { \
+ c+=n; \
+ l1=l2=0; \
+ switch (n) { \
+ case 8: l2 =((unsigned long)(*(--(c))))<<24L; \
+ case 7: l2|=((unsigned long)(*(--(c))))<<16L; \
+ case 6: l2|=((unsigned long)(*(--(c))))<< 8L; \
+ case 5: l2|=((unsigned long)(*(--(c)))); \
+ case 4: l1 =((unsigned long)(*(--(c))))<<24L; \
+ case 3: l1|=((unsigned long)(*(--(c))))<<16L; \
+ case 2: l1|=((unsigned long)(*(--(c))))<< 8L; \
+ case 1: l1|=((unsigned long)(*(--(c)))); \
+ } \
+ }
+
+#undef l2c
+#define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \
+ *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>16L)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>24L)&0xff))
+
+/* NOTE - c is not incremented as per l2c */
+#undef l2cn
+#define l2cn(l1,l2,c,n) { \
+ c+=n; \
+ switch (n) { \
+ case 8: *(--(c))=(unsigned char)(((l2)>>24L)&0xff); \
+ case 7: *(--(c))=(unsigned char)(((l2)>>16L)&0xff); \
+ case 6: *(--(c))=(unsigned char)(((l2)>> 8L)&0xff); \
+ case 5: *(--(c))=(unsigned char)(((l2) )&0xff); \
+ case 4: *(--(c))=(unsigned char)(((l1)>>24L)&0xff); \
+ case 3: *(--(c))=(unsigned char)(((l1)>>16L)&0xff); \
+ case 2: *(--(c))=(unsigned char)(((l1)>> 8L)&0xff); \
+ case 1: *(--(c))=(unsigned char)(((l1) )&0xff); \
+ } \
+ }
+
+/* NOTE - c is not incremented as per n2l */
+#define n2ln(c,l1,l2,n) { \
+ c+=n; \
+ l1=l2=0; \
+ switch (n) { \
+ case 8: l2 =((unsigned long)(*(--(c)))) ; \
+ case 7: l2|=((unsigned long)(*(--(c))))<< 8; \
+ case 6: l2|=((unsigned long)(*(--(c))))<<16; \
+ case 5: l2|=((unsigned long)(*(--(c))))<<24; \
+ case 4: l1 =((unsigned long)(*(--(c)))) ; \
+ case 3: l1|=((unsigned long)(*(--(c))))<< 8; \
+ case 2: l1|=((unsigned long)(*(--(c))))<<16; \
+ case 1: l1|=((unsigned long)(*(--(c))))<<24; \
+ } \
+ }
+
+/* NOTE - c is not incremented as per l2n */
+#define l2nn(l1,l2,c,n) { \
+ c+=n; \
+ switch (n) { \
+ case 8: *(--(c))=(unsigned char)(((l2) )&0xff); \
+ case 7: *(--(c))=(unsigned char)(((l2)>> 8)&0xff); \
+ case 6: *(--(c))=(unsigned char)(((l2)>>16)&0xff); \
+ case 5: *(--(c))=(unsigned char)(((l2)>>24)&0xff); \
+ case 4: *(--(c))=(unsigned char)(((l1) )&0xff); \
+ case 3: *(--(c))=(unsigned char)(((l1)>> 8)&0xff); \
+ case 2: *(--(c))=(unsigned char)(((l1)>>16)&0xff); \
+ case 1: *(--(c))=(unsigned char)(((l1)>>24)&0xff); \
+ } \
+ }
+
+#undef n2l
+#define n2l(c,l) (l =((unsigned long)(*((c)++)))<<24L, \
+ l|=((unsigned long)(*((c)++)))<<16L, \
+ l|=((unsigned long)(*((c)++)))<< 8L, \
+ l|=((unsigned long)(*((c)++))))
+
+#undef l2n
+#define l2n(l,c) (*((c)++)=(unsigned char)(((l)>>24L)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>16L)&0xff), \
+ *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
+ *((c)++)=(unsigned char)(((l) )&0xff))
+
+/* This is actually a big endian algorithm, the most significant byte
+ * is used to lookup array 0 */
+
+#if defined(BF_PTR2)
+
+/*
+ * This is basically a special Intel version. Point is that Intel
+ * doesn't have many registers, but offers a reach choice of addressing
+ * modes. So we spare some registers by directly traversing BF_KEY
+ * structure and hiring the most decorated addressing mode. The code
+ * generated by EGCS is *perfectly* competitive with assembler
+ * implementation!
+ */
+#define BF_ENC(LL,R,KEY,Pi) (\
+ LL^=KEY[Pi], \
+ t= KEY[BF_ROUNDS+2 + 0 + ((R>>24)&0xFF)], \
+ t+= KEY[BF_ROUNDS+2 + 256 + ((R>>16)&0xFF)], \
+ t^= KEY[BF_ROUNDS+2 + 512 + ((R>>8 )&0xFF)], \
+ t+= KEY[BF_ROUNDS+2 + 768 + ((R )&0xFF)], \
+ LL^=t \
+ )
+
+#elif defined(BF_PTR)
+
+#ifndef BF_LONG_LOG2
+#define BF_LONG_LOG2 2 /* default to BF_LONG being 32 bits */
+#endif
+#define BF_M (0xFF<<BF_LONG_LOG2)
+#define BF_0 (24-BF_LONG_LOG2)
+#define BF_1 (16-BF_LONG_LOG2)
+#define BF_2 ( 8-BF_LONG_LOG2)
+#define BF_3 BF_LONG_LOG2 /* left shift */
+
+/*
+ * This is normally very good on RISC platforms where normally you
+ * have to explicitly "multiply" array index by sizeof(BF_LONG)
+ * in order to calculate the effective address. This implementation
+ * excuses CPU from this extra work. Power[PC] uses should have most
+ * fun as (R>>BF_i)&BF_M gets folded into a single instruction, namely
+ * rlwinm. So let'em double-check if their compiler does it.
+ */
+
+#define BF_ENC(LL,R,S,P) ( \
+ LL^=P, \
+ LL^= (((*(BF_LONG *)((unsigned char *)&(S[ 0])+((R>>BF_0)&BF_M))+ \
+ *(BF_LONG *)((unsigned char *)&(S[256])+((R>>BF_1)&BF_M)))^ \
+ *(BF_LONG *)((unsigned char *)&(S[512])+((R>>BF_2)&BF_M)))+ \
+ *(BF_LONG *)((unsigned char *)&(S[768])+((R<<BF_3)&BF_M))) \
+ )
+#else
+
+/*
+ * This is a *generic* version. Seem to perform best on platforms that
+ * offer explicit support for extraction of 8-bit nibbles preferably
+ * complemented with "multiplying" of array index by sizeof(BF_LONG).
+ * For the moment of this writing the list comprises Alpha CPU featuring
+ * extbl and s[48]addq instructions.
+ */
+
+#define BF_ENC(LL,R,S,P) ( \
+ LL^=P, \
+ LL^=((( S[ ((int)(R>>24)&0xff)] + \
+ S[0x0100+((int)(R>>16)&0xff)])^ \
+ S[0x0200+((int)(R>> 8)&0xff)])+ \
+ S[0x0300+((int)(R )&0xff)])&0xffffffffL \
+ )
+#endif
+
+#endif
diff --git a/src/libcrypto/libblowfish/bf_pi.h b/src/libcrypto/libblowfish/bf_pi.h
new file mode 100644
index 000000000..9949513c6
--- /dev/null
+++ b/src/libcrypto/libblowfish/bf_pi.h
@@ -0,0 +1,325 @@
+/* crypto/bf/bf_pi.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+static const BF_KEY bf_init= {
+ {
+ 0x243f6a88L, 0x85a308d3L, 0x13198a2eL, 0x03707344L,
+ 0xa4093822L, 0x299f31d0L, 0x082efa98L, 0xec4e6c89L,
+ 0x452821e6L, 0x38d01377L, 0xbe5466cfL, 0x34e90c6cL,
+ 0xc0ac29b7L, 0xc97c50ddL, 0x3f84d5b5L, 0xb5470917L,
+ 0x9216d5d9L, 0x8979fb1b
+ },{
+ 0xd1310ba6L, 0x98dfb5acL, 0x2ffd72dbL, 0xd01adfb7L,
+ 0xb8e1afedL, 0x6a267e96L, 0xba7c9045L, 0xf12c7f99L,
+ 0x24a19947L, 0xb3916cf7L, 0x0801f2e2L, 0x858efc16L,
+ 0x636920d8L, 0x71574e69L, 0xa458fea3L, 0xf4933d7eL,
+ 0x0d95748fL, 0x728eb658L, 0x718bcd58L, 0x82154aeeL,
+ 0x7b54a41dL, 0xc25a59b5L, 0x9c30d539L, 0x2af26013L,
+ 0xc5d1b023L, 0x286085f0L, 0xca417918L, 0xb8db38efL,
+ 0x8e79dcb0L, 0x603a180eL, 0x6c9e0e8bL, 0xb01e8a3eL,
+ 0xd71577c1L, 0xbd314b27L, 0x78af2fdaL, 0x55605c60L,
+ 0xe65525f3L, 0xaa55ab94L, 0x57489862L, 0x63e81440L,
+ 0x55ca396aL, 0x2aab10b6L, 0xb4cc5c34L, 0x1141e8ceL,
+ 0xa15486afL, 0x7c72e993L, 0xb3ee1411L, 0x636fbc2aL,
+ 0x2ba9c55dL, 0x741831f6L, 0xce5c3e16L, 0x9b87931eL,
+ 0xafd6ba33L, 0x6c24cf5cL, 0x7a325381L, 0x28958677L,
+ 0x3b8f4898L, 0x6b4bb9afL, 0xc4bfe81bL, 0x66282193L,
+ 0x61d809ccL, 0xfb21a991L, 0x487cac60L, 0x5dec8032L,
+ 0xef845d5dL, 0xe98575b1L, 0xdc262302L, 0xeb651b88L,
+ 0x23893e81L, 0xd396acc5L, 0x0f6d6ff3L, 0x83f44239L,
+ 0x2e0b4482L, 0xa4842004L, 0x69c8f04aL, 0x9e1f9b5eL,
+ 0x21c66842L, 0xf6e96c9aL, 0x670c9c61L, 0xabd388f0L,
+ 0x6a51a0d2L, 0xd8542f68L, 0x960fa728L, 0xab5133a3L,
+ 0x6eef0b6cL, 0x137a3be4L, 0xba3bf050L, 0x7efb2a98L,
+ 0xa1f1651dL, 0x39af0176L, 0x66ca593eL, 0x82430e88L,
+ 0x8cee8619L, 0x456f9fb4L, 0x7d84a5c3L, 0x3b8b5ebeL,
+ 0xe06f75d8L, 0x85c12073L, 0x401a449fL, 0x56c16aa6L,
+ 0x4ed3aa62L, 0x363f7706L, 0x1bfedf72L, 0x429b023dL,
+ 0x37d0d724L, 0xd00a1248L, 0xdb0fead3L, 0x49f1c09bL,
+ 0x075372c9L, 0x80991b7bL, 0x25d479d8L, 0xf6e8def7L,
+ 0xe3fe501aL, 0xb6794c3bL, 0x976ce0bdL, 0x04c006baL,
+ 0xc1a94fb6L, 0x409f60c4L, 0x5e5c9ec2L, 0x196a2463L,
+ 0x68fb6fafL, 0x3e6c53b5L, 0x1339b2ebL, 0x3b52ec6fL,
+ 0x6dfc511fL, 0x9b30952cL, 0xcc814544L, 0xaf5ebd09L,
+ 0xbee3d004L, 0xde334afdL, 0x660f2807L, 0x192e4bb3L,
+ 0xc0cba857L, 0x45c8740fL, 0xd20b5f39L, 0xb9d3fbdbL,
+ 0x5579c0bdL, 0x1a60320aL, 0xd6a100c6L, 0x402c7279L,
+ 0x679f25feL, 0xfb1fa3ccL, 0x8ea5e9f8L, 0xdb3222f8L,
+ 0x3c7516dfL, 0xfd616b15L, 0x2f501ec8L, 0xad0552abL,
+ 0x323db5faL, 0xfd238760L, 0x53317b48L, 0x3e00df82L,
+ 0x9e5c57bbL, 0xca6f8ca0L, 0x1a87562eL, 0xdf1769dbL,
+ 0xd542a8f6L, 0x287effc3L, 0xac6732c6L, 0x8c4f5573L,
+ 0x695b27b0L, 0xbbca58c8L, 0xe1ffa35dL, 0xb8f011a0L,
+ 0x10fa3d98L, 0xfd2183b8L, 0x4afcb56cL, 0x2dd1d35bL,
+ 0x9a53e479L, 0xb6f84565L, 0xd28e49bcL, 0x4bfb9790L,
+ 0xe1ddf2daL, 0xa4cb7e33L, 0x62fb1341L, 0xcee4c6e8L,
+ 0xef20cadaL, 0x36774c01L, 0xd07e9efeL, 0x2bf11fb4L,
+ 0x95dbda4dL, 0xae909198L, 0xeaad8e71L, 0x6b93d5a0L,
+ 0xd08ed1d0L, 0xafc725e0L, 0x8e3c5b2fL, 0x8e7594b7L,
+ 0x8ff6e2fbL, 0xf2122b64L, 0x8888b812L, 0x900df01cL,
+ 0x4fad5ea0L, 0x688fc31cL, 0xd1cff191L, 0xb3a8c1adL,
+ 0x2f2f2218L, 0xbe0e1777L, 0xea752dfeL, 0x8b021fa1L,
+ 0xe5a0cc0fL, 0xb56f74e8L, 0x18acf3d6L, 0xce89e299L,
+ 0xb4a84fe0L, 0xfd13e0b7L, 0x7cc43b81L, 0xd2ada8d9L,
+ 0x165fa266L, 0x80957705L, 0x93cc7314L, 0x211a1477L,
+ 0xe6ad2065L, 0x77b5fa86L, 0xc75442f5L, 0xfb9d35cfL,
+ 0xebcdaf0cL, 0x7b3e89a0L, 0xd6411bd3L, 0xae1e7e49L,
+ 0x00250e2dL, 0x2071b35eL, 0x226800bbL, 0x57b8e0afL,
+ 0x2464369bL, 0xf009b91eL, 0x5563911dL, 0x59dfa6aaL,
+ 0x78c14389L, 0xd95a537fL, 0x207d5ba2L, 0x02e5b9c5L,
+ 0x83260376L, 0x6295cfa9L, 0x11c81968L, 0x4e734a41L,
+ 0xb3472dcaL, 0x7b14a94aL, 0x1b510052L, 0x9a532915L,
+ 0xd60f573fL, 0xbc9bc6e4L, 0x2b60a476L, 0x81e67400L,
+ 0x08ba6fb5L, 0x571be91fL, 0xf296ec6bL, 0x2a0dd915L,
+ 0xb6636521L, 0xe7b9f9b6L, 0xff34052eL, 0xc5855664L,
+ 0x53b02d5dL, 0xa99f8fa1L, 0x08ba4799L, 0x6e85076aL,
+ 0x4b7a70e9L, 0xb5b32944L, 0xdb75092eL, 0xc4192623L,
+ 0xad6ea6b0L, 0x49a7df7dL, 0x9cee60b8L, 0x8fedb266L,
+ 0xecaa8c71L, 0x699a17ffL, 0x5664526cL, 0xc2b19ee1L,
+ 0x193602a5L, 0x75094c29L, 0xa0591340L, 0xe4183a3eL,
+ 0x3f54989aL, 0x5b429d65L, 0x6b8fe4d6L, 0x99f73fd6L,
+ 0xa1d29c07L, 0xefe830f5L, 0x4d2d38e6L, 0xf0255dc1L,
+ 0x4cdd2086L, 0x8470eb26L, 0x6382e9c6L, 0x021ecc5eL,
+ 0x09686b3fL, 0x3ebaefc9L, 0x3c971814L, 0x6b6a70a1L,
+ 0x687f3584L, 0x52a0e286L, 0xb79c5305L, 0xaa500737L,
+ 0x3e07841cL, 0x7fdeae5cL, 0x8e7d44ecL, 0x5716f2b8L,
+ 0xb03ada37L, 0xf0500c0dL, 0xf01c1f04L, 0x0200b3ffL,
+ 0xae0cf51aL, 0x3cb574b2L, 0x25837a58L, 0xdc0921bdL,
+ 0xd19113f9L, 0x7ca92ff6L, 0x94324773L, 0x22f54701L,
+ 0x3ae5e581L, 0x37c2dadcL, 0xc8b57634L, 0x9af3dda7L,
+ 0xa9446146L, 0x0fd0030eL, 0xecc8c73eL, 0xa4751e41L,
+ 0xe238cd99L, 0x3bea0e2fL, 0x3280bba1L, 0x183eb331L,
+ 0x4e548b38L, 0x4f6db908L, 0x6f420d03L, 0xf60a04bfL,
+ 0x2cb81290L, 0x24977c79L, 0x5679b072L, 0xbcaf89afL,
+ 0xde9a771fL, 0xd9930810L, 0xb38bae12L, 0xdccf3f2eL,
+ 0x5512721fL, 0x2e6b7124L, 0x501adde6L, 0x9f84cd87L,
+ 0x7a584718L, 0x7408da17L, 0xbc9f9abcL, 0xe94b7d8cL,
+ 0xec7aec3aL, 0xdb851dfaL, 0x63094366L, 0xc464c3d2L,
+ 0xef1c1847L, 0x3215d908L, 0xdd433b37L, 0x24c2ba16L,
+ 0x12a14d43L, 0x2a65c451L, 0x50940002L, 0x133ae4ddL,
+ 0x71dff89eL, 0x10314e55L, 0x81ac77d6L, 0x5f11199bL,
+ 0x043556f1L, 0xd7a3c76bL, 0x3c11183bL, 0x5924a509L,
+ 0xf28fe6edL, 0x97f1fbfaL, 0x9ebabf2cL, 0x1e153c6eL,
+ 0x86e34570L, 0xeae96fb1L, 0x860e5e0aL, 0x5a3e2ab3L,
+ 0x771fe71cL, 0x4e3d06faL, 0x2965dcb9L, 0x99e71d0fL,
+ 0x803e89d6L, 0x5266c825L, 0x2e4cc978L, 0x9c10b36aL,
+ 0xc6150ebaL, 0x94e2ea78L, 0xa5fc3c53L, 0x1e0a2df4L,
+ 0xf2f74ea7L, 0x361d2b3dL, 0x1939260fL, 0x19c27960L,
+ 0x5223a708L, 0xf71312b6L, 0xebadfe6eL, 0xeac31f66L,
+ 0xe3bc4595L, 0xa67bc883L, 0xb17f37d1L, 0x018cff28L,
+ 0xc332ddefL, 0xbe6c5aa5L, 0x65582185L, 0x68ab9802L,
+ 0xeecea50fL, 0xdb2f953bL, 0x2aef7dadL, 0x5b6e2f84L,
+ 0x1521b628L, 0x29076170L, 0xecdd4775L, 0x619f1510L,
+ 0x13cca830L, 0xeb61bd96L, 0x0334fe1eL, 0xaa0363cfL,
+ 0xb5735c90L, 0x4c70a239L, 0xd59e9e0bL, 0xcbaade14L,
+ 0xeecc86bcL, 0x60622ca7L, 0x9cab5cabL, 0xb2f3846eL,
+ 0x648b1eafL, 0x19bdf0caL, 0xa02369b9L, 0x655abb50L,
+ 0x40685a32L, 0x3c2ab4b3L, 0x319ee9d5L, 0xc021b8f7L,
+ 0x9b540b19L, 0x875fa099L, 0x95f7997eL, 0x623d7da8L,
+ 0xf837889aL, 0x97e32d77L, 0x11ed935fL, 0x16681281L,
+ 0x0e358829L, 0xc7e61fd6L, 0x96dedfa1L, 0x7858ba99L,
+ 0x57f584a5L, 0x1b227263L, 0x9b83c3ffL, 0x1ac24696L,
+ 0xcdb30aebL, 0x532e3054L, 0x8fd948e4L, 0x6dbc3128L,
+ 0x58ebf2efL, 0x34c6ffeaL, 0xfe28ed61L, 0xee7c3c73L,
+ 0x5d4a14d9L, 0xe864b7e3L, 0x42105d14L, 0x203e13e0L,
+ 0x45eee2b6L, 0xa3aaabeaL, 0xdb6c4f15L, 0xfacb4fd0L,
+ 0xc742f442L, 0xef6abbb5L, 0x654f3b1dL, 0x41cd2105L,
+ 0xd81e799eL, 0x86854dc7L, 0xe44b476aL, 0x3d816250L,
+ 0xcf62a1f2L, 0x5b8d2646L, 0xfc8883a0L, 0xc1c7b6a3L,
+ 0x7f1524c3L, 0x69cb7492L, 0x47848a0bL, 0x5692b285L,
+ 0x095bbf00L, 0xad19489dL, 0x1462b174L, 0x23820e00L,
+ 0x58428d2aL, 0x0c55f5eaL, 0x1dadf43eL, 0x233f7061L,
+ 0x3372f092L, 0x8d937e41L, 0xd65fecf1L, 0x6c223bdbL,
+ 0x7cde3759L, 0xcbee7460L, 0x4085f2a7L, 0xce77326eL,
+ 0xa6078084L, 0x19f8509eL, 0xe8efd855L, 0x61d99735L,
+ 0xa969a7aaL, 0xc50c06c2L, 0x5a04abfcL, 0x800bcadcL,
+ 0x9e447a2eL, 0xc3453484L, 0xfdd56705L, 0x0e1e9ec9L,
+ 0xdb73dbd3L, 0x105588cdL, 0x675fda79L, 0xe3674340L,
+ 0xc5c43465L, 0x713e38d8L, 0x3d28f89eL, 0xf16dff20L,
+ 0x153e21e7L, 0x8fb03d4aL, 0xe6e39f2bL, 0xdb83adf7L,
+ 0xe93d5a68L, 0x948140f7L, 0xf64c261cL, 0x94692934L,
+ 0x411520f7L, 0x7602d4f7L, 0xbcf46b2eL, 0xd4a20068L,
+ 0xd4082471L, 0x3320f46aL, 0x43b7d4b7L, 0x500061afL,
+ 0x1e39f62eL, 0x97244546L, 0x14214f74L, 0xbf8b8840L,
+ 0x4d95fc1dL, 0x96b591afL, 0x70f4ddd3L, 0x66a02f45L,
+ 0xbfbc09ecL, 0x03bd9785L, 0x7fac6dd0L, 0x31cb8504L,
+ 0x96eb27b3L, 0x55fd3941L, 0xda2547e6L, 0xabca0a9aL,
+ 0x28507825L, 0x530429f4L, 0x0a2c86daL, 0xe9b66dfbL,
+ 0x68dc1462L, 0xd7486900L, 0x680ec0a4L, 0x27a18deeL,
+ 0x4f3ffea2L, 0xe887ad8cL, 0xb58ce006L, 0x7af4d6b6L,
+ 0xaace1e7cL, 0xd3375fecL, 0xce78a399L, 0x406b2a42L,
+ 0x20fe9e35L, 0xd9f385b9L, 0xee39d7abL, 0x3b124e8bL,
+ 0x1dc9faf7L, 0x4b6d1856L, 0x26a36631L, 0xeae397b2L,
+ 0x3a6efa74L, 0xdd5b4332L, 0x6841e7f7L, 0xca7820fbL,
+ 0xfb0af54eL, 0xd8feb397L, 0x454056acL, 0xba489527L,
+ 0x55533a3aL, 0x20838d87L, 0xfe6ba9b7L, 0xd096954bL,
+ 0x55a867bcL, 0xa1159a58L, 0xcca92963L, 0x99e1db33L,
+ 0xa62a4a56L, 0x3f3125f9L, 0x5ef47e1cL, 0x9029317cL,
+ 0xfdf8e802L, 0x04272f70L, 0x80bb155cL, 0x05282ce3L,
+ 0x95c11548L, 0xe4c66d22L, 0x48c1133fL, 0xc70f86dcL,
+ 0x07f9c9eeL, 0x41041f0fL, 0x404779a4L, 0x5d886e17L,
+ 0x325f51ebL, 0xd59bc0d1L, 0xf2bcc18fL, 0x41113564L,
+ 0x257b7834L, 0x602a9c60L, 0xdff8e8a3L, 0x1f636c1bL,
+ 0x0e12b4c2L, 0x02e1329eL, 0xaf664fd1L, 0xcad18115L,
+ 0x6b2395e0L, 0x333e92e1L, 0x3b240b62L, 0xeebeb922L,
+ 0x85b2a20eL, 0xe6ba0d99L, 0xde720c8cL, 0x2da2f728L,
+ 0xd0127845L, 0x95b794fdL, 0x647d0862L, 0xe7ccf5f0L,
+ 0x5449a36fL, 0x877d48faL, 0xc39dfd27L, 0xf33e8d1eL,
+ 0x0a476341L, 0x992eff74L, 0x3a6f6eabL, 0xf4f8fd37L,
+ 0xa812dc60L, 0xa1ebddf8L, 0x991be14cL, 0xdb6e6b0dL,
+ 0xc67b5510L, 0x6d672c37L, 0x2765d43bL, 0xdcd0e804L,
+ 0xf1290dc7L, 0xcc00ffa3L, 0xb5390f92L, 0x690fed0bL,
+ 0x667b9ffbL, 0xcedb7d9cL, 0xa091cf0bL, 0xd9155ea3L,
+ 0xbb132f88L, 0x515bad24L, 0x7b9479bfL, 0x763bd6ebL,
+ 0x37392eb3L, 0xcc115979L, 0x8026e297L, 0xf42e312dL,
+ 0x6842ada7L, 0xc66a2b3bL, 0x12754cccL, 0x782ef11cL,
+ 0x6a124237L, 0xb79251e7L, 0x06a1bbe6L, 0x4bfb6350L,
+ 0x1a6b1018L, 0x11caedfaL, 0x3d25bdd8L, 0xe2e1c3c9L,
+ 0x44421659L, 0x0a121386L, 0xd90cec6eL, 0xd5abea2aL,
+ 0x64af674eL, 0xda86a85fL, 0xbebfe988L, 0x64e4c3feL,
+ 0x9dbc8057L, 0xf0f7c086L, 0x60787bf8L, 0x6003604dL,
+ 0xd1fd8346L, 0xf6381fb0L, 0x7745ae04L, 0xd736fcccL,
+ 0x83426b33L, 0xf01eab71L, 0xb0804187L, 0x3c005e5fL,
+ 0x77a057beL, 0xbde8ae24L, 0x55464299L, 0xbf582e61L,
+ 0x4e58f48fL, 0xf2ddfda2L, 0xf474ef38L, 0x8789bdc2L,
+ 0x5366f9c3L, 0xc8b38e74L, 0xb475f255L, 0x46fcd9b9L,
+ 0x7aeb2661L, 0x8b1ddf84L, 0x846a0e79L, 0x915f95e2L,
+ 0x466e598eL, 0x20b45770L, 0x8cd55591L, 0xc902de4cL,
+ 0xb90bace1L, 0xbb8205d0L, 0x11a86248L, 0x7574a99eL,
+ 0xb77f19b6L, 0xe0a9dc09L, 0x662d09a1L, 0xc4324633L,
+ 0xe85a1f02L, 0x09f0be8cL, 0x4a99a025L, 0x1d6efe10L,
+ 0x1ab93d1dL, 0x0ba5a4dfL, 0xa186f20fL, 0x2868f169L,
+ 0xdcb7da83L, 0x573906feL, 0xa1e2ce9bL, 0x4fcd7f52L,
+ 0x50115e01L, 0xa70683faL, 0xa002b5c4L, 0x0de6d027L,
+ 0x9af88c27L, 0x773f8641L, 0xc3604c06L, 0x61a806b5L,
+ 0xf0177a28L, 0xc0f586e0L, 0x006058aaL, 0x30dc7d62L,
+ 0x11e69ed7L, 0x2338ea63L, 0x53c2dd94L, 0xc2c21634L,
+ 0xbbcbee56L, 0x90bcb6deL, 0xebfc7da1L, 0xce591d76L,
+ 0x6f05e409L, 0x4b7c0188L, 0x39720a3dL, 0x7c927c24L,
+ 0x86e3725fL, 0x724d9db9L, 0x1ac15bb4L, 0xd39eb8fcL,
+ 0xed545578L, 0x08fca5b5L, 0xd83d7cd3L, 0x4dad0fc4L,
+ 0x1e50ef5eL, 0xb161e6f8L, 0xa28514d9L, 0x6c51133cL,
+ 0x6fd5c7e7L, 0x56e14ec4L, 0x362abfceL, 0xddc6c837L,
+ 0xd79a3234L, 0x92638212L, 0x670efa8eL, 0x406000e0L,
+ 0x3a39ce37L, 0xd3faf5cfL, 0xabc27737L, 0x5ac52d1bL,
+ 0x5cb0679eL, 0x4fa33742L, 0xd3822740L, 0x99bc9bbeL,
+ 0xd5118e9dL, 0xbf0f7315L, 0xd62d1c7eL, 0xc700c47bL,
+ 0xb78c1b6bL, 0x21a19045L, 0xb26eb1beL, 0x6a366eb4L,
+ 0x5748ab2fL, 0xbc946e79L, 0xc6a376d2L, 0x6549c2c8L,
+ 0x530ff8eeL, 0x468dde7dL, 0xd5730a1dL, 0x4cd04dc6L,
+ 0x2939bbdbL, 0xa9ba4650L, 0xac9526e8L, 0xbe5ee304L,
+ 0xa1fad5f0L, 0x6a2d519aL, 0x63ef8ce2L, 0x9a86ee22L,
+ 0xc089c2b8L, 0x43242ef6L, 0xa51e03aaL, 0x9cf2d0a4L,
+ 0x83c061baL, 0x9be96a4dL, 0x8fe51550L, 0xba645bd6L,
+ 0x2826a2f9L, 0xa73a3ae1L, 0x4ba99586L, 0xef5562e9L,
+ 0xc72fefd3L, 0xf752f7daL, 0x3f046f69L, 0x77fa0a59L,
+ 0x80e4a915L, 0x87b08601L, 0x9b09e6adL, 0x3b3ee593L,
+ 0xe990fd5aL, 0x9e34d797L, 0x2cf0b7d9L, 0x022b8b51L,
+ 0x96d5ac3aL, 0x017da67dL, 0xd1cf3ed6L, 0x7c7d2d28L,
+ 0x1f9f25cfL, 0xadf2b89bL, 0x5ad6b472L, 0x5a88f54cL,
+ 0xe029ac71L, 0xe019a5e6L, 0x47b0acfdL, 0xed93fa9bL,
+ 0xe8d3c48dL, 0x283b57ccL, 0xf8d56629L, 0x79132e28L,
+ 0x785f0191L, 0xed756055L, 0xf7960e44L, 0xe3d35e8cL,
+ 0x15056dd4L, 0x88f46dbaL, 0x03a16125L, 0x0564f0bdL,
+ 0xc3eb9e15L, 0x3c9057a2L, 0x97271aecL, 0xa93a072aL,
+ 0x1b3f6d9bL, 0x1e6321f5L, 0xf59c66fbL, 0x26dcf319L,
+ 0x7533d928L, 0xb155fdf5L, 0x03563482L, 0x8aba3cbbL,
+ 0x28517711L, 0xc20ad9f8L, 0xabcc5167L, 0xccad925fL,
+ 0x4de81751L, 0x3830dc8eL, 0x379d5862L, 0x9320f991L,
+ 0xea7a90c2L, 0xfb3e7bceL, 0x5121ce64L, 0x774fbe32L,
+ 0xa8b6e37eL, 0xc3293d46L, 0x48de5369L, 0x6413e680L,
+ 0xa2ae0810L, 0xdd6db224L, 0x69852dfdL, 0x09072166L,
+ 0xb39a460aL, 0x6445c0ddL, 0x586cdecfL, 0x1c20c8aeL,
+ 0x5bbef7ddL, 0x1b588d40L, 0xccd2017fL, 0x6bb4e3bbL,
+ 0xdda26a7eL, 0x3a59ff45L, 0x3e350a44L, 0xbcb4cdd5L,
+ 0x72eacea8L, 0xfa6484bbL, 0x8d6612aeL, 0xbf3c6f47L,
+ 0xd29be463L, 0x542f5d9eL, 0xaec2771bL, 0xf64e6370L,
+ 0x740e0d8dL, 0xe75b1357L, 0xf8721671L, 0xaf537d5dL,
+ 0x4040cb08L, 0x4eb4e2ccL, 0x34d2466aL, 0x0115af84L,
+ 0xe1b00428L, 0x95983a1dL, 0x06b89fb4L, 0xce6ea048L,
+ 0x6f3f3b82L, 0x3520ab82L, 0x011a1d4bL, 0x277227f8L,
+ 0x611560b1L, 0xe7933fdcL, 0xbb3a792bL, 0x344525bdL,
+ 0xa08839e1L, 0x51ce794bL, 0x2f32c9b7L, 0xa01fbac9L,
+ 0xe01cc87eL, 0xbcc7d1f6L, 0xcf0111c3L, 0xa1e8aac7L,
+ 0x1a908749L, 0xd44fbd9aL, 0xd0dadecbL, 0xd50ada38L,
+ 0x0339c32aL, 0xc6913667L, 0x8df9317cL, 0xe0b12b4fL,
+ 0xf79e59b7L, 0x43f5bb3aL, 0xf2d519ffL, 0x27d9459cL,
+ 0xbf97222cL, 0x15e6fc2aL, 0x0f91fc71L, 0x9b941525L,
+ 0xfae59361L, 0xceb69cebL, 0xc2a86459L, 0x12baa8d1L,
+ 0xb6c1075eL, 0xe3056a0cL, 0x10d25065L, 0xcb03a442L,
+ 0xe0ec6e0eL, 0x1698db3bL, 0x4c98a0beL, 0x3278e964L,
+ 0x9f1f9532L, 0xe0d392dfL, 0xd3a0342bL, 0x8971f21eL,
+ 0x1b0a7441L, 0x4ba3348cL, 0xc5be7120L, 0xc37632d8L,
+ 0xdf359f8dL, 0x9b992f2eL, 0xe60b6f47L, 0x0fe3f11dL,
+ 0xe54cda54L, 0x1edad891L, 0xce6279cfL, 0xcd3e7e6fL,
+ 0x1618b166L, 0xfd2c1d05L, 0x848fd2c5L, 0xf6fb2299L,
+ 0xf523f357L, 0xa6327623L, 0x93a83531L, 0x56cccd02L,
+ 0xacf08162L, 0x5a75ebb5L, 0x6e163697L, 0x88d273ccL,
+ 0xde966292L, 0x81b949d0L, 0x4c50901bL, 0x71c65614L,
+ 0xe6c6c7bdL, 0x327a140aL, 0x45e1d006L, 0xc3f27b9aL,
+ 0xc9aa53fdL, 0x62a80f00L, 0xbb25bfe2L, 0x35bdd2f6L,
+ 0x71126905L, 0xb2040222L, 0xb6cbcf7cL, 0xcd769c2bL,
+ 0x53113ec0L, 0x1640e3d3L, 0x38abbd60L, 0x2547adf0L,
+ 0xba38209cL, 0xf746ce76L, 0x77afa1c5L, 0x20756060L,
+ 0x85cbfe4eL, 0x8ae88dd8L, 0x7aaaf9b0L, 0x4cf9aa7eL,
+ 0x1948c25cL, 0x02fb8a8cL, 0x01c36ae4L, 0xd6ebe1f9L,
+ 0x90d4f869L, 0xa65cdea0L, 0x3f09252dL, 0xc208e69fL,
+ 0xb74e6132L, 0xce77e25bL, 0x578fdfe3L, 0x3ac372e6L,
+ }
+ };
+
diff --git a/src/libcrypto/libblowfish/bf_skey.c b/src/libcrypto/libblowfish/bf_skey.c
new file mode 100644
index 000000000..8cdbbd283
--- /dev/null
+++ b/src/libcrypto/libblowfish/bf_skey.c
@@ -0,0 +1,122 @@
+/* crypto/bf/bf_skey.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#include <linux/string.h>
+#else
+#include <stdio.h>
+#include <string.h>
+#endif
+
+#include "blowfish.h"
+#include "bf_locl.h"
+#include "bf_pi.h"
+
+void BF_set_key(BF_KEY *key, int len, const unsigned char *data)
+ {
+ int i;
+ BF_LONG *p,ri,in[2];
+ const unsigned char *d,*end;
+
+
+ memcpy((char *)key,(const char *)&bf_init,sizeof(BF_KEY));
+ p=key->P;
+
+ if (len > ((BF_ROUNDS+2)*4)) len=(BF_ROUNDS+2)*4;
+
+ d=data;
+ end= &(data[len]);
+ for (i=0; i<(BF_ROUNDS+2); i++)
+ {
+ ri= *(d++);
+ if (d >= end) d=data;
+
+ ri<<=8;
+ ri|= *(d++);
+ if (d >= end) d=data;
+
+ ri<<=8;
+ ri|= *(d++);
+ if (d >= end) d=data;
+
+ ri<<=8;
+ ri|= *(d++);
+ if (d >= end) d=data;
+
+ p[i]^=ri;
+ }
+
+ in[0]=0L;
+ in[1]=0L;
+ for (i=0; i<(BF_ROUNDS+2); i+=2)
+ {
+ BF_encrypt(in,key);
+ p[i ]=in[0];
+ p[i+1]=in[1];
+ }
+
+ p=key->S;
+ for (i=0; i<4*256; i+=2)
+ {
+ BF_encrypt(in,key);
+ p[i ]=in[0];
+ p[i+1]=in[1];
+ }
+ }
+
diff --git a/src/libcrypto/libblowfish/blowfish.h b/src/libcrypto/libblowfish/blowfish.h
new file mode 100644
index 000000000..ccb97e272
--- /dev/null
+++ b/src/libcrypto/libblowfish/blowfish.h
@@ -0,0 +1,133 @@
+/* crypto/bf/blowfish.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_BLOWFISH_H
+#define HEADER_BLOWFISH_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef NO_BF
+#error BF is disabled.
+#endif
+
+#define BF_ENCRYPT 1
+#define BF_DECRYPT 0
+
+/*
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * ! BF_LONG has to be at least 32 bits wide. If it's wider, then !
+ * ! BF_LONG_LOG2 has to be defined along. !
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ */
+
+#if defined(WIN16) || defined(__LP32__)
+#define BF_LONG unsigned long
+#elif defined(_CRAY) || defined(__ILP64__)
+#define BF_LONG unsigned long
+#define BF_LONG_LOG2 3
+#endif
+/*
+ * _CRAY note. I could declare short, but I have no idea what impact
+ * does it have on performance on none-T3E machines. I could declare
+ * int, but at least on C90 sizeof(int) can be chosen at compile time.
+ * So I've chosen long...
+ * <appro@fy.chalmers.se>
+ */
+
+/* des.h-like hack <jjo-ipsec@mendoza.gov.ar> */
+#ifndef BF_LONG
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <sys/types.h>
+#endif
+#define BF_LONG u_int32_t
+#endif
+
+#define BF_ROUNDS 16
+#define BF_BLOCK 8
+
+typedef struct bf_key_st
+ {
+ BF_LONG P[BF_ROUNDS+2];
+ BF_LONG S[4*256];
+ } BF_KEY;
+
+
+void BF_set_key(BF_KEY *key, int len, const unsigned char *data);
+
+void BF_encrypt(BF_LONG *data,const BF_KEY *key);
+void BF_decrypt(BF_LONG *data,const BF_KEY *key);
+
+void BF_ecb_encrypt(const unsigned char *in, unsigned char *out,
+ const BF_KEY *key, int enc);
+void BF_cbc_encrypt(const unsigned char *in, unsigned char *out, long length,
+ const BF_KEY *schedule, unsigned char *ivec, int enc);
+void BF_cfb64_encrypt(const unsigned char *in, unsigned char *out, long length,
+ const BF_KEY *schedule, unsigned char *ivec, int *num, int enc);
+void BF_ofb64_encrypt(const unsigned char *in, unsigned char *out, long length,
+ const BF_KEY *schedule, unsigned char *ivec, int *num);
+const char *BF_options(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libcrypto/libdes/cbc_enc.c b/src/libcrypto/libdes/cbc_enc.c
new file mode 100644
index 000000000..a06f9f99e
--- /dev/null
+++ b/src/libcrypto/libdes/cbc_enc.c
@@ -0,0 +1,135 @@
+/* crypto/des/cbc_enc.c */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include "des_locl.h"
+
+void des_cbc_encrypt(input, output, length, schedule, ivec, enc)
+des_cblock (*input);
+des_cblock (*output);
+long length;
+des_key_schedule schedule;
+des_cblock (*ivec);
+int enc;
+ {
+ register DES_LONG tin0,tin1;
+ register DES_LONG tout0,tout1,xor0,xor1;
+ register unsigned char *in,*out;
+ register long l=length;
+ DES_LONG tin[2];
+ unsigned char *iv;
+
+ in=(unsigned char *)input;
+ out=(unsigned char *)output;
+ iv=(unsigned char *)ivec;
+
+ if (enc)
+ {
+ c2l(iv,tout0);
+ c2l(iv,tout1);
+ for (l-=8; l>=0; l-=8)
+ {
+ c2l(in,tin0);
+ c2l(in,tin1);
+ tin0^=tout0; tin[0]=tin0;
+ tin1^=tout1; tin[1]=tin1;
+ des_encrypt((DES_LONG *)tin,schedule,DES_ENCRYPT);
+ tout0=tin[0]; l2c(tout0,out);
+ tout1=tin[1]; l2c(tout1,out);
+ }
+ if (l != -8)
+ {
+ c2ln(in,tin0,tin1,l+8);
+ tin0^=tout0; tin[0]=tin0;
+ tin1^=tout1; tin[1]=tin1;
+ des_encrypt((DES_LONG *)tin,schedule,DES_ENCRYPT);
+ tout0=tin[0]; l2c(tout0,out);
+ tout1=tin[1]; l2c(tout1,out);
+ }
+ }
+ else
+ {
+ c2l(iv,xor0);
+ c2l(iv,xor1);
+ for (l-=8; l>=0; l-=8)
+ {
+ c2l(in,tin0); tin[0]=tin0;
+ c2l(in,tin1); tin[1]=tin1;
+ des_encrypt((DES_LONG *)tin,schedule,DES_DECRYPT);
+ tout0=tin[0]^xor0;
+ tout1=tin[1]^xor1;
+ l2c(tout0,out);
+ l2c(tout1,out);
+ xor0=tin0;
+ xor1=tin1;
+ }
+ if (l != -8)
+ {
+ c2l(in,tin0); tin[0]=tin0;
+ c2l(in,tin1); tin[1]=tin1;
+ des_encrypt((DES_LONG *)tin,schedule,DES_DECRYPT);
+ tout0=tin[0]^xor0;
+ tout1=tin[1]^xor1;
+ l2cn(tout0,tout1,out,l+8);
+ /* xor0=tin0;
+ xor1=tin1; */
+ }
+ }
+ tin0=tin1=tout0=tout1=xor0=xor1=0;
+ tin[0]=tin[1]=0;
+ }
+
diff --git a/src/libcrypto/libdes/des.h b/src/libcrypto/libdes/des.h
new file mode 100644
index 000000000..baddf8647
--- /dev/null
+++ b/src/libcrypto/libdes/des.h
@@ -0,0 +1,308 @@
+/* crypto/des/des.org */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+/* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+ *
+ * Always modify des.org since des.h is automatically generated from
+ * it during SSLeay configuration.
+ *
+ * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+ */
+
+#ifndef HEADER_DES_H
+#define HEADER_DES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* If this is set to 'unsigned int' on a DEC Alpha, this gives about a
+ * %20 speed up (longs are 8 bytes, int's are 4). */
+/* Must be unsigned int on ia64/Itanium or DES breaks badly */
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <sys/types.h>
+#endif
+
+#ifndef DES_LONG
+#define DES_LONG u_int32_t
+#endif
+
+typedef unsigned char des_cblock[8];
+typedef struct des_ks_struct
+ {
+ union {
+ des_cblock _;
+ /* make sure things are correct size on machines with
+ * 8 byte longs */
+ DES_LONG pad[2];
+ } ks;
+#undef _
+#define _ ks._
+ } des_key_schedule[16];
+
+#define DES_KEY_SZ (sizeof(des_cblock))
+#define DES_SCHEDULE_SZ (sizeof(des_key_schedule))
+
+#define DES_ENCRYPT 1
+#define DES_DECRYPT 0
+
+#define DES_CBC_MODE 0
+#define DES_PCBC_MODE 1
+
+#define des_ecb2_encrypt(i,o,k1,k2,e) \
+ des_ecb3_encrypt((i),(o),(k1),(k2),(k1),(e))
+
+#define des_ede2_cbc_encrypt(i,o,l,k1,k2,iv,e) \
+ des_ede3_cbc_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(e))
+
+#define des_ede2_cfb64_encrypt(i,o,l,k1,k2,iv,n,e) \
+ des_ede3_cfb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n),(e))
+
+#define des_ede2_ofb64_encrypt(i,o,l,k1,k2,iv,n) \
+ des_ede3_ofb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n))
+
+#define C_Block des_cblock
+#define Key_schedule des_key_schedule
+#ifdef KERBEROS
+#define ENCRYPT DES_ENCRYPT
+#define DECRYPT DES_DECRYPT
+#endif
+#define KEY_SZ DES_KEY_SZ
+#define string_to_key des_string_to_key
+#define read_pw_string des_read_pw_string
+#define random_key des_random_key
+#define pcbc_encrypt des_pcbc_encrypt
+#define set_key des_set_key
+#define key_sched des_key_sched
+#define ecb_encrypt des_ecb_encrypt
+#define cbc_encrypt des_cbc_encrypt
+#define ncbc_encrypt des_ncbc_encrypt
+#define xcbc_encrypt des_xcbc_encrypt
+#define cbc_cksum des_cbc_cksum
+#define quad_cksum des_quad_cksum
+
+/* For compatibility with the MIT lib - eay 20/05/92 */
+typedef des_key_schedule bit_64;
+#define des_fixup_key_parity des_set_odd_parity
+#define des_check_key_parity check_parity
+
+extern int des_check_key; /* defaults to false */
+extern int des_rw_mode; /* defaults to DES_PCBC_MODE */
+
+/* The next line is used to disable full ANSI prototypes, if your
+ * compiler has problems with the prototypes, make sure this line always
+ * evaluates to true :-) */
+#if defined(MSDOS) || defined(__STDC__)
+#undef NOPROTO
+#endif
+#ifndef NOPROTO
+char *des_options(void);
+void des_ecb3_encrypt(des_cblock *input,des_cblock *output,
+ des_key_schedule ks1,des_key_schedule ks2,
+ des_key_schedule ks3, int enc);
+DES_LONG des_cbc_cksum(des_cblock *input,des_cblock *output,
+ long length,des_key_schedule schedule,des_cblock *ivec);
+void des_cbc_encrypt(des_cblock *input,des_cblock *output,long length,
+ des_key_schedule schedule,des_cblock *ivec,int enc);
+void des_ncbc_encrypt(des_cblock *input,des_cblock *output,long length,
+ des_key_schedule schedule,des_cblock *ivec,int enc);
+void des_xcbc_encrypt(des_cblock *input,des_cblock *output,long length,
+ des_key_schedule schedule,des_cblock *ivec,
+ des_cblock *inw,des_cblock *outw,int enc);
+void des_cfb_encrypt(unsigned char *in,unsigned char *out,int numbits,
+ long length,des_key_schedule schedule,des_cblock *ivec,int enc);
+void des_ecb_encrypt(des_cblock *input,des_cblock *output,
+ des_key_schedule ks,int enc);
+void des_encrypt(DES_LONG *data,des_key_schedule ks, int enc);
+void des_encrypt2(DES_LONG *data,des_key_schedule ks, int enc);
+void des_encrypt3(DES_LONG *data, des_key_schedule ks1,
+ des_key_schedule ks2, des_key_schedule ks3);
+void des_decrypt3(DES_LONG *data, des_key_schedule ks1,
+ des_key_schedule ks2, des_key_schedule ks3);
+void des_ede3_cbc_encrypt(des_cblock *input, des_cblock *output,
+ long length, des_key_schedule ks1, des_key_schedule ks2,
+ des_key_schedule ks3, des_cblock *ivec, int enc);
+void des_ede3_cfb64_encrypt(unsigned char *in, unsigned char *out,
+ long length, des_key_schedule ks1, des_key_schedule ks2,
+ des_key_schedule ks3, des_cblock *ivec, int *num, int enc);
+void des_ede3_ofb64_encrypt(unsigned char *in, unsigned char *out,
+ long length, des_key_schedule ks1, des_key_schedule ks2,
+ des_key_schedule ks3, des_cblock *ivec, int *num);
+
+void des_xwhite_in2out(des_cblock (*des_key), des_cblock (*in_white),
+ des_cblock (*out_white));
+
+int des_enc_read(int fd,char *buf,int len,des_key_schedule sched,
+ des_cblock *iv);
+int des_enc_write(int fd,char *buf,int len,des_key_schedule sched,
+ des_cblock *iv);
+char *des_fcrypt(const char *buf,const char *salt, char *ret);
+#ifdef PERL5
+char *des_crypt(const char *buf,const char *salt);
+#else
+/* some stupid compilers complain because I have declared char instead
+ * of const char */
+#ifndef __KERNEL__
+#ifdef HEADER_DES_LOCL_H
+char *crypt(const char *buf,const char *salt);
+#else /* HEADER_DES_LOCL_H */
+char *crypt(void);
+#endif /* HEADER_DES_LOCL_H */
+#endif /* __KERNEL__ */
+#endif /* PERL5 */
+void des_ofb_encrypt(unsigned char *in,unsigned char *out,
+ int numbits,long length,des_key_schedule schedule,des_cblock *ivec);
+void des_pcbc_encrypt(des_cblock *input,des_cblock *output,long length,
+ des_key_schedule schedule,des_cblock *ivec,int enc);
+DES_LONG des_quad_cksum(des_cblock *input,des_cblock *output,
+ long length,int out_count,des_cblock *seed);
+void des_random_seed(des_cblock key);
+void des_random_key(des_cblock ret);
+int des_read_password(des_cblock *key,char *prompt,int verify);
+int des_read_2passwords(des_cblock *key1,des_cblock *key2,
+ char *prompt,int verify);
+int des_read_pw_string(char *buf,int length,char *prompt,int verify);
+void des_set_odd_parity(des_cblock *key);
+int des_is_weak_key(des_cblock *key);
+int des_set_key(des_cblock *key,des_key_schedule schedule);
+int des_key_sched(des_cblock *key,des_key_schedule schedule);
+void des_string_to_key(char *str,des_cblock *key);
+void des_string_to_2keys(char *str,des_cblock *key1,des_cblock *key2);
+void des_cfb64_encrypt(unsigned char *in, unsigned char *out, long length,
+ des_key_schedule schedule, des_cblock *ivec, int *num, int enc);
+void des_ofb64_encrypt(unsigned char *in, unsigned char *out, long length,
+ des_key_schedule schedule, des_cblock *ivec, int *num);
+int des_read_pw(char *buf, char *buff, int size, char *prompt, int verify);
+
+/* Extra functions from Mark Murray <mark@grondar.za> */
+/* The following functions are not in the normal unix build or the
+ * SSLeay build. When using the SSLeay build, use RAND_seed()
+ * and RAND_bytes() instead. */
+int des_new_random_key(des_cblock *key);
+void des_init_random_number_generator(des_cblock *key);
+void des_set_random_generator_seed(des_cblock *key);
+void des_set_sequence_number(des_cblock new_sequence_number);
+void des_generate_random_block(des_cblock *block);
+
+#else
+
+char *des_options();
+void des_ecb3_encrypt();
+DES_LONG des_cbc_cksum();
+void des_cbc_encrypt();
+void des_ncbc_encrypt();
+void des_xcbc_encrypt();
+void des_cfb_encrypt();
+void des_ede3_cfb64_encrypt();
+void des_ede3_ofb64_encrypt();
+void des_ecb_encrypt();
+void des_encrypt();
+void des_encrypt2();
+void des_encrypt3();
+void des_decrypt3();
+void des_ede3_cbc_encrypt();
+int des_enc_read();
+int des_enc_write();
+char *des_fcrypt();
+#ifdef PERL5
+char *des_crypt();
+#else
+char *crypt();
+#endif
+void des_ofb_encrypt();
+void des_pcbc_encrypt();
+DES_LONG des_quad_cksum();
+void des_random_seed();
+void des_random_key();
+int des_read_password();
+int des_read_2passwords();
+int des_read_pw_string();
+void des_set_odd_parity();
+int des_is_weak_key();
+int des_set_key();
+int des_key_sched();
+void des_string_to_key();
+void des_string_to_2keys();
+void des_cfb64_encrypt();
+void des_ofb64_encrypt();
+int des_read_pw();
+void des_xwhite_in2out();
+
+/* Extra functions from Mark Murray <mark@grondar.za> */
+/* The following functions are not in the normal unix build or the
+ * SSLeay build. When using the SSLeay build, use RAND_seed()
+ * and RAND_bytes() instead. */
+#ifdef FreeBSD
+int des_new_random_key();
+void des_init_random_number_generator();
+void des_set_random_generator_seed();
+void des_set_sequence_number();
+void des_generate_random_block();
+#endif
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libcrypto/libdes/des_enc.c b/src/libcrypto/libdes/des_enc.c
new file mode 100644
index 000000000..1e1906d25
--- /dev/null
+++ b/src/libcrypto/libdes/des_enc.c
@@ -0,0 +1,502 @@
+/* crypto/des/des_enc.c */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include "des_locl.h"
+
+void des_encrypt(data, ks, enc)
+DES_LONG *data;
+des_key_schedule ks;
+int enc;
+ {
+ register DES_LONG l,r,t,u;
+#ifdef DES_PTR
+ register unsigned char *des_SP=(unsigned char *)des_SPtrans;
+#endif
+#ifndef DES_UNROLL
+ register int i;
+#endif
+ register DES_LONG *s;
+
+ r=data[0];
+ l=data[1];
+
+ IP(r,l);
+ /* Things have been modified so that the initial rotate is
+ * done outside the loop. This required the
+ * des_SPtrans values in sp.h to be rotated 1 bit to the right.
+ * One perl script later and things have a 5% speed up on a sparc2.
+ * Thanks to Richard Outerbridge <71755.204@CompuServe.COM>
+ * for pointing this out. */
+ /* clear the top bits on machines with 8byte longs */
+ /* shift left by 2 */
+ r=ROTATE(r,29)&0xffffffffL;
+ l=ROTATE(l,29)&0xffffffffL;
+
+ s=(DES_LONG *)ks;
+ /* I don't know if it is worth the effort of loop unrolling the
+ * inner loop */
+ if (enc)
+ {
+#ifdef DES_UNROLL
+ D_ENCRYPT(l,r, 0); /* 1 */
+ D_ENCRYPT(r,l, 2); /* 2 */
+ D_ENCRYPT(l,r, 4); /* 3 */
+ D_ENCRYPT(r,l, 6); /* 4 */
+ D_ENCRYPT(l,r, 8); /* 5 */
+ D_ENCRYPT(r,l,10); /* 6 */
+ D_ENCRYPT(l,r,12); /* 7 */
+ D_ENCRYPT(r,l,14); /* 8 */
+ D_ENCRYPT(l,r,16); /* 9 */
+ D_ENCRYPT(r,l,18); /* 10 */
+ D_ENCRYPT(l,r,20); /* 11 */
+ D_ENCRYPT(r,l,22); /* 12 */
+ D_ENCRYPT(l,r,24); /* 13 */
+ D_ENCRYPT(r,l,26); /* 14 */
+ D_ENCRYPT(l,r,28); /* 15 */
+ D_ENCRYPT(r,l,30); /* 16 */
+#else
+ for (i=0; i<32; i+=8)
+ {
+ D_ENCRYPT(l,r,i+0); /* 1 */
+ D_ENCRYPT(r,l,i+2); /* 2 */
+ D_ENCRYPT(l,r,i+4); /* 3 */
+ D_ENCRYPT(r,l,i+6); /* 4 */
+ }
+#endif
+ }
+ else
+ {
+#ifdef DES_UNROLL
+ D_ENCRYPT(l,r,30); /* 16 */
+ D_ENCRYPT(r,l,28); /* 15 */
+ D_ENCRYPT(l,r,26); /* 14 */
+ D_ENCRYPT(r,l,24); /* 13 */
+ D_ENCRYPT(l,r,22); /* 12 */
+ D_ENCRYPT(r,l,20); /* 11 */
+ D_ENCRYPT(l,r,18); /* 10 */
+ D_ENCRYPT(r,l,16); /* 9 */
+ D_ENCRYPT(l,r,14); /* 8 */
+ D_ENCRYPT(r,l,12); /* 7 */
+ D_ENCRYPT(l,r,10); /* 6 */
+ D_ENCRYPT(r,l, 8); /* 5 */
+ D_ENCRYPT(l,r, 6); /* 4 */
+ D_ENCRYPT(r,l, 4); /* 3 */
+ D_ENCRYPT(l,r, 2); /* 2 */
+ D_ENCRYPT(r,l, 0); /* 1 */
+#else
+ for (i=30; i>0; i-=8)
+ {
+ D_ENCRYPT(l,r,i-0); /* 16 */
+ D_ENCRYPT(r,l,i-2); /* 15 */
+ D_ENCRYPT(l,r,i-4); /* 14 */
+ D_ENCRYPT(r,l,i-6); /* 13 */
+ }
+#endif
+ }
+
+ /* rotate and clear the top bits on machines with 8byte longs */
+ l=ROTATE(l,3)&0xffffffffL;
+ r=ROTATE(r,3)&0xffffffffL;
+
+ FP(r,l);
+ data[0]=l;
+ data[1]=r;
+ l=r=t=u=0;
+ }
+
+void des_encrypt2(data, ks, enc)
+DES_LONG *data;
+des_key_schedule ks;
+int enc;
+ {
+ register DES_LONG l,r,t,u;
+#ifdef DES_PTR
+ register unsigned char *des_SP=(unsigned char *)des_SPtrans;
+#endif
+#ifndef DES_UNROLL
+ register int i;
+#endif
+ register DES_LONG *s;
+
+ r=data[0];
+ l=data[1];
+
+ /* Things have been modified so that the initial rotate is
+ * done outside the loop. This required the
+ * des_SPtrans values in sp.h to be rotated 1 bit to the right.
+ * One perl script later and things have a 5% speed up on a sparc2.
+ * Thanks to Richard Outerbridge <71755.204@CompuServe.COM>
+ * for pointing this out. */
+ /* clear the top bits on machines with 8byte longs */
+ r=ROTATE(r,29)&0xffffffffL;
+ l=ROTATE(l,29)&0xffffffffL;
+
+ s=(DES_LONG *)ks;
+ /* I don't know if it is worth the effort of loop unrolling the
+ * inner loop */
+ if (enc)
+ {
+#ifdef DES_UNROLL
+ D_ENCRYPT(l,r, 0); /* 1 */
+ D_ENCRYPT(r,l, 2); /* 2 */
+ D_ENCRYPT(l,r, 4); /* 3 */
+ D_ENCRYPT(r,l, 6); /* 4 */
+ D_ENCRYPT(l,r, 8); /* 5 */
+ D_ENCRYPT(r,l,10); /* 6 */
+ D_ENCRYPT(l,r,12); /* 7 */
+ D_ENCRYPT(r,l,14); /* 8 */
+ D_ENCRYPT(l,r,16); /* 9 */
+ D_ENCRYPT(r,l,18); /* 10 */
+ D_ENCRYPT(l,r,20); /* 11 */
+ D_ENCRYPT(r,l,22); /* 12 */
+ D_ENCRYPT(l,r,24); /* 13 */
+ D_ENCRYPT(r,l,26); /* 14 */
+ D_ENCRYPT(l,r,28); /* 15 */
+ D_ENCRYPT(r,l,30); /* 16 */
+#else
+ for (i=0; i<32; i+=8)
+ {
+ D_ENCRYPT(l,r,i+0); /* 1 */
+ D_ENCRYPT(r,l,i+2); /* 2 */
+ D_ENCRYPT(l,r,i+4); /* 3 */
+ D_ENCRYPT(r,l,i+6); /* 4 */
+ }
+#endif
+ }
+ else
+ {
+#ifdef DES_UNROLL
+ D_ENCRYPT(l,r,30); /* 16 */
+ D_ENCRYPT(r,l,28); /* 15 */
+ D_ENCRYPT(l,r,26); /* 14 */
+ D_ENCRYPT(r,l,24); /* 13 */
+ D_ENCRYPT(l,r,22); /* 12 */
+ D_ENCRYPT(r,l,20); /* 11 */
+ D_ENCRYPT(l,r,18); /* 10 */
+ D_ENCRYPT(r,l,16); /* 9 */
+ D_ENCRYPT(l,r,14); /* 8 */
+ D_ENCRYPT(r,l,12); /* 7 */
+ D_ENCRYPT(l,r,10); /* 6 */
+ D_ENCRYPT(r,l, 8); /* 5 */
+ D_ENCRYPT(l,r, 6); /* 4 */
+ D_ENCRYPT(r,l, 4); /* 3 */
+ D_ENCRYPT(l,r, 2); /* 2 */
+ D_ENCRYPT(r,l, 0); /* 1 */
+#else
+ for (i=30; i>0; i-=8)
+ {
+ D_ENCRYPT(l,r,i-0); /* 16 */
+ D_ENCRYPT(r,l,i-2); /* 15 */
+ D_ENCRYPT(l,r,i-4); /* 14 */
+ D_ENCRYPT(r,l,i-6); /* 13 */
+ }
+#endif
+ }
+ /* rotate and clear the top bits on machines with 8byte longs */
+ data[0]=ROTATE(l,3)&0xffffffffL;
+ data[1]=ROTATE(r,3)&0xffffffffL;
+ l=r=t=u=0;
+ }
+
+void des_encrypt3(data,ks1,ks2,ks3)
+DES_LONG *data;
+des_key_schedule ks1;
+des_key_schedule ks2;
+des_key_schedule ks3;
+ {
+ register DES_LONG l,r;
+
+ l=data[0];
+ r=data[1];
+ IP(l,r);
+ data[0]=l;
+ data[1]=r;
+ des_encrypt2((DES_LONG *)data,ks1,DES_ENCRYPT);
+ des_encrypt2((DES_LONG *)data,ks2,DES_DECRYPT);
+ des_encrypt2((DES_LONG *)data,ks3,DES_ENCRYPT);
+ l=data[0];
+ r=data[1];
+ FP(r,l);
+ data[0]=l;
+ data[1]=r;
+ }
+
+void des_decrypt3(data,ks1,ks2,ks3)
+DES_LONG *data;
+des_key_schedule ks1;
+des_key_schedule ks2;
+des_key_schedule ks3;
+ {
+ register DES_LONG l,r;
+
+ l=data[0];
+ r=data[1];
+ IP(l,r);
+ data[0]=l;
+ data[1]=r;
+ des_encrypt2((DES_LONG *)data,ks3,DES_DECRYPT);
+ des_encrypt2((DES_LONG *)data,ks2,DES_ENCRYPT);
+ des_encrypt2((DES_LONG *)data,ks1,DES_DECRYPT);
+ l=data[0];
+ r=data[1];
+ FP(r,l);
+ data[0]=l;
+ data[1]=r;
+ }
+
+#ifndef DES_DEFAULT_OPTIONS
+
+void des_ncbc_encrypt(input, output, length, schedule, ivec, enc)
+des_cblock (*input);
+des_cblock (*output);
+long length;
+des_key_schedule schedule;
+des_cblock (*ivec);
+int enc;
+ {
+ register DES_LONG tin0,tin1;
+ register DES_LONG tout0,tout1,xor0,xor1;
+ register unsigned char *in,*out;
+ register long l=length;
+ DES_LONG tin[2];
+ unsigned char *iv;
+
+ in=(unsigned char *)input;
+ out=(unsigned char *)output;
+ iv=(unsigned char *)ivec;
+
+ if (enc)
+ {
+ c2l(iv,tout0);
+ c2l(iv,tout1);
+ for (l-=8; l>=0; l-=8)
+ {
+ c2l(in,tin0);
+ c2l(in,tin1);
+ tin0^=tout0; tin[0]=tin0;
+ tin1^=tout1; tin[1]=tin1;
+ des_encrypt((DES_LONG *)tin,schedule,DES_ENCRYPT);
+ tout0=tin[0]; l2c(tout0,out);
+ tout1=tin[1]; l2c(tout1,out);
+ }
+ if (l != -8)
+ {
+ c2ln(in,tin0,tin1,l+8);
+ tin0^=tout0; tin[0]=tin0;
+ tin1^=tout1; tin[1]=tin1;
+ des_encrypt((DES_LONG *)tin,schedule,DES_ENCRYPT);
+ tout0=tin[0]; l2c(tout0,out);
+ tout1=tin[1]; l2c(tout1,out);
+ }
+ iv=(unsigned char *)ivec;
+ l2c(tout0,iv);
+ l2c(tout1,iv);
+ }
+ else
+ {
+ c2l(iv,xor0);
+ c2l(iv,xor1);
+ for (l-=8; l>=0; l-=8)
+ {
+ c2l(in,tin0); tin[0]=tin0;
+ c2l(in,tin1); tin[1]=tin1;
+ des_encrypt((DES_LONG *)tin,schedule,DES_DECRYPT);
+ tout0=tin[0]^xor0;
+ tout1=tin[1]^xor1;
+ l2c(tout0,out);
+ l2c(tout1,out);
+ xor0=tin0;
+ xor1=tin1;
+ }
+ if (l != -8)
+ {
+ c2l(in,tin0); tin[0]=tin0;
+ c2l(in,tin1); tin[1]=tin1;
+ des_encrypt((DES_LONG *)tin,schedule,DES_DECRYPT);
+ tout0=tin[0]^xor0;
+ tout1=tin[1]^xor1;
+ l2cn(tout0,tout1,out,l+8);
+ xor0=tin0;
+ xor1=tin1;
+ }
+
+ iv=(unsigned char *)ivec;
+ l2c(xor0,iv);
+ l2c(xor1,iv);
+ }
+ tin0=tin1=tout0=tout1=xor0=xor1=0;
+ tin[0]=tin[1]=0;
+ }
+
+void des_ede3_cbc_encrypt(input, output, length, ks1, ks2, ks3, ivec, enc)
+des_cblock (*input);
+des_cblock (*output);
+long length;
+des_key_schedule ks1;
+des_key_schedule ks2;
+des_key_schedule ks3;
+des_cblock (*ivec);
+int enc;
+ {
+ register DES_LONG tin0,tin1;
+ register DES_LONG tout0,tout1,xor0,xor1;
+ register unsigned char *in,*out;
+ register long l=length;
+ DES_LONG tin[2];
+ unsigned char *iv;
+
+ in=(unsigned char *)input;
+ out=(unsigned char *)output;
+ iv=(unsigned char *)ivec;
+
+ if (enc)
+ {
+ c2l(iv,tout0);
+ c2l(iv,tout1);
+ for (l-=8; l>=0; l-=8)
+ {
+ c2l(in,tin0);
+ c2l(in,tin1);
+ tin0^=tout0;
+ tin1^=tout1;
+
+ tin[0]=tin0;
+ tin[1]=tin1;
+ des_encrypt3((DES_LONG *)tin,ks1,ks2,ks3);
+ tout0=tin[0];
+ tout1=tin[1];
+
+ l2c(tout0,out);
+ l2c(tout1,out);
+ }
+ if (l != -8)
+ {
+ c2ln(in,tin0,tin1,l+8);
+ tin0^=tout0;
+ tin1^=tout1;
+
+ tin[0]=tin0;
+ tin[1]=tin1;
+ des_encrypt3((DES_LONG *)tin,ks1,ks2,ks3);
+ tout0=tin[0];
+ tout1=tin[1];
+
+ l2c(tout0,out);
+ l2c(tout1,out);
+ }
+ iv=(unsigned char *)ivec;
+ l2c(tout0,iv);
+ l2c(tout1,iv);
+ }
+ else
+ {
+ register DES_LONG t0,t1;
+
+ c2l(iv,xor0);
+ c2l(iv,xor1);
+ for (l-=8; l>=0; l-=8)
+ {
+ c2l(in,tin0);
+ c2l(in,tin1);
+
+ t0=tin0;
+ t1=tin1;
+
+ tin[0]=tin0;
+ tin[1]=tin1;
+ des_decrypt3((DES_LONG *)tin,ks1,ks2,ks3);
+ tout0=tin[0];
+ tout1=tin[1];
+
+ tout0^=xor0;
+ tout1^=xor1;
+ l2c(tout0,out);
+ l2c(tout1,out);
+ xor0=t0;
+ xor1=t1;
+ }
+ if (l != -8)
+ {
+ c2l(in,tin0);
+ c2l(in,tin1);
+
+ t0=tin0;
+ t1=tin1;
+
+ tin[0]=tin0;
+ tin[1]=tin1;
+ des_decrypt3((DES_LONG *)tin,ks1,ks2,ks3);
+ tout0=tin[0];
+ tout1=tin[1];
+
+ tout0^=xor0;
+ tout1^=xor1;
+ l2cn(tout0,tout1,out,l+8);
+ xor0=t0;
+ xor1=t1;
+ }
+
+ iv=(unsigned char *)ivec;
+ l2c(xor0,iv);
+ l2c(xor1,iv);
+ }
+ tin0=tin1=tout0=tout1=xor0=xor1=0;
+ tin[0]=tin[1]=0;
+ }
+
+#endif /* DES_DEFAULT_OPTIONS */
diff --git a/src/libcrypto/libdes/des_locl.h b/src/libcrypto/libdes/des_locl.h
new file mode 100644
index 000000000..4e0b3662f
--- /dev/null
+++ b/src/libcrypto/libdes/des_locl.h
@@ -0,0 +1,515 @@
+/* crypto/des/des_locl.org */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+/* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+ *
+ * Always modify des_locl.org since des_locl.h is automatically generated from
+ * it during SSLeay configuration.
+ *
+ * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+ */
+
+#ifndef HEADER_DES_LOCL_H
+#define HEADER_DES_LOCL_H
+
+#if defined(WIN32) || defined(WIN16)
+#ifndef MSDOS
+#define MSDOS
+#endif
+#endif
+
+#include "des.h"
+
+#ifndef DES_DEFAULT_OPTIONS
+/* the following is tweaked from a config script, that is why it is a
+ * protected undef/define */
+#ifndef DES_PTR
+#define DES_PTR
+#endif
+
+/* This helps C compiler generate the correct code for multiple functional
+ * units. It reduces register dependancies at the expense of 2 more
+ * registers */
+#ifndef DES_RISC1
+#define DES_RISC1
+#endif
+
+#ifndef DES_RISC2
+#undef DES_RISC2
+#endif
+
+#if defined(DES_RISC1) && defined(DES_RISC2)
+YOU SHOULD NOT HAVE BOTH DES_RISC1 AND DES_RISC2 DEFINED!!!!!
+#endif
+
+/* Unroll the inner loop, this sometimes helps, sometimes hinders.
+ * Very mucy CPU dependant */
+#ifndef DES_UNROLL
+#define DES_UNROLL
+#endif
+
+/* These default values were supplied by
+ * Peter Gutman <pgut001@cs.auckland.ac.nz>
+ * They are only used if nothing else has been defined */
+#if !defined(DES_PTR) && !defined(DES_RISC1) && !defined(DES_RISC2) && !defined(DES_UNROLL)
+/* Special defines which change the way the code is built depending on the
+ CPU and OS. For SGI machines you can use _MIPS_SZLONG (32 or 64) to find
+ even newer MIPS CPU's, but at the moment one size fits all for
+ optimization options. Older Sparc's work better with only UNROLL, but
+ there's no way to tell at compile time what it is you're running on */
+
+#if defined( sun ) /* Newer Sparc's */
+ #define DES_PTR
+ #define DES_RISC1
+ #define DES_UNROLL
+#elif defined( __ultrix ) /* Older MIPS */
+ #define DES_PTR
+ #define DES_RISC2
+ #define DES_UNROLL
+#elif defined( __osf1__ ) /* Alpha */
+ #define DES_PTR
+ #define DES_RISC2
+#elif defined ( _AIX ) /* RS6000 */
+ /* Unknown */
+#elif defined( __hpux ) /* HP-PA */
+ /* Unknown */
+#elif defined( __aux ) /* 68K */
+ /* Unknown */
+#elif defined( __dgux ) /* 88K (but P6 in latest boxes) */
+ #define DES_UNROLL
+#elif defined( __sgi ) /* Newer MIPS */
+ #define DES_PTR
+ #define DES_RISC2
+ #define DES_UNROLL
+#elif defined( i386 ) /* x86 boxes, should be gcc */
+ #define DES_PTR
+ #define DES_RISC1
+ #define DES_UNROLL
+#endif /* Systems-specific speed defines */
+#endif
+
+#endif /* DES_DEFAULT_OPTIONS */
+
+#ifdef MSDOS /* Visual C++ 2.1 (Windows NT/95) */
+#include <stdlib.h>
+#include <errno.h>
+#include <time.h>
+#include <io.h>
+#ifndef RAND
+#define RAND
+#endif
+#undef NOPROTO
+#endif
+
+#if defined(__STDC__) || defined(VMS) || defined(M_XENIX) || defined(MSDOS)
+#ifndef __KERNEL__
+#include <string.h>
+#else
+#include <linux/string.h>
+#endif
+#endif
+
+#ifndef RAND
+#define RAND
+#endif
+
+#ifdef linux
+#undef RAND
+#endif
+
+#ifdef MSDOS
+#define getpid() 2
+#define RAND
+#undef NOPROTO
+#endif
+
+#if defined(NOCONST)
+#define const
+#endif
+
+#ifdef __STDC__
+#undef NOPROTO
+#endif
+
+#ifdef RAND
+#define srandom(s) srand(s)
+#define random rand
+#endif
+
+#define ITERATIONS 16
+#define HALF_ITERATIONS 8
+
+/* used in des_read and des_write */
+#define MAXWRITE (1024*16)
+#define BSIZE (MAXWRITE+4)
+
+#define c2l(c,l) (l =((DES_LONG)(*((c)++))) , \
+ l|=((DES_LONG)(*((c)++)))<< 8L, \
+ l|=((DES_LONG)(*((c)++)))<<16L, \
+ l|=((DES_LONG)(*((c)++)))<<24L)
+
+/* NOTE - c is not incremented as per c2l */
+#define c2ln(c,l1,l2,n) { \
+ c+=n; \
+ l1=l2=0; \
+ switch (n) { \
+ case 8: l2 =((DES_LONG)(*(--(c))))<<24L; \
+ case 7: l2|=((DES_LONG)(*(--(c))))<<16L; \
+ case 6: l2|=((DES_LONG)(*(--(c))))<< 8L; \
+ case 5: l2|=((DES_LONG)(*(--(c)))); \
+ case 4: l1 =((DES_LONG)(*(--(c))))<<24L; \
+ case 3: l1|=((DES_LONG)(*(--(c))))<<16L; \
+ case 2: l1|=((DES_LONG)(*(--(c))))<< 8L; \
+ case 1: l1|=((DES_LONG)(*(--(c)))); \
+ } \
+ }
+
+#define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \
+ *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>16L)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>24L)&0xff))
+
+/* replacements for htonl and ntohl since I have no idea what to do
+ * when faced with machines with 8 byte longs. */
+#define HDRSIZE 4
+
+#define n2l(c,l) (l =((DES_LONG)(*((c)++)))<<24L, \
+ l|=((DES_LONG)(*((c)++)))<<16L, \
+ l|=((DES_LONG)(*((c)++)))<< 8L, \
+ l|=((DES_LONG)(*((c)++))))
+
+#define l2n(l,c) (*((c)++)=(unsigned char)(((l)>>24L)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>16L)&0xff), \
+ *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
+ *((c)++)=(unsigned char)(((l) )&0xff))
+
+/* NOTE - c is not incremented as per l2c */
+#define l2cn(l1,l2,c,n) { \
+ c+=n; \
+ switch (n) { \
+ case 8: *(--(c))=(unsigned char)(((l2)>>24L)&0xff); \
+ case 7: *(--(c))=(unsigned char)(((l2)>>16L)&0xff); \
+ case 6: *(--(c))=(unsigned char)(((l2)>> 8L)&0xff); \
+ case 5: *(--(c))=(unsigned char)(((l2) )&0xff); \
+ case 4: *(--(c))=(unsigned char)(((l1)>>24L)&0xff); \
+ case 3: *(--(c))=(unsigned char)(((l1)>>16L)&0xff); \
+ case 2: *(--(c))=(unsigned char)(((l1)>> 8L)&0xff); \
+ case 1: *(--(c))=(unsigned char)(((l1) )&0xff); \
+ } \
+ }
+
+#if defined(WIN32)
+#define ROTATE(a,n) (_lrotr(a,n))
+#else
+#define ROTATE(a,n) (((a)>>(n))+((a)<<(32-(n))))
+#endif
+
+/* Don't worry about the LOAD_DATA() stuff, that is used by
+ * fcrypt() to add it's little bit to the front */
+
+#ifdef DES_FCRYPT
+
+#define LOAD_DATA_tmp(R,S,u,t,E0,E1) \
+ { DES_LONG tmp; LOAD_DATA(R,S,u,t,E0,E1,tmp); }
+
+#define LOAD_DATA(R,S,u,t,E0,E1,tmp) \
+ t=R^(R>>16L); \
+ u=t&E0; t&=E1; \
+ tmp=(u<<16); u^=R^s[S ]; u^=tmp; \
+ tmp=(t<<16); t^=R^s[S+1]; t^=tmp
+#else
+#define LOAD_DATA_tmp(a,b,c,d,e,f) LOAD_DATA(a,b,c,d,e,f,g)
+#define LOAD_DATA(R,S,u,t,E0,E1,tmp) \
+ u=R^s[S ]; \
+ t=R^s[S+1]
+#endif
+
+/* The changes to this macro may help or hinder, depending on the
+ * compiler and the achitecture. gcc2 always seems to do well :-).
+ * Inspired by Dana How <how@isl.stanford.edu>
+ * DO NOT use the alternative version on machines with 8 byte longs.
+ * It does not seem to work on the Alpha, even when DES_LONG is 4
+ * bytes, probably an issue of accessing non-word aligned objects :-( */
+#ifdef DES_PTR
+
+/* It recently occured to me that 0^0^0^0^0^0^0 == 0, so there
+ * is no reason to not xor all the sub items together. This potentially
+ * saves a register since things can be xored directly into L */
+
+#if defined(DES_RISC1) || defined(DES_RISC2)
+#ifdef DES_RISC1
+#define D_ENCRYPT(LL,R,S) { \
+ unsigned int u1,u2,u3; \
+ LOAD_DATA(R,S,u,t,E0,E1,u1); \
+ u2=(int)u>>8L; \
+ u1=(int)u&0xfc; \
+ u2&=0xfc; \
+ t=ROTATE(t,4); \
+ u>>=16L; \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP +u1); \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x200+u2); \
+ u3=(int)(u>>8L); \
+ u1=(int)u&0xfc; \
+ u3&=0xfc; \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x400+u1); \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x600+u3); \
+ u2=(int)t>>8L; \
+ u1=(int)t&0xfc; \
+ u2&=0xfc; \
+ t>>=16L; \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x100+u1); \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x300+u2); \
+ u3=(int)t>>8L; \
+ u1=(int)t&0xfc; \
+ u3&=0xfc; \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x500+u1); \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x700+u3); }
+#endif
+#ifdef DES_RISC2
+#define D_ENCRYPT(LL,R,S) { \
+ unsigned int u1,u2,s1,s2; \
+ LOAD_DATA(R,S,u,t,E0,E1,u1); \
+ u2=(int)u>>8L; \
+ u1=(int)u&0xfc; \
+ u2&=0xfc; \
+ t=ROTATE(t,4); \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP +u1); \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x200+u2); \
+ s1=(int)(u>>16L); \
+ s2=(int)(u>>24L); \
+ s1&=0xfc; \
+ s2&=0xfc; \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x400+s1); \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x600+s2); \
+ u2=(int)t>>8L; \
+ u1=(int)t&0xfc; \
+ u2&=0xfc; \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x100+u1); \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x300+u2); \
+ s1=(int)(t>>16L); \
+ s2=(int)(t>>24L); \
+ s1&=0xfc; \
+ s2&=0xfc; \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x500+s1); \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x700+s2); }
+#endif
+#else
+#define D_ENCRYPT(LL,R,S) { \
+ LOAD_DATA_tmp(R,S,u,t,E0,E1); \
+ t=ROTATE(t,4); \
+ LL^= \
+ *(DES_LONG *)((unsigned char *)des_SP +((u )&0xfc))^ \
+ *(DES_LONG *)((unsigned char *)des_SP+0x200+((u>> 8L)&0xfc))^ \
+ *(DES_LONG *)((unsigned char *)des_SP+0x400+((u>>16L)&0xfc))^ \
+ *(DES_LONG *)((unsigned char *)des_SP+0x600+((u>>24L)&0xfc))^ \
+ *(DES_LONG *)((unsigned char *)des_SP+0x100+((t )&0xfc))^ \
+ *(DES_LONG *)((unsigned char *)des_SP+0x300+((t>> 8L)&0xfc))^ \
+ *(DES_LONG *)((unsigned char *)des_SP+0x500+((t>>16L)&0xfc))^ \
+ *(DES_LONG *)((unsigned char *)des_SP+0x700+((t>>24L)&0xfc)); }
+#endif
+
+#else /* original version */
+
+#if defined(DES_RISC1) || defined(DES_RISC2)
+#ifdef DES_RISC1
+#define D_ENCRYPT(LL,R,S) {\
+ unsigned int u1,u2,u3; \
+ LOAD_DATA(R,S,u,t,E0,E1,u1); \
+ u>>=2L; \
+ t=ROTATE(t,6); \
+ u2=(int)u>>8L; \
+ u1=(int)u&0x3f; \
+ u2&=0x3f; \
+ u>>=16L; \
+ LL^=des_SPtrans[0][u1]; \
+ LL^=des_SPtrans[2][u2]; \
+ u3=(int)u>>8L; \
+ u1=(int)u&0x3f; \
+ u3&=0x3f; \
+ LL^=des_SPtrans[4][u1]; \
+ LL^=des_SPtrans[6][u3]; \
+ u2=(int)t>>8L; \
+ u1=(int)t&0x3f; \
+ u2&=0x3f; \
+ t>>=16L; \
+ LL^=des_SPtrans[1][u1]; \
+ LL^=des_SPtrans[3][u2]; \
+ u3=(int)t>>8L; \
+ u1=(int)t&0x3f; \
+ u3&=0x3f; \
+ LL^=des_SPtrans[5][u1]; \
+ LL^=des_SPtrans[7][u3]; }
+#endif
+#ifdef DES_RISC2
+#define D_ENCRYPT(LL,R,S) {\
+ unsigned int u1,u2,s1,s2; \
+ LOAD_DATA(R,S,u,t,E0,E1,u1); \
+ u>>=2L; \
+ t=ROTATE(t,6); \
+ u2=(int)u>>8L; \
+ u1=(int)u&0x3f; \
+ u2&=0x3f; \
+ LL^=des_SPtrans[0][u1]; \
+ LL^=des_SPtrans[2][u2]; \
+ s1=(int)u>>16L; \
+ s2=(int)u>>24L; \
+ s1&=0x3f; \
+ s2&=0x3f; \
+ LL^=des_SPtrans[4][s1]; \
+ LL^=des_SPtrans[6][s2]; \
+ u2=(int)t>>8L; \
+ u1=(int)t&0x3f; \
+ u2&=0x3f; \
+ LL^=des_SPtrans[1][u1]; \
+ LL^=des_SPtrans[3][u2]; \
+ s1=(int)t>>16; \
+ s2=(int)t>>24L; \
+ s1&=0x3f; \
+ s2&=0x3f; \
+ LL^=des_SPtrans[5][s1]; \
+ LL^=des_SPtrans[7][s2]; }
+#endif
+
+#else
+
+#define D_ENCRYPT(LL,R,S) {\
+ LOAD_DATA_tmp(R,S,u,t,E0,E1); \
+ t=ROTATE(t,4); \
+ LL^=\
+ des_SPtrans[0][(u>> 2L)&0x3f]^ \
+ des_SPtrans[2][(u>>10L)&0x3f]^ \
+ des_SPtrans[4][(u>>18L)&0x3f]^ \
+ des_SPtrans[6][(u>>26L)&0x3f]^ \
+ des_SPtrans[1][(t>> 2L)&0x3f]^ \
+ des_SPtrans[3][(t>>10L)&0x3f]^ \
+ des_SPtrans[5][(t>>18L)&0x3f]^ \
+ des_SPtrans[7][(t>>26L)&0x3f]; }
+#endif
+#endif
+
+ /* IP and FP
+ * The problem is more of a geometric problem that random bit fiddling.
+ 0 1 2 3 4 5 6 7 62 54 46 38 30 22 14 6
+ 8 9 10 11 12 13 14 15 60 52 44 36 28 20 12 4
+ 16 17 18 19 20 21 22 23 58 50 42 34 26 18 10 2
+ 24 25 26 27 28 29 30 31 to 56 48 40 32 24 16 8 0
+
+ 32 33 34 35 36 37 38 39 63 55 47 39 31 23 15 7
+ 40 41 42 43 44 45 46 47 61 53 45 37 29 21 13 5
+ 48 49 50 51 52 53 54 55 59 51 43 35 27 19 11 3
+ 56 57 58 59 60 61 62 63 57 49 41 33 25 17 9 1
+
+ The output has been subject to swaps of the form
+ 0 1 -> 3 1 but the odd and even bits have been put into
+ 2 3 2 0
+ different words. The main trick is to remember that
+ t=((l>>size)^r)&(mask);
+ r^=t;
+ l^=(t<<size);
+ can be used to swap and move bits between words.
+
+ So l = 0 1 2 3 r = 16 17 18 19
+ 4 5 6 7 20 21 22 23
+ 8 9 10 11 24 25 26 27
+ 12 13 14 15 28 29 30 31
+ becomes (for size == 2 and mask == 0x3333)
+ t = 2^16 3^17 -- -- l = 0 1 16 17 r = 2 3 18 19
+ 6^20 7^21 -- -- 4 5 20 21 6 7 22 23
+ 10^24 11^25 -- -- 8 9 24 25 10 11 24 25
+ 14^28 15^29 -- -- 12 13 28 29 14 15 28 29
+
+ Thanks for hints from Richard Outerbridge - he told me IP&FP
+ could be done in 15 xor, 10 shifts and 5 ands.
+ When I finally started to think of the problem in 2D
+ I first got ~42 operations without xors. When I remembered
+ how to use xors :-) I got it to its final state.
+ */
+#define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\
+ (b)^=(t),\
+ (a)^=((t)<<(n)))
+
+#define IP(l,r) \
+ { \
+ register DES_LONG tt; \
+ PERM_OP(r,l,tt, 4,0x0f0f0f0fL); \
+ PERM_OP(l,r,tt,16,0x0000ffffL); \
+ PERM_OP(r,l,tt, 2,0x33333333L); \
+ PERM_OP(l,r,tt, 8,0x00ff00ffL); \
+ PERM_OP(r,l,tt, 1,0x55555555L); \
+ }
+
+#define FP(l,r) \
+ { \
+ register DES_LONG tt; \
+ PERM_OP(l,r,tt, 1,0x55555555L); \
+ PERM_OP(r,l,tt, 8,0x00ff00ffL); \
+ PERM_OP(l,r,tt, 2,0x33333333L); \
+ PERM_OP(r,l,tt,16,0x0000ffffL); \
+ PERM_OP(l,r,tt, 4,0x0f0f0f0fL); \
+ }
+
+extern const DES_LONG des_SPtrans[8][64];
+
+#ifndef NOPROTO
+void fcrypt_body(DES_LONG *out,des_key_schedule ks,
+ DES_LONG Eswap0, DES_LONG Eswap1);
+#else
+void fcrypt_body();
+#endif
+
+#endif
diff --git a/src/libcrypto/libdes/des_opts.c b/src/libcrypto/libdes/des_opts.c
new file mode 100644
index 000000000..b6693c405
--- /dev/null
+++ b/src/libcrypto/libdes/des_opts.c
@@ -0,0 +1,620 @@
+/* crypto/des/des_opts.c */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+/* define PART1, PART2, PART3 or PART4 to build only with a few of the options.
+ * This is for machines with 64k code segment size restrictions. */
+
+#ifndef MSDOS
+#define TIMES
+#endif
+
+#include <stdio.h>
+#ifndef MSDOS
+#include <unistd.h>
+#else
+#include <io.h>
+extern void exit();
+#endif
+#include <signal.h>
+#ifndef VMS
+#ifndef _IRIX
+#include <time.h>
+#endif
+#ifdef TIMES
+#include <sys/types.h>
+#include <sys/times.h>
+#endif
+#else /* VMS */
+#include <types.h>
+struct tms {
+ time_t tms_utime;
+ time_t tms_stime;
+ time_t tms_uchild; /* I dunno... */
+ time_t tms_uchildsys; /* so these names are a guess :-) */
+ }
+#endif
+#ifndef TIMES
+#include <sys/timeb.h>
+#endif
+
+#ifdef sun
+#include <limits.h>
+#include <sys/param.h>
+#endif
+
+#include "des_locl.h"
+#include "spr.h"
+
+#define DES_DEFAULT_OPTIONS
+
+#if !defined(PART1) && !defined(PART2) && !defined(PART3) && !defined(PART4)
+#define PART1
+#define PART2
+#define PART3
+#define PART4
+#endif
+
+#ifdef PART1
+
+#undef DES_UNROLL
+#undef DES_RISC1
+#undef DES_RISC2
+#undef DES_PTR
+#undef D_ENCRYPT
+#define des_encrypt des_encrypt_u4_cisc_idx
+#define des_encrypt2 des_encrypt2_u4_cisc_idx
+#define des_encrypt3 des_encrypt3_u4_cisc_idx
+#define des_decrypt3 des_decrypt3_u4_cisc_idx
+#undef HEADER_DES_LOCL_H
+#include "des_enc.c"
+
+#define DES_UNROLL
+#undef DES_RISC1
+#undef DES_RISC2
+#undef DES_PTR
+#undef D_ENCRYPT
+#undef des_encrypt
+#undef des_encrypt2
+#undef des_encrypt3
+#undef des_decrypt3
+#define des_encrypt des_encrypt_u16_cisc_idx
+#define des_encrypt2 des_encrypt2_u16_cisc_idx
+#define des_encrypt3 des_encrypt3_u16_cisc_idx
+#define des_decrypt3 des_decrypt3_u16_cisc_idx
+#undef HEADER_DES_LOCL_H
+#include "des_enc.c"
+
+#undef DES_UNROLL
+#define DES_RISC1
+#undef DES_RISC2
+#undef DES_PTR
+#undef D_ENCRYPT
+#undef des_encrypt
+#undef des_encrypt2
+#undef des_encrypt3
+#undef des_decrypt3
+#define des_encrypt des_encrypt_u4_risc1_idx
+#define des_encrypt2 des_encrypt2_u4_risc1_idx
+#define des_encrypt3 des_encrypt3_u4_risc1_idx
+#define des_decrypt3 des_decrypt3_u4_risc1_idx
+#undef HEADER_DES_LOCL_H
+#include "des_enc.c"
+
+#endif
+
+#ifdef PART2
+
+#undef DES_UNROLL
+#undef DES_RISC1
+#define DES_RISC2
+#undef DES_PTR
+#undef D_ENCRYPT
+#undef des_encrypt
+#undef des_encrypt2
+#undef des_encrypt3
+#undef des_decrypt3
+#define des_encrypt des_encrypt_u4_risc2_idx
+#define des_encrypt2 des_encrypt2_u4_risc2_idx
+#define des_encrypt3 des_encrypt3_u4_risc2_idx
+#define des_decrypt3 des_decrypt3_u4_risc2_idx
+#undef HEADER_DES_LOCL_H
+#include "des_enc.c"
+
+#define DES_UNROLL
+#define DES_RISC1
+#undef DES_RISC2
+#undef DES_PTR
+#undef D_ENCRYPT
+#undef des_encrypt
+#undef des_encrypt2
+#undef des_encrypt3
+#undef des_decrypt3
+#define des_encrypt des_encrypt_u16_risc1_idx
+#define des_encrypt2 des_encrypt2_u16_risc1_idx
+#define des_encrypt3 des_encrypt3_u16_risc1_idx
+#define des_decrypt3 des_decrypt3_u16_risc1_idx
+#undef HEADER_DES_LOCL_H
+#include "des_enc.c"
+
+#define DES_UNROLL
+#undef DES_RISC1
+#define DES_RISC2
+#undef DES_PTR
+#undef D_ENCRYPT
+#undef des_encrypt
+#undef des_encrypt2
+#undef des_encrypt3
+#undef des_decrypt3
+#define des_encrypt des_encrypt_u16_risc2_idx
+#define des_encrypt2 des_encrypt2_u16_risc2_idx
+#define des_encrypt3 des_encrypt3_u16_risc2_idx
+#define des_decrypt3 des_decrypt3_u16_risc2_idx
+#undef HEADER_DES_LOCL_H
+#include "des_enc.c"
+
+#endif
+
+#ifdef PART3
+
+#undef DES_UNROLL
+#undef DES_RISC1
+#undef DES_RISC2
+#define DES_PTR
+#undef D_ENCRYPT
+#undef des_encrypt
+#undef des_encrypt2
+#undef des_encrypt3
+#undef des_decrypt3
+#define des_encrypt des_encrypt_u4_cisc_ptr
+#define des_encrypt2 des_encrypt2_u4_cisc_ptr
+#define des_encrypt3 des_encrypt3_u4_cisc_ptr
+#define des_decrypt3 des_decrypt3_u4_cisc_ptr
+#undef HEADER_DES_LOCL_H
+#include "des_enc.c"
+
+#define DES_UNROLL
+#undef DES_RISC1
+#undef DES_RISC2
+#define DES_PTR
+#undef D_ENCRYPT
+#undef des_encrypt
+#undef des_encrypt2
+#undef des_encrypt3
+#undef des_decrypt3
+#define des_encrypt des_encrypt_u16_cisc_ptr
+#define des_encrypt2 des_encrypt2_u16_cisc_ptr
+#define des_encrypt3 des_encrypt3_u16_cisc_ptr
+#define des_decrypt3 des_decrypt3_u16_cisc_ptr
+#undef HEADER_DES_LOCL_H
+#include "des_enc.c"
+
+#undef DES_UNROLL
+#define DES_RISC1
+#undef DES_RISC2
+#define DES_PTR
+#undef D_ENCRYPT
+#undef des_encrypt
+#undef des_encrypt2
+#undef des_encrypt3
+#undef des_decrypt3
+#define des_encrypt des_encrypt_u4_risc1_ptr
+#define des_encrypt2 des_encrypt2_u4_risc1_ptr
+#define des_encrypt3 des_encrypt3_u4_risc1_ptr
+#define des_decrypt3 des_decrypt3_u4_risc1_ptr
+#undef HEADER_DES_LOCL_H
+#include "des_enc.c"
+
+#endif
+
+#ifdef PART4
+
+#undef DES_UNROLL
+#undef DES_RISC1
+#define DES_RISC2
+#define DES_PTR
+#undef D_ENCRYPT
+#undef des_encrypt
+#undef des_encrypt2
+#undef des_encrypt3
+#undef des_decrypt3
+#define des_encrypt des_encrypt_u4_risc2_ptr
+#define des_encrypt2 des_encrypt2_u4_risc2_ptr
+#define des_encrypt3 des_encrypt3_u4_risc2_ptr
+#define des_decrypt3 des_decrypt3_u4_risc2_ptr
+#undef HEADER_DES_LOCL_H
+#include "des_enc.c"
+
+#define DES_UNROLL
+#define DES_RISC1
+#undef DES_RISC2
+#define DES_PTR
+#undef D_ENCRYPT
+#undef des_encrypt
+#undef des_encrypt2
+#undef des_encrypt3
+#undef des_decrypt3
+#define des_encrypt des_encrypt_u16_risc1_ptr
+#define des_encrypt2 des_encrypt2_u16_risc1_ptr
+#define des_encrypt3 des_encrypt3_u16_risc1_ptr
+#define des_decrypt3 des_decrypt3_u16_risc1_ptr
+#undef HEADER_DES_LOCL_H
+#include "des_enc.c"
+
+#define DES_UNROLL
+#undef DES_RISC1
+#define DES_RISC2
+#define DES_PTR
+#undef D_ENCRYPT
+#undef des_encrypt
+#undef des_encrypt2
+#undef des_encrypt3
+#undef des_decrypt3
+#define des_encrypt des_encrypt_u16_risc2_ptr
+#define des_encrypt2 des_encrypt2_u16_risc2_ptr
+#define des_encrypt3 des_encrypt3_u16_risc2_ptr
+#define des_decrypt3 des_decrypt3_u16_risc2_ptr
+#undef HEADER_DES_LOCL_H
+#include "des_enc.c"
+
+#endif
+
+/* The following if from times(3) man page. It may need to be changed */
+#ifndef HZ
+# ifndef CLK_TCK
+# ifndef _BSD_CLK_TCK_ /* FreeBSD fix */
+# ifndef VMS
+# define HZ 100.0
+# else /* VMS */
+# define HZ 100.0
+# endif
+# else /* _BSD_CLK_TCK_ */
+# define HZ ((double)_BSD_CLK_TCK_)
+# endif
+# else /* CLK_TCK */
+# define HZ ((double)CLK_TCK)
+# endif
+#endif
+
+#define BUFSIZE ((long)1024)
+long run=0;
+
+#ifndef NOPROTO
+double Time_F(int s);
+#else
+double Time_F();
+#endif
+
+#ifdef SIGALRM
+#if defined(__STDC__) || defined(sgi)
+#define SIGRETTYPE void
+#else
+#define SIGRETTYPE int
+#endif
+
+#ifndef NOPROTO
+SIGRETTYPE sig_done(int sig);
+#else
+SIGRETTYPE sig_done();
+#endif
+
+SIGRETTYPE sig_done(sig)
+int sig;
+ {
+ signal(SIGALRM,sig_done);
+ run=0;
+#ifdef LINT
+ sig=sig;
+#endif
+ }
+#endif
+
+#define START 0
+#define STOP 1
+
+double Time_F(s)
+int s;
+ {
+ double ret;
+#ifdef TIMES
+ static struct tms tstart,tend;
+
+ if (s == START)
+ {
+ times(&tstart);
+ return(0);
+ }
+ else
+ {
+ times(&tend);
+ ret=((double)(tend.tms_utime-tstart.tms_utime))/HZ;
+ return((ret == 0.0)?1e-6:ret);
+ }
+#else /* !times() */
+ static struct timeb tstart,tend;
+ long i;
+
+ if (s == START)
+ {
+ ftime(&tstart);
+ return(0);
+ }
+ else
+ {
+ ftime(&tend);
+ i=(long)tend.millitm-(long)tstart.millitm;
+ ret=((double)(tend.time-tstart.time))+((double)i)/1000.0;
+ return((ret == 0.0)?1e-6:ret);
+ }
+#endif
+ }
+
+#ifdef SIGALRM
+#define print_name(name) fprintf(stderr,"Doing %s's for 10 seconds\n",name); alarm(10);
+#else
+#define print_name(name) fprintf(stderr,"Doing %s %ld times\n",name,cb);
+#endif
+
+#define time_it(func,name,index) \
+ print_name(name); \
+ Time_F(START); \
+ for (count=0,run=1; COND(cb); count++) \
+ { \
+ unsigned long d[2]; \
+ func(d,&(sch[0]),DES_ENCRYPT); \
+ } \
+ tm[index]=Time_F(STOP); \
+ fprintf(stderr,"%ld %s's in %.2f second\n",count,name,tm[index]); \
+ tm[index]=((double)COUNT(cb))/tm[index];
+
+#define print_it(name,index) \
+ fprintf(stderr,"%s bytes per sec = %12.2f (%5.1fuS)\n",name, \
+ tm[index]*8,1.0e6/tm[index]);
+
+int main(argc,argv)
+int argc;
+char **argv;
+ {
+ long count;
+ static unsigned char buf[BUFSIZE];
+ static des_cblock key ={0x12,0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0};
+ static des_cblock key2={0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0,0x12};
+ static des_cblock key3={0x56,0x78,0x9a,0xbc,0xde,0xf0,0x12,0x34};
+ des_key_schedule sch,sch2,sch3;
+ double d,tm[16],max=0;
+ int rank[16];
+ char *str[16];
+ int max_idx=0,i,num=0,j;
+#ifndef SIGALARM
+ long ca,cb,cc,cd,ce;
+#endif
+
+ for (i=0; i<12; i++)
+ {
+ tm[i]=0.0;
+ rank[i]=0;
+ }
+
+#ifndef TIMES
+ fprintf(stderr,"To get the most acurate results, try to run this\n");
+ fprintf(stderr,"program when this computer is idle.\n");
+#endif
+
+ des_set_key((C_Block *)key,sch);
+ des_set_key((C_Block *)key2,sch2);
+ des_set_key((C_Block *)key3,sch3);
+
+#ifndef SIGALRM
+ fprintf(stderr,"First we calculate the approximate speed ...\n");
+ des_set_key((C_Block *)key,sch);
+ count=10;
+ do {
+ long i;
+ unsigned long data[2];
+
+ count*=2;
+ Time_F(START);
+ for (i=count; i; i--)
+ des_encrypt(data,&(sch[0]),DES_ENCRYPT);
+ d=Time_F(STOP);
+ } while (d < 3.0);
+ ca=count;
+ cb=count*3;
+ cc=count*3*8/BUFSIZE+1;
+ cd=count*8/BUFSIZE+1;
+
+ ce=count/20+1;
+#define COND(d) (count != (d))
+#define COUNT(d) (d)
+#else
+#define COND(c) (run)
+#define COUNT(d) (count)
+ signal(SIGALRM,sig_done);
+ alarm(10);
+#endif
+
+#ifdef PART1
+ time_it(des_encrypt_u4_cisc_idx, "des_encrypt_u4_cisc_idx ", 0);
+ time_it(des_encrypt_u16_cisc_idx, "des_encrypt_u16_cisc_idx ", 1);
+ time_it(des_encrypt_u4_risc1_idx, "des_encrypt_u4_risc1_idx ", 2);
+ num+=3;
+#endif
+#ifdef PART2
+ time_it(des_encrypt_u16_risc1_idx,"des_encrypt_u16_risc1_idx", 3);
+ time_it(des_encrypt_u4_risc2_idx, "des_encrypt_u4_risc2_idx ", 4);
+ time_it(des_encrypt_u16_risc2_idx,"des_encrypt_u16_risc2_idx", 5);
+ num+=3;
+#endif
+#ifdef PART3
+ time_it(des_encrypt_u4_cisc_ptr, "des_encrypt_u4_cisc_ptr ", 6);
+ time_it(des_encrypt_u16_cisc_ptr, "des_encrypt_u16_cisc_ptr ", 7);
+ time_it(des_encrypt_u4_risc1_ptr, "des_encrypt_u4_risc1_ptr ", 8);
+ num+=3;
+#endif
+#ifdef PART4
+ time_it(des_encrypt_u16_risc1_ptr,"des_encrypt_u16_risc1_ptr", 9);
+ time_it(des_encrypt_u4_risc2_ptr, "des_encrypt_u4_risc2_ptr ",10);
+ time_it(des_encrypt_u16_risc2_ptr,"des_encrypt_u16_risc2_ptr",11);
+ num+=3;
+#endif
+
+#ifdef PART1
+ str[0]=" 4 c i";
+ print_it("des_encrypt_u4_cisc_idx ",0);
+ max=tm[0];
+ max_idx=0;
+ str[1]="16 c i";
+ print_it("des_encrypt_u16_cisc_idx ",1);
+ if (max < tm[1]) { max=tm[1]; max_idx=1; }
+ str[2]=" 4 r1 i";
+ print_it("des_encrypt_u4_risc1_idx ",2);
+ if (max < tm[2]) { max=tm[2]; max_idx=2; }
+#endif
+#ifdef PART2
+ str[3]="16 r1 i";
+ print_it("des_encrypt_u16_risc1_idx",3);
+ if (max < tm[3]) { max=tm[3]; max_idx=3; }
+ str[4]=" 4 r2 i";
+ print_it("des_encrypt_u4_risc2_idx ",4);
+ if (max < tm[4]) { max=tm[4]; max_idx=4; }
+ str[5]="16 r2 i";
+ print_it("des_encrypt_u16_risc2_idx",5);
+ if (max < tm[5]) { max=tm[5]; max_idx=5; }
+#endif
+#ifdef PART3
+ str[6]=" 4 c p";
+ print_it("des_encrypt_u4_cisc_ptr ",6);
+ if (max < tm[6]) { max=tm[6]; max_idx=6; }
+ str[7]="16 c p";
+ print_it("des_encrypt_u16_cisc_ptr ",7);
+ if (max < tm[7]) { max=tm[7]; max_idx=7; }
+ str[8]=" 4 r1 p";
+ print_it("des_encrypt_u4_risc1_ptr ",8);
+ if (max < tm[8]) { max=tm[8]; max_idx=8; }
+#endif
+#ifdef PART4
+ str[9]="16 r1 p";
+ print_it("des_encrypt_u16_risc1_ptr",9);
+ if (max < tm[9]) { max=tm[9]; max_idx=9; }
+ str[10]=" 4 r2 p";
+ print_it("des_encrypt_u4_risc2_ptr ",10);
+ if (max < tm[10]) { max=tm[10]; max_idx=10; }
+ str[11]="16 r2 p";
+ print_it("des_encrypt_u16_risc2_ptr",11);
+ if (max < tm[11]) { max=tm[11]; max_idx=11; }
+#endif
+ printf("options des ecb/s\n");
+ printf("%s %12.2f 100.0%%\n",str[max_idx],tm[max_idx]);
+ d=tm[max_idx];
+ tm[max_idx]= -2.0;
+ max= -1.0;
+ for (;;)
+ {
+ for (i=0; i<12; i++)
+ {
+ if (max < tm[i]) { max=tm[i]; j=i; }
+ }
+ if (max < 0.0) break;
+ printf("%s %12.2f %4.1f%%\n",str[j],tm[j],tm[j]/d*100.0);
+ tm[j]= -2.0;
+ max= -1.0;
+ }
+
+ switch (max_idx)
+ {
+ case 0:
+ printf("-DDES_DEFAULT_OPTIONS\n");
+ break;
+ case 1:
+ printf("-DDES_UNROLL\n");
+ break;
+ case 2:
+ printf("-DDES_RISC1\n");
+ break;
+ case 3:
+ printf("-DDES_UNROLL -DDES_RISC1\n");
+ break;
+ case 4:
+ printf("-DDES_RISC2\n");
+ break;
+ case 5:
+ printf("-DDES_UNROLL -DDES_RISC2\n");
+ break;
+ case 6:
+ printf("-DDES_PTR\n");
+ break;
+ case 7:
+ printf("-DDES_UNROLL -DDES_PTR\n");
+ break;
+ case 8:
+ printf("-DDES_RISC1 -DDES_PTR\n");
+ break;
+ case 9:
+ printf("-DDES_UNROLL -DDES_RISC1 -DDES_PTR\n");
+ break;
+ case 10:
+ printf("-DDES_RISC2 -DDES_PTR\n");
+ break;
+ case 11:
+ printf("-DDES_UNROLL -DDES_RISC2 -DDES_PTR\n");
+ break;
+ }
+ exit(0);
+#if defined(LINT) || defined(MSDOS)
+ return(0);
+#endif
+ }
diff --git a/src/libcrypto/libdes/des_ver.h b/src/libcrypto/libdes/des_ver.h
new file mode 100644
index 000000000..98352bc0d
--- /dev/null
+++ b/src/libcrypto/libdes/des_ver.h
@@ -0,0 +1,60 @@
+/* crypto/des/des_ver.h */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+extern char *DES_version; /* SSLeay version string */
+extern char *libdes_version; /* old libdes version string */
diff --git a/src/libcrypto/libdes/destest.c b/src/libcrypto/libdes/destest.c
new file mode 100644
index 000000000..ae896499e
--- /dev/null
+++ b/src/libcrypto/libdes/destest.c
@@ -0,0 +1,871 @@
+/* crypto/des/destest.c */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#if defined(WIN32) || defined(WIN16) || defined(WINDOWS)
+#ifndef MSDOS
+#define MSDOS
+#endif
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef MSDOS
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+#include <string.h>
+#include "des_locl.h"
+
+/* tisk tisk - the test keys don't all have odd parity :-( */
+/* test data */
+#define NUM_TESTS 34
+static unsigned char key_data[NUM_TESTS][8]={
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+ {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
+ {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+ {0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11},
+ {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF},
+ {0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+ {0xFE,0xDC,0xBA,0x98,0x76,0x54,0x32,0x10},
+ {0x7C,0xA1,0x10,0x45,0x4A,0x1A,0x6E,0x57},
+ {0x01,0x31,0xD9,0x61,0x9D,0xC1,0x37,0x6E},
+ {0x07,0xA1,0x13,0x3E,0x4A,0x0B,0x26,0x86},
+ {0x38,0x49,0x67,0x4C,0x26,0x02,0x31,0x9E},
+ {0x04,0xB9,0x15,0xBA,0x43,0xFE,0xB5,0xB6},
+ {0x01,0x13,0xB9,0x70,0xFD,0x34,0xF2,0xCE},
+ {0x01,0x70,0xF1,0x75,0x46,0x8F,0xB5,0xE6},
+ {0x43,0x29,0x7F,0xAD,0x38,0xE3,0x73,0xFE},
+ {0x07,0xA7,0x13,0x70,0x45,0xDA,0x2A,0x16},
+ {0x04,0x68,0x91,0x04,0xC2,0xFD,0x3B,0x2F},
+ {0x37,0xD0,0x6B,0xB5,0x16,0xCB,0x75,0x46},
+ {0x1F,0x08,0x26,0x0D,0x1A,0xC2,0x46,0x5E},
+ {0x58,0x40,0x23,0x64,0x1A,0xBA,0x61,0x76},
+ {0x02,0x58,0x16,0x16,0x46,0x29,0xB0,0x07},
+ {0x49,0x79,0x3E,0xBC,0x79,0xB3,0x25,0x8F},
+ {0x4F,0xB0,0x5E,0x15,0x15,0xAB,0x73,0xA7},
+ {0x49,0xE9,0x5D,0x6D,0x4C,0xA2,0x29,0xBF},
+ {0x01,0x83,0x10,0xDC,0x40,0x9B,0x26,0xD6},
+ {0x1C,0x58,0x7F,0x1C,0x13,0x92,0x4F,0xEF},
+ {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01},
+ {0x1F,0x1F,0x1F,0x1F,0x0E,0x0E,0x0E,0x0E},
+ {0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1,0xFE},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+ {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
+ {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF},
+ {0xFE,0xDC,0xBA,0x98,0x76,0x54,0x32,0x10}};
+
+static unsigned char plain_data[NUM_TESTS][8]={
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+ {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
+ {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x01},
+ {0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11},
+ {0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11},
+ {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+ {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF},
+ {0x01,0xA1,0xD6,0xD0,0x39,0x77,0x67,0x42},
+ {0x5C,0xD5,0x4C,0xA8,0x3D,0xEF,0x57,0xDA},
+ {0x02,0x48,0xD4,0x38,0x06,0xF6,0x71,0x72},
+ {0x51,0x45,0x4B,0x58,0x2D,0xDF,0x44,0x0A},
+ {0x42,0xFD,0x44,0x30,0x59,0x57,0x7F,0xA2},
+ {0x05,0x9B,0x5E,0x08,0x51,0xCF,0x14,0x3A},
+ {0x07,0x56,0xD8,0xE0,0x77,0x47,0x61,0xD2},
+ {0x76,0x25,0x14,0xB8,0x29,0xBF,0x48,0x6A},
+ {0x3B,0xDD,0x11,0x90,0x49,0x37,0x28,0x02},
+ {0x26,0x95,0x5F,0x68,0x35,0xAF,0x60,0x9A},
+ {0x16,0x4D,0x5E,0x40,0x4F,0x27,0x52,0x32},
+ {0x6B,0x05,0x6E,0x18,0x75,0x9F,0x5C,0xCA},
+ {0x00,0x4B,0xD6,0xEF,0x09,0x17,0x60,0x62},
+ {0x48,0x0D,0x39,0x00,0x6E,0xE7,0x62,0xF2},
+ {0x43,0x75,0x40,0xC8,0x69,0x8F,0x3C,0xFA},
+ {0x07,0x2D,0x43,0xA0,0x77,0x07,0x52,0x92},
+ {0x02,0xFE,0x55,0x77,0x81,0x17,0xF1,0x2A},
+ {0x1D,0x9D,0x5C,0x50,0x18,0xF7,0x28,0xC2},
+ {0x30,0x55,0x32,0x28,0x6D,0x6F,0x29,0x5A},
+ {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF},
+ {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF},
+ {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF},
+ {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+ {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}};
+
+static unsigned char cipher_data[NUM_TESTS][8]={
+ {0x8C,0xA6,0x4D,0xE9,0xC1,0xB1,0x23,0xA7},
+ {0x73,0x59,0xB2,0x16,0x3E,0x4E,0xDC,0x58},
+ {0x95,0x8E,0x6E,0x62,0x7A,0x05,0x55,0x7B},
+ {0xF4,0x03,0x79,0xAB,0x9E,0x0E,0xC5,0x33},
+ {0x17,0x66,0x8D,0xFC,0x72,0x92,0x53,0x2D},
+ {0x8A,0x5A,0xE1,0xF8,0x1A,0xB8,0xF2,0xDD},
+ {0x8C,0xA6,0x4D,0xE9,0xC1,0xB1,0x23,0xA7},
+ {0xED,0x39,0xD9,0x50,0xFA,0x74,0xBC,0xC4},
+ {0x69,0x0F,0x5B,0x0D,0x9A,0x26,0x93,0x9B},
+ {0x7A,0x38,0x9D,0x10,0x35,0x4B,0xD2,0x71},
+ {0x86,0x8E,0xBB,0x51,0xCA,0xB4,0x59,0x9A},
+ {0x71,0x78,0x87,0x6E,0x01,0xF1,0x9B,0x2A},
+ {0xAF,0x37,0xFB,0x42,0x1F,0x8C,0x40,0x95},
+ {0x86,0xA5,0x60,0xF1,0x0E,0xC6,0xD8,0x5B},
+ {0x0C,0xD3,0xDA,0x02,0x00,0x21,0xDC,0x09},
+ {0xEA,0x67,0x6B,0x2C,0xB7,0xDB,0x2B,0x7A},
+ {0xDF,0xD6,0x4A,0x81,0x5C,0xAF,0x1A,0x0F},
+ {0x5C,0x51,0x3C,0x9C,0x48,0x86,0xC0,0x88},
+ {0x0A,0x2A,0xEE,0xAE,0x3F,0xF4,0xAB,0x77},
+ {0xEF,0x1B,0xF0,0x3E,0x5D,0xFA,0x57,0x5A},
+ {0x88,0xBF,0x0D,0xB6,0xD7,0x0D,0xEE,0x56},
+ {0xA1,0xF9,0x91,0x55,0x41,0x02,0x0B,0x56},
+ {0x6F,0xBF,0x1C,0xAF,0xCF,0xFD,0x05,0x56},
+ {0x2F,0x22,0xE4,0x9B,0xAB,0x7C,0xA1,0xAC},
+ {0x5A,0x6B,0x61,0x2C,0xC2,0x6C,0xCE,0x4A},
+ {0x5F,0x4C,0x03,0x8E,0xD1,0x2B,0x2E,0x41},
+ {0x63,0xFA,0xC0,0xD0,0x34,0xD9,0xF7,0x93},
+ {0x61,0x7B,0x3A,0x0C,0xE8,0xF0,0x71,0x00},
+ {0xDB,0x95,0x86,0x05,0xF8,0xC8,0xC6,0x06},
+ {0xED,0xBF,0xD1,0xC6,0x6C,0x29,0xCC,0xC7},
+ {0x35,0x55,0x50,0xB2,0x15,0x0E,0x24,0x51},
+ {0xCA,0xAA,0xAF,0x4D,0xEA,0xF1,0xDB,0xAE},
+ {0xD5,0xD4,0x4F,0xF7,0x20,0x68,0x3D,0x0D},
+ {0x2A,0x2B,0xB0,0x08,0xDF,0x97,0xC2,0xF2}};
+
+static unsigned char cipher_ecb2[NUM_TESTS-1][8]={
+ {0x92,0x95,0xB5,0x9B,0xB3,0x84,0x73,0x6E},
+ {0x19,0x9E,0x9D,0x6D,0xF3,0x9A,0xA8,0x16},
+ {0x2A,0x4B,0x4D,0x24,0x52,0x43,0x84,0x27},
+ {0x35,0x84,0x3C,0x01,0x9D,0x18,0xC5,0xB6},
+ {0x4A,0x5B,0x2F,0x42,0xAA,0x77,0x19,0x25},
+ {0xA0,0x6B,0xA9,0xB8,0xCA,0x5B,0x17,0x8A},
+ {0xAB,0x9D,0xB7,0xFB,0xED,0x95,0xF2,0x74},
+ {0x3D,0x25,0x6C,0x23,0xA7,0x25,0x2F,0xD6},
+ {0xB7,0x6F,0xAB,0x4F,0xBD,0xBD,0xB7,0x67},
+ {0x8F,0x68,0x27,0xD6,0x9C,0xF4,0x1A,0x10},
+ {0x82,0x57,0xA1,0xD6,0x50,0x5E,0x81,0x85},
+ {0xA2,0x0F,0x0A,0xCD,0x80,0x89,0x7D,0xFA},
+ {0xCD,0x2A,0x53,0x3A,0xDB,0x0D,0x7E,0xF3},
+ {0xD2,0xC2,0xBE,0x27,0xE8,0x1B,0x68,0xE3},
+ {0xE9,0x24,0xCF,0x4F,0x89,0x3C,0x5B,0x0A},
+ {0xA7,0x18,0xC3,0x9F,0xFA,0x9F,0xD7,0x69},
+ {0x77,0x2C,0x79,0xB1,0xD2,0x31,0x7E,0xB1},
+ {0x49,0xAB,0x92,0x7F,0xD0,0x22,0x00,0xB7},
+ {0xCE,0x1C,0x6C,0x7D,0x85,0xE3,0x4A,0x6F},
+ {0xBE,0x91,0xD6,0xE1,0x27,0xB2,0xE9,0x87},
+ {0x70,0x28,0xAE,0x8F,0xD1,0xF5,0x74,0x1A},
+ {0xAA,0x37,0x80,0xBB,0xF3,0x22,0x1D,0xDE},
+ {0xA6,0xC4,0xD2,0x5E,0x28,0x93,0xAC,0xB3},
+ {0x22,0x07,0x81,0x5A,0xE4,0xB7,0x1A,0xAD},
+ {0xDC,0xCE,0x05,0xE7,0x07,0xBD,0xF5,0x84},
+ {0x26,0x1D,0x39,0x2C,0xB3,0xBA,0xA5,0x85},
+ {0xB4,0xF7,0x0F,0x72,0xFB,0x04,0xF0,0xDC},
+ {0x95,0xBA,0xA9,0x4E,0x87,0x36,0xF2,0x89},
+ {0xD4,0x07,0x3A,0xF1,0x5A,0x17,0x82,0x0E},
+ {0xEF,0x6F,0xAF,0xA7,0x66,0x1A,0x7E,0x89},
+ {0xC1,0x97,0xF5,0x58,0x74,0x8A,0x20,0xE7},
+ {0x43,0x34,0xCF,0xDA,0x22,0xC4,0x86,0xC8},
+ {0x08,0xD7,0xB4,0xFB,0x62,0x9D,0x08,0x85}};
+
+static unsigned char cbc_key [8]={0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef};
+static unsigned char cbc2_key[8]={0xf0,0xe1,0xd2,0xc3,0xb4,0xa5,0x96,0x87};
+static unsigned char cbc3_key[8]={0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10};
+static unsigned char cbc_iv [8]={0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10};
+static char cbc_data[40]="7654321 Now is the time for \0001";
+
+static unsigned char cbc_ok[32]={
+ 0xcc,0xd1,0x73,0xff,0xab,0x20,0x39,0xf4,
+ 0xac,0xd8,0xae,0xfd,0xdf,0xd8,0xa1,0xeb,
+ 0x46,0x8e,0x91,0x15,0x78,0x88,0xba,0x68,
+ 0x1d,0x26,0x93,0x97,0xf7,0xfe,0x62,0xb4};
+
+static unsigned char xcbc_ok[32]={
+ 0x86,0x74,0x81,0x0D,0x61,0xA4,0xA5,0x48,
+ 0xB9,0x93,0x03,0xE1,0xB8,0xBB,0xBD,0xBD,
+ 0x64,0x30,0x0B,0xB9,0x06,0x65,0x81,0x76,
+ 0x04,0x1D,0x77,0x62,0x17,0xCA,0x2B,0xD2,
+ };
+
+static unsigned char cbc3_ok[32]={
+ 0x3F,0xE3,0x01,0xC9,0x62,0xAC,0x01,0xD0,
+ 0x22,0x13,0x76,0x3C,0x1C,0xBD,0x4C,0xDC,
+ 0x79,0x96,0x57,0xC0,0x64,0xEC,0xF5,0xD4,
+ 0x1C,0x67,0x38,0x12,0xCF,0xDE,0x96,0x75};
+
+static unsigned char pcbc_ok[32]={
+ 0xcc,0xd1,0x73,0xff,0xab,0x20,0x39,0xf4,
+ 0x6d,0xec,0xb4,0x70,0xa0,0xe5,0x6b,0x15,
+ 0xae,0xa6,0xbf,0x61,0xed,0x7d,0x9c,0x9f,
+ 0xf7,0x17,0x46,0x3b,0x8a,0xb3,0xcc,0x88};
+
+static unsigned char cfb_key[8]={0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef};
+static unsigned char cfb_iv[8]={0x12,0x34,0x56,0x78,0x90,0xab,0xcd,0xef};
+static unsigned char cfb_buf1[40],cfb_buf2[40],cfb_tmp[8];
+static unsigned char plain[24]=
+ {
+ 0x4e,0x6f,0x77,0x20,0x69,0x73,
+ 0x20,0x74,0x68,0x65,0x20,0x74,
+ 0x69,0x6d,0x65,0x20,0x66,0x6f,
+ 0x72,0x20,0x61,0x6c,0x6c,0x20
+ };
+static unsigned char cfb_cipher8[24]= {
+ 0xf3,0x1f,0xda,0x07,0x01,0x14, 0x62,0xee,0x18,0x7f,0x43,0xd8,
+ 0x0a,0x7c,0xd9,0xb5,0xb0,0xd2, 0x90,0xda,0x6e,0x5b,0x9a,0x87 };
+static unsigned char cfb_cipher16[24]={
+ 0xF3,0x09,0x87,0x87,0x7F,0x57, 0xF7,0x3C,0x36,0xB6,0xDB,0x70,
+ 0xD8,0xD5,0x34,0x19,0xD3,0x86, 0xB2,0x23,0xB7,0xB2,0xAD,0x1B };
+static unsigned char cfb_cipher32[24]={
+ 0xF3,0x09,0x62,0x49,0xA4,0xDF, 0xA4,0x9F,0x33,0xDC,0x7B,0xAD,
+ 0x4C,0xC8,0x9F,0x64,0xE4,0x53, 0xE5,0xEC,0x67,0x20,0xDA,0xB6 };
+static unsigned char cfb_cipher48[24]={
+ 0xF3,0x09,0x62,0x49,0xC7,0xF4, 0x30,0xB5,0x15,0xEC,0xBB,0x85,
+ 0x97,0x5A,0x13,0x8C,0x68,0x60, 0xE2,0x38,0x34,0x3C,0xDC,0x1F };
+static unsigned char cfb_cipher64[24]={
+ 0xF3,0x09,0x62,0x49,0xC7,0xF4, 0x6E,0x51,0xA6,0x9E,0x83,0x9B,
+ 0x1A,0x92,0xF7,0x84,0x03,0x46, 0x71,0x33,0x89,0x8E,0xA6,0x22 };
+
+static unsigned char ofb_key[8]={0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef};
+static unsigned char ofb_iv[8]={0x12,0x34,0x56,0x78,0x90,0xab,0xcd,0xef};
+static unsigned char ofb_buf1[24],ofb_buf2[24],ofb_tmp[8];
+static unsigned char ofb_cipher[24]=
+ {
+ 0xf3,0x09,0x62,0x49,0xc7,0xf4,0x6e,0x51,
+ 0x35,0xf2,0x4a,0x24,0x2e,0xeb,0x3d,0x3f,
+ 0x3d,0x6d,0x5b,0xe3,0x25,0x5a,0xf8,0xc3
+ };
+
+DES_LONG cbc_cksum_ret=0xB462FEF7L;
+unsigned char cbc_cksum_data[8]={0x1D,0x26,0x93,0x97,0xf7,0xfe,0x62,0xb4};
+
+#ifndef NOPROTO
+static char *pt(unsigned char *p);
+static int cfb_test(int bits, unsigned char *cfb_cipher);
+static int cfb64_test(unsigned char *cfb_cipher);
+static int ede_cfb64_test(unsigned char *cfb_cipher);
+#else
+static char *pt();
+static int cfb_test();
+static int cfb64_test();
+static int ede_cfb64_test();
+#endif
+
+int main(argc,argv)
+int argc;
+char *argv[];
+ {
+ int i,j,err=0;
+ des_cblock in,out,outin,iv3;
+ des_key_schedule ks,ks2,ks3;
+ unsigned char cbc_in[40];
+ unsigned char cbc_out[40];
+ DES_LONG cs;
+ unsigned char qret[4][4],cret[8];
+ DES_LONG lqret[4];
+ int num;
+ char *str;
+
+ printf("Doing ecb\n");
+ for (i=0; i<NUM_TESTS; i++)
+ {
+ if ((j=des_key_sched((C_Block *)(key_data[i]),ks)) != 0)
+ {
+ printf("Key error %2d:%d\n",i+1,j);
+ err=1;
+ }
+ memcpy(in,plain_data[i],8);
+ memset(out,0,8);
+ memset(outin,0,8);
+ des_ecb_encrypt((C_Block *)in,(C_Block *)out,ks,DES_ENCRYPT);
+ des_ecb_encrypt((C_Block *)out,(C_Block *)outin,ks,DES_DECRYPT);
+
+ if (memcmp(out,cipher_data[i],8) != 0)
+ {
+ printf("Encryption error %2d\nk=%s p=%s o=%s act=%s\n",
+ i+1,pt(key_data[i]),pt(in),pt(cipher_data[i]),
+ pt(out));
+ err=1;
+ }
+ if (memcmp(in,outin,8) != 0)
+ {
+ printf("Decryption error %2d\nk=%s p=%s o=%s act=%s\n",
+ i+1,pt(key_data[i]),pt(out),pt(in),pt(outin));
+ err=1;
+ }
+ }
+
+#ifndef LIBDES_LIT
+ printf("Doing ede ecb\n");
+ for (i=0; i<(NUM_TESTS-1); i++)
+ {
+ if ((j=des_key_sched((C_Block *)(key_data[i]),ks)) != 0)
+ {
+ err=1;
+ printf("Key error %2d:%d\n",i+1,j);
+ }
+ if ((j=des_key_sched((C_Block *)(key_data[i+1]),ks2)) != 0)
+ {
+ printf("Key error %2d:%d\n",i+2,j);
+ err=1;
+ }
+ if ((j=des_key_sched((C_Block *)(key_data[i+2]),ks3)) != 0)
+ {
+ printf("Key error %2d:%d\n",i+3,j);
+ err=1;
+ }
+ memcpy(in,plain_data[i],8);
+ memset(out,0,8);
+ memset(outin,0,8);
+ des_ecb2_encrypt((C_Block *)in,(C_Block *)out,ks,ks2,
+ DES_ENCRYPT);
+ des_ecb2_encrypt((C_Block *)out,(C_Block *)outin,ks,ks2,
+ DES_DECRYPT);
+
+ if (memcmp(out,cipher_ecb2[i],8) != 0)
+ {
+ printf("Encryption error %2d\nk=%s p=%s o=%s act=%s\n",
+ i+1,pt(key_data[i]),pt(in),pt(cipher_ecb2[i]),
+ pt(out));
+ err=1;
+ }
+ if (memcmp(in,outin,8) != 0)
+ {
+ printf("Decryption error %2d\nk=%s p=%s o=%s act=%s\n",
+ i+1,pt(key_data[i]),pt(out),pt(in),pt(outin));
+ err=1;
+ }
+ }
+#endif
+
+ printf("Doing cbc\n");
+ if ((j=des_key_sched((C_Block *)cbc_key,ks)) != 0)
+ {
+ printf("Key error %d\n",j);
+ err=1;
+ }
+ memset(cbc_out,0,40);
+ memset(cbc_in,0,40);
+ memcpy(iv3,cbc_iv,sizeof(cbc_iv));
+ des_ncbc_encrypt((C_Block *)cbc_data,(C_Block *)cbc_out,
+ (long)strlen((char *)cbc_data)+1,ks,
+ (C_Block *)iv3,DES_ENCRYPT);
+ if (memcmp(cbc_out,cbc_ok,32) != 0)
+ printf("cbc_encrypt encrypt error\n");
+
+ memcpy(iv3,cbc_iv,sizeof(cbc_iv));
+ des_ncbc_encrypt((C_Block *)cbc_out,(C_Block *)cbc_in,
+ (long)strlen((char *)cbc_data)+1,ks,
+ (C_Block *)iv3,DES_DECRYPT);
+ if (memcmp(cbc_in,cbc_data,strlen((char *)cbc_data)) != 0)
+ {
+ printf("cbc_encrypt decrypt error\n");
+ err=1;
+ }
+
+#ifndef LIBDES_LIT
+ printf("Doing desx cbc\n");
+ if ((j=des_key_sched((C_Block *)cbc_key,ks)) != 0)
+ {
+ printf("Key error %d\n",j);
+ err=1;
+ }
+ memset(cbc_out,0,40);
+ memset(cbc_in,0,40);
+ memcpy(iv3,cbc_iv,sizeof(cbc_iv));
+ des_xcbc_encrypt((C_Block *)cbc_data,(C_Block *)cbc_out,
+ (long)strlen((char *)cbc_data)+1,ks,
+ (C_Block *)iv3,
+ (C_Block *)cbc2_key, (C_Block *)cbc3_key, DES_ENCRYPT);
+ if (memcmp(cbc_out,xcbc_ok,32) != 0)
+ {
+ printf("des_xcbc_encrypt encrypt error\n");
+ }
+ memcpy(iv3,cbc_iv,sizeof(cbc_iv));
+ des_xcbc_encrypt((C_Block *)cbc_out,(C_Block *)cbc_in,
+ (long)strlen((char *)cbc_data)+1,ks,
+ (C_Block *)iv3,
+ (C_Block *)cbc2_key, (C_Block *)cbc3_key, DES_DECRYPT);
+ if (memcmp(cbc_in,cbc_data,strlen((char *)cbc_data)+1) != 0)
+ {
+ printf("des_xcbc_encrypt decrypt error\n");
+ err=1;
+ }
+#endif
+
+ printf("Doing ede cbc\n");
+ if ((j=des_key_sched((C_Block *)cbc_key,ks)) != 0)
+ {
+ printf("Key error %d\n",j);
+ err=1;
+ }
+ if ((j=des_key_sched((C_Block *)cbc2_key,ks2)) != 0)
+ {
+ printf("Key error %d\n",j);
+ err=1;
+ }
+ if ((j=des_key_sched((C_Block *)cbc3_key,ks3)) != 0)
+ {
+ printf("Key error %d\n",j);
+ err=1;
+ }
+ memset(cbc_out,0,40);
+ memset(cbc_in,0,40);
+ i=strlen((char *)cbc_data)+1;
+ /* i=((i+7)/8)*8; */
+ memcpy(iv3,cbc_iv,sizeof(cbc_iv));
+
+ des_ede3_cbc_encrypt((C_Block *)cbc_data,(C_Block *)cbc_out,
+ 16L,ks,ks2,ks3,(C_Block *)iv3,DES_ENCRYPT);
+ des_ede3_cbc_encrypt((C_Block *)&(cbc_data[16]),
+ (C_Block *)&(cbc_out[16]),
+ (long)i-16,ks,ks2,ks3,(C_Block *)iv3,DES_ENCRYPT);
+ if (memcmp(cbc_out,cbc3_ok,
+ (unsigned int)(strlen((char *)cbc_data)+1+7)/8*8) != 0)
+ {
+ printf("des_ede3_cbc_encrypt encrypt error\n");
+ err=1;
+ }
+
+ memcpy(iv3,cbc_iv,sizeof(cbc_iv));
+ des_ede3_cbc_encrypt((C_Block *)cbc_out,(C_Block *)cbc_in,
+ (long)i,ks,ks2,ks3,(C_Block *)iv3,DES_DECRYPT);
+ if (memcmp(cbc_in,cbc_data,strlen(cbc_data)+1) != 0)
+ {
+ printf("des_ede3_cbc_encrypt decrypt error\n");
+ err=1;
+ }
+
+#ifndef LIBDES_LIT
+ printf("Doing pcbc\n");
+ if ((j=des_key_sched((C_Block *)cbc_key,ks)) != 0)
+ {
+ printf("Key error %d\n",j);
+ err=1;
+ }
+ memset(cbc_out,0,40);
+ memset(cbc_in,0,40);
+ des_pcbc_encrypt((C_Block *)cbc_data,(C_Block *)cbc_out,
+ (long)strlen(cbc_data)+1,ks,(C_Block *)cbc_iv,DES_ENCRYPT);
+ if (memcmp(cbc_out,pcbc_ok,32) != 0)
+ {
+ printf("pcbc_encrypt encrypt error\n");
+ err=1;
+ }
+ des_pcbc_encrypt((C_Block *)cbc_out,(C_Block *)cbc_in,
+ (long)strlen(cbc_data)+1,ks,(C_Block *)cbc_iv,DES_DECRYPT);
+ if (memcmp(cbc_in,cbc_data,strlen(cbc_data)+1) != 0)
+ {
+ printf("pcbc_encrypt decrypt error\n");
+ err=1;
+ }
+
+ printf("Doing ");
+ printf("cfb8 ");
+ err+=cfb_test(8,cfb_cipher8);
+ printf("cfb16 ");
+ err+=cfb_test(16,cfb_cipher16);
+ printf("cfb32 ");
+ err+=cfb_test(32,cfb_cipher32);
+ printf("cfb48 ");
+ err+=cfb_test(48,cfb_cipher48);
+ printf("cfb64 ");
+ err+=cfb_test(64,cfb_cipher64);
+
+ printf("cfb64() ");
+ err+=cfb64_test(cfb_cipher64);
+
+ memcpy(cfb_tmp,cfb_iv,sizeof(cfb_iv));
+ for (i=0; i<sizeof(plain); i++)
+ des_cfb_encrypt(&(plain[i]),&(cfb_buf1[i]),
+ 8,(long)1,ks,(C_Block *)cfb_tmp,DES_ENCRYPT);
+ if (memcmp(cfb_cipher8,cfb_buf1,sizeof(plain)) != 0)
+ {
+ printf("cfb_encrypt small encrypt error\n");
+ err=1;
+ }
+
+ memcpy(cfb_tmp,cfb_iv,sizeof(cfb_iv));
+ for (i=0; i<sizeof(plain); i++)
+ des_cfb_encrypt(&(cfb_buf1[i]),&(cfb_buf2[i]),
+ 8,(long)1,ks,(C_Block *)cfb_tmp,DES_DECRYPT);
+ if (memcmp(plain,cfb_buf2,sizeof(plain)) != 0)
+ {
+ printf("cfb_encrypt small decrypt error\n");
+ err=1;
+ }
+
+ printf("ede_cfb64() ");
+ err+=ede_cfb64_test(cfb_cipher64);
+
+ printf("done\n");
+
+ printf("Doing ofb\n");
+ des_key_sched((C_Block *)ofb_key,ks);
+ memcpy(ofb_tmp,ofb_iv,sizeof(ofb_iv));
+ des_ofb_encrypt(plain,ofb_buf1,64,(long)sizeof(plain)/8,ks,
+ (C_Block *)ofb_tmp);
+ if (memcmp(ofb_cipher,ofb_buf1,sizeof(ofb_buf1)) != 0)
+ {
+ printf("ofb_encrypt encrypt error\n");
+printf("%02X %02X %02X %02X %02X %02X %02X %02X\n",
+ofb_buf1[8+0], ofb_buf1[8+1], ofb_buf1[8+2], ofb_buf1[8+3],
+ofb_buf1[8+4], ofb_buf1[8+5], ofb_buf1[8+6], ofb_buf1[8+7]);
+printf("%02X %02X %02X %02X %02X %02X %02X %02X\n",
+ofb_buf1[8+0], ofb_cipher[8+1], ofb_cipher[8+2], ofb_cipher[8+3],
+ofb_buf1[8+4], ofb_cipher[8+5], ofb_cipher[8+6], ofb_cipher[8+7]);
+ err=1;
+ }
+ memcpy(ofb_tmp,ofb_iv,sizeof(ofb_iv));
+ des_ofb_encrypt(ofb_buf1,ofb_buf2,64,(long)sizeof(ofb_buf1)/8,ks,
+ (C_Block *)ofb_tmp);
+ if (memcmp(plain,ofb_buf2,sizeof(ofb_buf2)) != 0)
+ {
+ printf("ofb_encrypt decrypt error\n");
+printf("%02X %02X %02X %02X %02X %02X %02X %02X\n",
+ofb_buf2[8+0], ofb_buf2[8+1], ofb_buf2[8+2], ofb_buf2[8+3],
+ofb_buf2[8+4], ofb_buf2[8+5], ofb_buf2[8+6], ofb_buf2[8+7]);
+printf("%02X %02X %02X %02X %02X %02X %02X %02X\n",
+plain[8+0], plain[8+1], plain[8+2], plain[8+3],
+plain[8+4], plain[8+5], plain[8+6], plain[8+7]);
+ err=1;
+ }
+
+ printf("Doing ofb64\n");
+ des_key_sched((C_Block *)ofb_key,ks);
+ memcpy(ofb_tmp,ofb_iv,sizeof(ofb_iv));
+ memset(ofb_buf1,0,sizeof(ofb_buf1));
+ memset(ofb_buf2,0,sizeof(ofb_buf1));
+ num=0;
+ for (i=0; i<sizeof(plain); i++)
+ {
+ des_ofb64_encrypt(&(plain[i]),&(ofb_buf1[i]),1,ks,
+ (C_Block *)ofb_tmp,&num);
+ }
+ if (memcmp(ofb_cipher,ofb_buf1,sizeof(ofb_buf1)) != 0)
+ {
+ printf("ofb64_encrypt encrypt error\n");
+ err=1;
+ }
+ memcpy(ofb_tmp,ofb_iv,sizeof(ofb_iv));
+ num=0;
+ des_ofb64_encrypt(ofb_buf1,ofb_buf2,(long)sizeof(ofb_buf1),ks,
+ (C_Block *)ofb_tmp,&num);
+ if (memcmp(plain,ofb_buf2,sizeof(ofb_buf2)) != 0)
+ {
+ printf("ofb64_encrypt decrypt error\n");
+ err=1;
+ }
+
+ printf("Doing ede_ofb64\n");
+ des_key_sched((C_Block *)ofb_key,ks);
+ memcpy(ofb_tmp,ofb_iv,sizeof(ofb_iv));
+ memset(ofb_buf1,0,sizeof(ofb_buf1));
+ memset(ofb_buf2,0,sizeof(ofb_buf1));
+ num=0;
+ for (i=0; i<sizeof(plain); i++)
+ {
+ des_ede3_ofb64_encrypt(&(plain[i]),&(ofb_buf1[i]),1,ks,ks,ks,
+ (C_Block *)ofb_tmp,&num);
+ }
+ if (memcmp(ofb_cipher,ofb_buf1,sizeof(ofb_buf1)) != 0)
+ {
+ printf("ede_ofb64_encrypt encrypt error\n");
+ err=1;
+ }
+ memcpy(ofb_tmp,ofb_iv,sizeof(ofb_iv));
+ num=0;
+ des_ede3_ofb64_encrypt(ofb_buf1,ofb_buf2,(long)sizeof(ofb_buf1),ks,
+ ks,ks,(C_Block *)ofb_tmp,&num);
+ if (memcmp(plain,ofb_buf2,sizeof(ofb_buf2)) != 0)
+ {
+ printf("ede_ofb64_encrypt decrypt error\n");
+ err=1;
+ }
+
+ printf("Doing cbc_cksum\n");
+ des_key_sched((C_Block *)cbc_key,ks);
+ cs=des_cbc_cksum((C_Block *)cbc_data,(C_Block *)cret,
+ (long)strlen(cbc_data),ks,(C_Block *)cbc_iv);
+ if (cs != cbc_cksum_ret)
+ {
+ printf("bad return value (%08lX), should be %08lX\n",
+ (unsigned long)cs,(unsigned long)cbc_cksum_ret);
+ err=1;
+ }
+ if (memcmp(cret,cbc_cksum_data,8) != 0)
+ {
+ printf("bad cbc_cksum block returned\n");
+ err=1;
+ }
+
+ printf("Doing quad_cksum\n");
+ cs=quad_cksum((C_Block *)cbc_data,(C_Block *)qret,
+ (long)strlen(cbc_data),2,(C_Block *)cbc_iv);
+ for (i=0; i<4; i++)
+ {
+ lqret[i]=0;
+ memcpy(&(lqret[i]),&(qret[i][0]),4);
+ }
+ { /* Big-endian fix */
+ static DES_LONG l=1;
+ static unsigned char *c=(unsigned char *)&l;
+ DES_LONG ll;
+
+ if (!c[0])
+ {
+ ll=lqret[0]^lqret[3];
+ lqret[0]^=ll;
+ lqret[3]^=ll;
+ ll=lqret[1]^lqret[2];
+ lqret[1]^=ll;
+ lqret[2]^=ll;
+ }
+ }
+ if (cs != 0x70d7a63aL)
+ {
+ printf("quad_cksum error, ret %08lx should be 70d7a63a\n",
+ (unsigned long)cs);
+ err=1;
+ }
+ if (lqret[0] != 0x327eba8dL)
+ {
+ printf("quad_cksum error, out[0] %08lx is not %08lx\n",
+ (unsigned long)lqret[0],0x327eba8dL);
+ err=1;
+ }
+ if (lqret[1] != 0x201a49ccL)
+ {
+ printf("quad_cksum error, out[1] %08lx is not %08lx\n",
+ (unsigned long)lqret[1],0x201a49ccL);
+ err=1;
+ }
+ if (lqret[2] != 0x70d7a63aL)
+ {
+ printf("quad_cksum error, out[2] %08lx is not %08lx\n",
+ (unsigned long)lqret[2],0x70d7a63aL);
+ err=1;
+ }
+ if (lqret[3] != 0x501c2c26L)
+ {
+ printf("quad_cksum error, out[3] %08lx is not %08lx\n",
+ (unsigned long)lqret[3],0x501c2c26L);
+ err=1;
+ }
+#endif
+
+ printf("input word alignment test");
+ for (i=0; i<4; i++)
+ {
+ printf(" %d",i);
+ des_ncbc_encrypt((C_Block *)&(cbc_out[i]),(C_Block *)cbc_in,
+ (long)strlen(cbc_data)+1,ks,(C_Block *)cbc_iv,
+ DES_ENCRYPT);
+ }
+ printf("\noutput word alignment test");
+ for (i=0; i<4; i++)
+ {
+ printf(" %d",i);
+ des_ncbc_encrypt((C_Block *)cbc_out,(C_Block *)&(cbc_in[i]),
+ (long)strlen(cbc_data)+1,ks,(C_Block *)cbc_iv,
+ DES_ENCRYPT);
+ }
+ printf("\n");
+ printf("fast crypt test ");
+ str=crypt("testing","ef");
+ if (strcmp("efGnQx2725bI2",str) != 0)
+ {
+ printf("fast crypt error, %s should be efGnQx2725bI2\n",str);
+ err=1;
+ }
+ str=crypt("bca76;23","yA");
+ if (strcmp("yA1Rp/1hZXIJk",str) != 0)
+ {
+ printf("fast crypt error, %s should be yA1Rp/1hZXIJk\n",str);
+ err=1;
+ }
+ printf("\n");
+ exit(err);
+ return(0);
+ }
+
+static char *pt(p)
+unsigned char *p;
+ {
+ static char bufs[10][20];
+ static int bnum=0;
+ char *ret;
+ int i;
+ static char *f="0123456789ABCDEF";
+
+ ret= &(bufs[bnum++][0]);
+ bnum%=10;
+ for (i=0; i<8; i++)
+ {
+ ret[i*2]=f[(p[i]>>4)&0xf];
+ ret[i*2+1]=f[p[i]&0xf];
+ }
+ ret[16]='\0';
+ return(ret);
+ }
+
+#ifndef LIBDES_LIT
+
+static int cfb_test(bits, cfb_cipher)
+int bits;
+unsigned char *cfb_cipher;
+ {
+ des_key_schedule ks;
+ int i,err=0;
+
+ des_key_sched((C_Block *)cfb_key,ks);
+ memcpy(cfb_tmp,cfb_iv,sizeof(cfb_iv));
+ des_cfb_encrypt(plain,cfb_buf1,bits,(long)sizeof(plain),ks,
+ (C_Block *)cfb_tmp,DES_ENCRYPT);
+ if (memcmp(cfb_cipher,cfb_buf1,sizeof(plain)) != 0)
+ {
+ err=1;
+ printf("cfb_encrypt encrypt error\n");
+ for (i=0; i<24; i+=8)
+ printf("%s\n",pt(&(cfb_buf1[i])));
+ }
+ memcpy(cfb_tmp,cfb_iv,sizeof(cfb_iv));
+ des_cfb_encrypt(cfb_buf1,cfb_buf2,bits,(long)sizeof(plain),ks,
+ (C_Block *)cfb_tmp,DES_DECRYPT);
+ if (memcmp(plain,cfb_buf2,sizeof(plain)) != 0)
+ {
+ err=1;
+ printf("cfb_encrypt decrypt error\n");
+ for (i=0; i<24; i+=8)
+ printf("%s\n",pt(&(cfb_buf1[i])));
+ }
+ return(err);
+ }
+
+static int cfb64_test(cfb_cipher)
+unsigned char *cfb_cipher;
+ {
+ des_key_schedule ks;
+ int err=0,i,n;
+
+ des_key_sched((C_Block *)cfb_key,ks);
+ memcpy(cfb_tmp,cfb_iv,sizeof(cfb_iv));
+ n=0;
+ des_cfb64_encrypt(plain,cfb_buf1,(long)12,ks,
+ (C_Block *)cfb_tmp,&n,DES_ENCRYPT);
+ des_cfb64_encrypt(&(plain[12]),&(cfb_buf1[12]),
+ (long)sizeof(plain)-12,ks,
+ (C_Block *)cfb_tmp,&n,DES_ENCRYPT);
+ if (memcmp(cfb_cipher,cfb_buf1,sizeof(plain)) != 0)
+ {
+ err=1;
+ printf("cfb_encrypt encrypt error\n");
+ for (i=0; i<24; i+=8)
+ printf("%s\n",pt(&(cfb_buf1[i])));
+ }
+ memcpy(cfb_tmp,cfb_iv,sizeof(cfb_iv));
+ n=0;
+ des_cfb64_encrypt(cfb_buf1,cfb_buf2,(long)17,ks,
+ (C_Block *)cfb_tmp,&n,DES_DECRYPT);
+ des_cfb64_encrypt(&(cfb_buf1[17]),&(cfb_buf2[17]),
+ (long)sizeof(plain)-17,ks,
+ (C_Block *)cfb_tmp,&n,DES_DECRYPT);
+ if (memcmp(plain,cfb_buf2,sizeof(plain)) != 0)
+ {
+ err=1;
+ printf("cfb_encrypt decrypt error\n");
+ for (i=0; i<24; i+=8)
+ printf("%s\n",pt(&(cfb_buf2[i])));
+ }
+ return(err);
+ }
+
+static int ede_cfb64_test(cfb_cipher)
+unsigned char *cfb_cipher;
+ {
+ des_key_schedule ks;
+ int err=0,i,n;
+
+ des_key_sched((C_Block *)cfb_key,ks);
+ memcpy(cfb_tmp,cfb_iv,sizeof(cfb_iv));
+ n=0;
+ des_ede3_cfb64_encrypt(plain,cfb_buf1,(long)12,ks,ks,ks,
+ (C_Block *)cfb_tmp,&n,DES_ENCRYPT);
+ des_ede3_cfb64_encrypt(&(plain[12]),&(cfb_buf1[12]),
+ (long)sizeof(plain)-12,ks,ks,ks,
+ (C_Block *)cfb_tmp,&n,DES_ENCRYPT);
+ if (memcmp(cfb_cipher,cfb_buf1,sizeof(plain)) != 0)
+ {
+ err=1;
+ printf("ede_cfb_encrypt encrypt error\n");
+ for (i=0; i<24; i+=8)
+ printf("%s\n",pt(&(cfb_buf1[i])));
+ }
+ memcpy(cfb_tmp,cfb_iv,sizeof(cfb_iv));
+ n=0;
+ des_ede3_cfb64_encrypt(cfb_buf1,cfb_buf2,(long)17,ks,ks,ks,
+ (C_Block *)cfb_tmp,&n,DES_DECRYPT);
+ des_ede3_cfb64_encrypt(&(cfb_buf1[17]),&(cfb_buf2[17]),
+ (long)sizeof(plain)-17,ks,ks,ks,
+ (C_Block *)cfb_tmp,&n,DES_DECRYPT);
+ if (memcmp(plain,cfb_buf2,sizeof(plain)) != 0)
+ {
+ err=1;
+ printf("ede_cfb_encrypt decrypt error\n");
+ for (i=0; i<24; i+=8)
+ printf("%s\n",pt(&(cfb_buf2[i])));
+ }
+ return(err);
+ }
+
+#endif
+
diff --git a/src/libcrypto/libdes/ecb_enc.c b/src/libcrypto/libdes/ecb_enc.c
new file mode 100644
index 000000000..0b7afcf3a
--- /dev/null
+++ b/src/libcrypto/libdes/ecb_enc.c
@@ -0,0 +1,128 @@
+/* crypto/des/ecb_enc.c */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include "des_locl.h"
+#include "spr.h"
+
+char *libdes_version="libdes v 3.24 - 20-Apr-1996 - eay";
+char *DES_version="DES part of SSLeay 0.8.2b 08-Jan-1998";
+
+/* RCSID $Id: ecb_enc.c,v 1.1 2004/03/15 20:35:25 as Exp $ */
+/* This function ifdef'ed out for FreeS/WAN project. */
+#ifdef notdef
+char *des_options()
+ {
+ static int init=1;
+ static char buf[32];
+
+ if (init)
+ {
+ char *ptr,*unroll,*risc,*size;
+
+ init=0;
+#ifdef DES_PTR
+ ptr="ptr";
+#else
+ ptr="idx";
+#endif
+#if defined(DES_RISC1) || defined(DES_RISC2)
+#ifdef DES_RISC1
+ risc="risc1";
+#endif
+#ifdef DES_RISC2
+ risc="risc2";
+#endif
+#else
+ risc="cisc";
+#endif
+#ifdef DES_UNROLL
+ unroll="16";
+#else
+ unroll="4";
+#endif
+ if (sizeof(DES_LONG) != sizeof(long))
+ size="int";
+ else
+ size="long";
+ sprintf(buf,"des(%s,%s,%s,%s)",ptr,risc,unroll,size);
+ }
+ return(buf);
+ }
+#endif
+
+
+void des_ecb_encrypt(input, output, ks, enc)
+des_cblock (*input);
+des_cblock (*output);
+des_key_schedule ks;
+int enc;
+ {
+ register DES_LONG l;
+ register unsigned char *in,*out;
+ DES_LONG ll[2];
+
+ in=(unsigned char *)input;
+ out=(unsigned char *)output;
+ c2l(in,l); ll[0]=l;
+ c2l(in,l); ll[1]=l;
+ des_encrypt(ll,ks,enc);
+ l=ll[0]; l2c(l,out);
+ l=ll[1]; l2c(l,out);
+ l=ll[0]=ll[1]=0;
+ }
+
diff --git a/src/libcrypto/libdes/fcrypt.c b/src/libcrypto/libdes/fcrypt.c
new file mode 100644
index 000000000..8b9d0495b
--- /dev/null
+++ b/src/libcrypto/libdes/fcrypt.c
@@ -0,0 +1,152 @@
+/* NOCW */
+
+/* This version of crypt has been developed from my MIT compatable
+ * DES library.
+ * The library is available at pub/Crypto/DES at ftp.psy.uq.oz.au
+ * Eric Young (eay@cryptsoft.com)
+ */
+
+/* Modification by Jens Kupferschmidt (Cu)
+ * I have included directive PARA for shared memory computers.
+ * I have included a directive LONGCRYPT to using this routine to cipher
+ * passwords with more then 8 bytes like HP-UX 10.x it used. The MAXPLEN
+ * definition is the maximum of lenght of password and can changed. I have
+ * defined 24.
+ */
+
+#include "des_locl.h"
+
+/* Added more values to handle illegal salt values the way normal
+ * crypt() implementations do. The patch was sent by
+ * Bjorn Gronvall <bg@sics.se>
+ */
+static unsigned const char con_salt[128]={
+0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,
+0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,
+0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,
+0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,
+0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,
+0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x01,
+0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,
+0x0A,0x0B,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,0x20,0x21,0x22,
+0x23,0x24,0x25,0x20,0x21,0x22,0x23,0x24,
+0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,
+0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,
+0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,
+0x3D,0x3E,0x3F,0x40,0x41,0x42,0x43,0x44,
+};
+
+static unsigned const char cov_2char[64]={
+0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
+0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,
+0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,
+0x4D,0x4E,0x4F,0x50,0x51,0x52,0x53,0x54,
+0x55,0x56,0x57,0x58,0x59,0x5A,0x61,0x62,
+0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,
+0x6B,0x6C,0x6D,0x6E,0x6F,0x70,0x71,0x72,
+0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A
+};
+
+#ifndef NOPROTO
+void fcrypt_body(DES_LONG *out,des_key_schedule ks,
+ DES_LONG Eswap0, DES_LONG Eswap1);
+
+#ifdef PERL5
+char *des_crypt(const char *buf,const char *salt);
+#else
+char *crypt(const char *buf,const char *salt);
+#endif
+#else
+void fcrypt_body();
+#ifdef PERL5
+char *des_crypt();
+#else
+char *crypt();
+#endif
+#endif
+
+#ifdef PERL5
+char *des_crypt(buf,salt)
+#else
+char *crypt(buf,salt)
+#endif
+const char *buf;
+const char *salt;
+ {
+ static char buff[14];
+
+ return(des_fcrypt(buf,salt,buff));
+ }
+
+
+char *des_fcrypt(buf,salt,ret)
+const char *buf;
+const char *salt;
+char *ret;
+ {
+ unsigned int i,j,x,y;
+ DES_LONG Eswap0,Eswap1;
+ DES_LONG out[2],ll;
+ des_cblock key;
+ des_key_schedule ks;
+ unsigned char bb[9];
+ unsigned char *b=bb;
+ unsigned char c,u;
+
+ /* eay 25/08/92
+ * If you call crypt("pwd","*") as often happens when you
+ * have * as the pwd field in /etc/passwd, the function
+ * returns *\0XXXXXXXXX
+ * The \0 makes the string look like * so the pwd "*" would
+ * crypt to "*". This was found when replacing the crypt in
+ * our shared libraries. People found that the disbled
+ * accounts effectivly had no passwd :-(. */
+ x=ret[0]=((salt[0] == '\0')?'A':salt[0]);
+ Eswap0=con_salt[x]<<2;
+ x=ret[1]=((salt[1] == '\0')?'A':salt[1]);
+ Eswap1=con_salt[x]<<6;
+
+/* EAY
+r=strlen(buf);
+r=(r+7)/8;
+*/
+ for (i=0; i<8; i++)
+ {
+ c= *(buf++);
+ if (!c) break;
+ key[i]=(c<<1);
+ }
+ for (; i<8; i++)
+ key[i]=0;
+
+ des_set_key((des_cblock *)(key),ks);
+ fcrypt_body(&(out[0]),ks,Eswap0,Eswap1);
+
+ ll=out[0]; l2c(ll,b);
+ ll=out[1]; l2c(ll,b);
+ y=0;
+ u=0x80;
+ bb[8]=0;
+ for (i=2; i<13; i++)
+ {
+ c=0;
+ for (j=0; j<6; j++)
+ {
+ c<<=1;
+ if (bb[y] & u) c|=1;
+ u>>=1;
+ if (!u)
+ {
+ y++;
+ u=0x80;
+ }
+ }
+ ret[i]=cov_2char[c];
+ }
+ ret[13]='\0';
+ return(ret);
+ }
+
diff --git a/src/libcrypto/libdes/fcrypt_b.c b/src/libcrypto/libdes/fcrypt_b.c
new file mode 100644
index 000000000..5900645e7
--- /dev/null
+++ b/src/libcrypto/libdes/fcrypt_b.c
@@ -0,0 +1,148 @@
+/* crypto/des/fcrypt_b.c */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+/* #include <stdio.h> */
+
+/* This version of crypt has been developed from my MIT compatable
+ * DES library.
+ * The library is available at pub/Crypto/DES at ftp.psy.uq.oz.au
+ * Eric Young (eay@cryptsoft.com)
+ */
+
+#define DES_FCRYPT
+#include "des_locl.h"
+#undef DES_FCRYPT
+
+#undef PERM_OP
+#define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\
+ (b)^=(t),\
+ (a)^=((t)<<(n)))
+
+#undef HPERM_OP
+#define HPERM_OP(a,t,n,m) ((t)=((((a)<<(16-(n)))^(a))&(m)),\
+ (a)=(a)^(t)^(t>>(16-(n))))\
+
+void fcrypt_body(out, ks, Eswap0, Eswap1)
+DES_LONG *out;
+des_key_schedule ks;
+DES_LONG Eswap0;
+DES_LONG Eswap1;
+ {
+ register DES_LONG l,r,t,u;
+#ifdef DES_PTR
+ register unsigned char *des_SP=(unsigned char *)des_SPtrans;
+#endif
+ register DES_LONG *s;
+ register int j;
+ register DES_LONG E0,E1;
+
+ l=0;
+ r=0;
+
+ s=(DES_LONG *)ks;
+ E0=Eswap0;
+ E1=Eswap1;
+
+ for (j=0; j<25; j++)
+ {
+#ifdef DES_UNROLL
+ register int i;
+
+ for (i=0; i<32; i+=8)
+ {
+ D_ENCRYPT(l,r,i+0); /* 1 */
+ D_ENCRYPT(r,l,i+2); /* 2 */
+ D_ENCRYPT(l,r,i+4); /* 1 */
+ D_ENCRYPT(r,l,i+6); /* 2 */
+ }
+#else
+ D_ENCRYPT(l,r, 0); /* 1 */
+ D_ENCRYPT(r,l, 2); /* 2 */
+ D_ENCRYPT(l,r, 4); /* 3 */
+ D_ENCRYPT(r,l, 6); /* 4 */
+ D_ENCRYPT(l,r, 8); /* 5 */
+ D_ENCRYPT(r,l,10); /* 6 */
+ D_ENCRYPT(l,r,12); /* 7 */
+ D_ENCRYPT(r,l,14); /* 8 */
+ D_ENCRYPT(l,r,16); /* 9 */
+ D_ENCRYPT(r,l,18); /* 10 */
+ D_ENCRYPT(l,r,20); /* 11 */
+ D_ENCRYPT(r,l,22); /* 12 */
+ D_ENCRYPT(l,r,24); /* 13 */
+ D_ENCRYPT(r,l,26); /* 14 */
+ D_ENCRYPT(l,r,28); /* 15 */
+ D_ENCRYPT(r,l,30); /* 16 */
+#endif
+
+ t=l;
+ l=r;
+ r=t;
+ }
+ l=ROTATE(l,3)&0xffffffffL;
+ r=ROTATE(r,3)&0xffffffffL;
+
+ PERM_OP(l,r,t, 1,0x55555555L);
+ PERM_OP(r,l,t, 8,0x00ff00ffL);
+ PERM_OP(l,r,t, 2,0x33333333L);
+ PERM_OP(r,l,t,16,0x0000ffffL);
+ PERM_OP(l,r,t, 4,0x0f0f0f0fL);
+
+ out[0]=r;
+ out[1]=l;
+ }
+
diff --git a/src/libcrypto/libdes/podd.h b/src/libcrypto/libdes/podd.h
new file mode 100644
index 000000000..c00cd6ba0
--- /dev/null
+++ b/src/libcrypto/libdes/podd.h
@@ -0,0 +1,75 @@
+/* crypto/des/podd.h */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+static const unsigned char odd_parity[256]={
+ 1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14,
+ 16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31,
+ 32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47,
+ 49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62,
+ 64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79,
+ 81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94,
+ 97, 97, 98, 98,100,100,103,103,104,104,107,107,109,109,110,110,
+112,112,115,115,117,117,118,118,121,121,122,122,124,124,127,127,
+128,128,131,131,133,133,134,134,137,137,138,138,140,140,143,143,
+145,145,146,146,148,148,151,151,152,152,155,155,157,157,158,158,
+161,161,162,162,164,164,167,167,168,168,171,171,173,173,174,174,
+176,176,179,179,181,181,182,182,185,185,186,186,188,188,191,191,
+193,193,194,194,196,196,199,199,200,200,203,203,205,205,206,206,
+208,208,211,211,213,213,214,214,217,217,218,218,220,220,223,223,
+224,224,227,227,229,229,230,230,233,233,234,234,236,236,239,239,
+241,241,242,242,244,244,247,247,248,248,251,251,253,253,254,254};
diff --git a/src/libcrypto/libdes/set_key.c b/src/libcrypto/libdes/set_key.c
new file mode 100644
index 000000000..99ac27348
--- /dev/null
+++ b/src/libcrypto/libdes/set_key.c
@@ -0,0 +1,246 @@
+/* crypto/des/set_key.c */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+/* set_key.c v 1.4 eay 24/9/91
+ * 1.4 Speed up by 400% :-)
+ * 1.3 added register declarations.
+ * 1.2 unrolled make_key_sched a bit more
+ * 1.1 added norm_expand_bits
+ * 1.0 First working version
+ */
+#include "des_locl.h"
+#include "podd.h"
+#include "sk.h"
+
+#ifndef NOPROTO
+static int check_parity(des_cblock (*key));
+#else
+static int check_parity();
+#endif
+
+int des_check_key=0;
+
+void des_set_odd_parity(key)
+des_cblock (*key);
+ {
+ int i;
+
+ for (i=0; i<DES_KEY_SZ; i++)
+ (*key)[i]=odd_parity[(*key)[i]];
+ }
+
+static int check_parity(key)
+des_cblock (*key);
+ {
+ int i;
+
+ for (i=0; i<DES_KEY_SZ; i++)
+ {
+ if ((*key)[i] != odd_parity[(*key)[i]])
+ return(0);
+ }
+ return(1);
+ }
+
+/* Weak and semi week keys as take from
+ * %A D.W. Davies
+ * %A W.L. Price
+ * %T Security for Computer Networks
+ * %I John Wiley & Sons
+ * %D 1984
+ * Many thanks to smb@ulysses.att.com (Steven Bellovin) for the reference
+ * (and actual cblock values).
+ */
+#define NUM_WEAK_KEY 16
+static des_cblock weak_keys[NUM_WEAK_KEY]={
+ /* weak keys */
+ {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01},
+ {0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE},
+ {0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F},
+ {0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0},
+ /* semi-weak keys */
+ {0x01,0xFE,0x01,0xFE,0x01,0xFE,0x01,0xFE},
+ {0xFE,0x01,0xFE,0x01,0xFE,0x01,0xFE,0x01},
+ {0x1F,0xE0,0x1F,0xE0,0x0E,0xF1,0x0E,0xF1},
+ {0xE0,0x1F,0xE0,0x1F,0xF1,0x0E,0xF1,0x0E},
+ {0x01,0xE0,0x01,0xE0,0x01,0xF1,0x01,0xF1},
+ {0xE0,0x01,0xE0,0x01,0xF1,0x01,0xF1,0x01},
+ {0x1F,0xFE,0x1F,0xFE,0x0E,0xFE,0x0E,0xFE},
+ {0xFE,0x1F,0xFE,0x1F,0xFE,0x0E,0xFE,0x0E},
+ {0x01,0x1F,0x01,0x1F,0x01,0x0E,0x01,0x0E},
+ {0x1F,0x01,0x1F,0x01,0x0E,0x01,0x0E,0x01},
+ {0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1,0xFE},
+ {0xFE,0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1}};
+
+int des_is_weak_key(key)
+des_cblock (*key);
+ {
+ int i;
+
+ for (i=0; i<NUM_WEAK_KEY; i++)
+ /* Added == 0 to comparision, I obviously don't run
+ * this section very often :-(, thanks to
+ * engineering@MorningStar.Com for the fix
+ * eay 93/06/29
+ * Another problem, I was comparing only the first 4
+ * bytes, 97/03/18 */
+ if (memcmp(weak_keys[i],key,sizeof(des_cblock)) == 0) return(1);
+ return(0);
+ }
+
+/* NOW DEFINED IN des_local.h
+ * See ecb_encrypt.c for a pseudo description of these macros.
+ * #define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\
+ * (b)^=(t),\
+ * (a)=((a)^((t)<<(n))))
+ */
+
+#define HPERM_OP(a,t,n,m) ((t)=((((a)<<(16-(n)))^(a))&(m)),\
+ (a)=(a)^(t)^(t>>(16-(n))))
+
+/* return 0 if key parity is odd (correct),
+ * return -1 if key parity error,
+ * return -2 if illegal weak key.
+ */
+int des_set_key(key, schedule)
+des_cblock (*key);
+des_key_schedule schedule;
+ {
+ static int shifts2[16]={0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0};
+ register DES_LONG c,d,t,s,t2;
+ register unsigned char *in;
+ register DES_LONG *k;
+ register int i;
+
+ if (des_check_key)
+ {
+ if (!check_parity(key))
+ return(-1);
+
+ if (des_is_weak_key(key))
+ return(-2);
+ }
+
+ k=(DES_LONG *)schedule;
+ in=(unsigned char *)key;
+
+ c2l(in,c);
+ c2l(in,d);
+
+ /* do PC1 in 60 simple operations */
+/* PERM_OP(d,c,t,4,0x0f0f0f0fL);
+ HPERM_OP(c,t,-2, 0xcccc0000L);
+ HPERM_OP(c,t,-1, 0xaaaa0000L);
+ HPERM_OP(c,t, 8, 0x00ff0000L);
+ HPERM_OP(c,t,-1, 0xaaaa0000L);
+ HPERM_OP(d,t,-8, 0xff000000L);
+ HPERM_OP(d,t, 8, 0x00ff0000L);
+ HPERM_OP(d,t, 2, 0x33330000L);
+ d=((d&0x00aa00aaL)<<7L)|((d&0x55005500L)>>7L)|(d&0xaa55aa55L);
+ d=(d>>8)|((c&0xf0000000L)>>4);
+ c&=0x0fffffffL; */
+
+ /* I now do it in 47 simple operations :-)
+ * Thanks to John Fletcher (john_fletcher@lccmail.ocf.llnl.gov)
+ * for the inspiration. :-) */
+ PERM_OP (d,c,t,4,0x0f0f0f0fL);
+ HPERM_OP(c,t,-2,0xcccc0000L);
+ HPERM_OP(d,t,-2,0xcccc0000L);
+ PERM_OP (d,c,t,1,0x55555555L);
+ PERM_OP (c,d,t,8,0x00ff00ffL);
+ PERM_OP (d,c,t,1,0x55555555L);
+ d= (((d&0x000000ffL)<<16L)| (d&0x0000ff00L) |
+ ((d&0x00ff0000L)>>16L)|((c&0xf0000000L)>>4L));
+ c&=0x0fffffffL;
+
+ for (i=0; i<ITERATIONS; i++)
+ {
+ if (shifts2[i])
+ { c=((c>>2L)|(c<<26L)); d=((d>>2L)|(d<<26L)); }
+ else
+ { c=((c>>1L)|(c<<27L)); d=((d>>1L)|(d<<27L)); }
+ c&=0x0fffffffL;
+ d&=0x0fffffffL;
+ /* could be a few less shifts but I am to lazy at this
+ * point in time to investigate */
+ s= des_skb[0][ (c )&0x3f ]|
+ des_skb[1][((c>> 6)&0x03)|((c>> 7L)&0x3c)]|
+ des_skb[2][((c>>13)&0x0f)|((c>>14L)&0x30)]|
+ des_skb[3][((c>>20)&0x01)|((c>>21L)&0x06) |
+ ((c>>22L)&0x38)];
+ t= des_skb[4][ (d )&0x3f ]|
+ des_skb[5][((d>> 7L)&0x03)|((d>> 8L)&0x3c)]|
+ des_skb[6][ (d>>15L)&0x3f ]|
+ des_skb[7][((d>>21L)&0x0f)|((d>>22L)&0x30)];
+
+ /* table contained 0213 4657 */
+ t2=((t<<16L)|(s&0x0000ffffL))&0xffffffffL;
+ *(k++)=ROTATE(t2,30)&0xffffffffL;
+
+ t2=((s>>16L)|(t&0xffff0000L));
+ *(k++)=ROTATE(t2,26)&0xffffffffL;
+ }
+ return(0);
+ }
+
+int des_key_sched(key, schedule)
+des_cblock (*key);
+des_key_schedule schedule;
+ {
+ return(des_set_key(key,schedule));
+ }
diff --git a/src/libcrypto/libdes/sk.h b/src/libcrypto/libdes/sk.h
new file mode 100644
index 000000000..240703070
--- /dev/null
+++ b/src/libcrypto/libdes/sk.h
@@ -0,0 +1,204 @@
+/* crypto/des/sk.h */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+static const DES_LONG des_skb[8][64]={
+{
+/* for C bits (numbered as per FIPS 46) 1 2 3 4 5 6 */
+0x00000000L,0x00000010L,0x20000000L,0x20000010L,
+0x00010000L,0x00010010L,0x20010000L,0x20010010L,
+0x00000800L,0x00000810L,0x20000800L,0x20000810L,
+0x00010800L,0x00010810L,0x20010800L,0x20010810L,
+0x00000020L,0x00000030L,0x20000020L,0x20000030L,
+0x00010020L,0x00010030L,0x20010020L,0x20010030L,
+0x00000820L,0x00000830L,0x20000820L,0x20000830L,
+0x00010820L,0x00010830L,0x20010820L,0x20010830L,
+0x00080000L,0x00080010L,0x20080000L,0x20080010L,
+0x00090000L,0x00090010L,0x20090000L,0x20090010L,
+0x00080800L,0x00080810L,0x20080800L,0x20080810L,
+0x00090800L,0x00090810L,0x20090800L,0x20090810L,
+0x00080020L,0x00080030L,0x20080020L,0x20080030L,
+0x00090020L,0x00090030L,0x20090020L,0x20090030L,
+0x00080820L,0x00080830L,0x20080820L,0x20080830L,
+0x00090820L,0x00090830L,0x20090820L,0x20090830L,
+},{
+/* for C bits (numbered as per FIPS 46) 7 8 10 11 12 13 */
+0x00000000L,0x02000000L,0x00002000L,0x02002000L,
+0x00200000L,0x02200000L,0x00202000L,0x02202000L,
+0x00000004L,0x02000004L,0x00002004L,0x02002004L,
+0x00200004L,0x02200004L,0x00202004L,0x02202004L,
+0x00000400L,0x02000400L,0x00002400L,0x02002400L,
+0x00200400L,0x02200400L,0x00202400L,0x02202400L,
+0x00000404L,0x02000404L,0x00002404L,0x02002404L,
+0x00200404L,0x02200404L,0x00202404L,0x02202404L,
+0x10000000L,0x12000000L,0x10002000L,0x12002000L,
+0x10200000L,0x12200000L,0x10202000L,0x12202000L,
+0x10000004L,0x12000004L,0x10002004L,0x12002004L,
+0x10200004L,0x12200004L,0x10202004L,0x12202004L,
+0x10000400L,0x12000400L,0x10002400L,0x12002400L,
+0x10200400L,0x12200400L,0x10202400L,0x12202400L,
+0x10000404L,0x12000404L,0x10002404L,0x12002404L,
+0x10200404L,0x12200404L,0x10202404L,0x12202404L,
+},{
+/* for C bits (numbered as per FIPS 46) 14 15 16 17 19 20 */
+0x00000000L,0x00000001L,0x00040000L,0x00040001L,
+0x01000000L,0x01000001L,0x01040000L,0x01040001L,
+0x00000002L,0x00000003L,0x00040002L,0x00040003L,
+0x01000002L,0x01000003L,0x01040002L,0x01040003L,
+0x00000200L,0x00000201L,0x00040200L,0x00040201L,
+0x01000200L,0x01000201L,0x01040200L,0x01040201L,
+0x00000202L,0x00000203L,0x00040202L,0x00040203L,
+0x01000202L,0x01000203L,0x01040202L,0x01040203L,
+0x08000000L,0x08000001L,0x08040000L,0x08040001L,
+0x09000000L,0x09000001L,0x09040000L,0x09040001L,
+0x08000002L,0x08000003L,0x08040002L,0x08040003L,
+0x09000002L,0x09000003L,0x09040002L,0x09040003L,
+0x08000200L,0x08000201L,0x08040200L,0x08040201L,
+0x09000200L,0x09000201L,0x09040200L,0x09040201L,
+0x08000202L,0x08000203L,0x08040202L,0x08040203L,
+0x09000202L,0x09000203L,0x09040202L,0x09040203L,
+},{
+/* for C bits (numbered as per FIPS 46) 21 23 24 26 27 28 */
+0x00000000L,0x00100000L,0x00000100L,0x00100100L,
+0x00000008L,0x00100008L,0x00000108L,0x00100108L,
+0x00001000L,0x00101000L,0x00001100L,0x00101100L,
+0x00001008L,0x00101008L,0x00001108L,0x00101108L,
+0x04000000L,0x04100000L,0x04000100L,0x04100100L,
+0x04000008L,0x04100008L,0x04000108L,0x04100108L,
+0x04001000L,0x04101000L,0x04001100L,0x04101100L,
+0x04001008L,0x04101008L,0x04001108L,0x04101108L,
+0x00020000L,0x00120000L,0x00020100L,0x00120100L,
+0x00020008L,0x00120008L,0x00020108L,0x00120108L,
+0x00021000L,0x00121000L,0x00021100L,0x00121100L,
+0x00021008L,0x00121008L,0x00021108L,0x00121108L,
+0x04020000L,0x04120000L,0x04020100L,0x04120100L,
+0x04020008L,0x04120008L,0x04020108L,0x04120108L,
+0x04021000L,0x04121000L,0x04021100L,0x04121100L,
+0x04021008L,0x04121008L,0x04021108L,0x04121108L,
+},{
+/* for D bits (numbered as per FIPS 46) 1 2 3 4 5 6 */
+0x00000000L,0x10000000L,0x00010000L,0x10010000L,
+0x00000004L,0x10000004L,0x00010004L,0x10010004L,
+0x20000000L,0x30000000L,0x20010000L,0x30010000L,
+0x20000004L,0x30000004L,0x20010004L,0x30010004L,
+0x00100000L,0x10100000L,0x00110000L,0x10110000L,
+0x00100004L,0x10100004L,0x00110004L,0x10110004L,
+0x20100000L,0x30100000L,0x20110000L,0x30110000L,
+0x20100004L,0x30100004L,0x20110004L,0x30110004L,
+0x00001000L,0x10001000L,0x00011000L,0x10011000L,
+0x00001004L,0x10001004L,0x00011004L,0x10011004L,
+0x20001000L,0x30001000L,0x20011000L,0x30011000L,
+0x20001004L,0x30001004L,0x20011004L,0x30011004L,
+0x00101000L,0x10101000L,0x00111000L,0x10111000L,
+0x00101004L,0x10101004L,0x00111004L,0x10111004L,
+0x20101000L,0x30101000L,0x20111000L,0x30111000L,
+0x20101004L,0x30101004L,0x20111004L,0x30111004L,
+},{
+/* for D bits (numbered as per FIPS 46) 8 9 11 12 13 14 */
+0x00000000L,0x08000000L,0x00000008L,0x08000008L,
+0x00000400L,0x08000400L,0x00000408L,0x08000408L,
+0x00020000L,0x08020000L,0x00020008L,0x08020008L,
+0x00020400L,0x08020400L,0x00020408L,0x08020408L,
+0x00000001L,0x08000001L,0x00000009L,0x08000009L,
+0x00000401L,0x08000401L,0x00000409L,0x08000409L,
+0x00020001L,0x08020001L,0x00020009L,0x08020009L,
+0x00020401L,0x08020401L,0x00020409L,0x08020409L,
+0x02000000L,0x0A000000L,0x02000008L,0x0A000008L,
+0x02000400L,0x0A000400L,0x02000408L,0x0A000408L,
+0x02020000L,0x0A020000L,0x02020008L,0x0A020008L,
+0x02020400L,0x0A020400L,0x02020408L,0x0A020408L,
+0x02000001L,0x0A000001L,0x02000009L,0x0A000009L,
+0x02000401L,0x0A000401L,0x02000409L,0x0A000409L,
+0x02020001L,0x0A020001L,0x02020009L,0x0A020009L,
+0x02020401L,0x0A020401L,0x02020409L,0x0A020409L,
+},{
+/* for D bits (numbered as per FIPS 46) 16 17 18 19 20 21 */
+0x00000000L,0x00000100L,0x00080000L,0x00080100L,
+0x01000000L,0x01000100L,0x01080000L,0x01080100L,
+0x00000010L,0x00000110L,0x00080010L,0x00080110L,
+0x01000010L,0x01000110L,0x01080010L,0x01080110L,
+0x00200000L,0x00200100L,0x00280000L,0x00280100L,
+0x01200000L,0x01200100L,0x01280000L,0x01280100L,
+0x00200010L,0x00200110L,0x00280010L,0x00280110L,
+0x01200010L,0x01200110L,0x01280010L,0x01280110L,
+0x00000200L,0x00000300L,0x00080200L,0x00080300L,
+0x01000200L,0x01000300L,0x01080200L,0x01080300L,
+0x00000210L,0x00000310L,0x00080210L,0x00080310L,
+0x01000210L,0x01000310L,0x01080210L,0x01080310L,
+0x00200200L,0x00200300L,0x00280200L,0x00280300L,
+0x01200200L,0x01200300L,0x01280200L,0x01280300L,
+0x00200210L,0x00200310L,0x00280210L,0x00280310L,
+0x01200210L,0x01200310L,0x01280210L,0x01280310L,
+},{
+/* for D bits (numbered as per FIPS 46) 22 23 24 25 27 28 */
+0x00000000L,0x04000000L,0x00040000L,0x04040000L,
+0x00000002L,0x04000002L,0x00040002L,0x04040002L,
+0x00002000L,0x04002000L,0x00042000L,0x04042000L,
+0x00002002L,0x04002002L,0x00042002L,0x04042002L,
+0x00000020L,0x04000020L,0x00040020L,0x04040020L,
+0x00000022L,0x04000022L,0x00040022L,0x04040022L,
+0x00002020L,0x04002020L,0x00042020L,0x04042020L,
+0x00002022L,0x04002022L,0x00042022L,0x04042022L,
+0x00000800L,0x04000800L,0x00040800L,0x04040800L,
+0x00000802L,0x04000802L,0x00040802L,0x04040802L,
+0x00002800L,0x04002800L,0x00042800L,0x04042800L,
+0x00002802L,0x04002802L,0x00042802L,0x04042802L,
+0x00000820L,0x04000820L,0x00040820L,0x04040820L,
+0x00000822L,0x04000822L,0x00040822L,0x04040822L,
+0x00002820L,0x04002820L,0x00042820L,0x04042820L,
+0x00002822L,0x04002822L,0x00042822L,0x04042822L,
+}};
diff --git a/src/libcrypto/libdes/speed.c b/src/libcrypto/libdes/speed.c
new file mode 100644
index 000000000..e3d753b2e
--- /dev/null
+++ b/src/libcrypto/libdes/speed.c
@@ -0,0 +1,329 @@
+/* crypto/des/speed.c */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+/* 11-Sep-92 Andrew Daviel Support for Silicon Graphics IRIX added */
+/* 06-Apr-92 Luke Brennan Support for VMS and add extra signal calls */
+
+#ifndef MSDOS
+#define TIMES
+#endif
+
+#include <stdio.h>
+#ifndef MSDOS
+#include <unistd.h>
+#else
+#include <io.h>
+extern int exit();
+#endif
+#include <signal.h>
+#ifndef VMS
+#ifndef _IRIX
+#include <time.h>
+#endif
+#ifdef TIMES
+#include <sys/types.h>
+#include <sys/times.h>
+#endif
+#else /* VMS */
+#include <types.h>
+struct tms {
+ time_t tms_utime;
+ time_t tms_stime;
+ time_t tms_uchild; /* I dunno... */
+ time_t tms_uchildsys; /* so these names are a guess :-) */
+ }
+#endif
+#ifndef TIMES
+#include <sys/timeb.h>
+#endif
+
+#ifdef sun
+#include <limits.h>
+#include <sys/param.h>
+#endif
+
+#include "des_locl.h"
+
+/* The following if from times(3) man page. It may need to be changed */
+#ifndef HZ
+# ifndef CLK_TCK
+# ifndef _BSD_CLK_TCK_ /* FreeBSD fix */
+# ifndef VMS
+# define HZ 100.0
+# else /* VMS */
+# define HZ 100.0
+# endif
+# else /* _BSD_CLK_TCK_ */
+# define HZ ((double)_BSD_CLK_TCK_)
+# endif
+# else /* CLK_TCK */
+# define HZ ((double)CLK_TCK)
+# endif
+#endif
+
+#define BUFSIZE ((long)1024)
+long run=0;
+
+#ifndef NOPROTO
+double Time_F(int s);
+#else
+double Time_F();
+#endif
+
+#ifdef SIGALRM
+#if defined(__STDC__) || defined(sgi) || defined(_AIX)
+#define SIGRETTYPE void
+#else
+#define SIGRETTYPE int
+#endif
+
+#ifndef NOPROTO
+SIGRETTYPE sig_done(int sig);
+#else
+SIGRETTYPE sig_done();
+#endif
+
+SIGRETTYPE sig_done(sig)
+int sig;
+ {
+ signal(SIGALRM,sig_done);
+ run=0;
+#ifdef LINT
+ sig=sig;
+#endif
+ }
+#endif
+
+#define START 0
+#define STOP 1
+
+double Time_F(s)
+int s;
+ {
+ double ret;
+#ifdef TIMES
+ static struct tms tstart,tend;
+
+ if (s == START)
+ {
+ times(&tstart);
+ return(0);
+ }
+ else
+ {
+ times(&tend);
+ ret=((double)(tend.tms_utime-tstart.tms_utime))/HZ;
+ return((ret == 0.0)?1e-6:ret);
+ }
+#else /* !times() */
+ static struct timeb tstart,tend;
+ long i;
+
+ if (s == START)
+ {
+ ftime(&tstart);
+ return(0);
+ }
+ else
+ {
+ ftime(&tend);
+ i=(long)tend.millitm-(long)tstart.millitm;
+ ret=((double)(tend.time-tstart.time))+((double)i)/1e3;
+ return((ret == 0.0)?1e-6:ret);
+ }
+#endif
+ }
+
+int main(argc,argv)
+int argc;
+char **argv;
+ {
+ long count;
+ static unsigned char buf[BUFSIZE];
+ static des_cblock key ={0x12,0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0};
+ static des_cblock key2={0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0,0x12};
+ static des_cblock key3={0x56,0x78,0x9a,0xbc,0xde,0xf0,0x12,0x34};
+ des_key_schedule sch,sch2,sch3;
+ double a,b,c,d,e;
+#ifndef SIGALRM
+ long ca,cb,cc,cd,ce;
+#endif
+
+#ifndef TIMES
+ printf("To get the most acurate results, try to run this\n");
+ printf("program when this computer is idle.\n");
+#endif
+
+ des_set_key((C_Block *)key2,sch2);
+ des_set_key((C_Block *)key3,sch3);
+
+#ifndef SIGALRM
+ printf("First we calculate the approximate speed ...\n");
+ des_set_key((C_Block *)key,sch);
+ count=10;
+ do {
+ long i;
+ DES_LONG data[2];
+
+ count*=2;
+ Time_F(START);
+ for (i=count; i; i--)
+ des_encrypt(data,&(sch[0]),DES_ENCRYPT);
+ d=Time_F(STOP);
+ } while (d < 3.0);
+ ca=count;
+ cb=count*3;
+ cc=count*3*8/BUFSIZE+1;
+ cd=count*8/BUFSIZE+1;
+ ce=count/20+1;
+ printf("Doing set_key %ld times\n",ca);
+#define COND(d) (count != (d))
+#define COUNT(d) (d)
+#else
+#define COND(c) (run)
+#define COUNT(d) (count)
+ signal(SIGALRM,sig_done);
+ printf("Doing set_key for 10 seconds\n");
+ alarm(10);
+#endif
+
+ Time_F(START);
+ for (count=0,run=1; COND(ca); count++)
+ des_set_key((C_Block *)key,sch);
+ d=Time_F(STOP);
+ printf("%ld set_key's in %.2f seconds\n",count,d);
+ a=((double)COUNT(ca))/d;
+
+#ifdef SIGALRM
+ printf("Doing des_encrypt's for 10 seconds\n");
+ alarm(10);
+#else
+ printf("Doing des_encrypt %ld times\n",cb);
+#endif
+ Time_F(START);
+ for (count=0,run=1; COND(cb); count++)
+ {
+ DES_LONG data[2];
+
+ des_encrypt(data,&(sch[0]),DES_ENCRYPT);
+ }
+ d=Time_F(STOP);
+ printf("%ld des_encrypt's in %.2f second\n",count,d);
+ b=((double)COUNT(cb)*8)/d;
+
+#ifdef SIGALRM
+ printf("Doing des_cbc_encrypt on %ld byte blocks for 10 seconds\n",
+ BUFSIZE);
+ alarm(10);
+#else
+ printf("Doing des_cbc_encrypt %ld times on %ld byte blocks\n",cc,
+ BUFSIZE);
+#endif
+ Time_F(START);
+ for (count=0,run=1; COND(cc); count++)
+ des_ncbc_encrypt((C_Block *)buf,(C_Block *)buf,BUFSIZE,&(sch[0]),
+ (C_Block *)&(key[0]),DES_ENCRYPT);
+ d=Time_F(STOP);
+ printf("%ld des_cbc_encrypt's of %ld byte blocks in %.2f second\n",
+ count,BUFSIZE,d);
+ c=((double)COUNT(cc)*BUFSIZE)/d;
+
+#ifdef SIGALRM
+ printf("Doing des_ede_cbc_encrypt on %ld byte blocks for 10 seconds\n",
+ BUFSIZE);
+ alarm(10);
+#else
+ printf("Doing des_ede_cbc_encrypt %ld times on %ld byte blocks\n",cd,
+ BUFSIZE);
+#endif
+ Time_F(START);
+ for (count=0,run=1; COND(cd); count++)
+ des_ede3_cbc_encrypt((C_Block *)buf,(C_Block *)buf,BUFSIZE,
+ &(sch[0]),
+ &(sch2[0]),
+ &(sch3[0]),
+ (C_Block *)&(key[0]),
+ DES_ENCRYPT);
+ d=Time_F(STOP);
+ printf("%ld des_ede_cbc_encrypt's of %ld byte blocks in %.2f second\n",
+ count,BUFSIZE,d);
+ d=((double)COUNT(cd)*BUFSIZE)/d;
+
+#ifdef SIGALRM
+ printf("Doing crypt for 10 seconds\n");
+ alarm(10);
+#else
+ printf("Doing crypt %ld times\n",ce);
+#endif
+ Time_F(START);
+ for (count=0,run=1; COND(ce); count++)
+ crypt("testing1","ef");
+ e=Time_F(STOP);
+ printf("%ld crypts in %.2f second\n",count,e);
+ e=((double)COUNT(ce))/e;
+
+ printf("set_key per sec = %12.2f (%9.3fuS)\n",a,1.0e6/a);
+ printf("DES raw ecb bytes per sec = %12.2f (%9.3fuS)\n",b,8.0e6/b);
+ printf("DES cbc bytes per sec = %12.2f (%9.3fuS)\n",c,8.0e6/c);
+ printf("DES ede cbc bytes per sec = %12.2f (%9.3fuS)\n",d,8.0e6/d);
+ printf("crypt per sec = %12.2f (%9.3fuS)\n",e,1.0e6/e);
+ exit(0);
+#if defined(LINT) || defined(MSDOS)
+ return(0);
+#endif
+ }
diff --git a/src/libcrypto/libdes/spr.h b/src/libcrypto/libdes/spr.h
new file mode 100644
index 000000000..a84d6a723
--- /dev/null
+++ b/src/libcrypto/libdes/spr.h
@@ -0,0 +1,204 @@
+/* crypto/des/spr.h */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+const DES_LONG des_SPtrans[8][64]={
+{
+/* nibble 0 */
+0x02080800L, 0x00080000L, 0x02000002L, 0x02080802L,
+0x02000000L, 0x00080802L, 0x00080002L, 0x02000002L,
+0x00080802L, 0x02080800L, 0x02080000L, 0x00000802L,
+0x02000802L, 0x02000000L, 0x00000000L, 0x00080002L,
+0x00080000L, 0x00000002L, 0x02000800L, 0x00080800L,
+0x02080802L, 0x02080000L, 0x00000802L, 0x02000800L,
+0x00000002L, 0x00000800L, 0x00080800L, 0x02080002L,
+0x00000800L, 0x02000802L, 0x02080002L, 0x00000000L,
+0x00000000L, 0x02080802L, 0x02000800L, 0x00080002L,
+0x02080800L, 0x00080000L, 0x00000802L, 0x02000800L,
+0x02080002L, 0x00000800L, 0x00080800L, 0x02000002L,
+0x00080802L, 0x00000002L, 0x02000002L, 0x02080000L,
+0x02080802L, 0x00080800L, 0x02080000L, 0x02000802L,
+0x02000000L, 0x00000802L, 0x00080002L, 0x00000000L,
+0x00080000L, 0x02000000L, 0x02000802L, 0x02080800L,
+0x00000002L, 0x02080002L, 0x00000800L, 0x00080802L,
+},{
+/* nibble 1 */
+0x40108010L, 0x00000000L, 0x00108000L, 0x40100000L,
+0x40000010L, 0x00008010L, 0x40008000L, 0x00108000L,
+0x00008000L, 0x40100010L, 0x00000010L, 0x40008000L,
+0x00100010L, 0x40108000L, 0x40100000L, 0x00000010L,
+0x00100000L, 0x40008010L, 0x40100010L, 0x00008000L,
+0x00108010L, 0x40000000L, 0x00000000L, 0x00100010L,
+0x40008010L, 0x00108010L, 0x40108000L, 0x40000010L,
+0x40000000L, 0x00100000L, 0x00008010L, 0x40108010L,
+0x00100010L, 0x40108000L, 0x40008000L, 0x00108010L,
+0x40108010L, 0x00100010L, 0x40000010L, 0x00000000L,
+0x40000000L, 0x00008010L, 0x00100000L, 0x40100010L,
+0x00008000L, 0x40000000L, 0x00108010L, 0x40008010L,
+0x40108000L, 0x00008000L, 0x00000000L, 0x40000010L,
+0x00000010L, 0x40108010L, 0x00108000L, 0x40100000L,
+0x40100010L, 0x00100000L, 0x00008010L, 0x40008000L,
+0x40008010L, 0x00000010L, 0x40100000L, 0x00108000L,
+},{
+/* nibble 2 */
+0x04000001L, 0x04040100L, 0x00000100L, 0x04000101L,
+0x00040001L, 0x04000000L, 0x04000101L, 0x00040100L,
+0x04000100L, 0x00040000L, 0x04040000L, 0x00000001L,
+0x04040101L, 0x00000101L, 0x00000001L, 0x04040001L,
+0x00000000L, 0x00040001L, 0x04040100L, 0x00000100L,
+0x00000101L, 0x04040101L, 0x00040000L, 0x04000001L,
+0x04040001L, 0x04000100L, 0x00040101L, 0x04040000L,
+0x00040100L, 0x00000000L, 0x04000000L, 0x00040101L,
+0x04040100L, 0x00000100L, 0x00000001L, 0x00040000L,
+0x00000101L, 0x00040001L, 0x04040000L, 0x04000101L,
+0x00000000L, 0x04040100L, 0x00040100L, 0x04040001L,
+0x00040001L, 0x04000000L, 0x04040101L, 0x00000001L,
+0x00040101L, 0x04000001L, 0x04000000L, 0x04040101L,
+0x00040000L, 0x04000100L, 0x04000101L, 0x00040100L,
+0x04000100L, 0x00000000L, 0x04040001L, 0x00000101L,
+0x04000001L, 0x00040101L, 0x00000100L, 0x04040000L,
+},{
+/* nibble 3 */
+0x00401008L, 0x10001000L, 0x00000008L, 0x10401008L,
+0x00000000L, 0x10400000L, 0x10001008L, 0x00400008L,
+0x10401000L, 0x10000008L, 0x10000000L, 0x00001008L,
+0x10000008L, 0x00401008L, 0x00400000L, 0x10000000L,
+0x10400008L, 0x00401000L, 0x00001000L, 0x00000008L,
+0x00401000L, 0x10001008L, 0x10400000L, 0x00001000L,
+0x00001008L, 0x00000000L, 0x00400008L, 0x10401000L,
+0x10001000L, 0x10400008L, 0x10401008L, 0x00400000L,
+0x10400008L, 0x00001008L, 0x00400000L, 0x10000008L,
+0x00401000L, 0x10001000L, 0x00000008L, 0x10400000L,
+0x10001008L, 0x00000000L, 0x00001000L, 0x00400008L,
+0x00000000L, 0x10400008L, 0x10401000L, 0x00001000L,
+0x10000000L, 0x10401008L, 0x00401008L, 0x00400000L,
+0x10401008L, 0x00000008L, 0x10001000L, 0x00401008L,
+0x00400008L, 0x00401000L, 0x10400000L, 0x10001008L,
+0x00001008L, 0x10000000L, 0x10000008L, 0x10401000L,
+},{
+/* nibble 4 */
+0x08000000L, 0x00010000L, 0x00000400L, 0x08010420L,
+0x08010020L, 0x08000400L, 0x00010420L, 0x08010000L,
+0x00010000L, 0x00000020L, 0x08000020L, 0x00010400L,
+0x08000420L, 0x08010020L, 0x08010400L, 0x00000000L,
+0x00010400L, 0x08000000L, 0x00010020L, 0x00000420L,
+0x08000400L, 0x00010420L, 0x00000000L, 0x08000020L,
+0x00000020L, 0x08000420L, 0x08010420L, 0x00010020L,
+0x08010000L, 0x00000400L, 0x00000420L, 0x08010400L,
+0x08010400L, 0x08000420L, 0x00010020L, 0x08010000L,
+0x00010000L, 0x00000020L, 0x08000020L, 0x08000400L,
+0x08000000L, 0x00010400L, 0x08010420L, 0x00000000L,
+0x00010420L, 0x08000000L, 0x00000400L, 0x00010020L,
+0x08000420L, 0x00000400L, 0x00000000L, 0x08010420L,
+0x08010020L, 0x08010400L, 0x00000420L, 0x00010000L,
+0x00010400L, 0x08010020L, 0x08000400L, 0x00000420L,
+0x00000020L, 0x00010420L, 0x08010000L, 0x08000020L,
+},{
+/* nibble 5 */
+0x80000040L, 0x00200040L, 0x00000000L, 0x80202000L,
+0x00200040L, 0x00002000L, 0x80002040L, 0x00200000L,
+0x00002040L, 0x80202040L, 0x00202000L, 0x80000000L,
+0x80002000L, 0x80000040L, 0x80200000L, 0x00202040L,
+0x00200000L, 0x80002040L, 0x80200040L, 0x00000000L,
+0x00002000L, 0x00000040L, 0x80202000L, 0x80200040L,
+0x80202040L, 0x80200000L, 0x80000000L, 0x00002040L,
+0x00000040L, 0x00202000L, 0x00202040L, 0x80002000L,
+0x00002040L, 0x80000000L, 0x80002000L, 0x00202040L,
+0x80202000L, 0x00200040L, 0x00000000L, 0x80002000L,
+0x80000000L, 0x00002000L, 0x80200040L, 0x00200000L,
+0x00200040L, 0x80202040L, 0x00202000L, 0x00000040L,
+0x80202040L, 0x00202000L, 0x00200000L, 0x80002040L,
+0x80000040L, 0x80200000L, 0x00202040L, 0x00000000L,
+0x00002000L, 0x80000040L, 0x80002040L, 0x80202000L,
+0x80200000L, 0x00002040L, 0x00000040L, 0x80200040L,
+},{
+/* nibble 6 */
+0x00004000L, 0x00000200L, 0x01000200L, 0x01000004L,
+0x01004204L, 0x00004004L, 0x00004200L, 0x00000000L,
+0x01000000L, 0x01000204L, 0x00000204L, 0x01004000L,
+0x00000004L, 0x01004200L, 0x01004000L, 0x00000204L,
+0x01000204L, 0x00004000L, 0x00004004L, 0x01004204L,
+0x00000000L, 0x01000200L, 0x01000004L, 0x00004200L,
+0x01004004L, 0x00004204L, 0x01004200L, 0x00000004L,
+0x00004204L, 0x01004004L, 0x00000200L, 0x01000000L,
+0x00004204L, 0x01004000L, 0x01004004L, 0x00000204L,
+0x00004000L, 0x00000200L, 0x01000000L, 0x01004004L,
+0x01000204L, 0x00004204L, 0x00004200L, 0x00000000L,
+0x00000200L, 0x01000004L, 0x00000004L, 0x01000200L,
+0x00000000L, 0x01000204L, 0x01000200L, 0x00004200L,
+0x00000204L, 0x00004000L, 0x01004204L, 0x01000000L,
+0x01004200L, 0x00000004L, 0x00004004L, 0x01004204L,
+0x01000004L, 0x01004200L, 0x01004000L, 0x00004004L,
+},{
+/* nibble 7 */
+0x20800080L, 0x20820000L, 0x00020080L, 0x00000000L,
+0x20020000L, 0x00800080L, 0x20800000L, 0x20820080L,
+0x00000080L, 0x20000000L, 0x00820000L, 0x00020080L,
+0x00820080L, 0x20020080L, 0x20000080L, 0x20800000L,
+0x00020000L, 0x00820080L, 0x00800080L, 0x20020000L,
+0x20820080L, 0x20000080L, 0x00000000L, 0x00820000L,
+0x20000000L, 0x00800000L, 0x20020080L, 0x20800080L,
+0x00800000L, 0x00020000L, 0x20820000L, 0x00000080L,
+0x00800000L, 0x00020000L, 0x20000080L, 0x20820080L,
+0x00020080L, 0x20000000L, 0x00000000L, 0x00820000L,
+0x20800080L, 0x20020080L, 0x20020000L, 0x00800080L,
+0x20820000L, 0x00000080L, 0x00800080L, 0x20020000L,
+0x20820080L, 0x00800000L, 0x20800000L, 0x20000080L,
+0x00820000L, 0x00020080L, 0x20020080L, 0x20800000L,
+0x00000080L, 0x20820000L, 0x00820080L, 0x00000000L,
+0x20000000L, 0x20800080L, 0x00020000L, 0x00820080L,
+}};
diff --git a/src/libcrypto/libserpent/serpent.c b/src/libcrypto/libserpent/serpent.c
new file mode 100644
index 000000000..f2cea250e
--- /dev/null
+++ b/src/libcrypto/libserpent/serpent.c
@@ -0,0 +1,995 @@
+
+/* Optimized implementation of the Serpent AES candidate algorithm
+ * Designed by Anderson, Biham and Knudsen and Implemented by
+ * Gisle Sælensminde 2000.
+ *
+ * The implementation is based on the pentium optimised sboxes of
+ * Dag Arne Osvik. Even these sboxes are designed to be optimal for x86
+ * processors they are efficient on other processors as well, but the speedup
+ * isn't so impressive compared to other implementations.
+ *
+ * This program 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.
+ */
+
+#ifdef __KERNEL__
+#include <linux/init.h>
+#include <linux/types.h>
+
+#include <asm/byteorder.h>
+#else
+#include <sys/types.h>
+#include <asm/byteorder.h>
+#endif
+
+#include "serpent.h"
+
+#define rotl(reg, val) ((reg << val) | (reg >> (32 - val)))
+#define rotr(reg, val) ((reg >> val) | (reg << (32 - val)))
+
+#ifdef __cpu_to_be32
+#define BLOCK_SWAP
+#define io_swap(x) __cpu_to_be32(x)
+#else
+#undef BLOCK_SWAP
+#endif
+
+/* The sbox functions. The first four parameters is the input bits, and
+ * the last is a tempoary. These parameters are also used for output, but
+ * the bit order is permuted. The output bit order from S0 is
+ * (1 4 2 0 3), where 3 is the (now useless) tempoary.
+ */
+
+#define S0(r0,r1,r2,r3,r4) \
+ r3 = r3 ^ r0; \
+ r4 = r1; \
+ r1 = r1 & r3; \
+ r4 = r4 ^ r2; \
+ r1 = r1 ^ r0; \
+ r0 = r0 | r3; \
+ r0 = r0 ^ r4; \
+ r4 = r4 ^ r3; \
+ r3 = r3 ^ r2; \
+ r2 = r2 | r1; \
+ r2 = r2 ^ r4; \
+ r4 = -1 ^ r4; \
+ r4 = r4 | r1; \
+ r1 = r1 ^ r3; \
+ r1 = r1 ^ r4; \
+ r3 = r3 | r0; \
+ r1 = r1 ^ r3; \
+ r4 = r4 ^ r3;
+
+#define S1(r0,r1,r2,r3,r4) \
+ r1 = -1 ^ r1; \
+ r4 = r0; \
+ r0 = r0 ^ r1; \
+ r4 = r4 | r1; \
+ r4 = r4 ^ r3; \
+ r3 = r3 & r0; \
+ r2 = r2 ^ r4; \
+ r3 = r3 ^ r1; \
+ r3 = r3 | r2; \
+ r0 = r0 ^ r4; \
+ r3 = r3 ^ r0; \
+ r1 = r1 & r2; \
+ r0 = r0 | r1; \
+ r1 = r1 ^ r4; \
+ r0 = r0 ^ r2; \
+ r4 = r4 | r3; \
+ r0 = r0 ^ r4; \
+ r4 = -1 ^ r4; \
+ r1 = r1 ^ r3; \
+ r4 = r4 & r2; \
+ r1 = -1 ^ r1; \
+ r4 = r4 ^ r0; \
+ r1 = r1 ^ r4;
+
+#define S2(r0,r1,r2,r3,r4) \
+ r4 = r0; \
+ r0 = r0 & r2; \
+ r0 = r0 ^ r3; \
+ r2 = r2 ^ r1; \
+ r2 = r2 ^ r0; \
+ r3 = r3 | r4; \
+ r3 = r3 ^ r1; \
+ r4 = r4 ^ r2; \
+ r1 = r3; \
+ r3 = r3 | r4; \
+ r3 = r3 ^ r0; \
+ r0 = r0 & r1; \
+ r4 = r4 ^ r0; \
+ r1 = r1 ^ r3; \
+ r1 = r1 ^ r4; \
+ r4 = -1 ^ r4;
+
+#define S3(r0,r1,r2,r3,r4) \
+ r4 = r0 ; \
+ r0 = r0 | r3; \
+ r3 = r3 ^ r1; \
+ r1 = r1 & r4; \
+ r4 = r4 ^ r2; \
+ r2 = r2 ^ r3; \
+ r3 = r3 & r0; \
+ r4 = r4 | r1; \
+ r3 = r3 ^ r4; \
+ r0 = r0 ^ r1; \
+ r4 = r4 & r0; \
+ r1 = r1 ^ r3; \
+ r4 = r4 ^ r2; \
+ r1 = r1 | r0; \
+ r1 = r1 ^ r2; \
+ r0 = r0 ^ r3; \
+ r2 = r1; \
+ r1 = r1 | r3; \
+ r1 = r1 ^ r0;
+
+#define S4(r0,r1,r2,r3,r4) \
+ r1 = r1 ^ r3; \
+ r3 = -1 ^ r3; \
+ r2 = r2 ^ r3; \
+ r3 = r3 ^ r0; \
+ r4 = r1; \
+ r1 = r1 & r3; \
+ r1 = r1 ^ r2; \
+ r4 = r4 ^ r3; \
+ r0 = r0 ^ r4; \
+ r2 = r2 & r4; \
+ r2 = r2 ^ r0; \
+ r0 = r0 & r1; \
+ r3 = r3 ^ r0; \
+ r4 = r4 | r1; \
+ r4 = r4 ^ r0; \
+ r0 = r0 | r3; \
+ r0 = r0 ^ r2; \
+ r2 = r2 & r3; \
+ r0 = -1 ^ r0; \
+ r4 = r4 ^ r2;
+
+#define S5(r0,r1,r2,r3,r4) \
+ r0 = r0 ^ r1; \
+ r1 = r1 ^ r3; \
+ r3 = -1 ^ r3; \
+ r4 = r1; \
+ r1 = r1 & r0; \
+ r2 = r2 ^ r3; \
+ r1 = r1 ^ r2; \
+ r2 = r2 | r4; \
+ r4 = r4 ^ r3; \
+ r3 = r3 & r1; \
+ r3 = r3 ^ r0; \
+ r4 = r4 ^ r1; \
+ r4 = r4 ^ r2; \
+ r2 = r2 ^ r0; \
+ r0 = r0 & r3; \
+ r2 = -1 ^ r2; \
+ r0 = r0 ^ r4; \
+ r4 = r4 | r3; \
+ r2 = r2 ^ r4;
+
+#define S6(r0,r1,r2,r3,r4) \
+ r2 = -1 ^ r2; \
+ r4 = r3; \
+ r3 = r3 & r0; \
+ r0 = r0 ^ r4; \
+ r3 = r3 ^ r2; \
+ r2 = r2 | r4; \
+ r1 = r1 ^ r3; \
+ r2 = r2 ^ r0; \
+ r0 = r0 | r1; \
+ r2 = r2 ^ r1; \
+ r4 = r4 ^ r0; \
+ r0 = r0 | r3; \
+ r0 = r0 ^ r2; \
+ r4 = r4 ^ r3; \
+ r4 = r4 ^ r0; \
+ r3 = -1 ^ r3; \
+ r2 = r2 & r4; \
+ r2 = r2 ^ r3;
+
+#define S7(r0,r1,r2,r3,r4) \
+ r4 = r2; \
+ r2 = r2 & r1; \
+ r2 = r2 ^ r3; \
+ r3 = r3 & r1; \
+ r4 = r4 ^ r2; \
+ r2 = r2 ^ r1; \
+ r1 = r1 ^ r0; \
+ r0 = r0 | r4; \
+ r0 = r0 ^ r2; \
+ r3 = r3 ^ r1; \
+ r2 = r2 ^ r3; \
+ r3 = r3 & r0; \
+ r3 = r3 ^ r4; \
+ r4 = r4 ^ r2; \
+ r2 = r2 & r0; \
+ r4 = -1 ^ r4; \
+ r2 = r2 ^ r4; \
+ r4 = r4 & r0; \
+ r1 = r1 ^ r3; \
+ r4 = r4 ^ r1;
+
+/* The inverse sboxes */
+
+#define I0(r0,r1,r2,r3,r4) \
+ r2 = r2 ^ -1; \
+ r4 = r1; \
+ r1 = r1 | r0; \
+ r4 = r4 ^ -1; \
+ r1 = r1 ^ r2; \
+ r2 = r2 | r4; \
+ r1 = r1 ^ r3; \
+ r0 = r0 ^ r4; \
+ r2 = r2 ^ r0; \
+ r0 = r0 & r3; \
+ r4 = r4 ^ r0; \
+ r0 = r0 | r1; \
+ r0 = r0 ^ r2; \
+ r3 = r3 ^ r4; \
+ r2 = r2 ^ r1; \
+ r3 = r3 ^ r0; \
+ r3 = r3 ^ r1; \
+ r2 = r2 & r3; \
+ r4 = r4 ^ r2;
+
+#define I1(r0,r1,r2,r3,r4) \
+ r4 = r1; \
+ r1 = r1 ^ r3; \
+ r3 = r3 & r1; \
+ r4 = r4 ^ r2; \
+ r3 = r3 ^ r0; \
+ r0 = r0 | r1; \
+ r2 = r2 ^ r3; \
+ r0 = r0 ^ r4; \
+ r0 = r0 | r2; \
+ r1 = r1 ^ r3; \
+ r0 = r0 ^ r1; \
+ r1 = r1 | r3; \
+ r1 = r1 ^ r0; \
+ r4 = r4 ^ -1; \
+ r4 = r4 ^ r1; \
+ r1 = r1 | r0; \
+ r1 = r1 ^ r0; \
+ r1 = r1 | r4; \
+ r3 = r3 ^ r1;
+
+#define I2(r0,r1,r2,r3,r4) \
+ r2 = r2 ^ r3; \
+ r3 = r3 ^ r0; \
+ r4 = r3; \
+ r3 = r3 & r2; \
+ r3 = r3 ^ r1; \
+ r1 = r1 | r2; \
+ r1 = r1 ^ r4; \
+ r4 = r4 & r3; \
+ r2 = r2 ^ r3; \
+ r4 = r4 & r0; \
+ r4 = r4 ^ r2; \
+ r2 = r2 & r1; \
+ r2 = r2 | r0; \
+ r3 = r3 ^ -1; \
+ r2 = r2 ^ r3; \
+ r0 = r0 ^ r3; \
+ r0 = r0 & r1; \
+ r3 = r3 ^ r4; \
+ r3 = r3 ^ r0;
+
+#define I3(r0,r1,r2,r3,r4) \
+ r4 = r2; \
+ r2 = r2 ^ r1; \
+ r0 = r0 ^ r2; \
+ r4 = r4 & r2; \
+ r4 = r4 ^ r0; \
+ r0 = r0 & r1; \
+ r1 = r1 ^ r3; \
+ r3 = r3 | r4; \
+ r2 = r2 ^ r3; \
+ r0 = r0 ^ r3; \
+ r1 = r1 ^ r4; \
+ r3 = r3 & r2; \
+ r3 = r3 ^ r1; \
+ r1 = r1 ^ r0; \
+ r1 = r1 | r2; \
+ r0 = r0 ^ r3; \
+ r1 = r1 ^ r4; \
+ r0 = r0 ^ r1;
+
+#define I4(r0,r1,r2,r3,r4) \
+ r4 = r2; \
+ r2 = r2 & r3; \
+ r2 = r2 ^ r1; \
+ r1 = r1 | r3; \
+ r1 = r1 & r0; \
+ r4 = r4 ^ r2; \
+ r4 = r4 ^ r1; \
+ r1 = r1 & r2; \
+ r0 = r0 ^ -1; \
+ r3 = r3 ^ r4; \
+ r1 = r1 ^ r3; \
+ r3 = r3 & r0; \
+ r3 = r3 ^ r2; \
+ r0 = r0 ^ r1; \
+ r2 = r2 & r0; \
+ r3 = r3 ^ r0; \
+ r2 = r2 ^ r4; \
+ r2 = r2 | r3; \
+ r3 = r3 ^ r0; \
+ r2 = r2 ^ r1;
+
+#define I5(r0,r1,r2,r3,r4) \
+ r1 = r1 ^ -1; \
+ r4 = r3; \
+ r2 = r2 ^ r1; \
+ r3 = r3 | r0; \
+ r3 = r3 ^ r2; \
+ r2 = r2 | r1; \
+ r2 = r2 & r0; \
+ r4 = r4 ^ r3; \
+ r2 = r2 ^ r4; \
+ r4 = r4 | r0; \
+ r4 = r4 ^ r1; \
+ r1 = r1 & r2; \
+ r1 = r1 ^ r3; \
+ r4 = r4 ^ r2; \
+ r3 = r3 & r4; \
+ r4 = r4 ^ r1; \
+ r3 = r3 ^ r0; \
+ r3 = r3 ^ r4; \
+ r4 = r4 ^ -1;
+
+
+#define I6(r0,r1,r2,r3,r4) \
+ r0 = r0 ^ r2; \
+ r4 = r2; \
+ r2 = r2 & r0; \
+ r4 = r4 ^ r3; \
+ r2 = r2 ^ -1; \
+ r3 = r3 ^ r1; \
+ r2 = r2 ^ r3; \
+ r4 = r4 | r0; \
+ r0 = r0 ^ r2; \
+ r3 = r3 ^ r4; \
+ r4 = r4 ^ r1; \
+ r1 = r1 & r3; \
+ r1 = r1 ^ r0; \
+ r0 = r0 ^ r3; \
+ r0 = r0 | r2; \
+ r3 = r3 ^ r1; \
+ r4 = r4 ^ r0;
+
+#define I7(r0,r1,r2,r3,r4) \
+ r4 = r2; \
+ r2 = r2 ^ r0; \
+ r0 = r0 & r3; \
+ r4 = r4 | r3; \
+ r2 = r2 ^ -1; \
+ r3 = r3 ^ r1; \
+ r1 = r1 | r0; \
+ r0 = r0 ^ r2; \
+ r2 = r2 & r4; \
+ r3 = r3 & r4; \
+ r1 = r1 ^ r2; \
+ r2 = r2 ^ r0; \
+ r0 = r0 | r2; \
+ r4 = r4 ^ r1; \
+ r0 = r0 ^ r3; \
+ r3 = r3 ^ r4; \
+ r4 = r4 | r0; \
+ r3 = r3 ^ r2; \
+ r4 = r4 ^ r2;
+
+/* forward and inverse linear transformations */
+
+#define LINTRANS(r0,r1,r2,r3,r4) \
+ r0 = rotl(r0, 13); \
+ r2 = rotl(r2, 3); \
+ r3 = r3 ^ r2; \
+ r4 = r0 << 3; \
+ r1 = r1 ^ r0; \
+ r3 = r3 ^ r4; \
+ r1 = r1 ^ r2; \
+ r3 = rotl(r3, 7); \
+ r1 = rotl(r1, 1); \
+ r2 = r2 ^ r3; \
+ r4 = r1 << 7; \
+ r0 = r0 ^ r1; \
+ r2 = r2 ^ r4; \
+ r0 = r0 ^ r3; \
+ r2 = rotl(r2, 22); \
+ r0 = rotl(r0, 5);
+
+#define ILINTRANS(r0,r1,r2,r3,r4) \
+ r2 = rotr(r2, 22); \
+ r0 = rotr(r0, 5); \
+ r2 = r2 ^ r3; \
+ r4 = r1 << 7; \
+ r0 = r0 ^ r1; \
+ r2 = r2 ^ r4; \
+ r0 = r0 ^ r3; \
+ r3 = rotr(r3, 7); \
+ r1 = rotr(r1, 1); \
+ r3 = r3 ^ r2; \
+ r4 = r0 << 3; \
+ r1 = r1 ^ r0; \
+ r3 = r3 ^ r4; \
+ r1 = r1 ^ r2; \
+ r2 = rotr(r2, 3); \
+ r0 = rotr(r0, 13);
+
+
+#define KEYMIX(r0,r1,r2,r3,r4,IN) \
+ r0 = r0 ^ l_key[IN+8]; \
+ r1 = r1 ^ l_key[IN+9]; \
+ r2 = r2 ^ l_key[IN+10]; \
+ r3 = r3 ^ l_key[IN+11];
+
+#define GETKEY(r0, r1, r2, r3, IN) \
+ r0 = l_key[IN+8]; \
+ r1 = l_key[IN+9]; \
+ r2 = l_key[IN+10]; \
+ r3 = l_key[IN+11];
+
+#define SETKEY(r0, r1, r2, r3, IN) \
+ l_key[IN+8] = r0; \
+ l_key[IN+9] = r1; \
+ l_key[IN+10] = r2; \
+ l_key[IN+11] = r3;
+
+/* initialise the key schedule from the user supplied key */
+
+int serpent_set_key(serpent_context *cx, const unsigned char *key, int key_len)
+{ const u32 *in_key = (const u32 *)key;
+ /* l_key - storage for the key schedule */
+ u32 *l_key = cx->keyinfo;
+ u32 i,lk,r0,r1,r2,r3,r4;
+
+ if (key_len != 16 && key_len != 24 && key_len != 32)
+ return -1; /* unsupported key length */
+
+ key_len *= 8;
+
+ i = 0; lk = (key_len + 31) / 32;
+
+ while(i < lk)
+ {
+#ifdef BLOCK_SWAP
+ l_key[i] = io_swap(in_key[lk - i - 1]);
+#else
+ l_key[i] = in_key[i];
+#endif
+ i++;
+ }
+
+ if (key_len < 256)
+ {
+ while(i < 8)
+
+ l_key[i++] = 0;
+
+ i = key_len / 32; lk = 1 << key_len % 32;
+
+ l_key[i] &= lk - 1;
+ l_key[i] |= lk;
+ }
+
+ for(i = 0; i < 132; ++i)
+ {
+ lk = l_key[i] ^ l_key[i + 3] ^ l_key[i + 5]
+ ^ l_key[i + 7] ^ 0x9e3779b9 ^ i;
+
+ l_key[i + 8] = (lk << 11) | (lk >> 21);
+ }
+
+ GETKEY(r0, r1, r2, r3, 0);
+ S3(r0,r1,r2,r3,r4);
+ SETKEY(r1, r2, r3, r4, 0)
+
+ GETKEY(r0, r1, r2, r3, 4);
+ S2(r0,r1,r2,r3,r4);
+ SETKEY(r2, r3, r1, r4, 4)
+
+ GETKEY(r0, r1, r2, r3, 8);
+ S1(r0,r1,r2,r3,r4);
+ SETKEY(r3, r1, r2, r0, 8)
+
+ GETKEY(r0, r1, r2, r3, 12);
+ S0(r0,r1,r2,r3,r4);
+ SETKEY(r1, r4, r2, r0, 12)
+
+ GETKEY(r0, r1, r2, r3, 16);
+ S7(r0,r1,r2,r3,r4);
+ SETKEY(r2, r4, r3, r0, 16)
+
+ GETKEY(r0, r1, r2, r3, 20);
+ S6(r0,r1,r2,r3,r4)
+ SETKEY(r0, r1, r4, r2, 20)
+
+ GETKEY(r0, r1, r2, r3, 24);
+ S5(r0,r1,r2,r3,r4);
+ SETKEY(r1, r3, r0, r2, 24)
+
+ GETKEY(r0, r1, r2, r3, 28);
+ S4(r0,r1,r2,r3,r4)
+ SETKEY(r1, r4, r0, r3, 28)
+
+ GETKEY(r0, r1, r2, r3, 32);
+ S3(r0,r1,r2,r3,r4);
+ SETKEY(r1, r2, r3, r4, 32)
+
+ GETKEY(r0, r1, r2, r3, 36);
+ S2(r0,r1,r2,r3,r4);
+ SETKEY(r2, r3, r1, r4, 36)
+
+ GETKEY(r0, r1, r2, r3, 40);
+ S1(r0,r1,r2,r3,r4);
+ SETKEY(r3, r1, r2, r0, 40)
+
+ GETKEY(r0, r1, r2, r3, 44);
+ S0(r0,r1,r2,r3,r4);
+ SETKEY(r1, r4, r2, r0, 44)
+
+ GETKEY(r0, r1, r2, r3, 48);
+ S7(r0,r1,r2,r3,r4);
+ SETKEY(r2, r4, r3, r0, 48)
+
+ GETKEY(r0, r1, r2, r3, 52);
+ S6(r0,r1,r2,r3,r4)
+ SETKEY(r0, r1, r4, r2, 52)
+
+ GETKEY(r0, r1, r2, r3, 56);
+ S5(r0,r1,r2,r3,r4);
+ SETKEY(r1, r3, r0, r2, 56)
+
+ GETKEY(r0, r1, r2, r3, 60);
+ S4(r0,r1,r2,r3,r4)
+ SETKEY(r1, r4, r0, r3, 60)
+
+ GETKEY(r0, r1, r2, r3, 64);
+ S3(r0,r1,r2,r3,r4);
+ SETKEY(r1, r2, r3, r4, 64)
+
+ GETKEY(r0, r1, r2, r3, 68);
+ S2(r0,r1,r2,r3,r4);
+ SETKEY(r2, r3, r1, r4, 68)
+
+ GETKEY(r0, r1, r2, r3, 72);
+ S1(r0,r1,r2,r3,r4);
+ SETKEY(r3, r1, r2, r0, 72)
+
+ GETKEY(r0, r1, r2, r3, 76);
+ S0(r0,r1,r2,r3,r4);
+ SETKEY(r1, r4, r2, r0, 76)
+
+ GETKEY(r0, r1, r2, r3, 80);
+ S7(r0,r1,r2,r3,r4);
+ SETKEY(r2, r4, r3, r0, 80)
+
+ GETKEY(r0, r1, r2, r3, 84);
+ S6(r0,r1,r2,r3,r4)
+ SETKEY(r0, r1, r4, r2, 84)
+
+ GETKEY(r0, r1, r2, r3, 88);
+ S5(r0,r1,r2,r3,r4);
+ SETKEY(r1, r3, r0, r2, 88)
+
+ GETKEY(r0, r1, r2, r3, 92);
+ S4(r0,r1,r2,r3,r4)
+ SETKEY(r1, r4, r0, r3, 92)
+
+ GETKEY(r0, r1, r2, r3, 96);
+ S3(r0,r1,r2,r3,r4);
+ SETKEY(r1, r2, r3, r4, 96)
+
+ GETKEY(r0, r1, r2, r3, 100);
+ S2(r0,r1,r2,r3,r4);
+ SETKEY(r2, r3, r1, r4, 100)
+
+ GETKEY(r0, r1, r2, r3, 104);
+ S1(r0,r1,r2,r3,r4);
+ SETKEY(r3, r1, r2, r0, 104)
+
+ GETKEY(r0, r1, r2, r3, 108);
+ S0(r0,r1,r2,r3,r4);
+ SETKEY(r1, r4, r2, r0, 108)
+
+ GETKEY(r0, r1, r2, r3, 112);
+ S7(r0,r1,r2,r3,r4);
+ SETKEY(r2, r4, r3, r0, 112)
+
+ GETKEY(r0, r1, r2, r3, 116);
+ S6(r0,r1,r2,r3,r4)
+ SETKEY(r0, r1, r4, r2, 116)
+
+ GETKEY(r0, r1, r2, r3, 120);
+ S5(r0,r1,r2,r3,r4);
+ SETKEY(r1, r3, r0, r2, 120)
+
+ GETKEY(r0, r1, r2, r3, 124);
+ S4(r0,r1,r2,r3,r4)
+ SETKEY(r1, r4, r0, r3, 124)
+
+ GETKEY(r0, r1, r2, r3, 128);
+ S3(r0,r1,r2,r3,r4);
+ SETKEY(r1, r2, r3, r4, 128)
+
+ return 0;
+};
+
+/* Encryption and decryption functions. The rounds are fully inlined.
+ * The sboxes alters the bit order of the output, and the altered
+ * bit ordrer is used progressivly. */
+
+/* encrypt a block of text */
+
+int serpent_encrypt(serpent_context *cx, const u8 *in,
+ u8 *out)
+{ u32 *l_key = cx->keyinfo;
+ const u32 *in_blk = (const u32 *) in;
+ u32 *out_blk = (u32 *) out;
+ u32 r0,r1,r2,r3,r4;
+
+#ifdef BLOCK_SWAP
+ r0 = io_swap(in_blk[3]); r1 = io_swap(in_blk[2]);
+ r2 = io_swap(in_blk[1]); r3 = io_swap(in_blk[0]);
+#else
+ r0 = in_blk[0]; r1 = in_blk[1]; r2 = in_blk[2]; r3 = in_blk[3];
+#endif
+
+ /* round 1 */
+ KEYMIX(r0,r1,r2,r3,r4,0);
+ S0(r0,r1,r2,r3,r4);
+ LINTRANS(r1,r4,r2,r0,r3);
+
+ /* round 2 */
+ KEYMIX(r1,r4,r2,r0,r3,4);
+ S1(r1,r4,r2,r0,r3);
+ LINTRANS(r0,r4,r2,r1,r3);
+
+ /* round 3 */
+ KEYMIX(r0,r4,r2,r1,r3,8);
+ S2(r0,r4,r2,r1,r3);
+ LINTRANS(r2,r1,r4,r3,r0);
+
+ /* round 4 */
+ KEYMIX(r2,r1,r4,r3,r0,12);
+ S3(r2,r1,r4,r3,r0);
+ LINTRANS(r1,r4,r3,r0,r2);
+
+ /* round 5 */
+ KEYMIX(r1,r4,r3,r0,r2,16);
+ S4(r1,r4,r3,r0,r2)
+ LINTRANS(r4,r2,r1,r0,r3);
+
+ /* round 6 */
+ KEYMIX(r4,r2,r1,r0,r3,20);
+ S5(r4,r2,r1,r0,r3);
+ LINTRANS(r2,r0,r4,r1,r3);
+
+ /* round 7 */
+ KEYMIX(r2,r0,r4,r1,r3,24);
+ S6(r2,r0,r4,r1,r3)
+ LINTRANS(r2,r0,r3,r4,r1);
+
+ /* round 8 */
+ KEYMIX(r2,r0,r3,r4,r1,28);
+ S7(r2,r0,r3,r4,r1);
+ LINTRANS(r3,r1,r4,r2,r0);
+
+ /* round 9 */
+ KEYMIX(r3,r1,r4,r2,r0,32);
+ S0(r3,r1,r4,r2,r0);
+ LINTRANS(r1,r0,r4,r3,r2);
+
+ /* round 10 */
+ KEYMIX(r1,r0,r4,r3,r2,36);
+ S1(r1,r0,r4,r3,r2);
+ LINTRANS(r3,r0,r4,r1,r2);
+
+ /* round 11 */
+ KEYMIX(r3,r0,r4,r1,r2,40);
+ S2(r3,r0,r4,r1,r2);
+ LINTRANS(r4,r1,r0,r2,r3);
+
+ /* round 12 */
+ KEYMIX(r4,r1,r0,r2,r3,44);
+ S3(r4,r1,r0,r2,r3);
+ LINTRANS(r1,r0,r2,r3,r4);
+
+ /* round 13 */
+ KEYMIX(r1,r0,r2,r3,r4,48);
+ S4(r1,r0,r2,r3,r4)
+ LINTRANS(r0,r4,r1,r3,r2);
+
+ /* round 14 */
+ KEYMIX(r0,r4,r1,r3,r2,52);
+ S5(r0,r4,r1,r3,r2);
+ LINTRANS(r4,r3,r0,r1,r2);
+
+ /* round 15 */
+ KEYMIX(r4,r3,r0,r1,r2,56);
+ S6(r4,r3,r0,r1,r2)
+ LINTRANS(r4,r3,r2,r0,r1);
+
+ /* round 16 */
+ KEYMIX(r4,r3,r2,r0,r1,60);
+ S7(r4,r3,r2,r0,r1);
+ LINTRANS(r2,r1,r0,r4,r3);
+
+ /* round 17 */
+ KEYMIX(r2,r1,r0,r4,r3,64);
+ S0(r2,r1,r0,r4,r3);
+ LINTRANS(r1,r3,r0,r2,r4);
+
+ /* round 18 */
+ KEYMIX(r1,r3,r0,r2,r4,68);
+ S1(r1,r3,r0,r2,r4);
+ LINTRANS(r2,r3,r0,r1,r4);
+
+ /* round 19 */
+ KEYMIX(r2,r3,r0,r1,r4,72);
+ S2(r2,r3,r0,r1,r4);
+ LINTRANS(r0,r1,r3,r4,r2);
+
+ /* round 20 */
+ KEYMIX(r0,r1,r3,r4,r2,76);
+ S3(r0,r1,r3,r4,r2);
+ LINTRANS(r1,r3,r4,r2,r0);
+
+ /* round 21 */
+ KEYMIX(r1,r3,r4,r2,r0,80);
+ S4(r1,r3,r4,r2,r0)
+ LINTRANS(r3,r0,r1,r2,r4);
+
+ /* round 22 */
+ KEYMIX(r3,r0,r1,r2,r4,84);
+ S5(r3,r0,r1,r2,r4);
+ LINTRANS(r0,r2,r3,r1,r4);
+
+ /* round 23 */
+ KEYMIX(r0,r2,r3,r1,r4,88);
+ S6(r0,r2,r3,r1,r4)
+ LINTRANS(r0,r2,r4,r3,r1);
+
+ /* round 24 */
+ KEYMIX(r0,r2,r4,r3,r1,92);
+ S7(r0,r2,r4,r3,r1);
+ LINTRANS(r4,r1,r3,r0,r2);
+
+ /* round 25 */
+ KEYMIX(r4,r1,r3,r0,r2,96);
+ S0(r4,r1,r3,r0,r2);
+ LINTRANS(r1,r2,r3,r4,r0);
+
+ /* round 26 */
+ KEYMIX(r1,r2,r3,r4,r0,100);
+ S1(r1,r2,r3,r4,r0);
+ LINTRANS(r4,r2,r3,r1,r0);
+
+ /* round 27 */
+ KEYMIX(r4,r2,r3,r1,r0,104);
+ S2(r4,r2,r3,r1,r0);
+ LINTRANS(r3,r1,r2,r0,r4);
+
+ /* round 28 */
+ KEYMIX(r3,r1,r2,r0,r4,108);
+ S3(r3,r1,r2,r0,r4);
+ LINTRANS(r1,r2,r0,r4,r3);
+
+ /* round 29 */
+ KEYMIX(r1,r2,r0,r4,r3,112);
+ S4(r1,r2,r0,r4,r3)
+ LINTRANS(r2,r3,r1,r4,r0);
+
+ /* round 30 */
+ KEYMIX(r2,r3,r1,r4,r0,116);
+ S5(r2,r3,r1,r4,r0);
+ LINTRANS(r3,r4,r2,r1,r0);
+
+ /* round 31 */
+ KEYMIX(r3,r4,r2,r1,r0,120);
+ S6(r3,r4,r2,r1,r0)
+ LINTRANS(r3,r4,r0,r2,r1);
+
+ /* round 32 */
+ KEYMIX(r3,r4,r0,r2,r1,124);
+ S7(r3,r4,r0,r2,r1);
+ KEYMIX(r0,r1,r2,r3,r4,128);
+
+
+#ifdef BLOCK_SWAP
+ out_blk[3] = io_swap(r0); out_blk[2] = io_swap(r1);
+ out_blk[1] = io_swap(r2); out_blk[0] = io_swap(r3);
+#else
+ out_blk[0] = r0; out_blk[1] = r1; out_blk[2] = r2; out_blk[3] = r3;
+#endif
+ return 0;
+};
+
+/* decrypt a block of text */
+
+int serpent_decrypt(serpent_context *cx, const u8 *in,
+ u8 *out)
+{ u32 *l_key = cx->keyinfo;
+ const u32 *in_blk = (const u32 *)in;
+ u32 *out_blk = (u32 *)out;
+ u32 r0,r1,r2,r3,r4;
+
+#ifdef BLOCK_SWAP
+ r0 = io_swap(in_blk[3]); r1 = io_swap(in_blk[2]);
+ r2 = io_swap(in_blk[1]); r3 = io_swap(in_blk[0]);
+#else
+ r0 = in_blk[0]; r1 = in_blk[1]; r2 = in_blk[2]; r3 = in_blk[3];
+#endif
+
+ /* round 1 */
+ KEYMIX(r0,r1,r2,r3,r4,128);
+ I7(r0,r1,r2,r3,r4);
+ KEYMIX(r3,r0,r1,r4,r2,124);
+
+ /* round 2 */
+ ILINTRANS(r3,r0,r1,r4,r2);
+ I6(r3,r0,r1,r4,r2);
+ KEYMIX(r0,r1,r2,r4,r3,120);
+
+ /* round 3 */
+ ILINTRANS(r0,r1,r2,r4,r3);
+ I5(r0,r1,r2,r4,r3);
+ KEYMIX(r1,r3,r4,r2,r0,116);
+
+ /* round 4 */
+ ILINTRANS(r1,r3,r4,r2,r0);
+ I4(r1,r3,r4,r2,r0);
+ KEYMIX(r1,r2,r4,r0,r3,112);
+
+ /* round 5 */
+ ILINTRANS(r1,r2,r4,r0,r3);
+ I3(r1,r2,r4,r0,r3);
+ KEYMIX(r4,r2,r0,r1,r3,108);
+
+ /* round 6 */
+ ILINTRANS(r4,r2,r0,r1,r3);
+ I2(r4,r2,r0,r1,r3);
+ KEYMIX(r2,r3,r0,r1,r4,104);
+
+ /* round 7 */
+ ILINTRANS(r2,r3,r0,r1,r4);
+ I1(r2,r3,r0,r1,r4);
+ KEYMIX(r4,r2,r1,r0,r3,100);
+
+ /* round 8 */
+ ILINTRANS(r4,r2,r1,r0,r3);
+ I0(r4,r2,r1,r0,r3);
+ KEYMIX(r4,r3,r2,r0,r1,96);
+
+ /* round 9 */
+ ILINTRANS(r4,r3,r2,r0,r1);
+ I7(r4,r3,r2,r0,r1);
+ KEYMIX(r0,r4,r3,r1,r2,92);
+
+ /* round 10 */
+ ILINTRANS(r0,r4,r3,r1,r2);
+ I6(r0,r4,r3,r1,r2);
+ KEYMIX(r4,r3,r2,r1,r0,88);
+
+ /* round 11 */
+ ILINTRANS(r4,r3,r2,r1,r0);
+ I5(r4,r3,r2,r1,r0);
+ KEYMIX(r3,r0,r1,r2,r4,84);
+
+ /* round 12 */
+ ILINTRANS(r3,r0,r1,r2,r4);
+ I4(r3,r0,r1,r2,r4);
+ KEYMIX(r3,r2,r1,r4,r0,80);
+
+ /* round 13 */
+ ILINTRANS(r3,r2,r1,r4,r0);
+ I3(r3,r2,r1,r4,r0);
+ KEYMIX(r1,r2,r4,r3,r0,76);
+
+ /* round 14 */
+ ILINTRANS(r1,r2,r4,r3,r0);
+ I2(r1,r2,r4,r3,r0);
+ KEYMIX(r2,r0,r4,r3,r1,72);
+
+ /* round 15 */
+ ILINTRANS(r2,r0,r4,r3,r1);
+ I1(r2,r0,r4,r3,r1);
+ KEYMIX(r1,r2,r3,r4,r0,68);
+
+ /* round 16 */
+ ILINTRANS(r1,r2,r3,r4,r0);
+ I0(r1,r2,r3,r4,r0);
+ KEYMIX(r1,r0,r2,r4,r3,64);
+
+ /* round 17 */
+ ILINTRANS(r1,r0,r2,r4,r3);
+ I7(r1,r0,r2,r4,r3);
+ KEYMIX(r4,r1,r0,r3,r2,60);
+
+ /* round 18 */
+ ILINTRANS(r4,r1,r0,r3,r2);
+ I6(r4,r1,r0,r3,r2);
+ KEYMIX(r1,r0,r2,r3,r4,56);
+
+ /* round 19 */
+ ILINTRANS(r1,r0,r2,r3,r4);
+ I5(r1,r0,r2,r3,r4);
+ KEYMIX(r0,r4,r3,r2,r1,52);
+
+ /* round 20 */
+ ILINTRANS(r0,r4,r3,r2,r1);
+ I4(r0,r4,r3,r2,r1);
+ KEYMIX(r0,r2,r3,r1,r4,48);
+
+ /* round 21 */
+ ILINTRANS(r0,r2,r3,r1,r4);
+ I3(r0,r2,r3,r1,r4);
+ KEYMIX(r3,r2,r1,r0,r4,44);
+
+ /* round 22 */
+ ILINTRANS(r3,r2,r1,r0,r4);
+ I2(r3,r2,r1,r0,r4);
+ KEYMIX(r2,r4,r1,r0,r3,40);
+
+ /* round 23 */
+ ILINTRANS(r2,r4,r1,r0,r3);
+ I1(r2,r4,r1,r0,r3);
+ KEYMIX(r3,r2,r0,r1,r4,36);
+
+ /* round 24 */
+ ILINTRANS(r3,r2,r0,r1,r4);
+ I0(r3,r2,r0,r1,r4);
+ KEYMIX(r3,r4,r2,r1,r0,32);
+
+ /* round 25 */
+ ILINTRANS(r3,r4,r2,r1,r0);
+ I7(r3,r4,r2,r1,r0);
+ KEYMIX(r1,r3,r4,r0,r2,28);
+
+ /* round 26 */
+ ILINTRANS(r1,r3,r4,r0,r2);
+ I6(r1,r3,r4,r0,r2);
+ KEYMIX(r3,r4,r2,r0,r1,24);
+
+ /* round 27 */
+ ILINTRANS(r3,r4,r2,r0,r1);
+ I5(r3,r4,r2,r0,r1);
+ KEYMIX(r4,r1,r0,r2,r3,20);
+
+ /* round 28 */
+ ILINTRANS(r4,r1,r0,r2,r3);
+ I4(r4,r1,r0,r2,r3);
+ KEYMIX(r4,r2,r0,r3,r1,16);
+
+ /* round 29 */
+ ILINTRANS(r4,r2,r0,r3,r1);
+ I3(r4,r2,r0,r3,r1);
+ KEYMIX(r0,r2,r3,r4,r1,12);
+
+ /* round 30 */
+ ILINTRANS(r0,r2,r3,r4,r1);
+ I2(r0,r2,r3,r4,r1);
+ KEYMIX(r2,r1,r3,r4,r0,8);
+
+ /* round 31 */
+ ILINTRANS(r2,r1,r3,r4,r0);
+ I1(r2,r1,r3,r4,r0);
+ KEYMIX(r0,r2,r4,r3,r1,4);
+
+ /* round 32 */
+ ILINTRANS(r0,r2,r4,r3,r1);
+ I0(r0,r2,r4,r3,r1);
+ KEYMIX(r0,r1,r2,r3,r4,0);
+
+#ifdef BLOCK_SWAP
+ out_blk[3] = io_swap(r0); out_blk[2] = io_swap(r1);
+ out_blk[1] = io_swap(r2); out_blk[0] = io_swap(r3);
+#else
+ out_blk[0] = r0; out_blk[1] = r1; out_blk[2] = r2; out_blk[3] = r3;
+#endif
+ return 0;
+};
+
+
diff --git a/src/libcrypto/libserpent/serpent.h b/src/libcrypto/libserpent/serpent.h
new file mode 100644
index 000000000..6357f5bfa
--- /dev/null
+++ b/src/libcrypto/libserpent/serpent.h
@@ -0,0 +1,17 @@
+#ifndef SERPENT_H
+#define SERPENT_H
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <sys/types.h>
+#define u32 u_int32_t
+#define u8 u_int8_t
+#endif
+struct serpent_context {
+ u32 keyinfo[140]; /* storage for the key schedule */
+};
+typedef struct serpent_context serpent_context;
+int serpent_set_key(serpent_context *ctx, const u8 * in_key, int key_len);
+int serpent_decrypt(serpent_context *ctx, const u8 * in_blk, u8 * out_blk);
+int serpent_encrypt(serpent_context *ctx, const u8 * in_blk, u8 * out_blk);
+#endif /* SERPENT_H */
diff --git a/src/libcrypto/libserpent/serpent_cbc.c b/src/libcrypto/libserpent/serpent_cbc.c
new file mode 100644
index 000000000..3b546278a
--- /dev/null
+++ b/src/libcrypto/libserpent/serpent_cbc.c
@@ -0,0 +1,8 @@
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <sys/types.h>
+#endif
+#include "serpent_cbc.h"
+#include "cbc_generic.h"
+CBC_IMPL_BLK16(serpent_cbc_encrypt, serpent_context, u_int8_t *, serpent_encrypt, serpent_decrypt);
diff --git a/src/libcrypto/libserpent/serpent_cbc.h b/src/libcrypto/libserpent/serpent_cbc.h
new file mode 100644
index 000000000..3064fa3bc
--- /dev/null
+++ b/src/libcrypto/libserpent/serpent_cbc.h
@@ -0,0 +1,3 @@
+/* Glue header */
+#include "serpent.h"
+int serpent_cbc_encrypt(serpent_context *ctx, const u_int8_t * in, u_int8_t * out, int ilen, const u_int8_t * iv, int encrypt);
diff --git a/src/libcrypto/libsha2/hmac_sha2.c b/src/libcrypto/libsha2/hmac_sha2.c
new file mode 100644
index 000000000..ad107eb62
--- /dev/null
+++ b/src/libcrypto/libsha2/hmac_sha2.c
@@ -0,0 +1,32 @@
+#ifdef __KERNEL__
+#include <linux/types.h>
+#include <linux/string.h>
+#else
+#include <sys/types.h>
+#include <string.h>
+#endif
+#include "hmac_generic.h"
+#include "sha2.h"
+#include "hmac_sha2.h"
+
+void inline sha256_result(sha256_context *ctx, u_int8_t * hash, int hashlen) {
+ sha256_final(ctx);
+ memcpy(hash, &ctx->sha_out[0], hashlen);
+}
+void inline sha512_result(sha512_context *ctx, u_int8_t * hash, int hashlen) {
+ sha512_final(ctx);
+ memcpy(hash, &ctx->sha_out[0], hashlen);
+}
+HMAC_SET_KEY_IMPL (sha256_hmac_set_key,
+ sha256_hmac_context, SHA256_BLOCKSIZE,
+ sha256_init, sha256_write)
+HMAC_HASH_IMPL (sha256_hmac_hash,
+ sha256_hmac_context, sha256_context, SHA256_HASHLEN,
+ sha256_write, sha256_result)
+
+HMAC_SET_KEY_IMPL (sha512_hmac_set_key,
+ sha512_hmac_context, SHA512_BLOCKSIZE,
+ sha512_init, sha512_write)
+HMAC_HASH_IMPL (sha512_hmac_hash,
+ sha512_hmac_context, sha512_context, SHA512_HASHLEN,
+ sha512_write, sha512_result)
diff --git a/src/libcrypto/libsha2/hmac_sha2.h b/src/libcrypto/libsha2/hmac_sha2.h
new file mode 100644
index 000000000..b7f8c747c
--- /dev/null
+++ b/src/libcrypto/libsha2/hmac_sha2.h
@@ -0,0 +1,17 @@
+typedef struct {
+ sha256_context ictx,octx;
+} sha256_hmac_context;
+typedef struct {
+ sha512_context ictx,octx;
+} sha512_hmac_context;
+#define SHA256_BLOCKSIZE 64
+#define SHA256_HASHLEN 32
+#define SHA384_BLOCKSIZE 128 /* XXX ok? */
+#define SHA384_HASHLEN 48
+#define SHA512_BLOCKSIZE 128
+#define SHA512_HASHLEN 64
+
+void sha256_hmac_hash(sha256_hmac_context *hctx, const u_int8_t * dat, int len, u_int8_t * hash, int hashlen);
+void sha256_hmac_set_key(sha256_hmac_context *hctx, const u_int8_t * key, int keylen);
+void sha512_hmac_hash(sha512_hmac_context *hctx, const u_int8_t * dat, int len, u_int8_t * hash, int hashlen);
+void sha512_hmac_set_key(sha512_hmac_context *hctx, const u_int8_t * key, int keylen);
diff --git a/src/libcrypto/libsha2/sha2.c b/src/libcrypto/libsha2/sha2.c
new file mode 100644
index 000000000..4debdad67
--- /dev/null
+++ b/src/libcrypto/libsha2/sha2.c
@@ -0,0 +1,437 @@
+/*
+ * sha512.c
+ *
+ * Written by Jari Ruusu, April 16 2001
+ *
+ * Copyright 2001 by Jari Ruusu.
+ * Redistribution of this file is permitted under the GNU Public License.
+ */
+
+#ifdef __KERNEL__
+#include <linux/string.h>
+#include <linux/types.h>
+#else
+#include <string.h>
+#include <sys/types.h>
+#endif
+#include "sha2.h"
+
+/* Define one or more of these. If none is defined, you get all of them */
+#if !defined(SHA256_NEEDED)&&!defined(SHA512_NEEDED)&&!defined(SHA384_NEEDED)
+# define SHA256_NEEDED 1
+# define SHA512_NEEDED 1
+# define SHA384_NEEDED 1
+#endif
+
+#if defined(SHA256_NEEDED)
+static const u_int32_t sha256_hashInit[8] = {
+ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c,
+ 0x1f83d9ab, 0x5be0cd19
+};
+static const u_int32_t sha256_K[64] = {
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
+ 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
+ 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
+ 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
+ 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
+ 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+};
+#endif
+
+#if defined(SHA512_NEEDED)
+static const u_int64_t sha512_hashInit[8] = {
+ 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL,
+ 0xa54ff53a5f1d36f1ULL, 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
+ 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL
+};
+#endif
+
+#if defined(SHA384_NEEDED)
+static const u_int64_t sha384_hashInit[8] = {
+ 0xcbbb9d5dc1059ed8ULL, 0x629a292a367cd507ULL, 0x9159015a3070dd17ULL,
+ 0x152fecd8f70e5939ULL, 0x67332667ffc00b31ULL, 0x8eb44a8768581511ULL,
+ 0xdb0c2e0d64f98fa7ULL, 0x47b5481dbefa4fa4ULL
+};
+#endif
+
+#if defined(SHA512_NEEDED) || defined(SHA384_NEEDED)
+static const u_int64_t sha512_K[80] = {
+ 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL,
+ 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
+ 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL,
+ 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
+ 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL,
+ 0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
+ 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL,
+ 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
+ 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL,
+ 0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
+ 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL,
+ 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
+ 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL,
+ 0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
+ 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL,
+ 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
+ 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL,
+ 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
+ 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL,
+ 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
+ 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL,
+ 0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
+ 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL,
+ 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
+ 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL,
+ 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
+ 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
+};
+#endif
+
+#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z)))
+#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
+#define R(x,y) ((y) >> (x))
+
+#if defined(SHA256_NEEDED)
+void sha256_init(sha256_context *ctx)
+{
+ memcpy(&ctx->sha_H[0], &sha256_hashInit[0], sizeof(ctx->sha_H));
+ ctx->sha_blocks = 0;
+ ctx->sha_bufCnt = 0;
+}
+
+#define S(x,y) (((y) >> (x)) | ((y) << (32 - (x))))
+#define uSig0(x) ((S(2,(x))) ^ (S(13,(x))) ^ (S(22,(x))))
+#define uSig1(x) ((S(6,(x))) ^ (S(11,(x))) ^ (S(25,(x))))
+#define lSig0(x) ((S(7,(x))) ^ (S(18,(x))) ^ (R(3,(x))))
+#define lSig1(x) ((S(17,(x))) ^ (S(19,(x))) ^ (R(10,(x))))
+
+static void sha256_transform(sha256_context *ctx, const unsigned char *datap)
+{
+ register int j;
+ u_int32_t a, b, c, d, e, f, g, h;
+ u_int32_t T1, T2, W[64], Wm2, Wm15;
+
+ /* read the data, big endian byte order */
+ j = 0;
+ do {
+ W[j] = (((u_int32_t)(datap[0]))<<24) | (((u_int32_t)(datap[1]))<<16) |
+ (((u_int32_t)(datap[2]))<<8 ) | ((u_int32_t)(datap[3]));
+ datap += 4;
+ } while(++j < 16);
+
+ /* initialize variables a...h */
+ a = ctx->sha_H[0];
+ b = ctx->sha_H[1];
+ c = ctx->sha_H[2];
+ d = ctx->sha_H[3];
+ e = ctx->sha_H[4];
+ f = ctx->sha_H[5];
+ g = ctx->sha_H[6];
+ h = ctx->sha_H[7];
+
+ /* apply compression function */
+ j = 0;
+ do {
+ if(j >= 16) {
+ Wm2 = W[j - 2];
+ Wm15 = W[j - 15];
+ W[j] = lSig1(Wm2) + W[j - 7] + lSig0(Wm15) + W[j - 16];
+ }
+ T1 = h + uSig1(e) + Ch(e,f,g) + sha256_K[j] + W[j];
+ T2 = uSig0(a) + Maj(a,b,c);
+ h = g; g = f; f = e;
+ e = d + T1;
+ d = c; c = b; b = a;
+ a = T1 + T2;
+ } while(++j < 64);
+
+ /* compute intermediate hash value */
+ ctx->sha_H[0] += a;
+ ctx->sha_H[1] += b;
+ ctx->sha_H[2] += c;
+ ctx->sha_H[3] += d;
+ ctx->sha_H[4] += e;
+ ctx->sha_H[5] += f;
+ ctx->sha_H[6] += g;
+ ctx->sha_H[7] += h;
+
+ ctx->sha_blocks++;
+}
+
+void sha256_write(sha256_context *ctx, const unsigned char *datap, int length)
+{
+ while(length > 0) {
+ if(!ctx->sha_bufCnt) {
+ while(length >= sizeof(ctx->sha_out)) {
+ sha256_transform(ctx, datap);
+ datap += sizeof(ctx->sha_out);
+ length -= sizeof(ctx->sha_out);
+ }
+ if(!length) return;
+ }
+ ctx->sha_out[ctx->sha_bufCnt] = *datap++;
+ length--;
+ if(++ctx->sha_bufCnt == sizeof(ctx->sha_out)) {
+ sha256_transform(ctx, &ctx->sha_out[0]);
+ ctx->sha_bufCnt = 0;
+ }
+ }
+}
+
+void sha256_final(sha256_context *ctx)
+{
+ register int j;
+ u_int64_t bitLength;
+ u_int32_t i;
+ unsigned char padByte, *datap;
+
+ bitLength = (ctx->sha_blocks << 9) | (ctx->sha_bufCnt << 3);
+ padByte = 0x80;
+ sha256_write(ctx, &padByte, 1);
+
+ /* pad extra space with zeroes */
+ padByte = 0;
+ while(ctx->sha_bufCnt != 56) {
+ sha256_write(ctx, &padByte, 1);
+ }
+
+ /* write bit length, big endian byte order */
+ ctx->sha_out[56] = bitLength >> 56;
+ ctx->sha_out[57] = bitLength >> 48;
+ ctx->sha_out[58] = bitLength >> 40;
+ ctx->sha_out[59] = bitLength >> 32;
+ ctx->sha_out[60] = bitLength >> 24;
+ ctx->sha_out[61] = bitLength >> 16;
+ ctx->sha_out[62] = bitLength >> 8;
+ ctx->sha_out[63] = bitLength;
+ sha256_transform(ctx, &ctx->sha_out[0]);
+
+ /* return results in ctx->sha_out[0...31] */
+ datap = &ctx->sha_out[0];
+ j = 0;
+ do {
+ i = ctx->sha_H[j];
+ datap[0] = i >> 24;
+ datap[1] = i >> 16;
+ datap[2] = i >> 8;
+ datap[3] = i;
+ datap += 4;
+ } while(++j < 8);
+
+ /* clear sensitive information */
+ memset(&ctx->sha_out[32], 0, sizeof(sha256_context) - 32);
+}
+
+void sha256_hash_buffer(unsigned char *ib, int ile, unsigned char *ob, int ole)
+{
+ sha256_context ctx;
+
+ if(ole < 1) return;
+ memset(ob, 0, ole);
+ if(ole > 32) ole = 32;
+ sha256_init(&ctx);
+ sha256_write(&ctx, ib, ile);
+ sha256_final(&ctx);
+ memcpy(ob, &ctx.sha_out[0], ole);
+ memset(&ctx, 0, sizeof(ctx));
+}
+
+#endif
+
+#if defined(SHA512_NEEDED)
+void sha512_init(sha512_context *ctx)
+{
+ memcpy(&ctx->sha_H[0], &sha512_hashInit[0], sizeof(ctx->sha_H));
+ ctx->sha_blocks = 0;
+ ctx->sha_blocksMSB = 0;
+ ctx->sha_bufCnt = 0;
+}
+#endif
+
+#if defined(SHA512_NEEDED) || defined(SHA384_NEEDED)
+#undef S
+#undef uSig0
+#undef uSig1
+#undef lSig0
+#undef lSig1
+#define S(x,y) (((y) >> (x)) | ((y) << (64 - (x))))
+#define uSig0(x) ((S(28,(x))) ^ (S(34,(x))) ^ (S(39,(x))))
+#define uSig1(x) ((S(14,(x))) ^ (S(18,(x))) ^ (S(41,(x))))
+#define lSig0(x) ((S(1,(x))) ^ (S(8,(x))) ^ (R(7,(x))))
+#define lSig1(x) ((S(19,(x))) ^ (S(61,(x))) ^ (R(6,(x))))
+
+static void sha512_transform(sha512_context *ctx, const unsigned char *datap)
+{
+ register int j;
+ u_int64_t a, b, c, d, e, f, g, h;
+ u_int64_t T1, T2, W[80], Wm2, Wm15;
+
+ /* read the data, big endian byte order */
+ j = 0;
+ do {
+ W[j] = (((u_int64_t)(datap[0]))<<56) | (((u_int64_t)(datap[1]))<<48) |
+ (((u_int64_t)(datap[2]))<<40) | (((u_int64_t)(datap[3]))<<32) |
+ (((u_int64_t)(datap[4]))<<24) | (((u_int64_t)(datap[5]))<<16) |
+ (((u_int64_t)(datap[6]))<<8 ) | ((u_int64_t)(datap[7]));
+ datap += 8;
+ } while(++j < 16);
+
+ /* initialize variables a...h */
+ a = ctx->sha_H[0];
+ b = ctx->sha_H[1];
+ c = ctx->sha_H[2];
+ d = ctx->sha_H[3];
+ e = ctx->sha_H[4];
+ f = ctx->sha_H[5];
+ g = ctx->sha_H[6];
+ h = ctx->sha_H[7];
+
+ /* apply compression function */
+ j = 0;
+ do {
+ if(j >= 16) {
+ Wm2 = W[j - 2];
+ Wm15 = W[j - 15];
+ W[j] = lSig1(Wm2) + W[j - 7] + lSig0(Wm15) + W[j - 16];
+ }
+ T1 = h + uSig1(e) + Ch(e,f,g) + sha512_K[j] + W[j];
+ T2 = uSig0(a) + Maj(a,b,c);
+ h = g; g = f; f = e;
+ e = d + T1;
+ d = c; c = b; b = a;
+ a = T1 + T2;
+ } while(++j < 80);
+
+ /* compute intermediate hash value */
+ ctx->sha_H[0] += a;
+ ctx->sha_H[1] += b;
+ ctx->sha_H[2] += c;
+ ctx->sha_H[3] += d;
+ ctx->sha_H[4] += e;
+ ctx->sha_H[5] += f;
+ ctx->sha_H[6] += g;
+ ctx->sha_H[7] += h;
+
+ ctx->sha_blocks++;
+ if(!ctx->sha_blocks) ctx->sha_blocksMSB++;
+}
+
+void sha512_write(sha512_context *ctx, const unsigned char *datap, int length)
+{
+ while(length > 0) {
+ if(!ctx->sha_bufCnt) {
+ while(length >= sizeof(ctx->sha_out)) {
+ sha512_transform(ctx, datap);
+ datap += sizeof(ctx->sha_out);
+ length -= sizeof(ctx->sha_out);
+ }
+ if(!length) return;
+ }
+ ctx->sha_out[ctx->sha_bufCnt] = *datap++;
+ length--;
+ if(++ctx->sha_bufCnt == sizeof(ctx->sha_out)) {
+ sha512_transform(ctx, &ctx->sha_out[0]);
+ ctx->sha_bufCnt = 0;
+ }
+ }
+}
+
+void sha512_final(sha512_context *ctx)
+{
+ register int j;
+ u_int64_t bitLength, bitLengthMSB;
+ u_int64_t i;
+ unsigned char padByte, *datap;
+
+ bitLength = (ctx->sha_blocks << 10) | (ctx->sha_bufCnt << 3);
+ bitLengthMSB = (ctx->sha_blocksMSB << 10) | (ctx->sha_blocks >> 54);
+ padByte = 0x80;
+ sha512_write(ctx, &padByte, 1);
+
+ /* pad extra space with zeroes */
+ padByte = 0;
+ while(ctx->sha_bufCnt != 112) {
+ sha512_write(ctx, &padByte, 1);
+ }
+
+ /* write bit length, big endian byte order */
+ ctx->sha_out[112] = bitLengthMSB >> 56;
+ ctx->sha_out[113] = bitLengthMSB >> 48;
+ ctx->sha_out[114] = bitLengthMSB >> 40;
+ ctx->sha_out[115] = bitLengthMSB >> 32;
+ ctx->sha_out[116] = bitLengthMSB >> 24;
+ ctx->sha_out[117] = bitLengthMSB >> 16;
+ ctx->sha_out[118] = bitLengthMSB >> 8;
+ ctx->sha_out[119] = bitLengthMSB;
+ ctx->sha_out[120] = bitLength >> 56;
+ ctx->sha_out[121] = bitLength >> 48;
+ ctx->sha_out[122] = bitLength >> 40;
+ ctx->sha_out[123] = bitLength >> 32;
+ ctx->sha_out[124] = bitLength >> 24;
+ ctx->sha_out[125] = bitLength >> 16;
+ ctx->sha_out[126] = bitLength >> 8;
+ ctx->sha_out[127] = bitLength;
+ sha512_transform(ctx, &ctx->sha_out[0]);
+
+ /* return results in ctx->sha_out[0...63] */
+ datap = &ctx->sha_out[0];
+ j = 0;
+ do {
+ i = ctx->sha_H[j];
+ datap[0] = i >> 56;
+ datap[1] = i >> 48;
+ datap[2] = i >> 40;
+ datap[3] = i >> 32;
+ datap[4] = i >> 24;
+ datap[5] = i >> 16;
+ datap[6] = i >> 8;
+ datap[7] = i;
+ datap += 8;
+ } while(++j < 8);
+
+ /* clear sensitive information */
+ memset(&ctx->sha_out[64], 0, sizeof(sha512_context) - 64);
+}
+
+void sha512_hash_buffer(unsigned char *ib, int ile, unsigned char *ob, int ole)
+{
+ sha512_context ctx;
+
+ if(ole < 1) return;
+ memset(ob, 0, ole);
+ if(ole > 64) ole = 64;
+ sha512_init(&ctx);
+ sha512_write(&ctx, ib, ile);
+ sha512_final(&ctx);
+ memcpy(ob, &ctx.sha_out[0], ole);
+ memset(&ctx, 0, sizeof(ctx));
+}
+#endif
+
+#if defined(SHA384_NEEDED)
+void sha384_init(sha512_context *ctx)
+{
+ memcpy(&ctx->sha_H[0], &sha384_hashInit[0], sizeof(ctx->sha_H));
+ ctx->sha_blocks = 0;
+ ctx->sha_blocksMSB = 0;
+ ctx->sha_bufCnt = 0;
+}
+
+void sha384_hash_buffer(unsigned char *ib, int ile, unsigned char *ob, int ole)
+{
+ sha512_context ctx;
+
+ if(ole < 1) return;
+ memset(ob, 0, ole);
+ if(ole > 48) ole = 48;
+ sha384_init(&ctx);
+ sha512_write(&ctx, ib, ile);
+ sha512_final(&ctx);
+ memcpy(ob, &ctx.sha_out[0], ole);
+ memset(&ctx, 0, sizeof(ctx));
+}
+#endif
diff --git a/src/libcrypto/libsha2/sha2.h b/src/libcrypto/libsha2/sha2.h
new file mode 100644
index 000000000..2dc03cfa8
--- /dev/null
+++ b/src/libcrypto/libsha2/sha2.h
@@ -0,0 +1,52 @@
+#ifndef _SHA2_H
+#define _SHA2_H
+/*
+ * sha512.h
+ *
+ * Written by Jari Ruusu, April 16 2001
+ *
+ * Copyright 2001 by Jari Ruusu.
+ * Redistribution of this file is permitted under the GNU Public License.
+ */
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <sys/types.h>
+#endif
+
+typedef struct {
+ unsigned char sha_out[64]; /* results are here, bytes 0...31 */
+ u_int32_t sha_H[8];
+ u_int64_t sha_blocks;
+ int sha_bufCnt;
+} sha256_context;
+
+typedef struct {
+ unsigned char sha_out[128]; /* results are here, bytes 0...63 */
+ u_int64_t sha_H[8];
+ u_int64_t sha_blocks;
+ u_int64_t sha_blocksMSB;
+ int sha_bufCnt;
+} sha512_context;
+
+/* no sha384_context, use sha512_context */
+
+/* 256 bit hash, provides 128 bits of security against collision attacks */
+extern void sha256_init(sha256_context *);
+extern void sha256_write(sha256_context *, const unsigned char *, int);
+extern void sha256_final(sha256_context *);
+extern void sha256_hash_buffer(unsigned char *, int, unsigned char *, int);
+
+/* 512 bit hash, provides 256 bits of security against collision attacks */
+extern void sha512_init(sha512_context *);
+extern void sha512_write(sha512_context *, const unsigned char *, int);
+extern void sha512_final(sha512_context *);
+extern void sha512_hash_buffer(unsigned char *, int, unsigned char *, int);
+
+/* 384 bit hash, provides 192 bits of security against collision attacks */
+extern void sha384_init(sha512_context *);
+/* no sha384_write(), use sha512_write() */
+/* no sha384_final(), use sha512_final(), result in ctx->sha_out[0...47] */
+extern void sha384_hash_buffer(unsigned char *, int, unsigned char *, int);
+#endif /* _SHA2_H */
diff --git a/src/libcrypto/libtwofish/twofish.c b/src/libcrypto/libtwofish/twofish.c
new file mode 100644
index 000000000..0e01a92d2
--- /dev/null
+++ b/src/libcrypto/libtwofish/twofish.c
@@ -0,0 +1,861 @@
+/* NOTE: This implementation has been changed from the original
+ * source. See ChangeLog for more information.
+ * Maintained by Marc Mutz <Marc@Mutz.com>
+ */
+
+/* Twofish for GPG
+ * By Matthew Skala <mskala@ansuz.sooke.bc.ca>, July 26, 1998
+ * 256-bit key length added March 20, 1999
+ * Some modifications to reduce the text size by Werner Koch, April, 1998
+ *
+ * The original author has disclaimed all copyright interest in this
+ * code and thus putting it in the public domain.
+ *
+ * This code is a "clean room" implementation, written from the paper
+ * _Twofish: A 128-Bit Block Cipher_ by Bruce Schneier, John Kelsey,
+ * Doug Whiting, David Wagner, Chris Hall, and Niels Ferguson, available
+ * through http://www.counterpane.com/twofish.html
+ *
+ * For background information on multiplication in finite fields, used for
+ * the matrix operations in the key schedule, see the book _Contemporary
+ * Abstract Algebra_ by Joseph A. Gallian, especially chapter 22 in the
+ * Third Edition.
+ *
+ * Only the 128- and 256-bit key sizes are supported. This code is intended
+ * for GNU C on a 32-bit system, but it should work almost anywhere. Loops
+ * are unrolled, precomputation tables are used, etc., for maximum speed at
+ * some cost in memory consumption. */
+
+#ifdef __KERNEL__
+#include <linux/init.h>
+#include <linux/types.h>
+#else
+#include <sys/types.h>
+#define u8 u_int8_t
+#define u32 u_int32_t
+#endif
+
+#if 0 /* shouldn't this be #ifdef rotl32 ?
+ * Look at wordops.h: It includes asm/wordops.h.
+ * Anyway, we have to search in the macros for rot's,
+ * since they seem to be defined in a generic way. */
+#define rotl rotl32
+#define rotr rotr32
+#else
+#define rotl generic_rotl32
+#define rotr generic_rotr32
+#endif
+
+#include "twofish.h"
+/* The large precomputed tables for the Twofish cipher (twofish.c)
+ * Taken from the same source as twofish.c
+ * Marc Mutz <Marc@Mutz.com>
+ */
+
+/* These two tables are the q0 and q1 permutations, exactly as described in
+ * the Twofish paper. */
+
+static const u8 q0[256] = {
+ 0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76, 0x9A, 0x92, 0x80, 0x78,
+ 0xE4, 0xDD, 0xD1, 0x38, 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C,
+ 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48, 0xF2, 0xD0, 0x8B, 0x30,
+ 0x84, 0x54, 0xDF, 0x23, 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82,
+ 0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C, 0xA6, 0xEB, 0xA5, 0xBE,
+ 0x16, 0x0C, 0xE3, 0x61, 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B,
+ 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1, 0xE1, 0xE6, 0xBD, 0x45,
+ 0xE2, 0xF4, 0xB6, 0x66, 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7,
+ 0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA, 0xEA, 0x77, 0x39, 0xAF,
+ 0x33, 0xC9, 0x62, 0x71, 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8,
+ 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7, 0xA1, 0x1D, 0xAA, 0xED,
+ 0x06, 0x70, 0xB2, 0xD2, 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90,
+ 0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB, 0x9E, 0x9C, 0x52, 0x1B,
+ 0x5F, 0x93, 0x0A, 0xEF, 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B,
+ 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64, 0x2A, 0xCE, 0xCB, 0x2F,
+ 0xFC, 0x97, 0x05, 0x7A, 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A,
+ 0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02, 0xB8, 0xDA, 0xB0, 0x17,
+ 0x55, 0x1F, 0x8A, 0x7D, 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72,
+ 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, 0x6E, 0x50, 0xDE, 0x68,
+ 0x65, 0xBC, 0xDB, 0xF8, 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4,
+ 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00, 0x6F, 0x9D, 0x36, 0x42,
+ 0x4A, 0x5E, 0xC1, 0xE0
+};
+
+static const u8 q1[256] = {
+ 0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8, 0x4A, 0xD3, 0xE6, 0x6B,
+ 0x45, 0x7D, 0xE8, 0x4B, 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1,
+ 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F, 0x5E, 0xBA, 0xAE, 0x5B,
+ 0x8A, 0x00, 0xBC, 0x9D, 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5,
+ 0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3, 0xB2, 0x73, 0x4C, 0x54,
+ 0x92, 0x74, 0x36, 0x51, 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96,
+ 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C, 0x13, 0x95, 0x9C, 0xC7,
+ 0x24, 0x46, 0x3B, 0x70, 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8,
+ 0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC, 0x03, 0x6F, 0x08, 0xBF,
+ 0x40, 0xE7, 0x2B, 0xE2, 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9,
+ 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17, 0x66, 0x94, 0xA1, 0x1D,
+ 0x3D, 0xF0, 0xDE, 0xB3, 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E,
+ 0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49, 0x81, 0x88, 0xEE, 0x21,
+ 0xC4, 0x1A, 0xEB, 0xD9, 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01,
+ 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48, 0x4F, 0xF2, 0x65, 0x8E,
+ 0x78, 0x5C, 0x58, 0x19, 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64,
+ 0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5, 0xCE, 0xE9, 0x68, 0x44,
+ 0xE0, 0x4D, 0x43, 0x69, 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E,
+ 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC, 0x22, 0xC9, 0xC0, 0x9B,
+ 0x89, 0xD4, 0xED, 0xAB, 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9,
+ 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, 0x16, 0x25, 0x86, 0x56,
+ 0x55, 0x09, 0xBE, 0x91
+};
+
+/* These MDS tables are actually tables of MDS composed with q0 and q1,
+ * because it is only ever used that way and we can save some time by
+ * precomputing. Of course the main saving comes from precomputing the
+ * GF(2^8) multiplication involved in the MDS matrix multiply; by looking
+ * things up in these tables we reduce the matrix multiply to four lookups
+ * and three XORs. Semi-formally, the definition of these tables is:
+ * mds[0][i] = MDS (q1[i] 0 0 0)^T mds[1][i] = MDS (0 q0[i] 0 0)^T
+ * mds[2][i] = MDS (0 0 q1[i] 0)^T mds[3][i] = MDS (0 0 0 q0[i])^T
+ * where ^T means "transpose", the matrix multiply is performed in GF(2^8)
+ * represented as GF(2)[x]/v(x) where v(x)=x^8+x^6+x^5+x^3+1 as described
+ * by Schneier et al, and I'm casually glossing over the byte/word
+ * conversion issues. */
+
+static const u32 mds[4][256] = {
+ {0xBCBC3275, 0xECEC21F3, 0x202043C6, 0xB3B3C9F4, 0xDADA03DB, 0x02028B7B,
+ 0xE2E22BFB, 0x9E9EFAC8, 0xC9C9EC4A, 0xD4D409D3, 0x18186BE6, 0x1E1E9F6B,
+ 0x98980E45, 0xB2B2387D, 0xA6A6D2E8, 0x2626B74B, 0x3C3C57D6, 0x93938A32,
+ 0x8282EED8, 0x525298FD, 0x7B7BD437, 0xBBBB3771, 0x5B5B97F1, 0x474783E1,
+ 0x24243C30, 0x5151E20F, 0xBABAC6F8, 0x4A4AF31B, 0xBFBF4887, 0x0D0D70FA,
+ 0xB0B0B306, 0x7575DE3F, 0xD2D2FD5E, 0x7D7D20BA, 0x666631AE, 0x3A3AA35B,
+ 0x59591C8A, 0x00000000, 0xCDCD93BC, 0x1A1AE09D, 0xAEAE2C6D, 0x7F7FABC1,
+ 0x2B2BC7B1, 0xBEBEB90E, 0xE0E0A080, 0x8A8A105D, 0x3B3B52D2, 0x6464BAD5,
+ 0xD8D888A0, 0xE7E7A584, 0x5F5FE807, 0x1B1B1114, 0x2C2CC2B5, 0xFCFCB490,
+ 0x3131272C, 0x808065A3, 0x73732AB2, 0x0C0C8173, 0x79795F4C, 0x6B6B4154,
+ 0x4B4B0292, 0x53536974, 0x94948F36, 0x83831F51, 0x2A2A3638, 0xC4C49CB0,
+ 0x2222C8BD, 0xD5D5F85A, 0xBDBDC3FC, 0x48487860, 0xFFFFCE62, 0x4C4C0796,
+ 0x4141776C, 0xC7C7E642, 0xEBEB24F7, 0x1C1C1410, 0x5D5D637C, 0x36362228,
+ 0x6767C027, 0xE9E9AF8C, 0x4444F913, 0x1414EA95, 0xF5F5BB9C, 0xCFCF18C7,
+ 0x3F3F2D24, 0xC0C0E346, 0x7272DB3B, 0x54546C70, 0x29294CCA, 0xF0F035E3,
+ 0x0808FE85, 0xC6C617CB, 0xF3F34F11, 0x8C8CE4D0, 0xA4A45993, 0xCACA96B8,
+ 0x68683BA6, 0xB8B84D83, 0x38382820, 0xE5E52EFF, 0xADAD569F, 0x0B0B8477,
+ 0xC8C81DC3, 0x9999FFCC, 0x5858ED03, 0x19199A6F, 0x0E0E0A08, 0x95957EBF,
+ 0x70705040, 0xF7F730E7, 0x6E6ECF2B, 0x1F1F6EE2, 0xB5B53D79, 0x09090F0C,
+ 0x616134AA, 0x57571682, 0x9F9F0B41, 0x9D9D803A, 0x111164EA, 0x2525CDB9,
+ 0xAFAFDDE4, 0x4545089A, 0xDFDF8DA4, 0xA3A35C97, 0xEAEAD57E, 0x353558DA,
+ 0xEDEDD07A, 0x4343FC17, 0xF8F8CB66, 0xFBFBB194, 0x3737D3A1, 0xFAFA401D,
+ 0xC2C2683D, 0xB4B4CCF0, 0x32325DDE, 0x9C9C71B3, 0x5656E70B, 0xE3E3DA72,
+ 0x878760A7, 0x15151B1C, 0xF9F93AEF, 0x6363BFD1, 0x3434A953, 0x9A9A853E,
+ 0xB1B1428F, 0x7C7CD133, 0x88889B26, 0x3D3DA65F, 0xA1A1D7EC, 0xE4E4DF76,
+ 0x8181942A, 0x91910149, 0x0F0FFB81, 0xEEEEAA88, 0x161661EE, 0xD7D77321,
+ 0x9797F5C4, 0xA5A5A81A, 0xFEFE3FEB, 0x6D6DB5D9, 0x7878AEC5, 0xC5C56D39,
+ 0x1D1DE599, 0x7676A4CD, 0x3E3EDCAD, 0xCBCB6731, 0xB6B6478B, 0xEFEF5B01,
+ 0x12121E18, 0x6060C523, 0x6A6AB0DD, 0x4D4DF61F, 0xCECEE94E, 0xDEDE7C2D,
+ 0x55559DF9, 0x7E7E5A48, 0x2121B24F, 0x03037AF2, 0xA0A02665, 0x5E5E198E,
+ 0x5A5A6678, 0x65654B5C, 0x62624E58, 0xFDFD4519, 0x0606F48D, 0x404086E5,
+ 0xF2F2BE98, 0x3333AC57, 0x17179067, 0x05058E7F, 0xE8E85E05, 0x4F4F7D64,
+ 0x89896AAF, 0x10109563, 0x74742FB6, 0x0A0A75FE, 0x5C5C92F5, 0x9B9B74B7,
+ 0x2D2D333C, 0x3030D6A5, 0x2E2E49CE, 0x494989E9, 0x46467268, 0x77775544,
+ 0xA8A8D8E0, 0x9696044D, 0x2828BD43, 0xA9A92969, 0xD9D97929, 0x8686912E,
+ 0xD1D187AC, 0xF4F44A15, 0x8D8D1559, 0xD6D682A8, 0xB9B9BC0A, 0x42420D9E,
+ 0xF6F6C16E, 0x2F2FB847, 0xDDDD06DF, 0x23233934, 0xCCCC6235, 0xF1F1C46A,
+ 0xC1C112CF, 0x8585EBDC, 0x8F8F9E22, 0x7171A1C9, 0x9090F0C0, 0xAAAA539B,
+ 0x0101F189, 0x8B8BE1D4, 0x4E4E8CED, 0x8E8E6FAB, 0xABABA212, 0x6F6F3EA2,
+ 0xE6E6540D, 0xDBDBF252, 0x92927BBB, 0xB7B7B602, 0x6969CA2F, 0x3939D9A9,
+ 0xD3D30CD7, 0xA7A72361, 0xA2A2AD1E, 0xC3C399B4, 0x6C6C4450, 0x07070504,
+ 0x04047FF6, 0x272746C2, 0xACACA716, 0xD0D07625, 0x50501386, 0xDCDCF756,
+ 0x84841A55, 0xE1E15109, 0x7A7A25BE, 0x1313EF91},
+
+ {0xA9D93939, 0x67901717, 0xB3719C9C, 0xE8D2A6A6, 0x04050707, 0xFD985252,
+ 0xA3658080, 0x76DFE4E4, 0x9A084545, 0x92024B4B, 0x80A0E0E0, 0x78665A5A,
+ 0xE4DDAFAF, 0xDDB06A6A, 0xD1BF6363, 0x38362A2A, 0x0D54E6E6, 0xC6432020,
+ 0x3562CCCC, 0x98BEF2F2, 0x181E1212, 0xF724EBEB, 0xECD7A1A1, 0x6C774141,
+ 0x43BD2828, 0x7532BCBC, 0x37D47B7B, 0x269B8888, 0xFA700D0D, 0x13F94444,
+ 0x94B1FBFB, 0x485A7E7E, 0xF27A0303, 0xD0E48C8C, 0x8B47B6B6, 0x303C2424,
+ 0x84A5E7E7, 0x54416B6B, 0xDF06DDDD, 0x23C56060, 0x1945FDFD, 0x5BA33A3A,
+ 0x3D68C2C2, 0x59158D8D, 0xF321ECEC, 0xAE316666, 0xA23E6F6F, 0x82165757,
+ 0x63951010, 0x015BEFEF, 0x834DB8B8, 0x2E918686, 0xD9B56D6D, 0x511F8383,
+ 0x9B53AAAA, 0x7C635D5D, 0xA63B6868, 0xEB3FFEFE, 0xA5D63030, 0xBE257A7A,
+ 0x16A7ACAC, 0x0C0F0909, 0xE335F0F0, 0x6123A7A7, 0xC0F09090, 0x8CAFE9E9,
+ 0x3A809D9D, 0xF5925C5C, 0x73810C0C, 0x2C273131, 0x2576D0D0, 0x0BE75656,
+ 0xBB7B9292, 0x4EE9CECE, 0x89F10101, 0x6B9F1E1E, 0x53A93434, 0x6AC4F1F1,
+ 0xB499C3C3, 0xF1975B5B, 0xE1834747, 0xE66B1818, 0xBDC82222, 0x450E9898,
+ 0xE26E1F1F, 0xF4C9B3B3, 0xB62F7474, 0x66CBF8F8, 0xCCFF9999, 0x95EA1414,
+ 0x03ED5858, 0x56F7DCDC, 0xD4E18B8B, 0x1C1B1515, 0x1EADA2A2, 0xD70CD3D3,
+ 0xFB2BE2E2, 0xC31DC8C8, 0x8E195E5E, 0xB5C22C2C, 0xE9894949, 0xCF12C1C1,
+ 0xBF7E9595, 0xBA207D7D, 0xEA641111, 0x77840B0B, 0x396DC5C5, 0xAF6A8989,
+ 0x33D17C7C, 0xC9A17171, 0x62CEFFFF, 0x7137BBBB, 0x81FB0F0F, 0x793DB5B5,
+ 0x0951E1E1, 0xADDC3E3E, 0x242D3F3F, 0xCDA47676, 0xF99D5555, 0xD8EE8282,
+ 0xE5864040, 0xC5AE7878, 0xB9CD2525, 0x4D049696, 0x44557777, 0x080A0E0E,
+ 0x86135050, 0xE730F7F7, 0xA1D33737, 0x1D40FAFA, 0xAA346161, 0xED8C4E4E,
+ 0x06B3B0B0, 0x706C5454, 0xB22A7373, 0xD2523B3B, 0x410B9F9F, 0x7B8B0202,
+ 0xA088D8D8, 0x114FF3F3, 0x3167CBCB, 0xC2462727, 0x27C06767, 0x90B4FCFC,
+ 0x20283838, 0xF67F0404, 0x60784848, 0xFF2EE5E5, 0x96074C4C, 0x5C4B6565,
+ 0xB1C72B2B, 0xAB6F8E8E, 0x9E0D4242, 0x9CBBF5F5, 0x52F2DBDB, 0x1BF34A4A,
+ 0x5FA63D3D, 0x9359A4A4, 0x0ABCB9B9, 0xEF3AF9F9, 0x91EF1313, 0x85FE0808,
+ 0x49019191, 0xEE611616, 0x2D7CDEDE, 0x4FB22121, 0x8F42B1B1, 0x3BDB7272,
+ 0x47B82F2F, 0x8748BFBF, 0x6D2CAEAE, 0x46E3C0C0, 0xD6573C3C, 0x3E859A9A,
+ 0x6929A9A9, 0x647D4F4F, 0x2A948181, 0xCE492E2E, 0xCB17C6C6, 0x2FCA6969,
+ 0xFCC3BDBD, 0x975CA3A3, 0x055EE8E8, 0x7AD0EDED, 0xAC87D1D1, 0x7F8E0505,
+ 0xD5BA6464, 0x1AA8A5A5, 0x4BB72626, 0x0EB9BEBE, 0xA7608787, 0x5AF8D5D5,
+ 0x28223636, 0x14111B1B, 0x3FDE7575, 0x2979D9D9, 0x88AAEEEE, 0x3C332D2D,
+ 0x4C5F7979, 0x02B6B7B7, 0xB896CACA, 0xDA583535, 0xB09CC4C4, 0x17FC4343,
+ 0x551A8484, 0x1FF64D4D, 0x8A1C5959, 0x7D38B2B2, 0x57AC3333, 0xC718CFCF,
+ 0x8DF40606, 0x74695353, 0xB7749B9B, 0xC4F59797, 0x9F56ADAD, 0x72DAE3E3,
+ 0x7ED5EAEA, 0x154AF4F4, 0x229E8F8F, 0x12A2ABAB, 0x584E6262, 0x07E85F5F,
+ 0x99E51D1D, 0x34392323, 0x6EC1F6F6, 0x50446C6C, 0xDE5D3232, 0x68724646,
+ 0x6526A0A0, 0xBC93CDCD, 0xDB03DADA, 0xF8C6BABA, 0xC8FA9E9E, 0xA882D6D6,
+ 0x2BCF6E6E, 0x40507070, 0xDCEB8585, 0xFE750A0A, 0x328A9393, 0xA48DDFDF,
+ 0xCA4C2929, 0x10141C1C, 0x2173D7D7, 0xF0CCB4B4, 0xD309D4D4, 0x5D108A8A,
+ 0x0FE25151, 0x00000000, 0x6F9A1919, 0x9DE01A1A, 0x368F9494, 0x42E6C7C7,
+ 0x4AECC9C9, 0x5EFDD2D2, 0xC1AB7F7F, 0xE0D8A8A8},
+
+ {0xBC75BC32, 0xECF3EC21, 0x20C62043, 0xB3F4B3C9, 0xDADBDA03, 0x027B028B,
+ 0xE2FBE22B, 0x9EC89EFA, 0xC94AC9EC, 0xD4D3D409, 0x18E6186B, 0x1E6B1E9F,
+ 0x9845980E, 0xB27DB238, 0xA6E8A6D2, 0x264B26B7, 0x3CD63C57, 0x9332938A,
+ 0x82D882EE, 0x52FD5298, 0x7B377BD4, 0xBB71BB37, 0x5BF15B97, 0x47E14783,
+ 0x2430243C, 0x510F51E2, 0xBAF8BAC6, 0x4A1B4AF3, 0xBF87BF48, 0x0DFA0D70,
+ 0xB006B0B3, 0x753F75DE, 0xD25ED2FD, 0x7DBA7D20, 0x66AE6631, 0x3A5B3AA3,
+ 0x598A591C, 0x00000000, 0xCDBCCD93, 0x1A9D1AE0, 0xAE6DAE2C, 0x7FC17FAB,
+ 0x2BB12BC7, 0xBE0EBEB9, 0xE080E0A0, 0x8A5D8A10, 0x3BD23B52, 0x64D564BA,
+ 0xD8A0D888, 0xE784E7A5, 0x5F075FE8, 0x1B141B11, 0x2CB52CC2, 0xFC90FCB4,
+ 0x312C3127, 0x80A38065, 0x73B2732A, 0x0C730C81, 0x794C795F, 0x6B546B41,
+ 0x4B924B02, 0x53745369, 0x9436948F, 0x8351831F, 0x2A382A36, 0xC4B0C49C,
+ 0x22BD22C8, 0xD55AD5F8, 0xBDFCBDC3, 0x48604878, 0xFF62FFCE, 0x4C964C07,
+ 0x416C4177, 0xC742C7E6, 0xEBF7EB24, 0x1C101C14, 0x5D7C5D63, 0x36283622,
+ 0x672767C0, 0xE98CE9AF, 0x441344F9, 0x149514EA, 0xF59CF5BB, 0xCFC7CF18,
+ 0x3F243F2D, 0xC046C0E3, 0x723B72DB, 0x5470546C, 0x29CA294C, 0xF0E3F035,
+ 0x088508FE, 0xC6CBC617, 0xF311F34F, 0x8CD08CE4, 0xA493A459, 0xCAB8CA96,
+ 0x68A6683B, 0xB883B84D, 0x38203828, 0xE5FFE52E, 0xAD9FAD56, 0x0B770B84,
+ 0xC8C3C81D, 0x99CC99FF, 0x580358ED, 0x196F199A, 0x0E080E0A, 0x95BF957E,
+ 0x70407050, 0xF7E7F730, 0x6E2B6ECF, 0x1FE21F6E, 0xB579B53D, 0x090C090F,
+ 0x61AA6134, 0x57825716, 0x9F419F0B, 0x9D3A9D80, 0x11EA1164, 0x25B925CD,
+ 0xAFE4AFDD, 0x459A4508, 0xDFA4DF8D, 0xA397A35C, 0xEA7EEAD5, 0x35DA3558,
+ 0xED7AEDD0, 0x431743FC, 0xF866F8CB, 0xFB94FBB1, 0x37A137D3, 0xFA1DFA40,
+ 0xC23DC268, 0xB4F0B4CC, 0x32DE325D, 0x9CB39C71, 0x560B56E7, 0xE372E3DA,
+ 0x87A78760, 0x151C151B, 0xF9EFF93A, 0x63D163BF, 0x345334A9, 0x9A3E9A85,
+ 0xB18FB142, 0x7C337CD1, 0x8826889B, 0x3D5F3DA6, 0xA1ECA1D7, 0xE476E4DF,
+ 0x812A8194, 0x91499101, 0x0F810FFB, 0xEE88EEAA, 0x16EE1661, 0xD721D773,
+ 0x97C497F5, 0xA51AA5A8, 0xFEEBFE3F, 0x6DD96DB5, 0x78C578AE, 0xC539C56D,
+ 0x1D991DE5, 0x76CD76A4, 0x3EAD3EDC, 0xCB31CB67, 0xB68BB647, 0xEF01EF5B,
+ 0x1218121E, 0x602360C5, 0x6ADD6AB0, 0x4D1F4DF6, 0xCE4ECEE9, 0xDE2DDE7C,
+ 0x55F9559D, 0x7E487E5A, 0x214F21B2, 0x03F2037A, 0xA065A026, 0x5E8E5E19,
+ 0x5A785A66, 0x655C654B, 0x6258624E, 0xFD19FD45, 0x068D06F4, 0x40E54086,
+ 0xF298F2BE, 0x335733AC, 0x17671790, 0x057F058E, 0xE805E85E, 0x4F644F7D,
+ 0x89AF896A, 0x10631095, 0x74B6742F, 0x0AFE0A75, 0x5CF55C92, 0x9BB79B74,
+ 0x2D3C2D33, 0x30A530D6, 0x2ECE2E49, 0x49E94989, 0x46684672, 0x77447755,
+ 0xA8E0A8D8, 0x964D9604, 0x284328BD, 0xA969A929, 0xD929D979, 0x862E8691,
+ 0xD1ACD187, 0xF415F44A, 0x8D598D15, 0xD6A8D682, 0xB90AB9BC, 0x429E420D,
+ 0xF66EF6C1, 0x2F472FB8, 0xDDDFDD06, 0x23342339, 0xCC35CC62, 0xF16AF1C4,
+ 0xC1CFC112, 0x85DC85EB, 0x8F228F9E, 0x71C971A1, 0x90C090F0, 0xAA9BAA53,
+ 0x018901F1, 0x8BD48BE1, 0x4EED4E8C, 0x8EAB8E6F, 0xAB12ABA2, 0x6FA26F3E,
+ 0xE60DE654, 0xDB52DBF2, 0x92BB927B, 0xB702B7B6, 0x692F69CA, 0x39A939D9,
+ 0xD3D7D30C, 0xA761A723, 0xA21EA2AD, 0xC3B4C399, 0x6C506C44, 0x07040705,
+ 0x04F6047F, 0x27C22746, 0xAC16ACA7, 0xD025D076, 0x50865013, 0xDC56DCF7,
+ 0x8455841A, 0xE109E151, 0x7ABE7A25, 0x139113EF},
+
+ {0xD939A9D9, 0x90176790, 0x719CB371, 0xD2A6E8D2, 0x05070405, 0x9852FD98,
+ 0x6580A365, 0xDFE476DF, 0x08459A08, 0x024B9202, 0xA0E080A0, 0x665A7866,
+ 0xDDAFE4DD, 0xB06ADDB0, 0xBF63D1BF, 0x362A3836, 0x54E60D54, 0x4320C643,
+ 0x62CC3562, 0xBEF298BE, 0x1E12181E, 0x24EBF724, 0xD7A1ECD7, 0x77416C77,
+ 0xBD2843BD, 0x32BC7532, 0xD47B37D4, 0x9B88269B, 0x700DFA70, 0xF94413F9,
+ 0xB1FB94B1, 0x5A7E485A, 0x7A03F27A, 0xE48CD0E4, 0x47B68B47, 0x3C24303C,
+ 0xA5E784A5, 0x416B5441, 0x06DDDF06, 0xC56023C5, 0x45FD1945, 0xA33A5BA3,
+ 0x68C23D68, 0x158D5915, 0x21ECF321, 0x3166AE31, 0x3E6FA23E, 0x16578216,
+ 0x95106395, 0x5BEF015B, 0x4DB8834D, 0x91862E91, 0xB56DD9B5, 0x1F83511F,
+ 0x53AA9B53, 0x635D7C63, 0x3B68A63B, 0x3FFEEB3F, 0xD630A5D6, 0x257ABE25,
+ 0xA7AC16A7, 0x0F090C0F, 0x35F0E335, 0x23A76123, 0xF090C0F0, 0xAFE98CAF,
+ 0x809D3A80, 0x925CF592, 0x810C7381, 0x27312C27, 0x76D02576, 0xE7560BE7,
+ 0x7B92BB7B, 0xE9CE4EE9, 0xF10189F1, 0x9F1E6B9F, 0xA93453A9, 0xC4F16AC4,
+ 0x99C3B499, 0x975BF197, 0x8347E183, 0x6B18E66B, 0xC822BDC8, 0x0E98450E,
+ 0x6E1FE26E, 0xC9B3F4C9, 0x2F74B62F, 0xCBF866CB, 0xFF99CCFF, 0xEA1495EA,
+ 0xED5803ED, 0xF7DC56F7, 0xE18BD4E1, 0x1B151C1B, 0xADA21EAD, 0x0CD3D70C,
+ 0x2BE2FB2B, 0x1DC8C31D, 0x195E8E19, 0xC22CB5C2, 0x8949E989, 0x12C1CF12,
+ 0x7E95BF7E, 0x207DBA20, 0x6411EA64, 0x840B7784, 0x6DC5396D, 0x6A89AF6A,
+ 0xD17C33D1, 0xA171C9A1, 0xCEFF62CE, 0x37BB7137, 0xFB0F81FB, 0x3DB5793D,
+ 0x51E10951, 0xDC3EADDC, 0x2D3F242D, 0xA476CDA4, 0x9D55F99D, 0xEE82D8EE,
+ 0x8640E586, 0xAE78C5AE, 0xCD25B9CD, 0x04964D04, 0x55774455, 0x0A0E080A,
+ 0x13508613, 0x30F7E730, 0xD337A1D3, 0x40FA1D40, 0x3461AA34, 0x8C4EED8C,
+ 0xB3B006B3, 0x6C54706C, 0x2A73B22A, 0x523BD252, 0x0B9F410B, 0x8B027B8B,
+ 0x88D8A088, 0x4FF3114F, 0x67CB3167, 0x4627C246, 0xC06727C0, 0xB4FC90B4,
+ 0x28382028, 0x7F04F67F, 0x78486078, 0x2EE5FF2E, 0x074C9607, 0x4B655C4B,
+ 0xC72BB1C7, 0x6F8EAB6F, 0x0D429E0D, 0xBBF59CBB, 0xF2DB52F2, 0xF34A1BF3,
+ 0xA63D5FA6, 0x59A49359, 0xBCB90ABC, 0x3AF9EF3A, 0xEF1391EF, 0xFE0885FE,
+ 0x01914901, 0x6116EE61, 0x7CDE2D7C, 0xB2214FB2, 0x42B18F42, 0xDB723BDB,
+ 0xB82F47B8, 0x48BF8748, 0x2CAE6D2C, 0xE3C046E3, 0x573CD657, 0x859A3E85,
+ 0x29A96929, 0x7D4F647D, 0x94812A94, 0x492ECE49, 0x17C6CB17, 0xCA692FCA,
+ 0xC3BDFCC3, 0x5CA3975C, 0x5EE8055E, 0xD0ED7AD0, 0x87D1AC87, 0x8E057F8E,
+ 0xBA64D5BA, 0xA8A51AA8, 0xB7264BB7, 0xB9BE0EB9, 0x6087A760, 0xF8D55AF8,
+ 0x22362822, 0x111B1411, 0xDE753FDE, 0x79D92979, 0xAAEE88AA, 0x332D3C33,
+ 0x5F794C5F, 0xB6B702B6, 0x96CAB896, 0x5835DA58, 0x9CC4B09C, 0xFC4317FC,
+ 0x1A84551A, 0xF64D1FF6, 0x1C598A1C, 0x38B27D38, 0xAC3357AC, 0x18CFC718,
+ 0xF4068DF4, 0x69537469, 0x749BB774, 0xF597C4F5, 0x56AD9F56, 0xDAE372DA,
+ 0xD5EA7ED5, 0x4AF4154A, 0x9E8F229E, 0xA2AB12A2, 0x4E62584E, 0xE85F07E8,
+ 0xE51D99E5, 0x39233439, 0xC1F66EC1, 0x446C5044, 0x5D32DE5D, 0x72466872,
+ 0x26A06526, 0x93CDBC93, 0x03DADB03, 0xC6BAF8C6, 0xFA9EC8FA, 0x82D6A882,
+ 0xCF6E2BCF, 0x50704050, 0xEB85DCEB, 0x750AFE75, 0x8A93328A, 0x8DDFA48D,
+ 0x4C29CA4C, 0x141C1014, 0x73D72173, 0xCCB4F0CC, 0x09D4D309, 0x108A5D10,
+ 0xE2510FE2, 0x00000000, 0x9A196F9A, 0xE01A9DE0, 0x8F94368F, 0xE6C742E6,
+ 0xECC94AEC, 0xFDD25EFD, 0xAB7FC1AB, 0xD8A8E0D8}
+};
+
+/* The exp_to_poly and poly_to_exp tables are used to perform efficient
+ * operations in GF(2^8) represented as GF(2)[x]/w(x) where
+ * w(x)=x^8+x^6+x^3+x^2+1. We care about doing that because it's part of the
+ * definition of the RS matrix in the key schedule. Elements of that field
+ * are polynomials of degree not greater than 7 and all coefficients 0 or 1,
+ * which can be represented naturally by bytes (just substitute x=2). In that
+ * form, GF(2^8) addition is the same as bitwise XOR, but GF(2^8)
+ * multiplication is inefficient without hardware support. To multiply
+ * faster, I make use of the fact x is a generator for the nonzero elements,
+ * so that every element p of GF(2)[x]/w(x) is either 0 or equal to (x)^n for
+ * some n in 0..254. Note that that caret is exponentiation in GF(2^8),
+ * *not* polynomial notation. So if I want to compute pq where p and q are
+ * in GF(2^8), I can just say:
+ * 1. if p=0 or q=0 then pq=0
+ * 2. otherwise, find m and n such that p=x^m and q=x^n
+ * 3. pq=(x^m)(x^n)=x^(m+n), so add m and n and find pq
+ * The translations in steps 2 and 3 are looked up in the tables
+ * poly_to_exp (for step 2) and exp_to_poly (for step 3). To see this
+ * in action, look at the CALC_S macro. As additional wrinkles, note that
+ * one of my operands is always a constant, so the poly_to_exp lookup on it
+ * is done in advance; I included the original values in the comments so
+ * readers can have some chance of recognizing that this *is* the RS matrix
+ * from the Twofish paper. I've only included the table entries I actually
+ * need; I never do a lookup on a variable input of zero and the biggest
+ * exponents I'll ever see are 254 (variable) and 237 (constant), so they'll
+ * never sum to more than 491. I'm repeating part of the exp_to_poly table
+ * so that I don't have to do mod-255 reduction in the exponent arithmetic.
+ * Since I know my constant operands are never zero, I only have to worry
+ * about zero values in the variable operand, and I do it with a simple
+ * conditional branch. I know conditionals are expensive, but I couldn't
+ * see a non-horrible way of avoiding them, and I did manage to group the
+ * statements so that each if covers four group multiplications. */
+
+static const u8 poly_to_exp[255] = {
+ 0x00, 0x01, 0x17, 0x02, 0x2E, 0x18, 0x53, 0x03, 0x6A, 0x2F, 0x93, 0x19,
+ 0x34, 0x54, 0x45, 0x04, 0x5C, 0x6B, 0xB6, 0x30, 0xA6, 0x94, 0x4B, 0x1A,
+ 0x8C, 0x35, 0x81, 0x55, 0xAA, 0x46, 0x0D, 0x05, 0x24, 0x5D, 0x87, 0x6C,
+ 0x9B, 0xB7, 0xC1, 0x31, 0x2B, 0xA7, 0xA3, 0x95, 0x98, 0x4C, 0xCA, 0x1B,
+ 0xE6, 0x8D, 0x73, 0x36, 0xCD, 0x82, 0x12, 0x56, 0x62, 0xAB, 0xF0, 0x47,
+ 0x4F, 0x0E, 0xBD, 0x06, 0xD4, 0x25, 0xD2, 0x5E, 0x27, 0x88, 0x66, 0x6D,
+ 0xD6, 0x9C, 0x79, 0xB8, 0x08, 0xC2, 0xDF, 0x32, 0x68, 0x2C, 0xFD, 0xA8,
+ 0x8A, 0xA4, 0x5A, 0x96, 0x29, 0x99, 0x22, 0x4D, 0x60, 0xCB, 0xE4, 0x1C,
+ 0x7B, 0xE7, 0x3B, 0x8E, 0x9E, 0x74, 0xF4, 0x37, 0xD8, 0xCE, 0xF9, 0x83,
+ 0x6F, 0x13, 0xB2, 0x57, 0xE1, 0x63, 0xDC, 0xAC, 0xC4, 0xF1, 0xAF, 0x48,
+ 0x0A, 0x50, 0x42, 0x0F, 0xBA, 0xBE, 0xC7, 0x07, 0xDE, 0xD5, 0x78, 0x26,
+ 0x65, 0xD3, 0xD1, 0x5F, 0xE3, 0x28, 0x21, 0x89, 0x59, 0x67, 0xFC, 0x6E,
+ 0xB1, 0xD7, 0xF8, 0x9D, 0xF3, 0x7A, 0x3A, 0xB9, 0xC6, 0x09, 0x41, 0xC3,
+ 0xAE, 0xE0, 0xDB, 0x33, 0x44, 0x69, 0x92, 0x2D, 0x52, 0xFE, 0x16, 0xA9,
+ 0x0C, 0x8B, 0x80, 0xA5, 0x4A, 0x5B, 0xB5, 0x97, 0xC9, 0x2A, 0xA2, 0x9A,
+ 0xC0, 0x23, 0x86, 0x4E, 0xBC, 0x61, 0xEF, 0xCC, 0x11, 0xE5, 0x72, 0x1D,
+ 0x3D, 0x7C, 0xEB, 0xE8, 0xE9, 0x3C, 0xEA, 0x8F, 0x7D, 0x9F, 0xEC, 0x75,
+ 0x1E, 0xF5, 0x3E, 0x38, 0xF6, 0xD9, 0x3F, 0xCF, 0x76, 0xFA, 0x1F, 0x84,
+ 0xA0, 0x70, 0xED, 0x14, 0x90, 0xB3, 0x7E, 0x58, 0xFB, 0xE2, 0x20, 0x64,
+ 0xD0, 0xDD, 0x77, 0xAD, 0xDA, 0xC5, 0x40, 0xF2, 0x39, 0xB0, 0xF7, 0x49,
+ 0xB4, 0x0B, 0x7F, 0x51, 0x15, 0x43, 0x91, 0x10, 0x71, 0xBB, 0xEE, 0xBF,
+ 0x85, 0xC8, 0xA1
+};
+
+static const u8 exp_to_poly[492] = {
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x4D, 0x9A, 0x79, 0xF2,
+ 0xA9, 0x1F, 0x3E, 0x7C, 0xF8, 0xBD, 0x37, 0x6E, 0xDC, 0xF5, 0xA7, 0x03,
+ 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xCD, 0xD7, 0xE3, 0x8B, 0x5B, 0xB6,
+ 0x21, 0x42, 0x84, 0x45, 0x8A, 0x59, 0xB2, 0x29, 0x52, 0xA4, 0x05, 0x0A,
+ 0x14, 0x28, 0x50, 0xA0, 0x0D, 0x1A, 0x34, 0x68, 0xD0, 0xED, 0x97, 0x63,
+ 0xC6, 0xC1, 0xCF, 0xD3, 0xEB, 0x9B, 0x7B, 0xF6, 0xA1, 0x0F, 0x1E, 0x3C,
+ 0x78, 0xF0, 0xAD, 0x17, 0x2E, 0x5C, 0xB8, 0x3D, 0x7A, 0xF4, 0xA5, 0x07,
+ 0x0E, 0x1C, 0x38, 0x70, 0xE0, 0x8D, 0x57, 0xAE, 0x11, 0x22, 0x44, 0x88,
+ 0x5D, 0xBA, 0x39, 0x72, 0xE4, 0x85, 0x47, 0x8E, 0x51, 0xA2, 0x09, 0x12,
+ 0x24, 0x48, 0x90, 0x6D, 0xDA, 0xF9, 0xBF, 0x33, 0x66, 0xCC, 0xD5, 0xE7,
+ 0x83, 0x4B, 0x96, 0x61, 0xC2, 0xC9, 0xDF, 0xF3, 0xAB, 0x1B, 0x36, 0x6C,
+ 0xD8, 0xFD, 0xB7, 0x23, 0x46, 0x8C, 0x55, 0xAA, 0x19, 0x32, 0x64, 0xC8,
+ 0xDD, 0xF7, 0xA3, 0x0B, 0x16, 0x2C, 0x58, 0xB0, 0x2D, 0x5A, 0xB4, 0x25,
+ 0x4A, 0x94, 0x65, 0xCA, 0xD9, 0xFF, 0xB3, 0x2B, 0x56, 0xAC, 0x15, 0x2A,
+ 0x54, 0xA8, 0x1D, 0x3A, 0x74, 0xE8, 0x9D, 0x77, 0xEE, 0x91, 0x6F, 0xDE,
+ 0xF1, 0xAF, 0x13, 0x26, 0x4C, 0x98, 0x7D, 0xFA, 0xB9, 0x3F, 0x7E, 0xFC,
+ 0xB5, 0x27, 0x4E, 0x9C, 0x75, 0xEA, 0x99, 0x7F, 0xFE, 0xB1, 0x2F, 0x5E,
+ 0xBC, 0x35, 0x6A, 0xD4, 0xE5, 0x87, 0x43, 0x86, 0x41, 0x82, 0x49, 0x92,
+ 0x69, 0xD2, 0xE9, 0x9F, 0x73, 0xE6, 0x81, 0x4F, 0x9E, 0x71, 0xE2, 0x89,
+ 0x5F, 0xBE, 0x31, 0x62, 0xC4, 0xC5, 0xC7, 0xC3, 0xCB, 0xDB, 0xFB, 0xBB,
+ 0x3B, 0x76, 0xEC, 0x95, 0x67, 0xCE, 0xD1, 0xEF, 0x93, 0x6B, 0xD6, 0xE1,
+ 0x8F, 0x53, 0xA6, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x4D,
+ 0x9A, 0x79, 0xF2, 0xA9, 0x1F, 0x3E, 0x7C, 0xF8, 0xBD, 0x37, 0x6E, 0xDC,
+ 0xF5, 0xA7, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xCD, 0xD7, 0xE3,
+ 0x8B, 0x5B, 0xB6, 0x21, 0x42, 0x84, 0x45, 0x8A, 0x59, 0xB2, 0x29, 0x52,
+ 0xA4, 0x05, 0x0A, 0x14, 0x28, 0x50, 0xA0, 0x0D, 0x1A, 0x34, 0x68, 0xD0,
+ 0xED, 0x97, 0x63, 0xC6, 0xC1, 0xCF, 0xD3, 0xEB, 0x9B, 0x7B, 0xF6, 0xA1,
+ 0x0F, 0x1E, 0x3C, 0x78, 0xF0, 0xAD, 0x17, 0x2E, 0x5C, 0xB8, 0x3D, 0x7A,
+ 0xF4, 0xA5, 0x07, 0x0E, 0x1C, 0x38, 0x70, 0xE0, 0x8D, 0x57, 0xAE, 0x11,
+ 0x22, 0x44, 0x88, 0x5D, 0xBA, 0x39, 0x72, 0xE4, 0x85, 0x47, 0x8E, 0x51,
+ 0xA2, 0x09, 0x12, 0x24, 0x48, 0x90, 0x6D, 0xDA, 0xF9, 0xBF, 0x33, 0x66,
+ 0xCC, 0xD5, 0xE7, 0x83, 0x4B, 0x96, 0x61, 0xC2, 0xC9, 0xDF, 0xF3, 0xAB,
+ 0x1B, 0x36, 0x6C, 0xD8, 0xFD, 0xB7, 0x23, 0x46, 0x8C, 0x55, 0xAA, 0x19,
+ 0x32, 0x64, 0xC8, 0xDD, 0xF7, 0xA3, 0x0B, 0x16, 0x2C, 0x58, 0xB0, 0x2D,
+ 0x5A, 0xB4, 0x25, 0x4A, 0x94, 0x65, 0xCA, 0xD9, 0xFF, 0xB3, 0x2B, 0x56,
+ 0xAC, 0x15, 0x2A, 0x54, 0xA8, 0x1D, 0x3A, 0x74, 0xE8, 0x9D, 0x77, 0xEE,
+ 0x91, 0x6F, 0xDE, 0xF1, 0xAF, 0x13, 0x26, 0x4C, 0x98, 0x7D, 0xFA, 0xB9,
+ 0x3F, 0x7E, 0xFC, 0xB5, 0x27, 0x4E, 0x9C, 0x75, 0xEA, 0x99, 0x7F, 0xFE,
+ 0xB1, 0x2F, 0x5E, 0xBC, 0x35, 0x6A, 0xD4, 0xE5, 0x87, 0x43, 0x86, 0x41,
+ 0x82, 0x49, 0x92, 0x69, 0xD2, 0xE9, 0x9F, 0x73, 0xE6, 0x81, 0x4F, 0x9E,
+ 0x71, 0xE2, 0x89, 0x5F, 0xBE, 0x31, 0x62, 0xC4, 0xC5, 0xC7, 0xC3, 0xCB
+};
+
+
+/* The table constants are indices of
+ * S-box entries, preprocessed through q0 and q1. */
+static const u8 calc_sb_tbl[512] = {
+ 0xA9, 0x75, 0x67, 0xF3, 0xB3, 0xC6, 0xE8, 0xF4,
+ 0x04, 0xDB, 0xFD, 0x7B, 0xA3, 0xFB, 0x76, 0xC8,
+ 0x9A, 0x4A, 0x92, 0xD3, 0x80, 0xE6, 0x78, 0x6B,
+ 0xE4, 0x45, 0xDD, 0x7D, 0xD1, 0xE8, 0x38, 0x4B,
+ 0x0D, 0xD6, 0xC6, 0x32, 0x35, 0xD8, 0x98, 0xFD,
+ 0x18, 0x37, 0xF7, 0x71, 0xEC, 0xF1, 0x6C, 0xE1,
+ 0x43, 0x30, 0x75, 0x0F, 0x37, 0xF8, 0x26, 0x1B,
+ 0xFA, 0x87, 0x13, 0xFA, 0x94, 0x06, 0x48, 0x3F,
+ 0xF2, 0x5E, 0xD0, 0xBA, 0x8B, 0xAE, 0x30, 0x5B,
+ 0x84, 0x8A, 0x54, 0x00, 0xDF, 0xBC, 0x23, 0x9D,
+ 0x19, 0x6D, 0x5B, 0xC1, 0x3D, 0xB1, 0x59, 0x0E,
+ 0xF3, 0x80, 0xAE, 0x5D, 0xA2, 0xD2, 0x82, 0xD5,
+ 0x63, 0xA0, 0x01, 0x84, 0x83, 0x07, 0x2E, 0x14,
+ 0xD9, 0xB5, 0x51, 0x90, 0x9B, 0x2C, 0x7C, 0xA3,
+ 0xA6, 0xB2, 0xEB, 0x73, 0xA5, 0x4C, 0xBE, 0x54,
+ 0x16, 0x92, 0x0C, 0x74, 0xE3, 0x36, 0x61, 0x51,
+ 0xC0, 0x38, 0x8C, 0xB0, 0x3A, 0xBD, 0xF5, 0x5A,
+ 0x73, 0xFC, 0x2C, 0x60, 0x25, 0x62, 0x0B, 0x96,
+ 0xBB, 0x6C, 0x4E, 0x42, 0x89, 0xF7, 0x6B, 0x10,
+ 0x53, 0x7C, 0x6A, 0x28, 0xB4, 0x27, 0xF1, 0x8C,
+ 0xE1, 0x13, 0xE6, 0x95, 0xBD, 0x9C, 0x45, 0xC7,
+ 0xE2, 0x24, 0xF4, 0x46, 0xB6, 0x3B, 0x66, 0x70,
+ 0xCC, 0xCA, 0x95, 0xE3, 0x03, 0x85, 0x56, 0xCB,
+ 0xD4, 0x11, 0x1C, 0xD0, 0x1E, 0x93, 0xD7, 0xB8,
+ 0xFB, 0xA6, 0xC3, 0x83, 0x8E, 0x20, 0xB5, 0xFF,
+ 0xE9, 0x9F, 0xCF, 0x77, 0xBF, 0xC3, 0xBA, 0xCC,
+ 0xEA, 0x03, 0x77, 0x6F, 0x39, 0x08, 0xAF, 0xBF,
+ 0x33, 0x40, 0xC9, 0xE7, 0x62, 0x2B, 0x71, 0xE2,
+ 0x81, 0x79, 0x79, 0x0C, 0x09, 0xAA, 0xAD, 0x82,
+ 0x24, 0x41, 0xCD, 0x3A, 0xF9, 0xEA, 0xD8, 0xB9,
+ 0xE5, 0xE4, 0xC5, 0x9A, 0xB9, 0xA4, 0x4D, 0x97,
+ 0x44, 0x7E, 0x08, 0xDA, 0x86, 0x7A, 0xE7, 0x17,
+ 0xA1, 0x66, 0x1D, 0x94, 0xAA, 0xA1, 0xED, 0x1D,
+ 0x06, 0x3D, 0x70, 0xF0, 0xB2, 0xDE, 0xD2, 0xB3,
+ 0x41, 0x0B, 0x7B, 0x72, 0xA0, 0xA7, 0x11, 0x1C,
+ 0x31, 0xEF, 0xC2, 0xD1, 0x27, 0x53, 0x90, 0x3E,
+ 0x20, 0x8F, 0xF6, 0x33, 0x60, 0x26, 0xFF, 0x5F,
+ 0x96, 0xEC, 0x5C, 0x76, 0xB1, 0x2A, 0xAB, 0x49,
+ 0x9E, 0x81, 0x9C, 0x88, 0x52, 0xEE, 0x1B, 0x21,
+ 0x5F, 0xC4, 0x93, 0x1A, 0x0A, 0xEB, 0xEF, 0xD9,
+ 0x91, 0xC5, 0x85, 0x39, 0x49, 0x99, 0xEE, 0xCD,
+ 0x2D, 0xAD, 0x4F, 0x31, 0x8F, 0x8B, 0x3B, 0x01,
+ 0x47, 0x18, 0x87, 0x23, 0x6D, 0xDD, 0x46, 0x1F,
+ 0xD6, 0x4E, 0x3E, 0x2D, 0x69, 0xF9, 0x64, 0x48,
+ 0x2A, 0x4F, 0xCE, 0xF2, 0xCB, 0x65, 0x2F, 0x8E,
+ 0xFC, 0x78, 0x97, 0x5C, 0x05, 0x58, 0x7A, 0x19,
+ 0xAC, 0x8D, 0x7F, 0xE5, 0xD5, 0x98, 0x1A, 0x57,
+ 0x4B, 0x67, 0x0E, 0x7F, 0xA7, 0x05, 0x5A, 0x64,
+ 0x28, 0xAF, 0x14, 0x63, 0x3F, 0xB6, 0x29, 0xFE,
+ 0x88, 0xF5, 0x3C, 0xB7, 0x4C, 0x3C, 0x02, 0xA5,
+ 0xB8, 0xCE, 0xDA, 0xE9, 0xB0, 0x68, 0x17, 0x44,
+ 0x55, 0xE0, 0x1F, 0x4D, 0x8A, 0x43, 0x7D, 0x69,
+ 0x57, 0x29, 0xC7, 0x2E, 0x8D, 0xAC, 0x74, 0x15,
+ 0xB7, 0x59, 0xC4, 0xA8, 0x9F, 0x0A, 0x72, 0x9E,
+ 0x7E, 0x6E, 0x15, 0x47, 0x22, 0xDF, 0x12, 0x34,
+ 0x58, 0x35, 0x07, 0x6A, 0x99, 0xCF, 0x34, 0xDC,
+ 0x6E, 0x22, 0x50, 0xC9, 0xDE, 0xC0, 0x68, 0x9B,
+ 0x65, 0x89, 0xBC, 0xD4, 0xDB, 0xED, 0xF8, 0xAB,
+ 0xC8, 0x12, 0xA8, 0xA2, 0x2B, 0x0D, 0x40, 0x52,
+ 0xDC, 0xBB, 0xFE, 0x02, 0x32, 0x2F, 0xA4, 0xA9,
+ 0xCA, 0xD7, 0x10, 0x61, 0x21, 0x1E, 0xF0, 0xB4,
+ 0xD3, 0x50, 0x5D, 0x04, 0x0F, 0xF6, 0x00, 0xC2,
+ 0x6F, 0x16, 0x9D, 0x25, 0x36, 0x86, 0x42, 0x56,
+ 0x4A, 0x55, 0x5E, 0x09, 0xC1, 0xBE, 0xE0, 0x91
+};
+
+/* Macro to perform one column of the RS matrix multiplication. The
+ * parameters a, b, c, and d are the four bytes of output; i is the index
+ * of the key bytes, and w, x, y, and z, are the column of constants from
+ * the RS matrix, preprocessed through the poly_to_exp table. */
+
+#define CALC_S(a, b, c, d, i, w, x, y, z) \
+ if (key[i]) { \
+ tmp = poly_to_exp[key[i] - 1]; \
+ (a) ^= exp_to_poly[tmp + (w)]; \
+ (b) ^= exp_to_poly[tmp + (x)]; \
+ (c) ^= exp_to_poly[tmp + (y)]; \
+ (d) ^= exp_to_poly[tmp + (z)]; \
+ }
+
+/* Macros to calculate the key-dependent S-boxes for a 128-bit key using
+ * the S vector from CALC_S. CALC_SB_2 computes a single entry in all
+ * four S-boxes, where i is the index of the entry to compute, and a and b
+ * are the index numbers preprocessed through the q0 and q1 tables
+ * respectively. */
+
+#define CALC_SB_2(i, a, b) \
+ ctx->s[0][i] = mds[0][q0[(a) ^ sa] ^ se]; \
+ ctx->s[1][i] = mds[1][q0[(b) ^ sb] ^ sf]; \
+ ctx->s[2][i] = mds[2][q1[(a) ^ sc] ^ sg]; \
+ ctx->s[3][i] = mds[3][q1[(b) ^ sd] ^ sh]
+
+/* Macro exactly like CALC_SB_2, but for 192-bit keys. */
+
+#define CALC_SB192_2(i, a, b) \
+ ctx->s[0][i] = mds[0][q0[q0[(b) ^ sa] ^ se] ^ si]; \
+ ctx->s[1][i] = mds[1][q0[q1[(b) ^ sb] ^ sf] ^ sj]; \
+ ctx->s[2][i] = mds[2][q1[q0[(a) ^ sc] ^ sg] ^ sk]; \
+ ctx->s[3][i] = mds[3][q1[q1[(a) ^ sd] ^ sh] ^ sl];
+
+/* Macro exactly like CALC_SB_2, but for 256-bit keys. */
+
+#define CALC_SB256_2(i, a, b) \
+ ctx->s[0][i] = mds[0][q0[q0[q1[(b) ^ sa] ^ se] ^ si] ^ sm]; \
+ ctx->s[1][i] = mds[1][q0[q1[q1[(a) ^ sb] ^ sf] ^ sj] ^ sn]; \
+ ctx->s[2][i] = mds[2][q1[q0[q0[(a) ^ sc] ^ sg] ^ sk] ^ so]; \
+ ctx->s[3][i] = mds[3][q1[q1[q0[(b) ^ sd] ^ sh] ^ sl] ^ sp];
+
+/* Macros to calculate the whitening and round subkeys. CALC_K_2 computes the
+ * last two stages of the h() function for a given index (either 2i or 2i+1).
+ * a, b, c, and d are the four bytes going into the last two stages. For
+ * 128-bit keys, this is the entire h() function and a and c are the index
+ * preprocessed through q0 and q1 respectively; for longer keys they are the
+ * output of previous stages. j is the index of the first key byte to use.
+ * CALC_K computes a pair of subkeys for 128-bit Twofish, by calling CALC_K_2
+ * twice, doing the Psuedo-Hadamard Transform, and doing the necessary
+ * rotations. Its parameters are: a, the array to write the results into,
+ * j, the index of the first output entry, k and l, the preprocessed indices
+ * for index 2i, and m and n, the preprocessed indices for index 2i+1.
+ * CALC_K192_2 expands CALC_K_2 to handle 192-bit keys, by doing an
+ * additional lookup-and-XOR stage. The parameters a, b, c and d are the
+ * four bytes going into the last three stages. For 192-bit keys, c = d
+ * are the index preprocessed through q0, and a = b are the index
+ * preprocessed through q1; j is the index of the first key byte to use.
+ * CALC_K192 is identical to CALC_K but for using the CALC_K192_2 macro
+ * instead of CALC_K_2.
+ * CALC_K256_2 expands CALC_K192_2 to handle 256-bit keys, by doing an
+ * additional lookup-and-XOR stage. The parameters a and b are the index
+ * preprocessed through q0 and q1 respectively; j is the index of the first
+ * key byte to use. CALC_K256 is identical to CALC_K but for using the
+ * CALC_K256_2 macro instead of CALC_K_2. */
+
+#define CALC_K_2(a, b, c, d, j) \
+ mds[0][q0[a ^ key[(j) + 8]] ^ key[j]] \
+ ^ mds[1][q0[b ^ key[(j) + 9]] ^ key[(j) + 1]] \
+ ^ mds[2][q1[c ^ key[(j) + 10]] ^ key[(j) + 2]] \
+ ^ mds[3][q1[d ^ key[(j) + 11]] ^ key[(j) + 3]]
+
+#define CALC_K(a, j, k, l, m, n) \
+ x = CALC_K_2 (k, l, k, l, 0); \
+ y = CALC_K_2 (m, n, m, n, 4); \
+ y = (y << 8) + (y >> 24); \
+ x += y; y += x; ctx->a[j] = x; \
+ ctx->a[(j) + 1] = (y << 9) + (y >> 23)
+
+#define CALC_K192_2(a, b, c, d, j) \
+ CALC_K_2 (q0[a ^ key[(j) + 16]], \
+ q1[b ^ key[(j) + 17]], \
+ q0[c ^ key[(j) + 18]], \
+ q1[d ^ key[(j) + 19]], j)
+
+#define CALC_K192(a, j, k, l, m, n) \
+ x = CALC_K192_2 (l, l, k, k, 0); \
+ y = CALC_K192_2 (n, n, m, m, 4); \
+ y = (y << 8) + (y >> 24); \
+ x += y; y += x; ctx->a[j] = x; \
+ ctx->a[(j) + 1] = (y << 9) + (y >> 23)
+
+#define CALC_K256_2(a, b, j) \
+ CALC_K192_2 (q1[b ^ key[(j) + 24]], \
+ q1[a ^ key[(j) + 25]], \
+ q0[a ^ key[(j) + 26]], \
+ q0[b ^ key[(j) + 27]], j)
+
+#define CALC_K256(a, j, k, l, m, n) \
+ x = CALC_K256_2 (k, l, 0); \
+ y = CALC_K256_2 (m, n, 4); \
+ y = (y << 8) + (y >> 24); \
+ x += y; y += x; ctx->a[j] = x; \
+ ctx->a[(j) + 1] = (y << 9) + (y >> 23)
+
+/* Perform the key setup. */
+
+int twofish_set_key (TWOFISH_context *ctx,
+ const unsigned char *key, int key_len)
+{
+
+ int i, j, k;
+
+ /* Temporaries for CALC_K. */
+ u32 x, y;
+
+ /* The S vector used to key the S-boxes, split up into individual bytes.
+ * 128-bit keys use only sa through sh; 256-bit use all of them. */
+ u8 sa = 0, sb = 0, sc = 0, sd = 0, se = 0, sf = 0, sg = 0, sh = 0;
+ u8 si = 0, sj = 0, sk = 0, sl = 0, sm = 0, sn = 0, so = 0, sp = 0;
+
+ /* Temporary for CALC_S. */
+ u8 tmp;
+
+ /* Check key length. */
+ if (key_len != 16 && key_len != 24 && key_len != 32)
+ return -1; /* unsupported key length */
+
+ /* Compute the first two words of the S vector. The magic numbers are
+ * the entries of the RS matrix, preprocessed through poly_to_exp. The
+ * numbers in the comments are the original (polynomial form) matrix
+ * entries. */
+ CALC_S (sa, sb, sc, sd, 0, 0x00, 0x2D, 0x01, 0x2D); /* 01 A4 02 A4 */
+ CALC_S (sa, sb, sc, sd, 1, 0x2D, 0xA4, 0x44, 0x8A); /* A4 56 A1 55 */
+ CALC_S (sa, sb, sc, sd, 2, 0x8A, 0xD5, 0xBF, 0xD1); /* 55 82 FC 87 */
+ CALC_S (sa, sb, sc, sd, 3, 0xD1, 0x7F, 0x3D, 0x99); /* 87 F3 C1 5A */
+ CALC_S (sa, sb, sc, sd, 4, 0x99, 0x46, 0x66, 0x96); /* 5A 1E 47 58 */
+ CALC_S (sa, sb, sc, sd, 5, 0x96, 0x3C, 0x5B, 0xED); /* 58 C6 AE DB */
+ CALC_S (sa, sb, sc, sd, 6, 0xED, 0x37, 0x4F, 0xE0); /* DB 68 3D 9E */
+ CALC_S (sa, sb, sc, sd, 7, 0xE0, 0xD0, 0x8C, 0x17); /* 9E E5 19 03 */
+ CALC_S (se, sf, sg, sh, 8, 0x00, 0x2D, 0x01, 0x2D); /* 01 A4 02 A4 */
+ CALC_S (se, sf, sg, sh, 9, 0x2D, 0xA4, 0x44, 0x8A); /* A4 56 A1 55 */
+ CALC_S (se, sf, sg, sh, 10, 0x8A, 0xD5, 0xBF, 0xD1); /* 55 82 FC 87 */
+ CALC_S (se, sf, sg, sh, 11, 0xD1, 0x7F, 0x3D, 0x99); /* 87 F3 C1 5A */
+ CALC_S (se, sf, sg, sh, 12, 0x99, 0x46, 0x66, 0x96); /* 5A 1E 47 58 */
+ CALC_S (se, sf, sg, sh, 13, 0x96, 0x3C, 0x5B, 0xED); /* 58 C6 AE DB */
+ CALC_S (se, sf, sg, sh, 14, 0xED, 0x37, 0x4F, 0xE0); /* DB 68 3D 9E */
+ CALC_S (se, sf, sg, sh, 15, 0xE0, 0xD0, 0x8C, 0x17); /* 9E E5 19 03 */
+
+ if (key_len == 24 || key_len == 32) { /* 192- or 256-bit key */
+ /* Calculate the third word of the S vector */
+ CALC_S (si, sj, sk, sl, 16, 0x00, 0x2D, 0x01, 0x2D); /* 01 A4 02 A4 */
+ CALC_S (si, sj, sk, sl, 17, 0x2D, 0xA4, 0x44, 0x8A); /* A4 56 A1 55 */
+ CALC_S (si, sj, sk, sl, 18, 0x8A, 0xD5, 0xBF, 0xD1); /* 55 82 FC 87 */
+ CALC_S (si, sj, sk, sl, 19, 0xD1, 0x7F, 0x3D, 0x99); /* 87 F3 C1 5A */
+ CALC_S (si, sj, sk, sl, 20, 0x99, 0x46, 0x66, 0x96); /* 5A 1E 47 58 */
+ CALC_S (si, sj, sk, sl, 21, 0x96, 0x3C, 0x5B, 0xED); /* 58 C6 AE DB */
+ CALC_S (si, sj, sk, sl, 22, 0xED, 0x37, 0x4F, 0xE0); /* DB 68 3D 9E */
+ CALC_S (si, sj, sk, sl, 23, 0xE0, 0xD0, 0x8C, 0x17); /* 9E E5 19 03 */
+ }
+
+ if (key_len == 32) { /* 256-bit key */
+ /* Calculate the fourth word of the S vector */
+ CALC_S (sm, sn, so, sp, 24, 0x00, 0x2D, 0x01, 0x2D); /* 01 A4 02 A4 */
+ CALC_S (sm, sn, so, sp, 25, 0x2D, 0xA4, 0x44, 0x8A); /* A4 56 A1 55 */
+ CALC_S (sm, sn, so, sp, 26, 0x8A, 0xD5, 0xBF, 0xD1); /* 55 82 FC 87 */
+ CALC_S (sm, sn, so, sp, 27, 0xD1, 0x7F, 0x3D, 0x99); /* 87 F3 C1 5A */
+ CALC_S (sm, sn, so, sp, 28, 0x99, 0x46, 0x66, 0x96); /* 5A 1E 47 58 */
+ CALC_S (sm, sn, so, sp, 29, 0x96, 0x3C, 0x5B, 0xED); /* 58 C6 AE DB */
+ CALC_S (sm, sn, so, sp, 30, 0xED, 0x37, 0x4F, 0xE0); /* DB 68 3D 9E */
+ CALC_S (sm, sn, so, sp, 31, 0xE0, 0xD0, 0x8C, 0x17); /* 9E E5 19 03 */
+
+ /* Compute the S-boxes. */
+ for ( i = j = 0, k = 1; i < 256; i++, j += 2, k += 2 ) {
+ CALC_SB256_2( i, calc_sb_tbl[j], calc_sb_tbl[k] );
+ }
+
+ /* Calculate whitening and round subkeys. The constants are
+ * indices of subkeys, preprocessed through q0 and q1. */
+ CALC_K256 (w, 0, 0xA9, 0x75, 0x67, 0xF3);
+ CALC_K256 (w, 2, 0xB3, 0xC6, 0xE8, 0xF4);
+ CALC_K256 (w, 4, 0x04, 0xDB, 0xFD, 0x7B);
+ CALC_K256 (w, 6, 0xA3, 0xFB, 0x76, 0xC8);
+ CALC_K256 (k, 0, 0x9A, 0x4A, 0x92, 0xD3);
+ CALC_K256 (k, 2, 0x80, 0xE6, 0x78, 0x6B);
+ CALC_K256 (k, 4, 0xE4, 0x45, 0xDD, 0x7D);
+ CALC_K256 (k, 6, 0xD1, 0xE8, 0x38, 0x4B);
+ CALC_K256 (k, 8, 0x0D, 0xD6, 0xC6, 0x32);
+ CALC_K256 (k, 10, 0x35, 0xD8, 0x98, 0xFD);
+ CALC_K256 (k, 12, 0x18, 0x37, 0xF7, 0x71);
+ CALC_K256 (k, 14, 0xEC, 0xF1, 0x6C, 0xE1);
+ CALC_K256 (k, 16, 0x43, 0x30, 0x75, 0x0F);
+ CALC_K256 (k, 18, 0x37, 0xF8, 0x26, 0x1B);
+ CALC_K256 (k, 20, 0xFA, 0x87, 0x13, 0xFA);
+ CALC_K256 (k, 22, 0x94, 0x06, 0x48, 0x3F);
+ CALC_K256 (k, 24, 0xF2, 0x5E, 0xD0, 0xBA);
+ CALC_K256 (k, 26, 0x8B, 0xAE, 0x30, 0x5B);
+ CALC_K256 (k, 28, 0x84, 0x8A, 0x54, 0x00);
+ CALC_K256 (k, 30, 0xDF, 0xBC, 0x23, 0x9D);
+ } else if (key_len == 24) { /* 192-bit key */
+ /* Compute the S-boxes. */
+ for ( i = j = 0, k = 1; i < 256; i++, j += 2, k += 2 ) {
+ CALC_SB192_2( i, calc_sb_tbl[j], calc_sb_tbl[k] );
+ }
+
+ /* Calculate whitening and round subkeys. The constants are
+ * indices of subkeys, preprocessed through q0 and q1. */
+ CALC_K192 (w, 0, 0xA9, 0x75, 0x67, 0xF3);
+ CALC_K192 (w, 2, 0xB3, 0xC6, 0xE8, 0xF4);
+ CALC_K192 (w, 4, 0x04, 0xDB, 0xFD, 0x7B);
+ CALC_K192 (w, 6, 0xA3, 0xFB, 0x76, 0xC8);
+ CALC_K192 (k, 0, 0x9A, 0x4A, 0x92, 0xD3);
+ CALC_K192 (k, 2, 0x80, 0xE6, 0x78, 0x6B);
+ CALC_K192 (k, 4, 0xE4, 0x45, 0xDD, 0x7D);
+ CALC_K192 (k, 6, 0xD1, 0xE8, 0x38, 0x4B);
+ CALC_K192 (k, 8, 0x0D, 0xD6, 0xC6, 0x32);
+ CALC_K192 (k, 10, 0x35, 0xD8, 0x98, 0xFD);
+ CALC_K192 (k, 12, 0x18, 0x37, 0xF7, 0x71);
+ CALC_K192 (k, 14, 0xEC, 0xF1, 0x6C, 0xE1);
+ CALC_K192 (k, 16, 0x43, 0x30, 0x75, 0x0F);
+ CALC_K192 (k, 18, 0x37, 0xF8, 0x26, 0x1B);
+ CALC_K192 (k, 20, 0xFA, 0x87, 0x13, 0xFA);
+ CALC_K192 (k, 22, 0x94, 0x06, 0x48, 0x3F);
+ CALC_K192 (k, 24, 0xF2, 0x5E, 0xD0, 0xBA);
+ CALC_K192 (k, 26, 0x8B, 0xAE, 0x30, 0x5B);
+ CALC_K192 (k, 28, 0x84, 0x8A, 0x54, 0x00);
+ CALC_K192 (k, 30, 0xDF, 0xBC, 0x23, 0x9D);
+ } else { /* 128-bit key */
+ /* Compute the S-boxes. */
+ for ( i = j = 0, k = 1; i < 256; i++, j += 2, k += 2 ) {
+ CALC_SB_2( i, calc_sb_tbl[j], calc_sb_tbl[k] );
+ }
+
+ /* Calculate whitening and round subkeys. The constants are
+ * indices of subkeys, preprocessed through q0 and q1. */
+ CALC_K (w, 0, 0xA9, 0x75, 0x67, 0xF3);
+ CALC_K (w, 2, 0xB3, 0xC6, 0xE8, 0xF4);
+ CALC_K (w, 4, 0x04, 0xDB, 0xFD, 0x7B);
+ CALC_K (w, 6, 0xA3, 0xFB, 0x76, 0xC8);
+ CALC_K (k, 0, 0x9A, 0x4A, 0x92, 0xD3);
+ CALC_K (k, 2, 0x80, 0xE6, 0x78, 0x6B);
+ CALC_K (k, 4, 0xE4, 0x45, 0xDD, 0x7D);
+ CALC_K (k, 6, 0xD1, 0xE8, 0x38, 0x4B);
+ CALC_K (k, 8, 0x0D, 0xD6, 0xC6, 0x32);
+ CALC_K (k, 10, 0x35, 0xD8, 0x98, 0xFD);
+ CALC_K (k, 12, 0x18, 0x37, 0xF7, 0x71);
+ CALC_K (k, 14, 0xEC, 0xF1, 0x6C, 0xE1);
+ CALC_K (k, 16, 0x43, 0x30, 0x75, 0x0F);
+ CALC_K (k, 18, 0x37, 0xF8, 0x26, 0x1B);
+ CALC_K (k, 20, 0xFA, 0x87, 0x13, 0xFA);
+ CALC_K (k, 22, 0x94, 0x06, 0x48, 0x3F);
+ CALC_K (k, 24, 0xF2, 0x5E, 0xD0, 0xBA);
+ CALC_K (k, 26, 0x8B, 0xAE, 0x30, 0x5B);
+ CALC_K (k, 28, 0x84, 0x8A, 0x54, 0x00);
+ CALC_K (k, 30, 0xDF, 0xBC, 0x23, 0x9D);
+ }
+
+ return 0;
+}
+
+/* Macros to compute the g() function in the encryption and decryption
+ * rounds. G1 is the straight g() function; G2 includes the 8-bit
+ * rotation for the high 32-bit word. */
+
+#define G1(a) \
+ (ctx->s[0][(a) & 0xFF]) ^ (ctx->s[1][((a) >> 8) & 0xFF]) \
+ ^ (ctx->s[2][((a) >> 16) & 0xFF]) ^ (ctx->s[3][(a) >> 24])
+
+#define G2(b) \
+ (ctx->s[1][(b) & 0xFF]) ^ (ctx->s[2][((b) >> 8) & 0xFF]) \
+ ^ (ctx->s[3][((b) >> 16) & 0xFF]) ^ (ctx->s[0][(b) >> 24])
+
+/* Encryption and decryption Feistel rounds. Each one calls the two g()
+ * macros, does the PHT, and performs the XOR and the appropriate bit
+ * rotations. The parameters are the round number (used to select subkeys),
+ * and the four 32-bit chunks of the text. */
+
+#define ENCROUND(n, a, b, c, d) \
+ x = G1 (a); y = G2 (b); \
+ x += y; y += x + ctx->k[2 * (n) + 1]; \
+ (c) ^= x + ctx->k[2 * (n)]; \
+ (c) = ((c) >> 1) + ((c) << 31); \
+ (d) = (((d) << 1)+((d) >> 31)) ^ y
+
+#define DECROUND(n, a, b, c, d) \
+ x = G1 (a); y = G2 (b); \
+ x += y; y += x; \
+ (d) ^= y + ctx->k[2 * (n) + 1]; \
+ (d) = ((d) >> 1) + ((d) << 31); \
+ (c) = (((c) << 1)+((c) >> 31)); \
+ (c) ^= (x + ctx->k[2 * (n)])
+
+/* Encryption and decryption cycles; each one is simply two Feistel rounds
+ * with the 32-bit chunks re-ordered to simulate the "swap" */
+
+#define ENCCYCLE(n) \
+ ENCROUND (2 * (n), a, b, c, d); \
+ ENCROUND (2 * (n) + 1, c, d, a, b)
+
+#define DECCYCLE(n) \
+ DECROUND (2 * (n) + 1, c, d, a, b); \
+ DECROUND (2 * (n), a, b, c, d)
+
+/* Macros to convert the input and output bytes into 32-bit words,
+ * and simultaneously perform the whitening step. INPACK packs word
+ * number n into the variable named by x, using whitening subkey number m.
+ * OUTUNPACK unpacks word number n from the variable named by x, using
+ * whitening subkey number m. */
+
+#define INPACK(n, x, m) \
+ x = in[4 * (n)] ^ (in[4 * (n) + 1] << 8) \
+ ^ (in[4 * (n) + 2] << 16) ^ (in[4 * (n) + 3] << 24) ^ ctx->w[m]
+
+#define OUTUNPACK(n, x, m) \
+ x ^= ctx->w[m]; \
+ out[4 * (n)] = x; out[4 * (n) + 1] = x >> 8; \
+ out[4 * (n) + 2] = x >> 16; out[4 * (n) + 3] = x >> 24
+
+/* Encrypt one block. in and out may be the same. */
+
+int twofish_encrypt (TWOFISH_context *ctx,
+ const u8 *in, u8 *out)
+{
+ /* The four 32-bit chunks of the text. */
+ u32 a, b, c, d;
+
+ /* Temporaries used by the round function. */
+ u32 x, y;
+
+ /* Input whitening and packing. */
+ INPACK (0, a, 0);
+ INPACK (1, b, 1);
+ INPACK (2, c, 2);
+ INPACK (3, d, 3);
+
+ /* Encryption Feistel cycles. */
+ ENCCYCLE (0);
+ ENCCYCLE (1);
+ ENCCYCLE (2);
+ ENCCYCLE (3);
+ ENCCYCLE (4);
+ ENCCYCLE (5);
+ ENCCYCLE (6);
+ ENCCYCLE (7);
+
+ /* Output whitening and unpacking. */
+ OUTUNPACK (0, c, 4);
+ OUTUNPACK (1, d, 5);
+ OUTUNPACK (2, a, 6);
+ OUTUNPACK (3, b, 7);
+
+ return 0;
+}
+
+/* Decrypt one block. in and out may be the same. */
+
+int twofish_decrypt (TWOFISH_context *ctx,
+ const u8 *in, u8 *out)
+{
+ /* The four 32-bit chunks of the text. */
+ u32 a, b, c, d;
+
+ /* Temporaries used by the round function. */
+ u32 x, y;
+
+ /* Input whitening and packing. */
+ INPACK (0, c, 4);
+ INPACK (1, d, 5);
+ INPACK (2, a, 6);
+ INPACK (3, b, 7);
+
+ /* Encryption Feistel cycles. */
+ DECCYCLE (7);
+ DECCYCLE (6);
+ DECCYCLE (5);
+ DECCYCLE (4);
+ DECCYCLE (3);
+ DECCYCLE (2);
+ DECCYCLE (1);
+ DECCYCLE (0);
+
+ /* Output whitening and unpacking. */
+ OUTUNPACK (0, a, 0);
+ OUTUNPACK (1, b, 1);
+ OUTUNPACK (2, c, 2);
+ OUTUNPACK (3, d, 3);
+
+ return 0;
+}
+
+/* eof */
diff --git a/src/libcrypto/libtwofish/twofish.h b/src/libcrypto/libtwofish/twofish.h
new file mode 100644
index 000000000..9b289f265
--- /dev/null
+++ b/src/libcrypto/libtwofish/twofish.h
@@ -0,0 +1,20 @@
+#ifndef TWOFISH_H
+#define TWOFISH_H
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <sys/types.h>
+#endif
+/* Structure for an expanded Twofish key. s contains the key-dependent
+ * S-boxes composed with the MDS matrix; w contains the eight "whitening"
+ * subkeys, K[0] through K[7]. k holds the remaining, "round" subkeys. Note
+ * that k[i] corresponds to what the Twofish paper calls K[i+8]. */
+typedef struct {
+ u_int32_t s[4][256], w[8], k[32];
+} TWOFISH_context;
+
+typedef TWOFISH_context twofish_context;
+int twofish_set_key(twofish_context *tf_ctx, const u_int8_t * in_key, int key_len);
+int twofish_encrypt(twofish_context *tf_ctx, const u_int8_t * in, u_int8_t * out);
+int twofish_decrypt(twofish_context * tf_ctx, const u_int8_t * in, u_int8_t * out);
+#endif /* TWOFISH_H */
diff --git a/src/libcrypto/libtwofish/twofish_cbc.c b/src/libcrypto/libtwofish/twofish_cbc.c
new file mode 100644
index 000000000..6e5cf9025
--- /dev/null
+++ b/src/libcrypto/libtwofish/twofish_cbc.c
@@ -0,0 +1,8 @@
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <sys/types.h>
+#endif
+#include "twofish_cbc.h"
+#include "cbc_generic.h"
+CBC_IMPL_BLK16(twofish_cbc_encrypt, twofish_context, u_int8_t *, twofish_encrypt, twofish_decrypt);
diff --git a/src/libcrypto/libtwofish/twofish_cbc.h b/src/libcrypto/libtwofish/twofish_cbc.h
new file mode 100644
index 000000000..9fdea3526
--- /dev/null
+++ b/src/libcrypto/libtwofish/twofish_cbc.h
@@ -0,0 +1,3 @@
+/* Glue header */
+#include "twofish.h"
+int twofish_cbc_encrypt(twofish_context *ctx, const u_int8_t * in, u_int8_t * out, int ilen, const u_int8_t* iv, int encrypt);
diff --git a/src/libfreeswan/Makefile.am b/src/libfreeswan/Makefile.am
new file mode 100644
index 000000000..d916fca17
--- /dev/null
+++ b/src/libfreeswan/Makefile.am
@@ -0,0 +1,19 @@
+noinst_LIBRARIES = libfreeswan.a
+libfreeswan_a_SOURCES = addrtoa.c addrtot.c addrtypeof.c anyaddr.c atoaddr.c atoasr.c \
+ atosa.c atosubnet.c atoul.c copyright.c datatot.c freeswan.h \
+ goodmask.c initaddr.c initsaid.c initsubnet.c internal.h ipcomp.h \
+ ipsec_ah.h ipsec_alg.h ipsec_encap.h ipsec_eroute.h ipsec_errs.h \
+ ipsec_esp.h ipsec_ipe4.h ipsec_kversion.h ipsec_life.h ipsec_md5h.h \
+ ipsec_param.h ipsec_policy.h ipsec_proto.h ipsec_radij.h ipsec_rcv.h \
+ ipsec_sa.h ipsec_sha1.h ipsec_stats.h ipsec_tunnel.h ipsec_xform.h \
+ ipsec_xmit.h keyblobtoid.c optionsfrom.c pfkey_v2_build.c pfkey_v2_debug.c \
+ pfkey_v2_ext_bits.c pfkey_v2_parse.c portof.c prng.c radij.h rangetoa.c \
+ pfkey.h pfkeyv2.h rangetosubnet.c sameaddr.c satoa.c \
+ satot.c subnetof.c subnettoa.c subnettot.c \
+ subnettypeof.c ttoaddr.c ttodata.c ttoprotoport.c ttosa.c ttosubnet.c ttoul.c \
+ ultoa.c ultot.c version.c
+INCLUDES = -I$(top_srcdir)/src/pluto
+dist_man3_MANS = anyaddr.3 atoaddr.3 atoasr.3 atosa.3 atoul.3 goodmask.3 initaddr.3 initsubnet.3 \
+ keyblobtoid.3 optionsfrom.3 portof.3 prng.3 rangetosubnet.3 sameaddr.3 subnetof.3 \
+ ttoaddr.3 ttodata.3 ttosa.3 ttoul.3 version.3
+
diff --git a/src/libfreeswan/Makefile.in b/src/libfreeswan/Makefile.in
new file mode 100644
index 000000000..97b53d7c0
--- /dev/null
+++ b/src/libfreeswan/Makefile.in
@@ -0,0 +1,574 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/libfreeswan
+DIST_COMMON = $(dist_man3_MANS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+ARFLAGS = cru
+libfreeswan_a_AR = $(AR) $(ARFLAGS)
+libfreeswan_a_LIBADD =
+am_libfreeswan_a_OBJECTS = addrtoa.$(OBJEXT) addrtot.$(OBJEXT) \
+ addrtypeof.$(OBJEXT) anyaddr.$(OBJEXT) atoaddr.$(OBJEXT) \
+ atoasr.$(OBJEXT) atosa.$(OBJEXT) atosubnet.$(OBJEXT) \
+ atoul.$(OBJEXT) copyright.$(OBJEXT) datatot.$(OBJEXT) \
+ goodmask.$(OBJEXT) initaddr.$(OBJEXT) initsaid.$(OBJEXT) \
+ initsubnet.$(OBJEXT) keyblobtoid.$(OBJEXT) \
+ optionsfrom.$(OBJEXT) pfkey_v2_build.$(OBJEXT) \
+ pfkey_v2_debug.$(OBJEXT) pfkey_v2_ext_bits.$(OBJEXT) \
+ pfkey_v2_parse.$(OBJEXT) portof.$(OBJEXT) prng.$(OBJEXT) \
+ rangetoa.$(OBJEXT) rangetosubnet.$(OBJEXT) sameaddr.$(OBJEXT) \
+ satoa.$(OBJEXT) satot.$(OBJEXT) subnetof.$(OBJEXT) \
+ subnettoa.$(OBJEXT) subnettot.$(OBJEXT) subnettypeof.$(OBJEXT) \
+ ttoaddr.$(OBJEXT) ttodata.$(OBJEXT) ttoprotoport.$(OBJEXT) \
+ ttosa.$(OBJEXT) ttosubnet.$(OBJEXT) ttoul.$(OBJEXT) \
+ ultoa.$(OBJEXT) ultot.$(OBJEXT) version.$(OBJEXT)
+libfreeswan_a_OBJECTS = $(am_libfreeswan_a_OBJECTS)
+DEFAULT_INCLUDES = -I. -I$(srcdir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libfreeswan_a_SOURCES)
+DIST_SOURCES = $(libfreeswan_a_SOURCES)
+man3dir = $(mandir)/man3
+am__installdirs = "$(DESTDIR)$(man3dir)"
+NROFF = nroff
+MANS = $(dist_man3_MANS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_EAP_SIM_FALSE = @BUILD_EAP_SIM_FALSE@
+BUILD_EAP_SIM_TRUE = @BUILD_EAP_SIM_TRUE@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GPERF = @GPERF@
+GREP = @GREP@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+USE_CISCO_QUIRKS_FALSE = @USE_CISCO_QUIRKS_FALSE@
+USE_CISCO_QUIRKS_TRUE = @USE_CISCO_QUIRKS_TRUE@
+USE_LEAK_DETECTIVE_FALSE = @USE_LEAK_DETECTIVE_FALSE@
+USE_LEAK_DETECTIVE_TRUE = @USE_LEAK_DETECTIVE_TRUE@
+USE_LIBCURL_FALSE = @USE_LIBCURL_FALSE@
+USE_LIBCURL_TRUE = @USE_LIBCURL_TRUE@
+USE_LIBLDAP_FALSE = @USE_LIBLDAP_FALSE@
+USE_LIBLDAP_TRUE = @USE_LIBLDAP_TRUE@
+USE_NAT_TRANSPORT_FALSE = @USE_NAT_TRANSPORT_FALSE@
+USE_NAT_TRANSPORT_TRUE = @USE_NAT_TRANSPORT_TRUE@
+USE_SMARTCARD_FALSE = @USE_SMARTCARD_FALSE@
+USE_SMARTCARD_TRUE = @USE_SMARTCARD_TRUE@
+USE_VENDORID_FALSE = @USE_VENDORID_FALSE@
+USE_VENDORID_TRUE = @USE_VENDORID_TRUE@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+confdir = @confdir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+eapdir = @eapdir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+ipsecdir = @ipsecdir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+piddir = @piddir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+noinst_LIBRARIES = libfreeswan.a
+libfreeswan_a_SOURCES = addrtoa.c addrtot.c addrtypeof.c anyaddr.c atoaddr.c atoasr.c \
+ atosa.c atosubnet.c atoul.c copyright.c datatot.c freeswan.h \
+ goodmask.c initaddr.c initsaid.c initsubnet.c internal.h ipcomp.h \
+ ipsec_ah.h ipsec_alg.h ipsec_encap.h ipsec_eroute.h ipsec_errs.h \
+ ipsec_esp.h ipsec_ipe4.h ipsec_kversion.h ipsec_life.h ipsec_md5h.h \
+ ipsec_param.h ipsec_policy.h ipsec_proto.h ipsec_radij.h ipsec_rcv.h \
+ ipsec_sa.h ipsec_sha1.h ipsec_stats.h ipsec_tunnel.h ipsec_xform.h \
+ ipsec_xmit.h keyblobtoid.c optionsfrom.c pfkey_v2_build.c pfkey_v2_debug.c \
+ pfkey_v2_ext_bits.c pfkey_v2_parse.c portof.c prng.c radij.h rangetoa.c \
+ pfkey.h pfkeyv2.h rangetosubnet.c sameaddr.c satoa.c \
+ satot.c subnetof.c subnettoa.c subnettot.c \
+ subnettypeof.c ttoaddr.c ttodata.c ttoprotoport.c ttosa.c ttosubnet.c ttoul.c \
+ ultoa.c ultot.c version.c
+
+INCLUDES = -I$(top_srcdir)/src/pluto
+dist_man3_MANS = anyaddr.3 atoaddr.3 atoasr.3 atosa.3 atoul.3 goodmask.3 initaddr.3 initsubnet.3 \
+ keyblobtoid.3 optionsfrom.3 portof.3 prng.3 rangetosubnet.3 sameaddr.3 subnetof.3 \
+ ttoaddr.3 ttodata.3 ttosa.3 ttoul.3 version.3
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libfreeswan/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/libfreeswan/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+libfreeswan.a: $(libfreeswan_a_OBJECTS) $(libfreeswan_a_DEPENDENCIES)
+ -rm -f libfreeswan.a
+ $(libfreeswan_a_AR) libfreeswan.a $(libfreeswan_a_OBJECTS) $(libfreeswan_a_LIBADD)
+ $(RANLIB) libfreeswan.a
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/addrtoa.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/addrtot.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/addrtypeof.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/anyaddr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atoaddr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atoasr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atosa.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atosubnet.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atoul.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/copyright.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/datatot.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/goodmask.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/initaddr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/initsaid.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/initsubnet.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keyblobtoid.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/optionsfrom.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pfkey_v2_build.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pfkey_v2_debug.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pfkey_v2_ext_bits.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pfkey_v2_parse.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/portof.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/prng.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rangetoa.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rangetosubnet.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sameaddr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/satoa.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/satot.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/subnetof.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/subnettoa.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/subnettot.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/subnettypeof.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ttoaddr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ttodata.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ttoprotoport.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ttosa.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ttosubnet.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ttoul.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ultoa.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ultot.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+install-man3: $(man3_MANS) $(man_MANS)
+ @$(NORMAL_INSTALL)
+ test -z "$(man3dir)" || $(mkdir_p) "$(DESTDIR)$(man3dir)"
+ @list='$(man3_MANS) $(dist_man3_MANS) $(nodist_man3_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.3*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 3*) ;; \
+ *) ext='3' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man3dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man3dir)/$$inst"; \
+ done
+uninstall-man3:
+ @$(NORMAL_UNINSTALL)
+ @list='$(man3_MANS) $(dist_man3_MANS) $(nodist_man3_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.3*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 3*) ;; \
+ *) ext='3' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f '$(DESTDIR)$(man3dir)/$$inst'"; \
+ rm -f "$(DESTDIR)$(man3dir)/$$inst"; \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LIBRARIES) $(MANS)
+installdirs:
+ for dir in "$(DESTDIR)$(man3dir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-man
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man: install-man3
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-man
+
+uninstall-man: uninstall-man3
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am install-man \
+ install-man3 install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \
+ uninstall-am uninstall-info-am uninstall-man uninstall-man3
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/libfreeswan/addrtoa.c b/src/libfreeswan/addrtoa.c
new file mode 100644
index 000000000..b1cc038ed
--- /dev/null
+++ b/src/libfreeswan/addrtoa.c
@@ -0,0 +1,68 @@
+/*
+ * addresses to ASCII
+ * Copyright (C) 1998, 1999 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.
+ *
+ * RCSID $Id: addrtoa.c,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+#define NBYTES 4 /* bytes in an address */
+#define PERBYTE 4 /* three digits plus a dot or NUL */
+#define BUFLEN (NBYTES*PERBYTE)
+
+#if BUFLEN != ADDRTOA_BUF
+#error "ADDRTOA_BUF in freeswan.h inconsistent with addrtoa() code"
+#endif
+
+/*
+ - addrtoa - convert binary address to ASCII dotted decimal
+ */
+size_t /* space needed for full conversion */
+addrtoa(addr, format, dst, dstlen)
+struct in_addr addr;
+int format; /* character */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ unsigned long a = ntohl(addr.s_addr);
+ int i;
+ size_t n;
+ unsigned long byte;
+ char buf[BUFLEN];
+ char *p;
+
+ switch (format) {
+ case 0:
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ p = buf;
+ for (i = NBYTES-1; i >= 0; i--) {
+ byte = (a >> (i*8)) & 0xff;
+ p += ultoa(byte, 10, p, PERBYTE);
+ if (i != 0)
+ *(p-1) = '.';
+ }
+ n = p - buf;
+
+ if (dstlen > 0) {
+ if (n > dstlen)
+ buf[dstlen - 1] = '\0';
+ strcpy(dst, buf);
+ }
+ return n;
+}
diff --git a/src/libfreeswan/addrtot.c b/src/libfreeswan/addrtot.c
new file mode 100644
index 000000000..f229789f0
--- /dev/null
+++ b/src/libfreeswan/addrtot.c
@@ -0,0 +1,302 @@
+/*
+ * addresses to text
+ * 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.
+ *
+ * RCSID $Id: addrtot.c,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+#define IP4BYTES 4 /* bytes in an IPv4 address */
+#define PERBYTE 4 /* three digits plus a dot or NUL */
+#define IP6BYTES 16 /* bytes in an IPv6 address */
+
+/* forwards */
+static size_t normal4(const unsigned char *s, size_t len, char *b, char **dp);
+static size_t normal6(const unsigned char *s, size_t len, char *b, char **dp, int squish);
+static size_t reverse4(const unsigned char *s, size_t len, char *b, char **dp);
+static size_t reverse6(const unsigned char *s, size_t len, char *b, char **dp);
+
+/*
+ - addrtot - convert binary address to text (dotted decimal or IPv6 string)
+ */
+size_t /* space needed for full conversion */
+addrtot(src, format, dst, dstlen)
+const ip_address *src;
+int format; /* character */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ const unsigned char *b;
+ size_t n;
+ char buf[1+ADDRTOT_BUF+1]; /* :address: */
+ char *p;
+ int t = addrtypeof(src);
+# define TF(t, f) (((t)<<8) | (f))
+
+ n = addrbytesptr(src, &b);
+ if (n == 0)
+ return 0;
+
+ switch (TF(t, format)) {
+ case TF(AF_INET, 0):
+ n = normal4(b, n, buf, &p);
+ break;
+ case TF(AF_INET6, 0):
+ n = normal6(b, n, buf, &p, 1);
+ break;
+ case TF(AF_INET, 'Q'):
+ n = normal4(b, n, buf, &p);
+ break;
+ case TF(AF_INET6, 'Q'):
+ n = normal6(b, n, buf, &p, 0);
+ break;
+ case TF(AF_INET, 'r'):
+ n = reverse4(b, n, buf, &p);
+ break;
+ case TF(AF_INET6, 'r'):
+ n = reverse6(b, n, buf, &p);
+ break;
+ default: /* including (AF_INET, 'R') */
+ return 0;
+ break;
+ }
+
+ if (dstlen > 0) {
+ if (dstlen < n)
+ p[dstlen - 1] = '\0';
+ strcpy(dst, p);
+ }
+ return n;
+}
+
+/*
+ - normal4 - normal IPv4 address-text conversion
+ */
+static size_t /* size of text, including NUL */
+normal4(srcp, srclen, buf, dstp)
+const unsigned char *srcp;
+size_t srclen;
+char *buf; /* guaranteed large enough */
+char **dstp; /* where to put result pointer */
+{
+ int i;
+ char *p;
+
+ if (srclen != IP4BYTES) /* "can't happen" */
+ return 0;
+ p = buf;
+ for (i = 0; i < IP4BYTES; i++) {
+ p += ultot(srcp[i], 10, p, PERBYTE);
+ if (i != IP4BYTES - 1)
+ *(p-1) = '.'; /* overwrites the NUL */
+ }
+ *dstp = buf;
+ return p - buf;
+}
+
+/*
+ - normal6 - normal IPv6 address-text conversion
+ */
+static size_t /* size of text, including NUL */
+normal6(srcp, srclen, buf, dstp, squish)
+const unsigned char *srcp;
+size_t srclen;
+char *buf; /* guaranteed large enough, plus 2 */
+char **dstp; /* where to put result pointer */
+int squish; /* whether to squish out 0:0 */
+{
+ int i;
+ unsigned long piece;
+ char *p;
+ char *q;
+
+ if (srclen != IP6BYTES) /* "can't happen" */
+ return 0;
+ p = buf;
+ *p++ = ':';
+ for (i = 0; i < IP6BYTES/2; i++) {
+ piece = (srcp[2*i] << 8) + srcp[2*i + 1];
+ p += ultot(piece, 16, p, 5); /* 5 = abcd + NUL */
+ *(p-1) = ':'; /* overwrites the NUL */
+ }
+ *p = '\0';
+ q = strstr(buf, ":0:0:");
+ if (squish && q != NULL) { /* zero squishing is possible */
+ p = q + 1;
+ while (*p == '0' && *(p+1) == ':')
+ p += 2;
+ q++;
+ *q++ = ':'; /* overwrite first 0 */
+ while (*p != '\0')
+ *q++ = *p++;
+ *q = '\0';
+ if (!(*(q-1) == ':' && *(q-2) == ':'))
+ *--q = '\0'; /* strip final : unless :: */
+ p = buf;
+ if (!(*p == ':' && *(p+1) == ':'))
+ p++; /* skip initial : unless :: */
+ } else {
+ q = p;
+ *--q = '\0'; /* strip final : */
+ p = buf + 1; /* skip initial : */
+ }
+ *dstp = p;
+ return q - p + 1;
+}
+
+/*
+ - reverse4 - IPv4 reverse-lookup conversion
+ */
+static size_t /* size of text, including NUL */
+reverse4(srcp, srclen, buf, dstp)
+const unsigned char *srcp;
+size_t srclen;
+char *buf; /* guaranteed large enough */
+char **dstp; /* where to put result pointer */
+{
+ int i;
+ char *p;
+
+ if (srclen != IP4BYTES) /* "can't happen" */
+ return 0;
+ p = buf;
+ for (i = IP4BYTES-1; i >= 0; i--) {
+ p += ultot(srcp[i], 10, p, PERBYTE);
+ *(p-1) = '.'; /* overwrites the NUL */
+ }
+ strcpy(p, "IN-ADDR.ARPA.");
+ *dstp = buf;
+ return strlen(buf) + 1;
+}
+
+/*
+ - reverse6 - IPv6 reverse-lookup conversion (RFC 1886)
+ * A trifle inefficient, really shouldn't use ultot...
+ */
+static size_t /* size of text, including NUL */
+reverse6(srcp, srclen, buf, dstp)
+const unsigned char *srcp;
+size_t srclen;
+char *buf; /* guaranteed large enough */
+char **dstp; /* where to put result pointer */
+{
+ int i;
+ unsigned long piece;
+ char *p;
+
+ if (srclen != IP6BYTES) /* "can't happen" */
+ return 0;
+ p = buf;
+ for (i = IP6BYTES-1; i >= 0; i--) {
+ piece = srcp[i];
+ p += ultot(piece&0xf, 16, p, 2);
+ *(p-1) = '.';
+ p += ultot(piece>>4, 16, p, 2);
+ *(p-1) = '.';
+ }
+ strcpy(p, "IP6.ARPA.");
+ *dstp = buf;
+ return strlen(buf) + 1;
+}
+
+/*
+ - reverse6 - modern IPv6 reverse-lookup conversion (RFC 2874)
+ * this version removed as it was obsoleted in the end.
+ */
+
+#ifdef ADDRTOT_MAIN
+
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+void regress(void);
+
+int
+main(int argc, char *argv[])
+{
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s {addr|net/mask|begin...end|-r}\n",
+ argv[0]);
+ exit(2);
+ }
+
+ if (strcmp(argv[1], "-r") == 0) {
+ regress();
+ fprintf(stderr, "regress() returned?!?\n");
+ exit(1);
+ }
+ exit(0);
+}
+
+struct rtab {
+ char *input;
+ char format;
+ char *output; /* NULL means error expected */
+} rtab[] = {
+ {"1.2.3.0", 0, "1.2.3.0"},
+ {"1:2::3:4", 0, "1:2::3:4"},
+ {"1:2::3:4", 'Q', "1:2:0:0:0:0:3:4"},
+ {"1:2:0:0:3:4:0:0", 0, "1:2::3:4:0:0"},
+ {"1.2.3.4", 'r' , "4.3.2.1.IN-ADDR.ARPA."},
+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f 0 1 2 3 4 5 6 7 8 9 a b c d e f */
+ {"1:2::3:4", 'r', "4.0.0.0.3.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.1.0.0.0.IP6.ARPA."},
+ {NULL, 0, NULL}
+};
+
+void
+regress()
+{
+ struct rtab *r;
+ int status = 0;
+ ip_address a;
+ char in[100];
+ char buf[100];
+ const char *oops;
+ size_t n;
+
+ for (r = rtab; r->input != NULL; r++) {
+ strcpy(in, r->input);
+
+ /* convert it *to* internal format */
+ oops = ttoaddr(in, strlen(in), 0, &a);
+
+ /* now convert it back */
+
+ n = addrtot(&a, r->format, buf, sizeof(buf));
+
+ if (n == 0 && r->output == NULL)
+ {} /* okay, error expected */
+
+ else if (n == 0) {
+ printf("`%s' atoasr failed\n", r->input);
+ status = 1;
+
+ } else if (r->output == NULL) {
+ printf("`%s' atoasr succeeded unexpectedly '%c'\n",
+ r->input, r->format);
+ status = 1;
+ } else {
+ if (strcasecmp(r->output, buf) != 0) {
+ printf("`%s' '%c' gave `%s', expected `%s'\n",
+ r->input, r->format, buf, r->output);
+ status = 1;
+ }
+ }
+ }
+ exit(status);
+}
+
+#endif /* ADDRTOT_MAIN */
diff --git a/src/libfreeswan/addrtypeof.c b/src/libfreeswan/addrtypeof.c
new file mode 100644
index 000000000..e63509911
--- /dev/null
+++ b/src/libfreeswan/addrtypeof.c
@@ -0,0 +1,94 @@
+/*
+ * extract parts of an ip_address
+ * 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.
+ *
+ * RCSID $Id: addrtypeof.c,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - addrtypeof - get the type of an ip_address
+ */
+int
+addrtypeof(src)
+const ip_address *src;
+{
+ return src->u.v4.sin_family;
+}
+
+/*
+ - addrbytesptr - get pointer to the address bytes of an ip_address
+ */
+size_t /* 0 for error */
+addrbytesptr(src, dstp)
+const ip_address *src;
+const unsigned char **dstp; /* NULL means just a size query */
+{
+ const unsigned char *p;
+ size_t n;
+
+ switch (src->u.v4.sin_family) {
+ case AF_INET:
+ p = (const unsigned char *)&src->u.v4.sin_addr.s_addr;
+ n = 4;
+ break;
+ case AF_INET6:
+ p = (const unsigned char *)&src->u.v6.sin6_addr;
+ n = 16;
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ if (dstp != NULL)
+ *dstp = p;
+ return n;
+}
+
+/*
+ - addrlenof - get length of the address bytes of an ip_address
+ */
+size_t /* 0 for error */
+addrlenof(src)
+const ip_address *src;
+{
+ return addrbytesptr(src, NULL);
+}
+
+/*
+ - addrbytesof - get the address bytes of an ip_address
+ */
+size_t /* 0 for error */
+addrbytesof(src, dst, dstlen)
+const ip_address *src;
+unsigned char *dst;
+size_t dstlen;
+{
+ const unsigned char *p;
+ size_t n;
+ size_t ncopy;
+
+ n = addrbytesptr(src, &p);
+ if (n == 0)
+ return 0;
+
+ if (dstlen > 0) {
+ ncopy = n;
+ if (ncopy > dstlen)
+ ncopy = dstlen;
+ memcpy(dst, p, ncopy);
+ }
+ return n;
+}
diff --git a/src/libfreeswan/anyaddr.3 b/src/libfreeswan/anyaddr.3
new file mode 100644
index 000000000..4594a9ff9
--- /dev/null
+++ b/src/libfreeswan/anyaddr.3
@@ -0,0 +1,87 @@
+.TH IPSEC_ANYADDR 3 "8 Sept 2000"
+.\" RCSID $Id: anyaddr.3,v 1.1 2004/03/15 20:35:25 as Exp $
+.SH NAME
+ipsec anyaddr \- get "any" address
+.br
+ipsec isanyaddr \- test address for equality to "any" address
+.br
+ipsec unspecaddr \- get "unspecified" address
+.br
+ipsec isunspecaddr \- test address for equality to "unspecified" address
+.br
+ipsec loopbackaddr \- get loopback address
+.br
+ipsec isloopbackaddr \- test address for equality to loopback address
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "const char *anyaddr(int af, ip_address *dst);"
+.br
+.B "int isanyaddr(const ip_address *src);"
+.br
+.B "const char *unspecaddr(int af, ip_address *dst);"
+.br
+.B "int isunspecaddr(const ip_address *src);"
+.br
+.B "const char *loopbackaddr(int af, ip_address *dst);"
+.br
+.B "int isloopbackaddr(const ip_address *src);"
+.SH DESCRIPTION
+These functions fill in, and test for, special values of the
+.I ip_address
+type.
+.PP
+.I Anyaddr
+fills in the destination
+.I *dst
+with the ``any'' address of address family
+.IR af
+(normally
+.B AF_INET
+or
+.BR AF_INET6 ).
+The IPv4 ``any'' address is the one embodied in the old
+.B INADDR_ANY
+macro.
+.PP
+.I Isanyaddr
+returns
+.B 1
+if the
+.I src
+address equals the ``any'' address,
+and
+.B 0
+otherwise.
+.PP
+Similarly,
+.I unspecaddr
+supplies, and
+.I isunspecaddr
+tests for,
+the ``unspecified'' address,
+which may be the same as the ``any'' address.
+.PP
+Similarly,
+.I loopbackaddr
+supplies, and
+.I islookbackaddr
+tests for,
+the loopback address.
+.PP
+.IR Anyaddr ,
+.IR unspecaddr ,
+and
+.I loopbackaddr
+return
+.B NULL
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+.SH SEE ALSO
+inet(3), ipsec_addrtot(3), ipsec_sameaddr(3)
+.SH DIAGNOSTICS
+Fatal errors in the address-supplying functions are:
+unknown address family.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
diff --git a/src/libfreeswan/anyaddr.c b/src/libfreeswan/anyaddr.c
new file mode 100644
index 000000000..08aae6334
--- /dev/null
+++ b/src/libfreeswan/anyaddr.c
@@ -0,0 +1,146 @@
+/*
+ * special addresses
+ * 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.
+ *
+ * RCSID $Id: anyaddr.c,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/* these are mostly fallbacks for the no-IPv6-support-in-library case */
+#ifndef IN6ADDR_ANY_INIT
+#define IN6ADDR_ANY_INIT {{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }}
+#endif
+#ifndef IN6ADDR_LOOPBACK_INIT
+#define IN6ADDR_LOOPBACK_INIT {{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }}
+#endif
+
+static struct in6_addr v6any = IN6ADDR_ANY_INIT;
+static struct in6_addr v6loop = IN6ADDR_LOOPBACK_INIT;
+
+/*
+ - anyaddr - initialize to the any-address value
+ */
+err_t /* NULL for success, else string literal */
+anyaddr(af, dst)
+int af; /* address family */
+ip_address *dst;
+{
+ uint32_t v4any = htonl(INADDR_ANY);
+
+ switch (af) {
+ case AF_INET:
+ return initaddr((unsigned char *)&v4any, sizeof(v4any), af, dst);
+ break;
+ case AF_INET6:
+ return initaddr((unsigned char *)&v6any, sizeof(v6any), af, dst);
+ break;
+ default:
+ return "unknown address family in anyaddr/unspecaddr";
+ break;
+ }
+}
+
+/*
+ - unspecaddr - initialize to the unspecified-address value
+ */
+err_t /* NULL for success, else string literal */
+unspecaddr(af, dst)
+int af; /* address family */
+ip_address *dst;
+{
+ return anyaddr(af, dst);
+}
+
+/*
+ - loopbackaddr - initialize to the loopback-address value
+ */
+err_t /* NULL for success, else string literal */
+loopbackaddr(af, dst)
+int af; /* address family */
+ip_address *dst;
+{
+ uint32_t v4loop = htonl(INADDR_LOOPBACK);
+
+ switch (af) {
+ case AF_INET:
+ return initaddr((unsigned char *)&v4loop, sizeof(v4loop), af, dst);
+ break;
+ case AF_INET6:
+ return initaddr((unsigned char *)&v6loop, sizeof(v6loop), af, dst);
+ break;
+ default:
+ return "unknown address family in loopbackaddr";
+ break;
+ }
+}
+
+/*
+ - isanyaddr - test for the any-address value
+ */
+int
+isanyaddr(src)
+const ip_address *src;
+{
+ uint32_t v4any = htonl(INADDR_ANY);
+ int cmp;
+
+ switch (src->u.v4.sin_family) {
+ case AF_INET:
+ cmp = memcmp(&src->u.v4.sin_addr.s_addr, &v4any, sizeof(v4any));
+ break;
+ case AF_INET6:
+ cmp = memcmp(&src->u.v6.sin6_addr, &v6any, sizeof(v6any));
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ return (cmp == 0) ? 1 : 0;
+}
+
+/*
+ - isunspecaddr - test for the unspecified-address value
+ */
+int
+isunspecaddr(src)
+const ip_address *src;
+{
+ return isanyaddr(src);
+}
+
+/*
+ - isloopbackaddr - test for the loopback-address value
+ */
+int
+isloopbackaddr(src)
+const ip_address *src;
+{
+ uint32_t v4loop = htonl(INADDR_LOOPBACK);
+ int cmp;
+
+ switch (src->u.v4.sin_family) {
+ case AF_INET:
+ cmp = memcmp(&src->u.v4.sin_addr.s_addr, &v4loop, sizeof(v4loop));
+ break;
+ case AF_INET6:
+ cmp = memcmp(&src->u.v6.sin6_addr, &v6loop, sizeof(v6loop));
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ return (cmp == 0) ? 1 : 0;
+}
diff --git a/src/libfreeswan/atoaddr.3 b/src/libfreeswan/atoaddr.3
new file mode 100644
index 000000000..a7dc8dca3
--- /dev/null
+++ b/src/libfreeswan/atoaddr.3
@@ -0,0 +1,294 @@
+.TH IPSEC_ATOADDR 3 "11 June 2001"
+.\" RCSID $Id: atoaddr.3,v 1.1 2004/03/15 20:35:25 as Exp $
+.SH NAME
+ipsec atoaddr, addrtoa \- convert Internet addresses to and from ASCII
+.br
+ipsec atosubnet, subnettoa \- convert subnet/mask ASCII form to and from addresses
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "const char *atoaddr(const char *src, size_t srclen,"
+.ti +1c
+.B "struct in_addr *addr);"
+.br
+.B "size_t addrtoa(struct in_addr addr, int format,"
+.ti +1c
+.B "char *dst, size_t dstlen);"
+.sp
+.B "const char *atosubnet(const char *src, size_t srclen,"
+.ti +1c
+.B "struct in_addr *addr, struct in_addr *mask);"
+.br
+.B "size_t subnettoa(struct in_addr addr, struct in_addr mask,"
+.ti +1c
+.B "int format, char *dst, size_t dstlen);"
+.SH DESCRIPTION
+These functions are obsolete; see
+.IR ipsec_ttoaddr (3)
+for their replacements.
+.PP
+.I Atoaddr
+converts an ASCII name or dotted-decimal address into a binary address
+(in network byte order).
+.I Addrtoa
+does the reverse conversion, back to an ASCII dotted-decimal address.
+.I Atosubnet
+and
+.I subnettoa
+do likewise for the ``address/mask'' ASCII form used to write a
+specification of a subnet.
+.PP
+An address is specified in ASCII as a
+dotted-decimal address (e.g.
+.BR 1.2.3.4 ),
+an eight-digit network-order hexadecimal number with the usual C prefix (e.g.
+.BR 0x01020304 ,
+which is synonymous with
+.BR 1.2.3.4 ),
+an eight-digit host-order hexadecimal number with a
+.B 0h
+prefix (e.g.
+.BR 0h01020304 ,
+which is synonymous with
+.B 1.2.3.4
+on a big-endian host and
+.B 4.3.2.1
+on a little-endian host),
+a DNS name to be looked up via
+.IR gethostbyname (3),
+or an old-style network name to be looked up via
+.IR getnetbyname (3).
+.PP
+A dotted-decimal address may be incomplete, in which case
+ASCII-to-binary conversion implicitly appends
+as many instances of
+.B .0
+as necessary to bring it up to four components.
+The components of a dotted-decimal address are always taken as
+decimal, and leading zeros are ignored.
+For example,
+.B 10
+is synonymous with
+.BR 10.0.0.0 ,
+and
+.B 128.009.000.032
+is synonymous with
+.BR 128.9.0.32
+(the latter example is verbatim from RFC 1166).
+The result of
+.I addrtoa
+is always complete and does not contain leading zeros.
+.PP
+The letters in
+a hexadecimal address may be uppercase or lowercase or any mixture thereof.
+Use of hexadecimal addresses is
+.B strongly
+.BR discouraged ;
+they are included only to save hassles when dealing with
+the handful of perverted programs which already print
+network addresses in hexadecimal.
+.PP
+DNS names may be complete (optionally terminated with a ``.'')
+or incomplete, and are looked up as specified by local system configuration
+(see
+.IR resolver (5)).
+The
+.I h_addr
+value returned by
+.IR gethostbyname (3)
+is used,
+so with current DNS implementations,
+the result when the name corresponds to more than one address is
+difficult to predict.
+Name lookup resorts to
+.IR getnetbyname (3)
+only if
+.IR gethostbyname (3)
+fails.
+.PP
+A subnet specification is of the form \fInetwork\fB/\fImask\fR.
+The
+.I network
+and
+.I mask
+can be any form acceptable to
+.IR atoaddr .
+In addition, the
+.I mask
+can be a decimal integer (leading zeros ignored) giving a bit count,
+in which case
+it stands for a mask with that number of high bits on and all others off
+(e.g.,
+.B 24
+means
+.BR 255.255.255.0 ).
+In any case, the mask must be contiguous
+(a sequence of high bits on and all remaining low bits off).
+As a special case, the subnet specification
+.B %default
+is a synonym for
+.BR 0.0.0.0/0 .
+.PP
+.I Atosubnet
+ANDs the mask with the address before returning,
+so that any non-network bits in the address are turned off
+(e.g.,
+.B 10.1.2.3/24
+is synonymous with
+.BR 10.1.2.0/24 ).
+.I Subnettoa
+generates the decimal-integer-bit-count
+form of the mask,
+with no leading zeros,
+unless the mask is non-contiguous.
+.PP
+The
+.I srclen
+parameter of
+.I atoaddr
+and
+.I atosubnet
+specifies the length of the ASCII string pointed to by
+.IR src ;
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+.I srclen
+value of
+.B 0
+is taken to mean
+.BR strlen(src) .
+.PP
+The
+.I dstlen
+parameter of
+.I addrtoa
+and
+.I subnettoa
+specifies the size of the
+.I dst
+parameter;
+under no circumstances are more than
+.I dstlen
+bytes written to
+.IR dst .
+A result which will not fit is truncated.
+.I Dstlen
+can be zero, in which case
+.I dst
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+.I freeswan.h
+header file defines constants,
+.B ADDRTOA_BUF
+and
+.BR SUBNETTOA_BUF ,
+which are the sizes of buffers just large enough for worst-case results.
+.PP
+The
+.I format
+parameter of
+.I addrtoa
+and
+.I subnettoa
+specifies what format is to be used for the conversion.
+The value
+.B 0
+(not the ASCII character
+.BR '0' ,
+but a zero value)
+specifies a reasonable default,
+and is in fact the only format currently available.
+This parameter is a hedge against future needs.
+.PP
+The ASCII-to-binary functions return NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+The binary-to-ASCII functions return
+.B 0
+for a failure, and otherwise
+always return the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+.SH SEE ALSO
+inet(3)
+.SH DIAGNOSTICS
+Fatal errors in
+.I atoaddr
+are:
+empty input;
+attempt to allocate temporary storage for a very long name failed;
+name lookup failed;
+syntax error in dotted-decimal form;
+dotted-decimal component too large to fit in 8 bits.
+.PP
+Fatal errors in
+.I atosubnet
+are:
+no
+.B /
+in
+.IR src ;
+.I atoaddr
+error in conversion of
+.I network
+or
+.IR mask ;
+bit-count mask too big;
+mask non-contiguous.
+.PP
+Fatal errors in
+.I addrtoa
+and
+.I subnettoa
+are:
+unknown format.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+The interpretation of incomplete dotted-decimal addresses
+(e.g.
+.B 10/24
+means
+.BR 10.0.0.0/24 )
+differs from that of some older conversion
+functions, e.g. those of
+.IR inet (3).
+The behavior of the older functions has never been
+particularly consistent or particularly useful.
+.PP
+Ignoring leading zeros in dotted-decimal components and bit counts
+is arguably the most useful behavior in this application,
+but it might occasionally cause confusion with the historical use of leading
+zeros to denote octal numbers.
+.PP
+It is barely possible that somebody, somewhere,
+might have a legitimate use for non-contiguous subnet masks.
+.PP
+.IR Getnetbyname (3)
+is a historical dreg.
+.PP
+The restriction of ASCII-to-binary error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+.PP
+The ASCII-to-binary error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+.PP
+.RS
+.nf
+.B "const char *error;"
+.sp
+.B "error = atoaddr( /* ... */ );"
+.B "if (error != NULL) {"
+.B " /* something went wrong */"
+.fi
+.RE
diff --git a/src/libfreeswan/atoaddr.c b/src/libfreeswan/atoaddr.c
new file mode 100644
index 000000000..0c787b10d
--- /dev/null
+++ b/src/libfreeswan/atoaddr.c
@@ -0,0 +1,238 @@
+/*
+ * conversion from ASCII forms of addresses to internal ones
+ * Copyright (C) 1998, 1999 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.
+ *
+ * RCSID $Id: atoaddr.c,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ * Define NOLEADINGZEROS to interpret 032 as an error, not as 32. There
+ * is deliberately no way to interpret it as 26 (i.e., as octal).
+ */
+
+/*
+ * Legal characters in a domain name. Underscore technically is not,
+ * but is a common misunderstanding.
+ */
+static const char namechars[] = "abcdefghijklmnopqrstuvwxyz0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ-_.";
+
+static const char *try8hex(const char *, size_t, struct in_addr *);
+static const char *try8hosthex(const char *, size_t, struct in_addr *);
+static const char *trydotted(const char *, size_t, struct in_addr *);
+static const char *getbyte(const char **, const char *, int *);
+
+/*
+ - atoaddr - convert ASCII name or dotted-decimal address to binary address
+ */
+const char * /* NULL for success, else string literal */
+atoaddr(src, srclen, addrp)
+const char *src;
+size_t srclen; /* 0 means "apply strlen" */
+struct in_addr *addrp;
+{
+ struct hostent *h;
+ struct netent *ne = NULL;
+ const char *oops;
+# define HEXLEN 10 /* strlen("0x11223344") */
+# ifndef ATOADDRBUF
+# define ATOADDRBUF 100
+# endif
+ char namebuf[ATOADDRBUF];
+ char *p = namebuf;
+ char *q;
+
+ if (srclen == 0)
+ srclen = strlen(src);
+ if (srclen == 0)
+ return "empty string";
+
+ /* might it be hex? */
+ if (srclen == HEXLEN && *src == '0' && CIEQ(*(src+1), 'x'))
+ return try8hex(src+2, srclen-2, addrp);
+ if (srclen == HEXLEN && *src == '0' && CIEQ(*(src+1), 'h'))
+ return try8hosthex(src+2, srclen-2, addrp);
+
+ /* try it as dotted decimal */
+ oops = trydotted(src, srclen, addrp);
+ if (oops == NULL)
+ return NULL; /* it worked */
+ if (*oops != '?')
+ return oops; /* it *was* probably meant as a d.q. */
+
+ /* try it as a name -- first, NUL-terminate it */
+ if (srclen > sizeof(namebuf)-1) {
+ p = (char *) MALLOC(srclen+1);
+ if (p == NULL)
+ return "unable to allocate temporary space for name";
+ }
+ p[0] = '\0';
+ strncat(p, src, srclen);
+
+ /* next, check that it's a vaguely legal name */
+ for (q = p; *q != '\0'; q++)
+ if (!isprint(*q))
+ return "unprintable character in name";
+ if (strspn(p, namechars) != srclen)
+ return "illegal (non-DNS-name) character in name";
+
+ /* try as host name, failing that as /etc/networks network name */
+ h = gethostbyname(p);
+ if (h == NULL)
+ ne = getnetbyname(p);
+ if (p != namebuf)
+ FREE(p);
+ if (h == NULL && ne == NULL)
+ return "name lookup failed";
+
+ if (h != NULL)
+ memcpy(&addrp->s_addr, h->h_addr, sizeof(addrp->s_addr));
+ else
+ addrp->s_addr = htonl(ne->n_net);
+ return NULL;
+}
+
+/*
+ - try8hosthex - try conversion as an eight-digit host-order hex number
+ */
+const char * /* NULL for success, else string literal */
+try8hosthex(src, srclen, addrp)
+const char *src;
+size_t srclen; /* should be 8 */
+struct in_addr *addrp;
+{
+ const char *oops;
+ unsigned long addr;
+
+ if (srclen != 8)
+ return "internal error, try8hex called with bad length";
+
+ oops = atoul(src, srclen, 16, &addr);
+ if (oops != NULL)
+ return oops;
+
+ addrp->s_addr = addr;
+ return NULL;
+}
+
+/*
+ - try8hex - try conversion as an eight-digit network-order hex number
+ */
+const char * /* NULL for success, else string literal */
+try8hex(src, srclen, addrp)
+const char *src;
+size_t srclen; /* should be 8 */
+struct in_addr *addrp;
+{
+ const char *oops;
+
+ oops = try8hosthex(src, srclen, addrp);
+ if (oops != NULL)
+ return oops;
+
+ addrp->s_addr = htonl(addrp->s_addr);
+ return NULL;
+}
+
+/*
+ - trydotted - try conversion as dotted decimal
+ *
+ * If the first char of a complaint is '?', that means "didn't look like
+ * dotted decimal at all".
+ */
+const char * /* NULL for success, else string literal */
+trydotted(src, srclen, addrp)
+const char *src;
+size_t srclen;
+struct in_addr *addrp;
+{
+ const char *stop = src + srclen; /* just past end */
+ int byte;
+ const char *oops;
+ unsigned long addr;
+ int i;
+# define NBYTES 4
+# define BYTE 8
+
+ addr = 0;
+ for (i = 0; i < NBYTES && src < stop; i++) {
+ oops = getbyte(&src, stop, &byte);
+ if (oops != NULL) {
+ if (*oops != '?')
+ return oops; /* bad number */
+ if (i > 1)
+ return oops+1; /* failed number */
+ return oops; /* with leading '?' */
+ }
+ addr = (addr << BYTE) | byte;
+ if (i < 3 && src < stop && *src++ != '.') {
+ if (i == 0)
+ return "?syntax error in dotted-decimal address";
+ else
+ return "syntax error in dotted-decimal address";
+ }
+ }
+ addr <<= (NBYTES - i) * BYTE;
+ if (src != stop)
+ return "extra garbage on end of dotted-decimal address";
+
+ addrp->s_addr = htonl(addr);
+ return NULL;
+}
+
+/*
+ - getbyte - try to scan a byte in dotted decimal
+ * A subtlety here is that all this arithmetic on ASCII digits really is
+ * highly portable -- ANSI C guarantees that digits 0-9 are contiguous.
+ * It's easier to just do it ourselves than set up for a call to atoul().
+ *
+ * If the first char of a complaint is '?', that means "didn't look like a
+ * number at all".
+ */
+const char * /* NULL for success, else string literal */
+getbyte(srcp, stop, retp)
+const char **srcp; /* *srcp is updated */
+const char *stop; /* first untouchable char */
+int *retp; /* return-value pointer */
+{
+ char c;
+ const char *p;
+ int no;
+
+ if (*srcp >= stop)
+ return "?empty number in dotted-decimal address";
+
+ if (stop - *srcp >= 3 && **srcp == '0' && CIEQ(*(*srcp+1), 'x'))
+ return "hex numbers not supported in dotted-decimal addresses";
+#ifdef NOLEADINGZEROS
+ if (stop - *srcp >= 2 && **srcp == '0' && isdigit(*(*srcp+1)))
+ return "octal numbers not supported in dotted-decimal addresses";
+#endif /* NOLEADINGZEROS */
+
+ /* must be decimal, if it's numeric at all */
+ no = 0;
+ p = *srcp;
+ while (p < stop && no <= 255 && (c = *p) >= '0' && c <= '9') {
+ no = no*10 + (c - '0');
+ p++;
+ }
+ if (p == *srcp)
+ return "?non-numeric component in dotted-decimal address";
+ *srcp = p;
+ if (no > 255)
+ return "byte overflow in dotted-decimal address";
+ *retp = no;
+ return NULL;
+}
diff --git a/src/libfreeswan/atoasr.3 b/src/libfreeswan/atoasr.3
new file mode 100644
index 000000000..1bd805db1
--- /dev/null
+++ b/src/libfreeswan/atoasr.3
@@ -0,0 +1,186 @@
+.TH IPSEC_ATOASR 3 "11 June 2001"
+.\" RCSID $Id: atoasr.3,v 1.1 2004/03/15 20:35:25 as Exp $
+.SH NAME
+ipsec atoasr \- convert ASCII to Internet address, subnet, or range
+.br
+ipsec rangetoa \- convert Internet address range to ASCII
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "const char *atoasr(const char *src, size_t srclen,"
+.ti +1c
+.B "char *type, struct in_addr *addrs);"
+.br
+.B "size_t rangetoa(struct in_addr *addrs, int format,
+.ti +1c
+.B "char *dst, size_t dstlen);"
+.SH DESCRIPTION
+These functions are obsolete;
+there is no current equivalent,
+because so far they have not proved useful.
+.PP
+.I Atoasr
+converts an ASCII address, subnet, or address range
+into a suitable combination of binary addresses
+(in network byte order).
+.I Rangetoa
+converts an address range back into ASCII,
+using dotted-decimal form for the addresses
+(the other reverse conversions are handled by
+.IR ipsec_addrtoa (3)
+and
+.IR ipsec_subnettoa (3)).
+.PP
+A single address can be any form acceptable to
+.IR ipsec_atoaddr (3):
+dotted decimal, DNS name, or hexadecimal number.
+A subnet
+specification uses the form \fInetwork\fB/\fImask\fR
+interpreted by
+.IR ipsec_atosubnet (3).
+.PP
+An address range is two
+.IR ipsec_atoaddr (3)
+addresses separated by a
+.B ...
+delimiter.
+If there are four dots rather than three, the first is taken as
+part of the begin address,
+e.g. for a complete DNS name which ends with
+.B .
+to suppress completion attempts.
+The begin address of a range must be
+less than or equal to the end address.
+.PP
+The
+.I srclen
+parameter of
+.I atoasr
+specifies the length of the ASCII string pointed to by
+.IR src ;
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+.I srclen
+value of
+.B 0
+is taken to mean
+.BR strlen(src) .
+.PP
+The
+.I type
+parameter of
+.I atoasr
+must point to a
+.B char
+variable used to record which form was found.
+The
+.I addrs
+parameter must point to a two-element array of
+.B "struct in_addr"
+which receives the results.
+The values stored into
+.BR *type ,
+and the corresponding values in the array, are:
+.PP
+.ta 3c +2c +3c
+ *type addrs[0] addrs[1]
+.sp 0.8
+address \&\fB'a'\fR address -
+.br
+subnet \&\fB's'\fR network mask
+.br
+range \&\fB'r'\fR begin end
+.PP
+The
+.I dstlen
+parameter of
+.I rangetoa
+specifies the size of the
+.I dst
+parameter;
+under no circumstances are more than
+.I dstlen
+bytes written to
+.IR dst .
+A result which will not fit is truncated.
+.I Dstlen
+can be zero, in which case
+.I dst
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+.I freeswan.h
+header file defines a constant,
+.BR RANGETOA_BUF ,
+which is the size of a buffer just large enough for worst-case results.
+.PP
+The
+.I format
+parameter of
+.I rangetoa
+specifies what format is to be used for the conversion.
+The value
+.B 0
+(not the ASCII character
+.BR '0' ,
+but a zero value)
+specifies a reasonable default,
+and is in fact the only format currently available.
+This parameter is a hedge against future needs.
+.PP
+.I Atoasr
+returns NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+.I Rangetoa
+returns
+.B 0
+for a failure, and otherwise
+always returns the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+.SH SEE ALSO
+ipsec_atoaddr(3), ipsec_atosubnet(3)
+.SH DIAGNOSTICS
+Fatal errors in
+.I atoasr
+are:
+empty input;
+error in
+.IR ipsec_atoaddr (3)
+or
+.IR ipsec_atosubnet (3)
+during conversion;
+begin address of range exceeds end address.
+.PP
+Fatal errors in
+.I rangetoa
+are:
+unknown format.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+The restriction of error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+.PP
+The error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+.PP
+.RS
+.nf
+.B "const char *error;"
+.sp
+.B "error = atoasr( /* ... */ );"
+.B "if (error != NULL) {"
+.B " /* something went wrong */"
+.fi
+.RE
diff --git a/src/libfreeswan/atoasr.c b/src/libfreeswan/atoasr.c
new file mode 100644
index 000000000..a68409bfb
--- /dev/null
+++ b/src/libfreeswan/atoasr.c
@@ -0,0 +1,212 @@
+/*
+ * convert from ASCII form of address/subnet/range to binary
+ * Copyright (C) 1998, 1999 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.
+ *
+ * RCSID $Id: atoasr.c,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - atoasr - convert ASCII to address, subnet, or range
+ */
+const char * /* NULL for success, else string literal */
+atoasr(src, srclen, typep, addrsp)
+const char *src;
+size_t srclen; /* 0 means "apply strlen" */
+char *typep; /* return type code: 'a', 's', 'r' */
+struct in_addr addrsp[2];
+{
+ const char *punct;
+ const char *stop;
+ const char *oops;
+
+ if (srclen == 0)
+ srclen = strlen(src);
+ if (srclen == 0)
+ return "empty string";
+
+ /* subnet is easy to spot */
+ punct = memchr(src, '/', srclen);
+ if (punct != NULL) {
+ *typep = 's';
+ return atosubnet(src, srclen, &addrsp[0], &addrsp[1]);
+ }
+
+ /* try for a range */
+ stop = src + srclen;
+ for (punct = src; (punct = memchr(punct, '.', stop - punct)) != NULL;
+ punct++)
+ if (stop - punct > 3 && *(punct+1) == '.' && *(punct+2) == '.')
+ break; /* NOTE BREAK OUT */
+ if (punct == NULL) {
+ /* didn't find the range delimiter, must be plain address */
+ *typep = 'a';
+ return atoaddr(src, srclen, &addrsp[0]);
+ }
+
+ /* looks like a range */
+ *typep = 'r';
+ if (stop - punct > 4 && *(punct+3) == '.')
+ punct++; /* first dot is trailing dot of name */
+ oops = atoaddr(src, punct - src, &addrsp[0]);
+ if (oops != NULL)
+ return oops;
+ oops = atoaddr(punct+3, stop - (punct+3), &addrsp[1]);
+ if (oops != NULL)
+ return oops;
+ if (ntohl(addrsp[0].s_addr) > ntohl(addrsp[1].s_addr))
+ return "invalid range, begin > end";
+ return NULL;
+}
+
+
+
+#ifdef ATOASR_MAIN
+
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+void regress(void);
+
+int
+main(int argc, char *argv[])
+{
+ struct in_addr a[2];
+ char buf[100];
+ const char *oops;
+ size_t n;
+ char type;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s {addr|net/mask|begin...end|-r}\n",
+ argv[0]);
+ exit(2);
+ }
+
+ if (strcmp(argv[1], "-r") == 0) {
+ regress();
+ fprintf(stderr, "regress() returned?!?\n");
+ exit(1);
+ }
+
+ oops = atoasr(argv[1], 0, &type, a);
+ if (oops != NULL) {
+ fprintf(stderr, "%s: conversion failed: %s\n", argv[0], oops);
+ exit(1);
+ }
+ switch (type) {
+ case 'a':
+ n = addrtoa(a[0], 0, buf, sizeof(buf));
+ break;
+ case 's':
+ n = subnettoa(a[0], a[1], 0, buf, sizeof(buf));
+ break;
+ case 'r':
+ n = rangetoa(a, 0, buf, sizeof(buf));
+ break;
+ default:
+ fprintf(stderr, "%s: unknown type '%c'\n", argv[0], type);
+ exit(1);
+ break;
+ }
+ if (n > sizeof(buf)) {
+ fprintf(stderr, "%s: reverse conversion of ", argv[0]);
+ fprintf(stderr, "%s ", inet_ntoa(a[0]));
+ fprintf(stderr, "%s", inet_ntoa(a[1]));
+ fprintf(stderr, " failed: need %ld bytes, have only %ld\n",
+ (long)n, (long)sizeof(buf));
+ exit(1);
+ }
+ printf("%s\n", buf);
+
+ exit(0);
+}
+
+struct rtab {
+ char *input;
+ char *output; /* NULL means error expected */
+} rtab[] = {
+ {"1.2.3.0", "1.2.3.0"},
+ {"1.2.3.0/255.255.255.0", "1.2.3.0/24"},
+ {"1.2.3.0...1.2.3.5", "1.2.3.0...1.2.3.5"},
+ {"1.2.3.4.5", NULL},
+ {"1.2.3.4/", NULL},
+ {"1.2.3.4...", NULL},
+ {"1.2.3.4....", NULL},
+ {"localhost/32", "127.0.0.1/32"},
+ {"localhost...127.0.0.3", "127.0.0.1...127.0.0.3"},
+ {"127.0.0.0...localhost", "127.0.0.0...127.0.0.1"},
+ {"127.0.0.3...localhost", NULL},
+ {NULL, NULL}
+};
+
+void
+regress(void)
+{
+ struct rtab *r;
+ int status = 0;
+ struct in_addr a[2];
+ char in[100];
+ char buf[100];
+ const char *oops;
+ size_t n;
+ char type;
+
+ for (r = rtab; r->input != NULL; r++) {
+ strcpy(in, r->input);
+ oops = atoasr(in, 0, &type, a);
+ if (oops != NULL && r->output == NULL)
+ {} /* okay, error expected */
+ else if (oops != NULL) {
+ printf("`%s' atoasr failed: %s\n", r->input, oops);
+ status = 1;
+ } else if (r->output == NULL) {
+ printf("`%s' atoasr succeeded unexpectedly '%c'\n",
+ r->input, type);
+ status = 1;
+ } else {
+ switch (type) {
+ case 'a':
+ n = addrtoa(a[0], 0, buf, sizeof(buf));
+ break;
+ case 's':
+ n = subnettoa(a[0], a[1], 0, buf, sizeof(buf));
+ break;
+ case 'r':
+ n = rangetoa(a, 0, buf, sizeof(buf));
+ break;
+ default:
+ fprintf(stderr, "`%s' unknown type '%c'\n",
+ r->input, type);
+ n = 0;
+ status = 1;
+ break;
+ }
+ if (n > sizeof(buf)) {
+ printf("`%s' '%c' reverse failed: need %ld\n",
+ r->input, type, (long)n);
+ status = 1;
+ } else if (n > 0 && strcmp(r->output, buf) != 0) {
+ printf("`%s' '%c' gave `%s', expected `%s'\n",
+ r->input, type, buf, r->output);
+ status = 1;
+ }
+ }
+ }
+ exit(status);
+}
+
+#endif /* ATOASR_MAIN */
diff --git a/src/libfreeswan/atosa.3 b/src/libfreeswan/atosa.3
new file mode 100644
index 000000000..116483a73
--- /dev/null
+++ b/src/libfreeswan/atosa.3
@@ -0,0 +1,218 @@
+.TH IPSEC_ATOSA 3 "11 June 2001"
+.\" RCSID $Id: atosa.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec atosa, satoa \- convert IPsec Security Association IDs to and from ASCII
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "const char *atosa(const char *src, size_t srclen,"
+.ti +1c
+.B "struct sa_id *sa);
+.br
+.B "size_t satoa(struct sa_id sa, int format,"
+.ti +1c
+.B "char *dst, size_t dstlen);"
+.sp
+.B "struct sa_id {"
+.ti +1c
+.B "struct in_addr dst;"
+.ti +1c
+.B "ipsec_spi_t spi;"
+.ti +1c
+.B "int proto;"
+.br
+.B "};"
+.SH DESCRIPTION
+These functions are obsolete; see
+.IR ipsec_ttosa (3)
+for their replacements.
+.PP
+.I Atosa
+converts an ASCII Security Association (SA) specifier into an
+.B sa_id
+structure (containing
+a destination-host address
+in network byte order,
+an SPI number in network byte order, and
+a protocol code).
+.I Satoa
+does the reverse conversion, back to an ASCII SA specifier.
+.PP
+An SA is specified in ASCII with a mail-like syntax, e.g.
+.BR esp507@1.2.3.4 .
+An SA specifier contains
+a protocol prefix (currently
+.BR ah ,
+.BR esp ,
+or
+.BR tun ),
+an unsigned integer SPI number,
+and an IP address.
+The SPI number can be decimal or hexadecimal
+(with
+.B 0x
+prefix), as accepted by
+.IR ipsec_atoul (3).
+The IP address can be any form accepted by
+.IR ipsec_atoaddr (3),
+e.g. dotted-decimal address or DNS name.
+.PP
+As a special case, the SA specifier
+.B %passthrough
+signifies the special SA used to indicate that packets should be
+passed through unaltered.
+(At present, this is a synonym for
+.BR tun0x0@0.0.0.0 ,
+but that is subject to change without notice.)
+This form is known to both
+.I atosa
+and
+.IR satoa ,
+so the internal form of
+.B %passthrough
+is never visible.
+.PP
+The
+.B <freeswan.h>
+header file supplies the
+.B sa_id
+structure, as well as a data type
+.B ipsec_spi_t
+which is an unsigned 32-bit integer.
+(There is no consistency between kernel and user on what such a type
+is called, hence the header hides the differences.)
+.PP
+The protocol code uses the same numbers that IP does.
+For user convenience, given the difficulty in acquiring the exact set of
+protocol names used by the kernel,
+.B <freeswan.h>
+defines the names
+.BR SA_ESP ,
+.BR SA_AH ,
+and
+.B SA_IPIP
+to have the same values as the kernel names
+.BR IPPROTO_ESP ,
+.BR IPPROTO_AH ,
+and
+.BR IPPROTO_IPIP .
+.PP
+The
+.I srclen
+parameter of
+.I atosa
+specifies the length of the ASCII string pointed to by
+.IR src ;
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+.I srclen
+value of
+.B 0
+is taken to mean
+.BR strlen(src) .
+.PP
+The
+.I dstlen
+parameter of
+.I satoa
+specifies the size of the
+.I dst
+parameter;
+under no circumstances are more than
+.I dstlen
+bytes written to
+.IR dst .
+A result which will not fit is truncated.
+.I Dstlen
+can be zero, in which case
+.I dst
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+.I freeswan.h
+header file defines a constant,
+.BR SATOA_BUF ,
+which is the size of a buffer just large enough for worst-case results.
+.PP
+The
+.I format
+parameter of
+.I satoa
+specifies what format is to be used for the conversion.
+The value
+.B 0
+(not the ASCII character
+.BR '0' ,
+but a zero value)
+specifies a reasonable default
+(currently
+lowercase protocol prefix, lowercase hexadecimal SPI, dotted-decimal address).
+The value
+.B d
+causes the SPI to be generated in decimal instead.
+.PP
+.I Atosa
+returns
+.B NULL
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+.I Satoa
+returns
+.B 0
+for a failure, and otherwise
+always returns the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+.SH SEE ALSO
+ipsec_atoul(3), ipsec_atoaddr(3), inet(3)
+.SH DIAGNOSTICS
+Fatal errors in
+.I atosa
+are:
+empty input;
+input too small to be a legal SA specifier;
+no
+.B @
+in input;
+unknown protocol prefix;
+conversion error in
+.I atoul
+or
+.IR atoaddr .
+.PP
+Fatal errors in
+.I satoa
+are:
+unknown format; unknown protocol code.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+The
+.B tun
+protocol code is a FreeS/WANism which may eventually disappear.
+.PP
+The restriction of ASCII-to-binary error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+.PP
+The ASCII-to-binary error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+.PP
+.RS
+.nf
+.B "const char *error;"
+.sp
+.B "error = atoaddr( /* ... */ );"
+.B "if (error != NULL) {"
+.B " /* something went wrong */"
+.fi
+.RE
diff --git a/src/libfreeswan/atosa.c b/src/libfreeswan/atosa.c
new file mode 100644
index 000000000..cc3b055d0
--- /dev/null
+++ b/src/libfreeswan/atosa.c
@@ -0,0 +1,200 @@
+/*
+ * convert from ASCII form of SA ID to binary
+ * Copyright (C) 1998, 1999 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.
+ *
+ * RCSID $Id: atosa.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+static struct satype {
+ char *prefix;
+ size_t prelen; /* strlen(prefix) */
+ int proto;
+} satypes[] = {
+ { "ah", 2, SA_AH },
+ { "esp", 3, SA_ESP },
+ { "tun", 3, SA_IPIP },
+ { "comp", 4, SA_COMP },
+ { NULL, 0, 0, }
+};
+
+/*
+ - atosa - convert ASCII "ah507@10.0.0.1" to SA identifier
+ */
+const char * /* NULL for success, else string literal */
+atosa(src, srclen, sa)
+const char *src;
+size_t srclen; /* 0 means "apply strlen" */
+struct sa_id *sa;
+{
+ const char *at;
+ const char *addr;
+ const char *spi = NULL;
+ struct satype *sat;
+ unsigned long ul;
+ const char *oops;
+# define MINLEN 5 /* ah0@0 is as short as it can get */
+ static char ptname[] = PASSTHROUGHNAME;
+# define PTNLEN (sizeof(ptname)-1) /* -1 for NUL */
+
+ if (srclen == 0)
+ srclen = strlen(src);
+ if (srclen == 0)
+ return "empty string";
+ if (srclen < MINLEN)
+ return "string too short to be SA specifier";
+ if (srclen == PTNLEN && memcmp(src, ptname, PTNLEN) == 0) {
+ src = PASSTHROUGHIS;
+ srclen = strlen(src);
+ }
+
+ at = memchr(src, '@', srclen);
+ if (at == NULL)
+ return "no @ in SA specifier";
+
+ for (sat = satypes; sat->prefix != NULL; sat++)
+ if (sat->prelen < srclen &&
+ strncmp(src, sat->prefix, sat->prelen) == 0) {
+ sa->proto = sat->proto;
+ spi = src + sat->prelen;
+ break; /* NOTE BREAK OUT */
+ }
+ if (sat->prefix == NULL)
+ return "SA specifier lacks valid protocol prefix";
+
+ if (spi >= at)
+ return "no SPI in SA specifier";
+ oops = atoul(spi, at - spi, 13, &ul);
+ if (oops != NULL)
+ return oops;
+ sa->spi = htonl(ul);
+
+ addr = at + 1;
+ oops = atoaddr(addr, srclen - (addr - src), &sa->dst);
+ if (oops != NULL)
+ return oops;
+
+ return NULL;
+}
+
+
+
+#ifdef ATOSA_MAIN
+
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+void regress(void);
+
+int
+main(int argc, char *argv[])
+{
+ struct sa_id sa;
+ char buf[100];
+ const char *oops;
+ size_t n;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s {ahnnn@aaa|-r}\n", argv[0]);
+ exit(2);
+ }
+
+ if (strcmp(argv[1], "-r") == 0) {
+ regress();
+ fprintf(stderr, "regress() returned?!?\n");
+ exit(1);
+ }
+
+ oops = atosa(argv[1], 0, &sa);
+ if (oops != NULL) {
+ fprintf(stderr, "%s: conversion failed: %s\n", argv[0], oops);
+ exit(1);
+ }
+ n = satoa(sa, 0, buf, sizeof(buf));
+ if (n > sizeof(buf)) {
+ fprintf(stderr, "%s: reverse conv of `%d'", argv[0], sa.proto);
+ fprintf(stderr, "%lu@", (long unsigned int)sa.spi);
+ fprintf(stderr, "%s", inet_ntoa(sa.dst));
+ fprintf(stderr, " failed: need %ld bytes, have only %ld\n",
+ (long)n, (long)sizeof(buf));
+ exit(1);
+ }
+ printf("%s\n", buf);
+
+ exit(0);
+}
+
+struct rtab {
+ char *input;
+ char *output; /* NULL means error expected */
+} rtab[] = {
+ {"esp257@1.2.3.0", "esp257@1.2.3.0"},
+ {"ah0x20@1.2.3.4", "ah32@1.2.3.4"},
+ {"tun011@111.2.3.99", "tun11@111.2.3.99"},
+ {"", NULL},
+ {"_", NULL},
+ {"ah2.2", NULL},
+ {"goo2@1.2.3.4", NULL},
+ {"esp9@1.2.3.4", "esp9@1.2.3.4"},
+ {"espp9@1.2.3.4", NULL},
+ {"es9@1.2.3.4", NULL},
+ {"ah@1.2.3.4", NULL},
+ {"esp7x7@1.2.3.4", NULL},
+ {"esp77@1.0x2.3.4", NULL},
+ {PASSTHROUGHNAME, PASSTHROUGHNAME},
+ {NULL, NULL}
+};
+
+void
+regress(void)
+{
+ struct rtab *r;
+ int status = 0;
+ struct sa_id sa;
+ char in[100];
+ char buf[100];
+ const char *oops;
+ size_t n;
+
+ for (r = rtab; r->input != NULL; r++) {
+ strcpy(in, r->input);
+ oops = atosa(in, 0, &sa);
+ if (oops != NULL && r->output == NULL)
+ {} /* okay, error expected */
+ else if (oops != NULL) {
+ printf("`%s' atosa failed: %s\n", r->input, oops);
+ status = 1;
+ } else if (r->output == NULL) {
+ printf("`%s' atosa succeeded unexpectedly\n",
+ r->input);
+ status = 1;
+ } else {
+ n = satoa(sa, 'd', buf, sizeof(buf));
+ if (n > sizeof(buf)) {
+ printf("`%s' satoa failed: need %ld\n",
+ r->input, (long)n);
+ status = 1;
+ } else if (strcmp(r->output, buf) != 0) {
+ printf("`%s' gave `%s', expected `%s'\n",
+ r->input, buf, r->output);
+ status = 1;
+ }
+ }
+ }
+ exit(status);
+}
+
+#endif /* ATOSA_MAIN */
diff --git a/src/libfreeswan/atosubnet.c b/src/libfreeswan/atosubnet.c
new file mode 100644
index 000000000..9300c2895
--- /dev/null
+++ b/src/libfreeswan/atosubnet.c
@@ -0,0 +1,216 @@
+/*
+ * convert from ASCII form of subnet specification to binary
+ * Copyright (C) 1998, 1999 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.
+ *
+ * RCSID $Id: atosubnet.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+#ifndef DEFAULTSUBNET
+#define DEFAULTSUBNET "%default"
+#endif
+
+/*
+ - atosubnet - convert ASCII "addr/mask" to address and mask
+ * Mask can be integer bit count.
+ */
+const char * /* NULL for success, else string literal */
+atosubnet(src, srclen, addrp, maskp)
+const char *src;
+size_t srclen; /* 0 means "apply strlen" */
+struct in_addr *addrp;
+struct in_addr *maskp;
+{
+ const char *slash;
+ const char *mask;
+ size_t mlen;
+ const char *oops;
+ unsigned long bc;
+ static char def[] = DEFAULTSUBNET;
+# define DEFLEN (sizeof(def) - 1) /* -1 for NUL */
+ static char defis[] = "0/0";
+# define DEFILEN (sizeof(defis) - 1)
+
+ if (srclen == 0)
+ srclen = strlen(src);
+ if (srclen == 0)
+ return "empty string";
+
+ if (srclen == DEFLEN && strncmp(src, def, srclen) == 0) {
+ src = defis;
+ srclen = DEFILEN;
+ }
+
+ slash = memchr(src, '/', srclen);
+ if (slash == NULL)
+ return "no / in subnet specification";
+ mask = slash + 1;
+ mlen = srclen - (mask - src);
+
+ oops = atoaddr(src, slash-src, addrp);
+ if (oops != NULL)
+ return oops;
+
+ oops = atoul(mask, mlen, 10, &bc);
+ if (oops == NULL) {
+ /* atoul succeeded, it's a bit-count mask */
+ if (bc > ABITS)
+ return "bit-count mask too large";
+#ifdef NOLEADINGZEROS
+ if (mlen > 1 && *mask == '0')
+ return "octal not allowed in mask";
+#endif /* NOLEADINGZEROS */
+ *maskp = bitstomask((int)bc);
+ } else {
+ oops = atoaddr(mask, mlen, maskp);
+ if (oops != NULL)
+ return oops;
+ if (!goodmask(*maskp))
+ return "non-contiguous mask";
+ }
+
+ addrp->s_addr &= maskp->s_addr;
+ return NULL;
+}
+
+
+
+#ifdef ATOSUBNET_MAIN
+
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+void regress(void);
+
+int
+main(int argc, char *argv[])
+{
+ struct in_addr a;
+ struct in_addr m;
+ char buf[100];
+ const char *oops;
+ size_t n;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s {addr/mask|-r}\n", argv[0]);
+ exit(2);
+ }
+
+ if (strcmp(argv[1], "-r") == 0) {
+ regress();
+ fprintf(stderr, "regress() returned?!?\n");
+ exit(1);
+ }
+
+ oops = atosubnet(argv[1], 0, &a, &m);
+ if (oops != NULL) {
+ fprintf(stderr, "%s: conversion failed: %s\n", argv[0], oops);
+ exit(1);
+ }
+ n = subnettoa(a, m, 0, buf, sizeof(buf));
+ if (n > sizeof(buf)) {
+ fprintf(stderr, "%s: reverse conversion of ", argv[0]);
+ fprintf(stderr, "%s/", inet_ntoa(a));
+ fprintf(stderr, "%s", inet_ntoa(m));
+ fprintf(stderr, " failed: need %ld bytes, have only %ld\n",
+ (long)n, (long)sizeof(buf));
+ exit(1);
+ }
+ printf("%s\n", buf);
+
+ exit(0);
+}
+
+struct rtab {
+ char *input;
+ char *output; /* NULL means error expected */
+} rtab[] = {
+ {"1.2.3.0/255.255.255.0", "1.2.3.0/24"},
+ {"1.2.3.0/24", "1.2.3.0/24"},
+ {"1.2.3.1/255.255.255.240", "1.2.3.0/28"},
+ {"1.2.3.1/32", "1.2.3.1/32"},
+ {"1.2.3.1/0", "0.0.0.0/0"},
+/* "1.2.3.1/255.255.127.0", "1.2.3.0/255.255.127.0", */
+ {"1.2.3.1/255.255.127.0", NULL},
+ {"128.009.000.032/32", "128.9.0.32/32"},
+ {"128.0x9.0.32/32", NULL},
+ {"0x80090020/32", "128.9.0.32/32"},
+ {"0x800x0020/32", NULL},
+ {"128.9.0.32/0xffFF0000", "128.9.0.0/16"},
+ {"128.9.0.32/0xff0000FF", NULL},
+ {"128.9.0.32/0x0000ffFF", NULL},
+ {"128.9.0.32/0x00ffFF0000", NULL},
+ {"128.9.0.32/0xffFF", NULL},
+ {"128.9.0.32.27/32", NULL},
+ {"128.9.0k32/32", NULL},
+ {"328.9.0.32/32", NULL},
+ {"128.9..32/32", NULL},
+ {"10/8", "10.0.0.0/8"},
+ {"10.0/8", "10.0.0.0/8"},
+ {"10.0.0/8", "10.0.0.0/8"},
+ {"10.0.1/24", "10.0.1.0/24"},
+ {"_", NULL},
+ {"_/_", NULL},
+ {"1.2.3.1", NULL},
+ {"1.2.3.1/_", NULL},
+ {"1.2.3.1/24._", NULL},
+ {"1.2.3.1/99", NULL},
+ {"localhost/32", "127.0.0.1/32"},
+ {"%default", "0.0.0.0/0"},
+ {NULL, NULL}
+};
+
+void
+regress()
+{
+ struct rtab *r;
+ int status = 0;
+ struct in_addr a;
+ struct in_addr m;
+ char in[100];
+ char buf[100];
+ const char *oops;
+ size_t n;
+
+ for (r = rtab; r->input != NULL; r++) {
+ strcpy(in, r->input);
+ oops = atosubnet(in, 0, &a, &m);
+ if (oops != NULL && r->output == NULL)
+ {} /* okay, error expected */
+ else if (oops != NULL) {
+ printf("`%s' atosubnet failed: %s\n", r->input, oops);
+ status = 1;
+ } else if (r->output == NULL) {
+ printf("`%s' atosubnet succeeded unexpectedly\n",
+ r->input);
+ status = 1;
+ } else {
+ n = subnettoa(a, m, 0, buf, sizeof(buf));
+ if (n > sizeof(buf)) {
+ printf("`%s' subnettoa failed: need %ld\n",
+ r->input, (long)n);
+ status = 1;
+ } else if (strcmp(r->output, buf) != 0) {
+ printf("`%s' gave `%s', expected `%s'\n",
+ r->input, buf, r->output);
+ status = 1;
+ }
+ }
+ }
+ exit(status);
+}
+
+#endif /* ATOSUBNET_MAIN */
diff --git a/src/libfreeswan/atoul.3 b/src/libfreeswan/atoul.3
new file mode 100644
index 000000000..a606fa4a9
--- /dev/null
+++ b/src/libfreeswan/atoul.3
@@ -0,0 +1,161 @@
+.TH IPSEC_ATOUL 3 "11 June 2001"
+.\" RCSID $Id: atoul.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec atoul, ultoa \- convert unsigned-long numbers to and from ASCII
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "const char *atoul(const char *src, size_t srclen,"
+.ti +1c
+.B "int base, unsigned long *n);"
+.br
+.B "size_t ultoa(unsigned long n, int base, char *dst,"
+.ti +1c
+.B "size_t dstlen);"
+.SH DESCRIPTION
+These functions are obsolete; see
+.IR ipsec_ttoul (3)
+for their replacements.
+.PP
+.I Atoul
+converts an ASCII number into a binary
+.B "unsigned long"
+value.
+.I Ultoa
+does the reverse conversion, back to an ASCII version.
+.PP
+Numbers are specified in ASCII as
+decimal (e.g.
+.BR 123 ),
+octal with a leading zero (e.g.
+.BR 012 ,
+which has value 10),
+or hexadecimal with a leading
+.B 0x
+(e.g.
+.BR 0x1f ,
+which has value 31)
+in either upper or lower case.
+.PP
+The
+.I srclen
+parameter of
+.I atoul
+specifies the length of the ASCII string pointed to by
+.IR src ;
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+.I srclen
+value of
+.B 0
+is taken to mean
+.BR strlen(src) .
+.PP
+The
+.I base
+parameter of
+.I atoul
+can be
+.BR 8 ,
+.BR 10 ,
+or
+.BR 16 ,
+in which case the number supplied is assumed to be of that form
+(and in the case of
+.BR 16 ,
+to lack any
+.B 0x
+prefix).
+It can also be
+.BR 0 ,
+in which case the number is examined for a leading zero
+or a leading
+.B 0x
+to determine its base,
+or
+.B 13
+(halfway between 10 and 16),
+which has the same effect as
+.B 0
+except that a non-hexadecimal
+number is considered decimal regardless of any leading zero.
+.PP
+The
+.I dstlen
+parameter of
+.I ultoa
+specifies the size of the
+.I dst
+parameter;
+under no circumstances are more than
+.I dstlen
+bytes written to
+.IR dst .
+A result which will not fit is truncated.
+.I Dstlen
+can be zero, in which case
+.I dst
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+.PP
+The
+.I base
+parameter of
+.I ultoa
+must be
+.BR 8 ,
+.BR 10 ,
+or
+.BR 16 .
+.PP
+.I Atoul
+returns NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+.I Ultoa
+returns the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+.SH SEE ALSO
+atol(3), strtoul(3)
+.SH DIAGNOSTICS
+Fatal errors in
+.I atoul
+are:
+empty input;
+unknown
+.IR base ;
+non-digit character found;
+number too large for an
+.BR "unsigned long" .
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+There is no provision for reporting an invalid
+.I base
+parameter given to
+.IR ultoa .
+.PP
+The restriction of error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+.PP
+The error-reporting convention lends itself to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+.PP
+.RS
+.nf
+.B "const char *error;"
+.sp
+.B "error = atoul( /* ... */ );"
+.B "if (error != NULL) {"
+.B " /* something went wrong */"
+.fi
+.RE
diff --git a/src/libfreeswan/atoul.c b/src/libfreeswan/atoul.c
new file mode 100644
index 000000000..e32a8cdab
--- /dev/null
+++ b/src/libfreeswan/atoul.c
@@ -0,0 +1,90 @@
+/*
+ * convert from ASCII form of unsigned long to binary
+ * Copyright (C) 1998, 1999 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.
+ *
+ * RCSID $Id: atoul.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - atoul - convert ASCII substring to unsigned long number
+ */
+const char * /* NULL for success, else string literal */
+atoul(src, srclen, base, resultp)
+const char *src;
+size_t srclen; /* 0 means strlen(src) */
+int base; /* 0 means figure it out */
+unsigned long *resultp;
+{
+ const char *stop;
+ static char hex[] = "0123456789abcdef";
+ static char uchex[] = "0123456789ABCDEF";
+ int d;
+ char c;
+ char *p;
+ unsigned long r;
+ unsigned long rlimit;
+ int dlimit;
+
+ if (srclen == 0)
+ srclen = strlen(src);
+ if (srclen == 0)
+ return "empty string";
+
+ if (base == 0 || base == 13) {
+ if (srclen > 2 && *src == '0' && CIEQ(*(src+1), 'x'))
+ return atoul(src+2, srclen-2, 16, resultp);
+ if (srclen > 1 && *src == '0' && base != 13)
+ return atoul(src+1, srclen-1, 8, resultp);
+ return atoul(src, srclen, 10, resultp);
+ }
+ if (base != 8 && base != 10 && base != 16)
+ return "unsupported number base";
+
+ r = 0;
+ stop = src + srclen;
+ if (base == 16) {
+ while (src < stop) {
+ c = *src++;
+ p = strchr(hex, c);
+ if (p != NULL)
+ d = p - hex;
+ else {
+ p = strchr(uchex, c);
+ if (p == NULL)
+ return "non-hex-digit in hex number";
+ d = p - uchex;
+ }
+ r = (r << 4) | d;
+ }
+ /* defer length check to catch invalid digits first */
+ if (srclen > sizeof(unsigned long) * 2)
+ return "hex number too long";
+ } else {
+ rlimit = ULONG_MAX / base;
+ dlimit = (int)(ULONG_MAX - rlimit*base);
+ while (src < stop) {
+ c = *src++;
+ d = c - '0';
+ if (d < 0 || d >= base)
+ return "non-digit in number";
+ if (r > rlimit || (r == rlimit && d > dlimit))
+ return "unsigned-long overflow";
+ r = r*base + d;
+ }
+ }
+
+ *resultp = r;
+ return NULL;
+}
diff --git a/src/libfreeswan/copyright.c b/src/libfreeswan/copyright.c
new file mode 100644
index 000000000..0e836f6c2
--- /dev/null
+++ b/src/libfreeswan/copyright.c
@@ -0,0 +1,56 @@
+/*
+ * return IPsec copyright notice
+ * Copyright (C) 2001, 2002 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.
+ *
+ * RCSID $Id: copyright.c,v 1.6 2005/11/02 21:51:13 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+static const char *co[] = {
+ "Copyright (C) 1999-2005 Henry Spencer, Richard Guy Briggs,",
+ " D. Hugh Redelmeier, Sandy Harris, Claudia Schmeing,",
+ " Michael Richardson, Angelos D. Keromytis, John Ioannidis,",
+ "",
+ " Ken Bantoft, Stephen J. Bevan, JuanJo Ciarlante, Mathieu Lafon,",
+ " Stephane Laroche, Kai Martius, Tuomo Soini, Herbert Xu,",
+ "",
+ " Andreas Steffen, Martin Berner, Marco Bertossa, David Buechi,",
+ " Ueli Galizzi, Christoph Gysin, Andreas Hess, Patric Lichtsteiner,",
+ " Michael Meier, Andreas Schleiss, Ariane Seiler,",
+ " Mario Strasser, Lukas Suter, Roger Wegmann, Simon Zwahlen,",
+ " Zuercher Hochschule Winterthur (Switzerland).",
+ "",
+ " Jan Hutter, Martin Willi, Andreas Steffen,",
+ " Hochschule fuer Technik Rapperswil (Switzerland).",
+ "",
+ "This program is free software; you can redistribute it and/or modify it",
+ "under the terms of the GNU General Public License as published by the",
+ "Free Software Foundation; either version 2 of the License, or (at your",
+ "option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.",
+ "",
+ "This program is distributed in the hope that it will be useful, but",
+ "WITHOUT ANY WARRANTY; without even the implied warranty of",
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General",
+ "Public License (file COPYING in the distribution) for more details.",
+ NULL
+};
+
+/*
+ - ipsec_copyright_notice - return copyright notice, as a vector of strings
+ */
+const char **
+ipsec_copyright_notice()
+{
+ return co;
+}
diff --git a/src/libfreeswan/datatot.c b/src/libfreeswan/datatot.c
new file mode 100644
index 000000000..fbeb35fa9
--- /dev/null
+++ b/src/libfreeswan/datatot.c
@@ -0,0 +1,233 @@
+/*
+ * convert from binary data (e.g. key) to text form
+ * 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.
+ *
+ * RCSID $Id: datatot.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+static void convert(const char *src, size_t nreal, int format, char *out);
+
+/*
+ - datatot - convert data bytes to text
+ */
+size_t /* true length (with NUL) for success */
+datatot(src, srclen, format, dst, dstlen)
+const char *src;
+size_t srclen;
+int format; /* character indicating what format */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ size_t inblocksize; /* process this many bytes at a time */
+ size_t outblocksize; /* producing this many */
+ size_t breakevery; /* add a _ every this many (0 means don't) */
+ size_t sincebreak; /* output bytes since last _ */
+ char breakchar; /* character used to break between groups */
+ char inblock[10]; /* enough for any format */
+ char outblock[10]; /* enough for any format */
+ char fake[1]; /* fake output area for dstlen == 0 */
+ size_t needed; /* return value */
+ char *stop; /* where the terminating NUL will go */
+ size_t ntodo; /* remaining input */
+ size_t nreal;
+ char *out;
+ char *prefix;
+
+ breakevery = 0;
+ breakchar = '_';
+
+ switch (format) {
+ case 0:
+ case 'h':
+ format = 'x';
+ breakevery = 8;
+ /* FALLTHROUGH */
+ case 'x':
+ inblocksize = 1;
+ outblocksize = 2;
+ prefix = "0x";
+ break;
+ case ':':
+ format = 'x';
+ breakevery = 2;
+ breakchar = ':';
+ /* FALLTHROUGH */
+ case 16:
+ inblocksize = 1;
+ outblocksize = 2;
+ prefix = "";
+ format = 'x';
+ break;
+ case 's':
+ inblocksize = 3;
+ outblocksize = 4;
+ prefix = "0s";
+ break;
+ case 64: /* beware, equals ' ' */
+ inblocksize = 3;
+ outblocksize = 4;
+ prefix = "";
+ format = 's';
+ break;
+ default:
+ return 0;
+ break;
+ }
+ assert(inblocksize < sizeof(inblock));
+ assert(outblocksize < sizeof(outblock));
+ assert(breakevery % outblocksize == 0);
+
+ if (srclen == 0)
+ return 0;
+ ntodo = srclen;
+
+ if (dstlen == 0) { /* dispose of awkward special case */
+ dst = fake;
+ dstlen = 1;
+ }
+ stop = dst + dstlen - 1;
+
+ nreal = strlen(prefix);
+ needed = nreal; /* for starters */
+ if (dstlen <= nreal) { /* prefix won't fit */
+ strncpy(dst, prefix, dstlen - 1);
+ dst += dstlen - 1;
+ } else {
+ strcpy(dst, prefix);
+ dst += nreal;
+ }
+ assert(dst <= stop);
+ sincebreak = 0;
+
+ while (ntodo > 0) {
+ if (ntodo < inblocksize) { /* incomplete input */
+ memset(inblock, 0, sizeof(inblock));
+ memcpy(inblock, src, ntodo);
+ src = inblock;
+ nreal = ntodo;
+ ntodo = inblocksize;
+ } else
+ nreal = inblocksize;
+ out = (outblocksize > stop - dst) ? outblock : dst;
+
+ convert(src, nreal, format, out);
+ needed += outblocksize;
+ sincebreak += outblocksize;
+ if (dst < stop) {
+ if (out != dst) {
+ assert(outblocksize > stop - dst);
+ memcpy(dst, out, stop - dst);
+ dst = stop;
+ } else
+ dst += outblocksize;
+ }
+
+ src += inblocksize;
+ ntodo -= inblocksize;
+ if (breakevery != 0 && sincebreak >= breakevery && ntodo > 0) {
+ if (dst < stop)
+ *dst++ = breakchar;
+ needed++;
+ sincebreak = 0;
+ }
+ }
+
+ assert(dst <= stop);
+ *dst++ = '\0';
+ needed++;
+
+ return needed;
+}
+
+/*
+ - convert - convert one input block to one output block
+ */
+static void
+convert(src, nreal, format, out)
+const char *src;
+size_t nreal; /* how much of the input block is real */
+int format;
+char *out;
+{
+ static char hex[] = "0123456789abcdef";
+ static char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789+/";
+ unsigned char c;
+ unsigned char c1, c2, c3;
+
+ assert(nreal > 0);
+ switch (format) {
+ case 'x':
+ assert(nreal == 1);
+ c = (unsigned char)*src;
+ *out++ = hex[c >> 4];
+ *out++ = hex[c & 0xf];
+ break;
+ case 's':
+ c1 = (unsigned char)*src++;
+ c2 = (unsigned char)*src++;
+ c3 = (unsigned char)*src++;
+ *out++ = base64[c1 >> 2]; /* top 6 bits of c1 */
+ c = (c1 & 0x3) << 4; /* bottom 2 of c1... */
+ c |= c2 >> 4; /* ...top 4 of c2 */
+ *out++ = base64[c];
+ if (nreal == 1)
+ *out++ = '=';
+ else {
+ c = (c2 & 0xf) << 2; /* bottom 4 of c2... */
+ c |= c3 >> 6; /* ...top 2 of c3 */
+ *out++ = base64[c];
+ }
+ if (nreal <= 2)
+ *out++ = '=';
+ else
+ *out++ = base64[c3 & 0x3f]; /* bottom 6 of c3 */
+ break;
+ default:
+ assert(nreal == 0); /* unknown format */
+ break;
+ }
+}
+
+/*
+ - datatoa - convert data to ASCII
+ * backward-compatibility synonym for datatot
+ */
+size_t /* true length (with NUL) for success */
+datatoa(src, srclen, format, dst, dstlen)
+const char *src;
+size_t srclen;
+int format; /* character indicating what format */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ return datatot(src, srclen, format, dst, dstlen);
+}
+
+/*
+ - bytestoa - convert data bytes to ASCII
+ * backward-compatibility synonym for datatot
+ */
+size_t /* true length (with NUL) for success */
+bytestoa(src, srclen, format, dst, dstlen)
+const char *src;
+size_t srclen;
+int format; /* character indicating what format */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ return datatot(src, srclen, format, dst, dstlen);
+}
diff --git a/src/libfreeswan/freeswan.h b/src/libfreeswan/freeswan.h
new file mode 100644
index 000000000..b1bca870d
--- /dev/null
+++ b/src/libfreeswan/freeswan.h
@@ -0,0 +1,470 @@
+#ifndef _FREESWAN_H
+/*
+ * header file for FreeS/WAN library functions
+ * Copyright (C) 1998, 1999, 2000 Henry Spencer.
+ * Copyright (C) 1999, 2000, 2001 Richard Guy Briggs
+ *
+ * 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.
+ *
+ * RCSID $Id: freeswan.h,v 1.2 2004/03/22 21:53:17 as Exp $
+ */
+#define _FREESWAN_H /* seen it, no need to see it again */
+
+
+
+/*
+ * We've just got to have some datatypes defined... And annoyingly, just
+ * where we get them depends on whether we're in userland or not.
+ */
+#ifdef __KERNEL__
+
+# include <linux/types.h>
+# include <linux/in.h>
+
+#else /* __KERNEL__ */
+
+# include <stdio.h>
+# include <netinet/in.h>
+
+# define uint8_t u_int8_t
+# define uint16_t u_int16_t
+# define uint32_t u_int32_t
+# define uint64_t u_int64_t
+
+# define DEBUG_NO_STATIC static
+
+#endif /* __KERNEL__ */
+
+#include <ipsec_param.h>
+
+
+/*
+ * Grab the kernel version to see if we have NET_21, and therefore
+ * IPv6. Some of this is repeated from ipsec_kversions.h. Of course,
+ * we aren't really testing if the kernel has IPv6, but rather if the
+ * the include files do.
+ */
+#include <linux/version.h>
+#ifndef KERNEL_VERSION
+#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
+#define NET_21
+#endif
+
+#ifndef IPPROTO_COMP
+# define IPPROTO_COMP 108
+#endif /* !IPPROTO_COMP */
+
+#ifndef IPPROTO_INT
+# define IPPROTO_INT 61
+#endif /* !IPPROTO_INT */
+
+#ifdef CONFIG_IPSEC_DEBUG
+# define DEBUG_NO_STATIC
+#else /* CONFIG_IPSEC_DEBUG */
+# define DEBUG_NO_STATIC static
+#endif /* CONFIG_IPSEC_DEBUG */
+
+#define ESPINUDP_WITH_NON_IKE 1 /* draft-ietf-ipsec-nat-t-ike-00/01 */
+#define ESPINUDP_WITH_NON_ESP 2 /* draft-ietf-ipsec-nat-t-ike-02 */
+
+/*
+ * Basic data types for the address-handling functions.
+ * ip_address and ip_subnet are supposed to be opaque types; do not
+ * use their definitions directly, they are subject to change!
+ */
+
+/* first, some quick fakes in case we're on an old system with no IPv6 */
+#ifndef s6_addr16
+struct in6_addr {
+ union
+ {
+ __u8 u6_addr8[16];
+ __u16 u6_addr16[8];
+ __u32 u6_addr32[4];
+ } in6_u;
+#define s6_addr in6_u.u6_addr8
+#define s6_addr16 in6_u.u6_addr16
+#define s6_addr32 in6_u.u6_addr32
+};
+struct sockaddr_in6 {
+ unsigned short int sin6_family; /* AF_INET6 */
+ __u16 sin6_port; /* Transport layer port # */
+ __u32 sin6_flowinfo; /* IPv6 flow information */
+ struct in6_addr sin6_addr; /* IPv6 address */
+ __u32 sin6_scope_id; /* scope id (new in RFC2553) */
+};
+#endif /* !s6_addr16 */
+
+/* then the main types */
+typedef struct {
+ union {
+ struct sockaddr_in v4;
+ struct sockaddr_in6 v6;
+ } u;
+} ip_address;
+typedef struct {
+ ip_address addr;
+ int maskbits;
+} ip_subnet;
+
+/* and the SA ID stuff */
+#ifdef __KERNEL__
+typedef __u32 ipsec_spi_t;
+#else
+typedef u_int32_t ipsec_spi_t;
+#endif
+typedef struct { /* to identify an SA, we need: */
+ ip_address dst; /* A. destination host */
+ ipsec_spi_t spi; /* B. 32-bit SPI, assigned by dest. host */
+# define SPI_PASS 256 /* magic values... */
+# define SPI_DROP 257 /* ...for use... */
+# define SPI_REJECT 258 /* ...with SA_INT */
+# define SPI_HOLD 259
+# define SPI_TRAP 260
+# define SPI_TRAPSUBNET 261
+ int proto; /* C. protocol */
+# define SA_ESP 50 /* IPPROTO_ESP */
+# define SA_AH 51 /* IPPROTO_AH */
+# define SA_IPIP 4 /* IPPROTO_IPIP */
+# define SA_COMP 108 /* IPPROTO_COMP */
+# define SA_INT 61 /* IANA reserved for internal use */
+} ip_said;
+struct sa_id { /* old v4-only version */
+ struct in_addr dst;
+ ipsec_spi_t spi;
+ int proto;
+};
+
+/* misc */
+typedef const char *err_t; /* error message, or NULL for success */
+struct prng { /* pseudo-random-number-generator guts */
+ unsigned char sbox[256];
+ int i, j;
+ unsigned long count;
+};
+
+
+/*
+ * definitions for user space, taken from freeswan/ipsec_sa.h
+ */
+typedef uint32_t IPsecSAref_t;
+
+#define IPSEC_SA_REF_FIELD_WIDTH (8 * sizeof(IPsecSAref_t))
+
+#define IPsecSAref2NFmark(x) ((x) << (IPSEC_SA_REF_FIELD_WIDTH - IPSEC_SA_REF_TABLE_IDX_WIDTH))
+#define NFmark2IPsecSAref(x) ((x) >> (IPSEC_SA_REF_FIELD_WIDTH - IPSEC_SA_REF_TABLE_IDX_WIDTH))
+
+#define IPSEC_SAREF_NULL (~((IPsecSAref_t)0))
+
+/* GCC magic for use in function definitions! */
+#ifdef GCC_LINT
+# define PRINTF_LIKE(n) __attribute__ ((format(printf, n, n+1)))
+# define NEVER_RETURNS __attribute__ ((noreturn))
+# define UNUSED __attribute__ ((unused))
+# define BLANK_FORMAT " " /* GCC_LINT whines about empty formats */
+#else
+# define PRINTF_LIKE(n) /* ignore */
+# define NEVER_RETURNS /* ignore */
+# define UNUSED /* ignore */
+# define BLANK_FORMAT ""
+#endif
+
+
+
+
+
+/*
+ * new IPv6-compatible functions
+ */
+
+/* text conversions */
+err_t ttoul(const char *src, size_t srclen, int format, unsigned long *dst);
+size_t ultot(unsigned long src, int format, char *buf, size_t buflen);
+#define ULTOT_BUF (22+1) /* holds 64 bits in octal */
+err_t ttoaddr(const char *src, size_t srclen, int af, ip_address *dst);
+err_t tnatoaddr(const char *src, size_t srclen, int af, ip_address *dst);
+size_t addrtot(const ip_address *src, int format, char *buf, size_t buflen);
+/* RFC 1886 old IPv6 reverse-lookup format is the bulkiest */
+#define ADDRTOT_BUF (32*2 + 3 + 1 + 3 + 1 + 1)
+err_t ttosubnet(const char *src, size_t srclen, int af, ip_subnet *dst);
+size_t subnettot(const ip_subnet *src, int format, char *buf, size_t buflen);
+#define SUBNETTOT_BUF (ADDRTOT_BUF + 1 + 3)
+err_t ttosa(const char *src, size_t srclen, ip_said *dst);
+size_t satot(const ip_said *src, int format, char *bufptr, size_t buflen);
+#define SATOT_BUF (5 + ULTOA_BUF + 1 + ADDRTOT_BUF)
+err_t ttodata(const char *src, size_t srclen, int base, char *buf,
+ size_t buflen, size_t *needed);
+err_t ttodatav(const char *src, size_t srclen, int base,
+ char *buf, size_t buflen, size_t *needed,
+ char *errp, size_t errlen, unsigned int flags);
+#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 */
+
+size_t datatot(const char *src, size_t srclen, int format, char *buf,
+ size_t buflen);
+size_t keyblobtoid(const unsigned char *src, size_t srclen, char *dst,
+ size_t dstlen);
+size_t splitkeytoid(const unsigned char *e, size_t elen, const unsigned char *m,
+ size_t mlen, char *dst, size_t dstlen);
+#define KEYID_BUF 10 /* up to 9 text digits plus NUL */
+err_t ttoprotoport(char *src, size_t src_len, u_int8_t *proto, u_int16_t *port,
+ int *has_port_wildcard);
+
+/* initializations */
+void initsaid(const ip_address *addr, ipsec_spi_t spi, int proto, ip_said *dst);
+err_t loopbackaddr(int af, ip_address *dst);
+err_t unspecaddr(int af, ip_address *dst);
+err_t anyaddr(int af, ip_address *dst);
+err_t initaddr(const unsigned char *src, size_t srclen, int af, ip_address *dst);
+err_t initsubnet(const ip_address *addr, int maskbits, int clash, ip_subnet *dst);
+err_t addrtosubnet(const ip_address *addr, ip_subnet *dst);
+
+/* misc. conversions and related */
+err_t rangetosubnet(const ip_address *from, const ip_address *to, ip_subnet *dst);
+int addrtypeof(const ip_address *src);
+int subnettypeof(const ip_subnet *src);
+size_t addrlenof(const ip_address *src);
+size_t addrbytesptr(const ip_address *src, const unsigned char **dst);
+size_t addrbytesof(const ip_address *src, unsigned char *dst, size_t dstlen);
+int masktocount(const ip_address *src);
+void networkof(const ip_subnet *src, ip_address *dst);
+void maskof(const ip_subnet *src, ip_address *dst);
+
+/* tests */
+int sameaddr(const ip_address *a, const ip_address *b);
+int addrcmp(const ip_address *a, const ip_address *b);
+int samesubnet(const ip_subnet *a, const ip_subnet *b);
+int addrinsubnet(const ip_address *a, const ip_subnet *s);
+int subnetinsubnet(const ip_subnet *a, const ip_subnet *b);
+int subnetishost(const ip_subnet *s);
+int samesaid(const ip_said *a, const ip_said *b);
+int sameaddrtype(const ip_address *a, const ip_address *b);
+int samesubnettype(const ip_subnet *a, const ip_subnet *b);
+int isanyaddr(const ip_address *src);
+int isunspecaddr(const ip_address *src);
+int isloopbackaddr(const ip_address *src);
+
+/* low-level grot */
+int portof(const ip_address *src);
+void setportof(int port, ip_address *dst);
+struct sockaddr *sockaddrof(ip_address *src);
+size_t sockaddrlenof(const ip_address *src);
+
+/* PRNG */
+void prng_init(struct prng *prng, const unsigned char *key, size_t keylen);
+void prng_bytes(struct prng *prng, unsigned char *dst, size_t dstlen);
+unsigned long prng_count(struct prng *prng);
+void prng_final(struct prng *prng);
+
+/* odds and ends */
+const char *ipsec_version_code(void);
+const char *ipsec_version_string(void);
+const char **ipsec_copyright_notice(void);
+
+const char *dns_string_rr(int rr, char *buf, int bufsize);
+const char *dns_string_datetime(time_t seconds,
+ char *buf,
+ int bufsize);
+
+
+/*
+ * old functions, to be deleted eventually
+ */
+
+/* unsigned long */
+const char * /* NULL for success, else string literal */
+atoul(
+ const char *src,
+ size_t srclen, /* 0 means strlen(src) */
+ int base, /* 0 means figure it out */
+ unsigned long *resultp
+);
+size_t /* space needed for full conversion */
+ultoa(
+ unsigned long n,
+ int base,
+ char *dst,
+ size_t dstlen
+);
+#define ULTOA_BUF 21 /* just large enough for largest result, */
+ /* assuming 64-bit unsigned long! */
+
+/* Internet addresses */
+const char * /* NULL for success, else string literal */
+atoaddr(
+ const char *src,
+ size_t srclen, /* 0 means strlen(src) */
+ struct in_addr *addr
+);
+size_t /* space needed for full conversion */
+addrtoa(
+ struct in_addr addr,
+ int format, /* character; 0 means default */
+ char *dst,
+ size_t dstlen
+);
+#define ADDRTOA_BUF 16 /* just large enough for largest result */
+
+/* subnets */
+const char * /* NULL for success, else string literal */
+atosubnet(
+ const char *src,
+ size_t srclen, /* 0 means strlen(src) */
+ struct in_addr *addr,
+ struct in_addr *mask
+);
+size_t /* space needed for full conversion */
+subnettoa(
+ struct in_addr addr,
+ struct in_addr mask,
+ int format, /* character; 0 means default */
+ char *dst,
+ size_t dstlen
+);
+#define SUBNETTOA_BUF 32 /* large enough for worst case result */
+
+/* ranges */
+const char * /* NULL for success, else string literal */
+atoasr(
+ const char *src,
+ size_t srclen, /* 0 means strlen(src) */
+ char *type, /* 'a', 's', 'r' */
+ struct in_addr *addrs /* two-element array */
+);
+size_t /* space needed for full conversion */
+rangetoa(
+ struct in_addr *addrs, /* two-element array */
+ int format, /* character; 0 means default */
+ char *dst,
+ size_t dstlen
+);
+#define RANGETOA_BUF 34 /* large enough for worst case result */
+
+/* data types for SA conversion functions */
+
+/* SAs */
+const char * /* NULL for success, else string literal */
+atosa(
+ const char *src,
+ size_t srclen, /* 0 means strlen(src) */
+ struct sa_id *sa
+);
+size_t /* space needed for full conversion */
+satoa(
+ struct sa_id sa,
+ int format, /* character; 0 means default */
+ char *dst,
+ size_t dstlen
+);
+#define SATOA_BUF (3+ULTOA_BUF+ADDRTOA_BUF)
+
+/* generic data, e.g. keys */
+const char * /* NULL for success, else string literal */
+atobytes(
+ const char *src,
+ size_t srclen, /* 0 means strlen(src) */
+ char *dst,
+ size_t dstlen,
+ size_t *lenp /* NULL means don't bother telling me */
+);
+size_t /* 0 failure, else true size */
+bytestoa(
+ const char *src,
+ size_t srclen,
+ int format, /* character; 0 means default */
+ char *dst,
+ size_t dstlen
+);
+
+/* old versions of generic-data functions; deprecated */
+size_t /* 0 failure, else true size */
+atodata(
+ const char *src,
+ size_t srclen, /* 0 means strlen(src) */
+ char *dst,
+ size_t dstlen
+);
+size_t /* 0 failure, else true size */
+datatoa(
+ const char *src,
+ size_t srclen,
+ int format, /* character; 0 means default */
+ char *dst,
+ size_t dstlen
+);
+
+/* part extraction and special addresses */
+struct in_addr
+subnetof(
+ struct in_addr addr,
+ struct in_addr mask
+);
+struct in_addr
+hostof(
+ struct in_addr addr,
+ struct in_addr mask
+);
+struct in_addr
+broadcastof(
+ struct in_addr addr,
+ struct in_addr mask
+);
+
+/* mask handling */
+int
+goodmask(
+ struct in_addr mask
+);
+int
+masktobits(
+ struct in_addr mask
+);
+struct in_addr
+bitstomask(
+ int n
+);
+
+
+
+/*
+ * general utilities
+ */
+
+#ifndef __KERNEL__
+/* option pickup from files (userland only because of use of FILE) */
+const char *optionsfrom(const char *filename, int *argcp, char ***argvp,
+ int optind, FILE *errorreport);
+#endif
+
+/*
+ * Debugging levels for pfkey_lib_debug
+ */
+#define PF_KEY_DEBUG_PARSE_NONE 0
+#define PF_KEY_DEBUG_PARSE_PROBLEM 1
+#define PF_KEY_DEBUG_PARSE_STRUCT 2
+#define PF_KEY_DEBUG_PARSE_FLOW 4
+#define PF_KEY_DEBUG_PARSE_MAX 7
+
+extern unsigned int pfkey_lib_debug; /* bits selecting what to report */
+
+/*
+ * pluto and lwdnsq need to know the maximum size of the commands to,
+ * and replies from lwdnsq.
+ */
+
+#define LWDNSQ_CMDBUF_LEN 1024
+#define LWDNSQ_RESULT_LEN_MAX 4096
+
+#endif /* _FREESWAN_H */
diff --git a/src/libfreeswan/goodmask.3 b/src/libfreeswan/goodmask.3
new file mode 100644
index 000000000..4a573e51e
--- /dev/null
+++ b/src/libfreeswan/goodmask.3
@@ -0,0 +1,57 @@
+.TH IPSEC_GOODMASK 3 "11 June 2001"
+.\" RCSID $Id: goodmask.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec goodmask \- is this Internet subnet mask a valid one?
+.br
+ipsec masktobits \- convert Internet subnet mask to bit count
+.br
+ipsec bitstomask \- convert bit count to Internet subnet mask
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "int goodmask(struct in_addr mask);"
+.br
+.B "int masktobits(struct in_addr mask);"
+.br
+.B "struct in_addr bitstomask(int n);"
+.SH DESCRIPTION
+These functions are obsolete;
+see
+.IR ipsec_masktocount (3)
+for a partial replacement.
+.PP
+.I Goodmask
+reports whether the subnet
+.I mask
+is a valid one,
+i.e. consists of a (possibly empty) sequence of
+.BR 1 s
+followed by a (possibly empty) sequence of
+.BR 0 s.
+.I Masktobits
+takes a (valid) subnet mask and returns the number of
+.B 1
+bits in it.
+.I Bitstomask
+reverses this,
+returning the subnet mask corresponding to bit count
+.IR n .
+.PP
+All masks are in network byte order.
+.SH SEE ALSO
+inet(3), ipsec_atosubnet(3)
+.SH DIAGNOSTICS
+.I Masktobits
+returns
+.B \-1
+for an invalid mask.
+.I Bitstomask
+returns an all-zeros mask for a negative or out-of-range
+.IR n .
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+The error-reporting convention of
+.I bitstomask
+is less than ideal;
+zero is sometimes a legitimate mask.
diff --git a/src/libfreeswan/goodmask.c b/src/libfreeswan/goodmask.c
new file mode 100644
index 000000000..fe7a42335
--- /dev/null
+++ b/src/libfreeswan/goodmask.c
@@ -0,0 +1,97 @@
+/*
+ * minor utilities for subnet-mask manipulation
+ * Copyright (C) 1998, 1999 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.
+ *
+ * RCSID $Id: goodmask.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - goodmask - is this a good (^1*0*$) subnet mask?
+ * You are not expected to understand this. See Henry S. Warren Jr,
+ * "Functions realizable with word-parallel logical and two's-complement
+ * addition instructions", CACM 20.6 (June 1977), p.439.
+ */
+int /* predicate */
+goodmask(mask)
+struct in_addr mask;
+{
+ unsigned long x = ntohl(mask.s_addr);
+ /* clear rightmost contiguous string of 1-bits */
+# define CRCS1B(x) (((x|(x-1))+1)&x)
+# define TOPBIT (1UL << 31)
+
+ /* either zero, or has one string of 1-bits which is left-justified */
+ if (x == 0 || (CRCS1B(x) == 0 && (x&TOPBIT)))
+ return 1;
+ return 0;
+}
+
+/*
+ - masktobits - how many bits in this mask?
+ * The algorithm is essentially a binary search, but highly optimized
+ * for this particular task.
+ */
+int /* -1 means !goodmask() */
+masktobits(mask)
+struct in_addr mask;
+{
+ unsigned long m = ntohl(mask.s_addr);
+ int masklen;
+
+ if (!goodmask(mask))
+ return -1;
+
+ if (m&0x00000001UL)
+ return 32;
+ masklen = 0;
+ if (m&(0x0000ffffUL<<1)) { /* <<1 for 1-origin numbering */
+ masklen |= 0x10;
+ m <<= 16;
+ }
+ if (m&(0x00ff0000UL<<1)) {
+ masklen |= 0x08;
+ m <<= 8;
+ }
+ if (m&(0x0f000000UL<<1)) {
+ masklen |= 0x04;
+ m <<= 4;
+ }
+ if (m&(0x30000000UL<<1)) {
+ masklen |= 0x02;
+ m <<= 2;
+ }
+ if (m&(0x40000000UL<<1))
+ masklen |= 0x01;
+
+ return masklen;
+}
+
+/*
+ - bitstomask - return a mask with this many high bits on
+ */
+struct in_addr
+bitstomask(n)
+int n;
+{
+ struct in_addr result;
+
+ if (n > 0 && n <= ABITS)
+ result.s_addr = htonl(~((1UL << (ABITS - n)) - 1));
+ else if (n == 0)
+ result.s_addr = 0;
+ else
+ result.s_addr = 0; /* best error report we can do */
+ return result;
+}
diff --git a/src/libfreeswan/initaddr.3 b/src/libfreeswan/initaddr.3
new file mode 100644
index 000000000..b963f21cc
--- /dev/null
+++ b/src/libfreeswan/initaddr.3
@@ -0,0 +1,129 @@
+.TH IPSEC_INITADDR 3 "11 Sept 2000"
+.\" RCSID $Id: initaddr.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec initaddr \- initialize an ip_address
+.br
+ipsec addrtypeof \- get address type of an ip_address
+.br
+ipsec addrlenof \- get length of address within an ip_address
+.br
+ipsec addrbytesof \- get copy of address within an ip_address
+.br
+ipsec addrbytesptr \- get pointer to address within an ip_address
+.SH SYNOPSIS
+.B "#include <freeswan.h>"
+.sp
+.B "const char *initaddr(const char *src, size_t srclen,"
+.ti +1c
+.B "int af, ip_address *dst);"
+.br
+.B "int addrtypeof(const ip_address *src);"
+.br
+.B "size_t addrlenof(const ip_address *src);"
+.br
+.B "size_t addrbytesof(const ip_address *src,"
+.ti +1c
+.B "unsigned char *dst, size_t dstlen);"
+.br
+.B "size_t addrbytesptr(const ip_address *src,"
+.ti +1c
+.B "const unsigned char **dst);"
+.SH DESCRIPTION
+The
+.B <freeswan.h>
+library uses an internal type
+.I ip_address
+to contain one of the (currently two) types of IP address.
+These functions provide basic tools for creating and examining this type.
+.PP
+.I Initaddr
+initializes a variable
+.I *dst
+of type
+.I ip_address
+from an address
+(in network byte order,
+indicated by a pointer
+.I src
+and a length
+.IR srclen )
+and an address family
+.I af
+(typically
+.B AF_INET
+or
+.BR AF_INET6 ).
+The length must be consistent with the address family.
+.PP
+.I Addrtypeof
+returns the address type of an address,
+normally
+.B AF_INET
+or
+.BR AF_INET6 .
+(The
+.B <freeswan.h>
+header file arranges to include the necessary headers for these
+names to be known.)
+.PP
+.I Addrlenof
+returns the size (in bytes) of the address within an
+.IR ip_address ,
+to permit storage allocation etc.
+.PP
+.I Addrbytesof
+copies the address within the
+.I ip_address
+.I src
+to the buffer indicated by the pointer
+.I dst
+and the length
+.IR dstlen ,
+and returns the address length (in bytes).
+If the address will not fit,
+as many bytes as will fit are copied;
+the returned length is still the full length.
+It is the caller's responsibility to check the
+returned value to ensure that there was enough room.
+.PP
+.I Addrbytesptr
+sets
+.I *dst
+to a pointer to the internal address within the
+.IR ip_address ,
+and returns the address length (in bytes).
+If
+.I dst
+is
+.BR NULL ,
+it just returns the address length.
+The pointer points to
+.B const
+to discourage misuse.
+.PP
+.I Initaddr
+returns
+.B NULL
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+.PP
+The functions which return
+.I size_t
+return
+.B 0
+for a failure.
+.SH SEE ALSO
+inet(3), ipsec_ttoaddr(3)
+.SH DIAGNOSTICS
+An unknown address family is a fatal error for any of these functions
+except
+.IR addrtypeof .
+An address-size mismatch is a fatal error for
+.IR initaddr .
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+.I Addrtypeof
+should probably have been named
+.IR addrfamilyof .
diff --git a/src/libfreeswan/initaddr.c b/src/libfreeswan/initaddr.c
new file mode 100644
index 000000000..c215f6bdf
--- /dev/null
+++ b/src/libfreeswan/initaddr.c
@@ -0,0 +1,51 @@
+/*
+ * initialize address structure
+ * 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.
+ *
+ * RCSID $Id: initaddr.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - initaddr - initialize ip_address from bytes
+ */
+err_t /* NULL for success, else string literal */
+initaddr(src, srclen, af, dst)
+const unsigned char *src;
+size_t srclen;
+int af; /* address family */
+ip_address *dst;
+{
+ switch (af) {
+ case AF_INET:
+ if (srclen != 4)
+ return "IPv4 address must be exactly 4 bytes";
+ dst->u.v4.sin_family = af;
+ dst->u.v4.sin_port = 0; /* unused */
+ memcpy((char *)&dst->u.v4.sin_addr.s_addr, src, srclen);
+ break;
+ case AF_INET6:
+ if (srclen != 16)
+ return "IPv6 address must be exactly 16 bytes";
+ dst->u.v6.sin6_family = af;
+ dst->u.v6.sin6_flowinfo = 0; /* unused */
+ dst->u.v6.sin6_port = 0; /* unused */
+ memcpy((char *)&dst->u.v6.sin6_addr, src, srclen);
+ break;
+ default:
+ return "unknown address family in initaddr";
+ break;
+ }
+ return NULL;
+}
diff --git a/src/libfreeswan/initsaid.c b/src/libfreeswan/initsaid.c
new file mode 100644
index 000000000..4790f6981
--- /dev/null
+++ b/src/libfreeswan/initsaid.c
@@ -0,0 +1,33 @@
+/*
+ * initialize SA ID structure
+ * 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.
+ *
+ * RCSID $Id: initsaid.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - initsaid - initialize SA ID from bits
+ */
+void
+initsaid(addr, spi, proto, dst)
+const ip_address *addr;
+ipsec_spi_t spi;
+int proto;
+ip_said *dst;
+{
+ dst->dst = *addr;
+ dst->spi = spi;
+ dst->proto = proto;
+}
diff --git a/src/libfreeswan/initsubnet.3 b/src/libfreeswan/initsubnet.3
new file mode 100644
index 000000000..670f71778
--- /dev/null
+++ b/src/libfreeswan/initsubnet.3
@@ -0,0 +1,137 @@
+.TH IPSEC_INITSUBNET 3 "12 March 2002"
+.\" RCSID $Id: initsubnet.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec initsubnet \- initialize an ip_subnet
+.br
+ipsec addrtosubnet \- initialize a singleton ip_subnet
+.br
+ipsec subnettypeof \- get address type of an ip_subnet
+.br
+ipsec masktocount \- convert subnet mask to bit count
+.br
+ipsec networkof \- get base address of an ip_subnet
+.br
+ipsec maskof \- get subnet mask of an ip_subnet
+.SH SYNOPSIS
+.B "#include <freeswan.h>"
+.sp
+.B "const char *initsubnet(const ip_address *addr,"
+.ti +1c
+.B "int maskbits, int clash, ip_subnet *dst);"
+.br
+.B "const char *addrtosubnet(const ip_address *addr,"
+.ti +1c
+.B "ip_subnet *dst);"
+.sp
+.B "int subnettypeof(const ip_subnet *src);"
+.br
+.B "int masktocount(const ip_address *src);"
+.br
+.B "void networkof(const ip_subnet *src, ip_address *dst);"
+.br
+.B "void maskof(const ip_subnet *src, ip_address *dst);"
+.SH DESCRIPTION
+The
+.B <freeswan.h>
+library uses an internal type
+.I ip_subnet
+to contain a description of an IP subnet
+(base address plus mask).
+These functions provide basic tools for creating and examining this type.
+.PP
+.I Initsubnet
+initializes a variable
+.I *dst
+of type
+.I ip_subnet
+from a base address and
+a count of mask bits.
+The
+.I clash
+parameter specifies what to do if the base address includes
+.B 1
+bits outside the prefix specified by the mask
+(that is, in the ``host number'' part of the address):
+.RS
+.IP '0' 5
+zero out host-number bits
+.IP 'x'
+non-zero host-number bits are an error
+.RE
+.PP
+.I Initsubnet
+returns
+.B NULL
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+.PP
+.I Addrtosubnet
+initializes an
+.I ip_subnet
+variable
+.I *dst
+to a ``singleton subnet'' containing the single address
+.IR *addr .
+It returns
+.B NULL
+for success and
+a pointer to a string-literal error message for failure.
+.PP
+.I Subnettypeof
+returns the address type of a subnet,
+normally
+.B AF_INET
+or
+.BR AF_INET6 .
+(The
+.B <freeswan.h>
+header file arranges to include the necessary headers for these
+names to be known.)
+.PP
+.I Masktocount
+converts a subnet mask, expressed as an address, to a bit count
+suitable for use with
+.IR initsubnet .
+It returns
+.B \-1
+for error; see DIAGNOSTICS.
+.PP
+.I Networkof
+fills in
+.I *dst
+with the base address of subnet
+.IR src .
+.PP
+.I Maskof
+fills in
+.I *dst
+with the subnet mask of subnet
+.IR src ,
+expressed as an address.
+.SH SEE ALSO
+inet(3), ipsec_ttosubnet(3), ipsec_rangetosubnet(3)
+.SH DIAGNOSTICS
+Fatal errors in
+.I initsubnet
+are:
+unknown address family;
+unknown
+.I clash
+value;
+impossible mask bit count;
+non-zero host-number bits and
+.I clash
+is
+.BR 'x' .
+Fatal errors in
+.I addrtosubnet
+are:
+unknown address family.
+Fatal errors in
+.I masktocount
+are:
+unknown address family;
+mask bits not contiguous.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
diff --git a/src/libfreeswan/initsubnet.c b/src/libfreeswan/initsubnet.c
new file mode 100644
index 000000000..75ca72f36
--- /dev/null
+++ b/src/libfreeswan/initsubnet.c
@@ -0,0 +1,95 @@
+/*
+ * initialize subnet structure
+ * Copyright (C) 2000, 2002 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.
+ *
+ * RCSID $Id: initsubnet.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - initsubnet - initialize ip_subnet from address and count
+ *
+ * The only hard part is checking for host-part bits turned on.
+ */
+err_t /* NULL for success, else string literal */
+initsubnet(addr, count, clash, dst)
+const ip_address *addr;
+int count;
+int clash; /* '0' zero host-part bits, 'x' die on them */
+ip_subnet *dst;
+{
+ unsigned char *p;
+ int n;
+ int c;
+ unsigned m;
+ int die;
+
+ dst->addr = *addr;
+ n = addrbytesptr(&dst->addr, (const unsigned char **)&p);
+ if (n == 0)
+ return "unknown address family";
+
+ switch (clash) {
+ case '0':
+ die = 0;
+ break;
+ case 'x':
+ die = 1;
+ break;
+ default:
+ return "unknown clash-control value in initsubnet";
+ break;
+ }
+
+ c = count / 8;
+ if (c > n)
+ return "impossible mask count";
+ p += c;
+ n -= c;
+
+ m = 0xff;
+ c = count % 8;
+ if (n > 0 && c != 0) /* partial byte */
+ m >>= c;
+ for (; n > 0; n--) {
+ if ((*p & m) != 0) {
+ if (die)
+ return "improper subnet, host-part bits on";
+ *p &= ~m;
+ }
+ m = 0xff;
+ p++;
+ }
+
+ dst->maskbits = count;
+ return NULL;
+}
+
+/*
+ - addrtosubnet - initialize ip_subnet from a single address
+ */
+err_t /* NULL for success, else string literal */
+addrtosubnet(addr, dst)
+const ip_address *addr;
+ip_subnet *dst;
+{
+ int n;
+
+ dst->addr = *addr;
+ n = addrbytesptr(&dst->addr, (const unsigned char **)NULL);
+ if (n == 0)
+ return "unknown address family";
+ dst->maskbits = n*8;
+ return NULL;
+}
diff --git a/src/libfreeswan/internal.h b/src/libfreeswan/internal.h
new file mode 100644
index 000000000..16ad78da0
--- /dev/null
+++ b/src/libfreeswan/internal.h
@@ -0,0 +1,81 @@
+/*
+ * internal definitions for use within the library; do not export!
+ * Copyright (C) 1998, 1999 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.
+ *
+ * RCSID $Id: internal.h,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+
+#ifndef ABITS
+#define ABITS 32 /* bits in an IPv4 address */
+#endif
+
+/* case-independent ASCII character equality comparison */
+#define CIEQ(c1, c2) ( ((c1)&~040) == ((c2)&~040) )
+
+/* syntax for passthrough SA */
+#ifndef PASSTHROUGHNAME
+#define PASSTHROUGHNAME "%passthrough"
+#define PASSTHROUGH4NAME "%passthrough4"
+#define PASSTHROUGH6NAME "%passthrough6"
+#define PASSTHROUGHIS "tun0@0.0.0.0"
+#define PASSTHROUGH4IS "tun0@0.0.0.0"
+#define PASSTHROUGH6IS "tun0@::"
+#define PASSTHROUGHTYPE "tun"
+#define PASSTHROUGHSPI 0
+#define PASSTHROUGHDST 0
+#endif
+
+/*
+ * Headers, greatly complicated by stupid and unnecessary inconsistencies
+ * between the user environment and the kernel environment. These are done
+ * here so that this mess need exist in only one place.
+ *
+ * It may seem like a -I or two could avoid most of this, but on closer
+ * inspection it is not quite that easy.
+ */
+
+/* things that need to come from one place or the other, depending */
+#ifdef __KERNEL__
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#define assert(foo) /* nothing */
+#else
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#endif
+
+/* things that exist only in userland */
+#ifndef __KERNEL__
+
+/* You'd think this would be okay in the kernel too -- it's just a */
+/* bunch of constants -- but no, in RH5.1 it screws up other things. */
+/* (Credit: Mike Warfield tracked this problem down. Thanks Mike!) */
+/* Fortunately, we don't need it in the kernel subset of the library. */
+#include <limits.h>
+
+/* header files for things that should never be called in kernel */
+#include <netdb.h>
+
+/* memory allocation, currently user-only, macro-ized just in case */
+#include <stdlib.h>
+#define MALLOC(n) malloc(n)
+#define FREE(p) free(p)
+
+#endif /* __KERNEL__ */
+
diff --git a/src/libfreeswan/ipcomp.h b/src/libfreeswan/ipcomp.h
new file mode 100644
index 000000000..ed8095517
--- /dev/null
+++ b/src/libfreeswan/ipcomp.h
@@ -0,0 +1,61 @@
+/*
+ * IPCOMP zlib interface code.
+ * Copyright (C) 2000 Svenning Soerensen <svenning@post5.tele.dk>
+ * Copyright (C) 2000, 2001 Richard Guy Briggs <rgb@conscoop.ottawa.on.ca>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: ipcomp.h,v 1.1 2004/03/15 20:35:25 as Exp $
+
+ */
+
+/* SSS */
+
+#ifndef _IPCOMP_H
+#define _IPCOMP_H
+
+/* Prefix all global deflate symbols with "ipcomp_" to avoid collisions with ppp_deflate & ext2comp */
+#ifndef IPCOMP_PREFIX
+#define IPCOMP_PREFIX
+#endif /* IPCOMP_PREFIX */
+
+#ifndef IPPROTO_COMP
+#define IPPROTO_COMP 108
+#endif /* IPPROTO_COMP */
+
+#ifdef CONFIG_IPSEC_DEBUG
+extern int sysctl_ipsec_debug_ipcomp;
+#endif /* CONFIG_IPSEC_DEBUG */
+
+struct ipcomphdr { /* IPCOMP header */
+ __u8 ipcomp_nh; /* Next header (protocol) */
+ __u8 ipcomp_flags; /* Reserved, must be 0 */
+ __u16 ipcomp_cpi; /* Compression Parameter Index */
+};
+
+extern struct inet_protocol comp_protocol;
+extern int sysctl_ipsec_debug_ipcomp;
+
+#define IPCOMP_UNCOMPRESSABLE 0x000000001
+#define IPCOMP_COMPRESSIONERROR 0x000000002
+#define IPCOMP_PARMERROR 0x000000004
+#define IPCOMP_DECOMPRESSIONERROR 0x000000008
+
+#define IPCOMP_ADAPT_INITIAL_TRIES 8
+#define IPCOMP_ADAPT_INITIAL_SKIP 4
+#define IPCOMP_ADAPT_SUBSEQ_TRIES 2
+#define IPCOMP_ADAPT_SUBSEQ_SKIP 8
+
+/* Function prototypes */
+struct sk_buff *skb_compress(struct sk_buff *skb, struct ipsec_sa *ips, unsigned int *flags);
+struct sk_buff *skb_decompress(struct sk_buff *skb, struct ipsec_sa *ips, unsigned int *flags);
+
+#endif /* _IPCOMP_H */
diff --git a/src/libfreeswan/ipsec_ah.h b/src/libfreeswan/ipsec_ah.h
new file mode 100644
index 000000000..e088288d3
--- /dev/null
+++ b/src/libfreeswan/ipsec_ah.h
@@ -0,0 +1,235 @@
+/*
+ * Authentication Header declarations
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 1999, 2000, 2001 Richard Guy Briggs.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: ipsec_ah.h,v 1.2 2004/03/22 21:53:18 as Exp $
+ */
+
+#include "ipsec_md5h.h"
+#include "ipsec_sha1.h"
+
+#ifndef IPPROTO_AH
+#define IPPROTO_AH 51
+#endif /* IPPROTO_AH */
+
+#define AH_FLENGTH 12 /* size of fixed part */
+#define AHMD5_KMAX 64 /* MD5 max 512 bits key */
+#define AHMD5_AMAX 12 /* MD5 96 bits of authenticator */
+
+#define AHMD596_KLEN 16 /* MD5 128 bits key */
+#define AHSHA196_KLEN 20 /* SHA1 160 bits key */
+
+#define AHMD596_ALEN 16 /* MD5 128 bits authentication length */
+#define AHSHA196_ALEN 20 /* SHA1 160 bits authentication length */
+
+#define AHMD596_BLKLEN 64 /* MD5 block length */
+#define AHSHA196_BLKLEN 64 /* SHA1 block length */
+#define AHSHA2_256_BLKLEN 64 /* SHA2-256 block length */
+#define AHSHA2_384_BLKLEN 128 /* SHA2-384 block length (?) */
+#define AHSHA2_512_BLKLEN 128 /* SHA2-512 block length */
+
+#define AH_BLKLEN_MAX 128 /* keep up to date! */
+
+#define AH_AMAX AHSHA196_ALEN /* keep up to date! */
+#define AHHMAC_HASHLEN 12 /* authenticator length of 96bits */
+#define AHHMAC_RPLLEN 4 /* 32 bit replay counter */
+
+#define DB_AH_PKTRX 0x0001
+#define DB_AH_PKTRX2 0x0002
+#define DB_AH_DMP 0x0004
+#define DB_AH_IPSA 0x0010
+#define DB_AH_XF 0x0020
+#define DB_AH_INAU 0x0040
+#define DB_AH_REPLAY 0x0100
+
+#ifdef __KERNEL__
+
+/* General HMAC algorithm is described in RFC 2104 */
+
+#define HMAC_IPAD 0x36
+#define HMAC_OPAD 0x5C
+
+struct md5_ctx {
+ MD5_CTX ictx; /* context after H(K XOR ipad) */
+ MD5_CTX octx; /* context after H(K XOR opad) */
+};
+
+struct sha1_ctx {
+ SHA1_CTX ictx; /* context after H(K XOR ipad) */
+ SHA1_CTX octx; /* context after H(K XOR opad) */
+};
+
+struct auth_alg {
+ void (*init)(void *ctx);
+ void (*update)(void *ctx, unsigned char *bytes, __u32 len);
+ void (*final)(unsigned char *hash, void *ctx);
+ int hashlen;
+};
+
+extern struct inet_protocol ah_protocol;
+
+struct options;
+
+extern int
+ah_rcv(struct sk_buff *skb,
+ struct device *dev,
+ struct options *opt,
+ __u32 daddr,
+ unsigned short len,
+ __u32 saddr,
+ int redo,
+ struct inet_protocol *protocol);
+
+struct ahhdr /* Generic AH header */
+{
+ __u8 ah_nh; /* Next header (protocol) */
+ __u8 ah_hl; /* AH length, in 32-bit words */
+ __u16 ah_rv; /* reserved, must be 0 */
+ __u32 ah_spi; /* Security Parameters Index */
+ __u32 ah_rpl; /* Replay prevention */
+ __u8 ah_data[AHHMAC_HASHLEN];/* Authentication hash */
+};
+#define AH_BASIC_LEN 8 /* basic AH header is 8 bytes, nh,hl,rv,spi
+ * and the ah_hl, says how many bytes after that
+ * to cover. */
+
+
+#ifdef CONFIG_IPSEC_DEBUG
+extern int debug_ah;
+#endif /* CONFIG_IPSEC_DEBUG */
+#endif /* __KERNEL__ */
+
+/*
+ * $Log: ipsec_ah.h,v $
+ * Revision 1.2 2004/03/22 21:53:18 as
+ * merged alg-0.8.1 branch with HEAD
+ *
+ * Revision 1.1.4.1 2004/03/16 09:48:18 as
+ * alg-0.8.1rc12 patch merged
+ *
+ * Revision 1.1 2004/03/15 20:35:25 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.20 2003/02/06 02:21:34 rgb
+ *
+ * Moved "struct auth_alg" from ipsec_rcv.c to ipsec_ah.h .
+ * Changed "struct ah" to "struct ahhdr" and "struct esp" to "struct esphdr".
+ * Removed "#ifdef INBOUND_POLICY_CHECK_eroute" dead code.
+ *
+ * Revision 1.19 2002/09/16 21:19:13 mcr
+ * fixes for west-ah-icmp-01 - length of AH header must be
+ * calculated properly, and next_header field properly copied.
+ *
+ * Revision 1.18 2002/05/14 02:37:02 rgb
+ * Change reference from _TDB to _IPSA.
+ *
+ * Revision 1.17 2002/04/24 07:36:46 mcr
+ * Moved from ./klips/net/ipsec/ipsec_ah.h,v
+ *
+ * Revision 1.16 2002/02/20 01:27:06 rgb
+ * Ditched a pile of structs only used by the old Netlink interface.
+ *
+ * Revision 1.15 2001/12/11 02:35:57 rgb
+ * Change "struct net_device" to "struct device" for 2.2 compatibility.
+ *
+ * Revision 1.14 2001/11/26 09:23:47 rgb
+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
+ *
+ * Revision 1.13.2.1 2001/09/25 02:18:24 mcr
+ * replace "struct device" with "struct netdevice"
+ *
+ * Revision 1.13 2001/06/14 19:35:08 rgb
+ * Update copyright date.
+ *
+ * Revision 1.12 2000/09/12 03:21:20 rgb
+ * Cleared out unused htonq.
+ *
+ * Revision 1.11 2000/09/08 19:12:55 rgb
+ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
+ *
+ * Revision 1.10 2000/01/21 06:13:10 rgb
+ * Tidied up spacing.
+ * Added macros for HMAC padding magic numbers.(kravietz)
+ *
+ * Revision 1.9 1999/12/07 18:16:23 rgb
+ * Fixed comments at end of #endif lines.
+ *
+ * Revision 1.8 1999/04/11 00:28:56 henry
+ * GPL boilerplate
+ *
+ * Revision 1.7 1999/04/06 04:54:25 rgb
+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+ * patch shell fixes.
+ *
+ * Revision 1.6 1999/01/26 02:06:01 rgb
+ * Removed CONFIG_IPSEC_ALGO_SWITCH macro.
+ *
+ * Revision 1.5 1999/01/22 06:17:49 rgb
+ * Updated macro comments.
+ * Added context types to support algorithm switch code.
+ * 64-bit clean-up -- converting 'u long long' to __u64.
+ *
+ * Revision 1.4 1998/07/14 15:54:56 rgb
+ * Add #ifdef __KERNEL__ to protect kernel-only structures.
+ *
+ * Revision 1.3 1998/06/30 18:05:16 rgb
+ * Comment out references to htonq.
+ *
+ * Revision 1.2 1998/06/25 19:33:46 rgb
+ * Add prototype for protocol receive function.
+ * Rearrange for more logical layout.
+ *
+ * Revision 1.1 1998/06/18 21:27:43 henry
+ * move sources from klips/src to klips/net/ipsec, to keep stupid
+ * kernel-build scripts happier in the presence of symlinks
+ *
+ * Revision 1.4 1998/05/18 22:28:43 rgb
+ * Disable key printing facilities from /proc/net/ipsec_*.
+ *
+ * Revision 1.3 1998/04/21 21:29:07 rgb
+ * Rearrange debug switches to change on the fly debug output from user
+ * space. Only kernel changes checked in at this time. radij.c was also
+ * changed to temporarily remove buggy debugging code in rj_delete causing
+ * an OOPS and hence, netlink device open errors.
+ *
+ * Revision 1.2 1998/04/12 22:03:17 rgb
+ * Updated ESP-3DES-HMAC-MD5-96,
+ * ESP-DES-HMAC-MD5-96,
+ * AH-HMAC-MD5-96,
+ * AH-HMAC-SHA1-96 since Henry started freeswan cvs repository
+ * from old standards (RFC182[5-9] to new (as of March 1998) drafts.
+ *
+ * Fixed eroute references in /proc/net/ipsec*.
+ *
+ * Started to patch module unloading memory leaks in ipsec_netlink and
+ * radij tree unloading.
+ *
+ * Revision 1.1 1998/04/09 03:05:55 henry
+ * sources moved up from linux/net/ipsec
+ *
+ * Revision 1.1.1.1 1998/04/08 05:35:02 henry
+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
+ *
+ * Revision 0.4 1997/01/15 01:28:15 ji
+ * Added definitions for new AH transforms.
+ *
+ * Revision 0.3 1996/11/20 14:35:48 ji
+ * Minor Cleanup.
+ * Rationalized debugging code.
+ *
+ * Revision 0.2 1996/11/02 00:18:33 ji
+ * First limited release.
+ *
+ *
+ */
diff --git a/src/libfreeswan/ipsec_alg.h b/src/libfreeswan/ipsec_alg.h
new file mode 100644
index 000000000..a393784b1
--- /dev/null
+++ b/src/libfreeswan/ipsec_alg.h
@@ -0,0 +1,254 @@
+/*
+ * Modular extensions service and registration functions interface
+ *
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * $Id: ipsec_alg.h,v 1.2 2004/03/22 21:53:18 as Exp $
+ *
+ */
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 IPSEC_ALG_H
+#define IPSEC_ALG_H
+
+/*
+ * gcc >= 3.2 has removed __FUNCTION__, replaced by C99 __func__
+ * *BUT* its a compiler variable.
+ */
+#if (__GNUC__ >= 3)
+#ifndef __FUNCTION__
+#define __FUNCTION__ __func__
+#endif
+#endif
+
+/* Version 0.8.1-0 */
+#define IPSEC_ALG_VERSION 0x00080100
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <asm/atomic.h>
+/*
+ * The following structs are used via pointers in ipsec_alg object to
+ * avoid ipsec_alg.h coupling with freeswan headers, thus simplifying
+ * module development
+ */
+struct ipsec_sa;
+struct esp;
+
+/**************************************
+ *
+ * Main registration object
+ *
+ *************************************/
+#define IPSEC_ALG_VERSION_QUAD(v) \
+ (v>>24),((v>>16)&0xff),((v>>8)&0xff),(v&0xff)
+/*
+ * Main ipsec_alg objects: "OOPrograming wannabe"
+ * Hierachy (carefully handled with _minimal_ cast'ing):
+ *
+ * ipsec_alg+
+ * +->ipsec_alg_enc (ixt_alg_type=SADB_EXT_SUPPORTED_ENCRYPT)
+ * +->ipsec_alg_auth (ixt_alg_type=SADB_EXT_SUPPORTED_AUTH)
+ */
+
+/***************************************************************
+ *
+ * INTERFACE object: struct ipsec_alg
+ *
+ ***************************************************************/
+
+/*
+ * common part for every struct ipsec_alg_*
+ * (sortof poor's man OOP)
+ */
+#define IPSEC_ALG_STRUCT_COMMON \
+ unsigned ixt_version; /* only allow this version (or 'near')*/ \
+ struct list_head ixt_list; /* dlinked list */ \
+ struct module *ixt_module; /* THIS_MODULE */ \
+ unsigned ixt_state; /* state flags */ \
+ atomic_t ixt_refcnt; /* ref. count when pointed from ipsec_sa */ \
+ char ixt_name[16]; /* descriptive short name, eg. "3des" */ \
+ void *ixt_data; /* private for algo implementation */ \
+ uint8_t ixt_blocksize; /* blocksize in bytes */ \
+ \
+ /* THIS IS A COPY of struct supported (lib/pfkey.h) \
+ * please keep in sync until we migrate 'supported' stuff \
+ * to ipsec_alg \
+ */ \
+ uint16_t ixt_alg_type; /* correspond to IPSEC_ALG_{ENCRYPT,AUTH} */ \
+ uint8_t ixt_alg_id; /* enc. alg. number, eg. ESP_3DES */ \
+ uint8_t ixt_ivlen; /* ivlen in bits, expected to be multiple of 8! */ \
+ uint16_t ixt_keyminbits;/* min. keybits (of entropy) */ \
+ uint16_t ixt_keymaxbits;/* max. keybits (of entropy) */
+
+#define ixt_support ixt_alg_type
+
+#define IPSEC_ALG_ST_SUPP 0x01
+#define IPSEC_ALG_ST_REGISTERED 0x02
+#define IPSEC_ALG_ST_EXCL 0x04
+struct ipsec_alg {
+ IPSEC_ALG_STRUCT_COMMON
+};
+/*
+ * Note the const in cbc_encrypt IV arg:
+ * some ciphers like to toast passed IV (eg. 3DES): make a local IV copy
+ */
+struct ipsec_alg_enc {
+ IPSEC_ALG_STRUCT_COMMON
+ unsigned ixt_e_keylen; /* raw key length in bytes */
+ unsigned ixt_e_ctx_size; /* sa_p->key_e_size */
+ int (*ixt_e_set_key)(struct ipsec_alg_enc *alg, __u8 *key_e, const __u8 *key, size_t keysize);
+ __u8 *(*ixt_e_new_key)(struct ipsec_alg_enc *alg, const __u8 *key, size_t keysize);
+ void (*ixt_e_destroy_key)(struct ipsec_alg_enc *alg, __u8 *key_e);
+ int (*ixt_e_cbc_encrypt)(struct ipsec_alg_enc *alg, __u8 *key_e, __u8 *in, int ilen, const __u8 *iv, int encrypt);
+};
+struct ipsec_alg_auth {
+ IPSEC_ALG_STRUCT_COMMON
+ unsigned ixt_a_keylen; /* raw key length in bytes */
+ unsigned ixt_a_ctx_size; /* sa_p->key_a_size */
+ unsigned ixt_a_authlen; /* 'natural' auth. hash len (bytes) */
+ int (*ixt_a_hmac_set_key)(struct ipsec_alg_auth *alg, __u8 *key_a, const __u8 *key, int keylen);
+ int (*ixt_a_hmac_hash)(struct ipsec_alg_auth *alg, __u8 *key_a, const __u8 *dat, int len, __u8 *hash, int hashlen);
+};
+/*
+ * These are _copies_ of SADB_EXT_SUPPORTED_{AUTH,ENCRYPT},
+ * to avoid header coupling for true constants
+ * about headers ... "cp is your friend" --Linus
+ */
+#define IPSEC_ALG_TYPE_AUTH 14
+#define IPSEC_ALG_TYPE_ENCRYPT 15
+
+/***************************************************************
+ *
+ * INTERFACE for module loading,testing, and unloading
+ *
+ ***************************************************************/
+/* - registration calls */
+int register_ipsec_alg(struct ipsec_alg *);
+int unregister_ipsec_alg(struct ipsec_alg *);
+/* - optional (simple test) for algos */
+int ipsec_alg_test(unsigned alg_type, unsigned alg_id, int testparm);
+/* inline wrappers (usefull for type validation */
+static inline int register_ipsec_alg_enc(struct ipsec_alg_enc *ixt) {
+ return register_ipsec_alg((struct ipsec_alg*)ixt);
+}
+static inline int unregister_ipsec_alg_enc(struct ipsec_alg_enc *ixt) {
+ return unregister_ipsec_alg((struct ipsec_alg*)ixt);
+}
+static inline int register_ipsec_alg_auth(struct ipsec_alg_auth *ixt) {
+ return register_ipsec_alg((struct ipsec_alg*)ixt);
+}
+static inline int unregister_ipsec_alg_auth(struct ipsec_alg_auth *ixt) {
+ return unregister_ipsec_alg((struct ipsec_alg*)ixt);
+}
+
+/*****************************************************************
+ *
+ * INTERFACE for ENC services: key creation, encrypt function
+ *
+ *****************************************************************/
+
+#define IPSEC_ALG_ENCRYPT 1
+#define IPSEC_ALG_DECRYPT 0
+
+/* encryption key context creation function */
+int ipsec_alg_enc_key_create(struct ipsec_sa *sa_p);
+/*
+ * ipsec_alg_esp_encrypt(): encrypt ilen bytes in idat returns
+ * 0 or ERR<0
+ */
+int ipsec_alg_esp_encrypt(struct ipsec_sa *sa_p, __u8 *idat, int ilen, const __u8 *iv, int action);
+
+/***************************************************************
+ *
+ * INTERFACE for AUTH services: key creation, hash functions
+ *
+ ***************************************************************/
+int ipsec_alg_auth_key_create(struct ipsec_sa *sa_p);
+int ipsec_alg_sa_esp_hash(const struct ipsec_sa *sa_p, const __u8 *espp, int len, __u8 *hash, int hashlen) ;
+#define ipsec_alg_sa_esp_update(c,k,l) ipsec_alg_sa_esp_hash(c,k,l,NULL,0)
+
+/* only called from ipsec_init.c */
+int ipsec_alg_init(void);
+
+/* algo module glue for static algos */
+void ipsec_alg_static_init(void);
+typedef int (*ipsec_alg_init_func_t) (void);
+
+/**********************************************
+ *
+ * INTERFACE for ipsec_sa init and wipe
+ *
+ **********************************************/
+
+/* returns true if ipsec_sa has ipsec_alg obj attached */
+/*
+ * Initializes ipsec_sa's ipsec_alg object, using already loaded
+ * proto, authalg, encalg.; links ipsec_alg objects (enc, auth)
+ */
+int ipsec_alg_sa_init(struct ipsec_sa *sa_p);
+/*
+ * Destroys ipsec_sa's ipsec_alg object
+ * unlinking ipsec_alg objects
+ */
+int ipsec_alg_sa_wipe(struct ipsec_sa *sa_p);
+
+/**********************************************
+ *
+ * 2.2 backport for some 2.4 useful module stuff
+ *
+ **********************************************/
+#ifdef MODULE
+#ifndef THIS_MODULE
+#define THIS_MODULE (&__this_module)
+#endif
+#ifndef module_init
+typedef int (*__init_module_func_t)(void);
+typedef void (*__cleanup_module_func_t)(void);
+
+#define module_init(x) \
+ int init_module(void) __attribute__((alias(#x))); \
+ static inline __init_module_func_t __init_module_inline(void) \
+ { return x; }
+#define module_exit(x) \
+ void cleanup_module(void) __attribute__((alias(#x))); \
+ static inline __cleanup_module_func_t __cleanup_module_inline(void) \
+ { return x; }
+#endif
+
+#define IPSEC_ALG_MODULE_INIT( func_name ) \
+ static int func_name(void); \
+ module_init(func_name); \
+ static int __init func_name(void)
+#define IPSEC_ALG_MODULE_EXIT( func_name ) \
+ static void func_name(void); \
+ module_exit(func_name); \
+ static void __exit func_name(void)
+#else /* not MODULE */
+#ifndef THIS_MODULE
+#define THIS_MODULE NULL
+#endif
+/*
+ * I only want module_init() magic
+ * when algo.c file *is THE MODULE*, in all other
+ * cases, initialization is called explicitely from ipsec_alg_init()
+ */
+#define IPSEC_ALG_MODULE_INIT( func_name ) \
+ extern int func_name(void); \
+ int func_name(void)
+#define IPSEC_ALG_MODULE_EXIT( func_name ) \
+ extern void func_name(void); \
+ void func_name(void)
+#endif
+
+#endif /* IPSEC_ALG_H */
diff --git a/src/libfreeswan/ipsec_encap.h b/src/libfreeswan/ipsec_encap.h
new file mode 100644
index 000000000..17cd69269
--- /dev/null
+++ b/src/libfreeswan/ipsec_encap.h
@@ -0,0 +1,143 @@
+/*
+ * declarations relevant to encapsulation-like operations
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 1999, 2000, 2001 Richard Guy Briggs.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: ipsec_encap.h,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+
+#ifndef _IPSEC_ENCAP_H_
+
+#define SENT_IP4 16 /* data is two struct in_addr + proto + ports*/
+ /* (2 * sizeof(struct in_addr)) */
+ /* sizeof(struct sockaddr_encap)
+ - offsetof(struct sockaddr_encap, Sen.Sip4.Src) */
+
+struct sockaddr_encap
+{
+ __u8 sen_len; /* length */
+ __u8 sen_family; /* AF_ENCAP */
+ __u16 sen_type; /* see SENT_* */
+ union
+ {
+ struct /* SENT_IP4 */
+ {
+ struct in_addr Src;
+ struct in_addr Dst;
+ __u8 Proto;
+ __u16 Sport;
+ __u16 Dport;
+ } Sip4;
+ } Sen;
+};
+
+#define sen_ip_src Sen.Sip4.Src
+#define sen_ip_dst Sen.Sip4.Dst
+#define sen_proto Sen.Sip4.Proto
+#define sen_sport Sen.Sip4.Sport
+#define sen_dport Sen.Sip4.Dport
+
+#ifndef AF_ENCAP
+#define AF_ENCAP 26
+#endif /* AF_ENCAP */
+
+#define _IPSEC_ENCAP_H_
+#endif /* _IPSEC_ENCAP_H_ */
+
+/*
+ * $Log: ipsec_encap.h,v $
+ * Revision 1.1 2004/03/15 20:35:25 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.17 2002/04/24 07:36:46 mcr
+ * Moved from ./klips/net/ipsec/ipsec_encap.h,v
+ *
+ * Revision 1.16 2001/11/26 09:23:47 rgb
+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
+ *
+ * Revision 1.15.2.1 2001/09/25 02:18:54 mcr
+ * struct eroute moved to ipsec_eroute.h
+ *
+ * Revision 1.15 2001/09/14 16:58:36 rgb
+ * Added support for storing the first and last packets through a HOLD.
+ *
+ * Revision 1.14 2001/09/08 21:13:31 rgb
+ * Added pfkey ident extension support for ISAKMPd. (NetCelo)
+ *
+ * Revision 1.13 2001/06/14 19:35:08 rgb
+ * Update copyright date.
+ *
+ * Revision 1.12 2001/05/27 06:12:10 rgb
+ * Added structures for pid, packet count and last access time to eroute.
+ * Added packet count to beginning of /proc/net/ipsec_eroute.
+ *
+ * Revision 1.11 2000/09/08 19:12:56 rgb
+ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
+ *
+ * Revision 1.10 2000/03/22 16:15:36 rgb
+ * Fixed renaming of dev_get (MB).
+ *
+ * Revision 1.9 2000/01/21 06:13:26 rgb
+ * Added a macro for AF_ENCAP
+ *
+ * Revision 1.8 1999/12/31 14:56:55 rgb
+ * MB fix for 2.3 dev-use-count.
+ *
+ * Revision 1.7 1999/11/18 04:09:18 rgb
+ * Replaced all kernel version macros to shorter, readable form.
+ *
+ * Revision 1.6 1999/09/24 00:34:13 rgb
+ * Add Marc Boucher's support for 2.3.xx+.
+ *
+ * Revision 1.5 1999/04/11 00:28:57 henry
+ * GPL boilerplate
+ *
+ * Revision 1.4 1999/04/06 04:54:25 rgb
+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+ * patch shell fixes.
+ *
+ * Revision 1.3 1998/10/19 14:44:28 rgb
+ * Added inclusion of freeswan.h.
+ * sa_id structure implemented and used: now includes protocol.
+ *
+ * Revision 1.2 1998/07/14 18:19:33 rgb
+ * Added #ifdef __KERNEL__ directives to restrict scope of header.
+ *
+ * Revision 1.1 1998/06/18 21:27:44 henry
+ * move sources from klips/src to klips/net/ipsec, to keep stupid
+ * kernel-build scripts happier in the presence of symlinks
+ *
+ * Revision 1.2 1998/04/21 21:29:10 rgb
+ * Rearrange debug switches to change on the fly debug output from user
+ * space. Only kernel changes checked in at this time. radij.c was also
+ * changed to temporarily remove buggy debugging code in rj_delete causing
+ * an OOPS and hence, netlink device open errors.
+ *
+ * Revision 1.1 1998/04/09 03:05:58 henry
+ * sources moved up from linux/net/ipsec
+ *
+ * Revision 1.1.1.1 1998/04/08 05:35:02 henry
+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
+ *
+ * Revision 0.4 1997/01/15 01:28:15 ji
+ * Minor cosmetic changes.
+ *
+ * Revision 0.3 1996/11/20 14:35:48 ji
+ * Minor Cleanup.
+ * Rationalized debugging code.
+ *
+ * Revision 0.2 1996/11/02 00:18:33 ji
+ * First limited release.
+ *
+ *
+ */
diff --git a/src/libfreeswan/ipsec_eroute.h b/src/libfreeswan/ipsec_eroute.h
new file mode 100644
index 000000000..2ee2a10b8
--- /dev/null
+++ b/src/libfreeswan/ipsec_eroute.h
@@ -0,0 +1,103 @@
+/*
+ * @(#) declarations of eroute structures
+ *
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 1999, 2000, 2001 Richard Guy Briggs <rgb@freeswan.org>
+ * Copyright (C) 2001 Michael Richardson <mcr@freeswan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: ipsec_eroute.h,v 1.1 2004/03/15 20:35:25 as Exp $
+ *
+ * derived from ipsec_encap.h 1.15 on 2001/9/18 by mcr.
+ *
+ */
+
+#ifndef _IPSEC_EROUTE_H_
+
+#include "radij.h"
+#include "ipsec_encap.h"
+#include "ipsec_radij.h"
+
+/*
+ * The "type" is really part of the address as far as the routing
+ * system is concerned. By using only one bit in the type field
+ * for each type, we sort-of make sure that different types of
+ * encapsulation addresses won't be matched against the wrong type.
+ */
+
+/*
+ * An entry in the radix tree
+ */
+
+struct rjtentry
+{
+ struct radij_node rd_nodes[2]; /* tree glue, and other values */
+#define rd_key(r) ((struct sockaddr_encap *)((r)->rd_nodes->rj_key))
+#define rd_mask(r) ((struct sockaddr_encap *)((r)->rd_nodes->rj_mask))
+ short rd_flags;
+ short rd_count;
+};
+
+struct ident
+{
+ __u16 type; /* identity type */
+ __u64 id; /* identity id */
+ __u8 len; /* identity len */
+ caddr_t data; /* identity data */
+};
+
+/*
+ * An encapsulation route consists of a pointer to a
+ * radix tree entry and a SAID (a destination_address/SPI/protocol triple).
+ */
+
+struct eroute
+{
+ struct rjtentry er_rjt;
+ struct sa_id er_said;
+ uint32_t er_pid;
+ uint32_t er_count;
+ uint64_t er_lasttime;
+ struct sockaddr_encap er_eaddr; /* MCR get rid of _encap, it is silly*/
+ struct sockaddr_encap er_emask;
+ struct ident er_ident_s;
+ struct ident er_ident_d;
+ struct sk_buff* er_first;
+ struct sk_buff* er_last;
+};
+
+#define er_dst er_said.dst
+#define er_spi er_said.spi
+
+#define _IPSEC_EROUTE_H_
+#endif /* _IPSEC_EROUTE_H_ */
+
+/*
+ * $Log: ipsec_eroute.h,v $
+ * Revision 1.1 2004/03/15 20:35:25 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.3 2002/04/24 07:36:46 mcr
+ * Moved from ./klips/net/ipsec/ipsec_eroute.h,v
+ *
+ * Revision 1.2 2001/11/26 09:16:13 rgb
+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
+ *
+ * Revision 1.1.2.1 2001/09/25 02:18:54 mcr
+ * struct eroute moved to ipsec_eroute.h
+ *
+ *
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ *
+ */
diff --git a/src/libfreeswan/ipsec_errs.h b/src/libfreeswan/ipsec_errs.h
new file mode 100644
index 000000000..f14b5e675
--- /dev/null
+++ b/src/libfreeswan/ipsec_errs.h
@@ -0,0 +1,53 @@
+/*
+ * @(#) definition of ipsec_errs structure
+ *
+ * Copyright (C) 2001 Richard Guy Briggs <rgb@freeswan.org>
+ * and Michael Richardson <mcr@freeswan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: ipsec_errs.h,v 1.1 2004/03/15 20:35:25 as Exp $
+ *
+ */
+
+/*
+ * This file describes the errors/statistics that FreeSWAN collects.
+ *
+ */
+
+struct ipsec_errs {
+ __u32 ips_alg_errs; /* number of algorithm errors */
+ __u32 ips_auth_errs; /* # of authentication errors */
+ __u32 ips_encsize_errs; /* # of encryption size errors*/
+ __u32 ips_encpad_errs; /* # of encryption pad errors*/
+ __u32 ips_replaywin_errs; /* # of pkt sequence errors */
+};
+
+/*
+ * $Log: ipsec_errs.h,v $
+ * Revision 1.1 2004/03/15 20:35:25 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.3 2002/04/24 07:36:46 mcr
+ * Moved from ./klips/net/ipsec/ipsec_errs.h,v
+ *
+ * Revision 1.2 2001/11/26 09:16:13 rgb
+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
+ *
+ * Revision 1.1.2.1 2001/09/25 02:25:57 mcr
+ * lifetime structure created and common functions created.
+ *
+ *
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ *
+ */
diff --git a/src/libfreeswan/ipsec_esp.h b/src/libfreeswan/ipsec_esp.h
new file mode 100644
index 000000000..c7d5ea15d
--- /dev/null
+++ b/src/libfreeswan/ipsec_esp.h
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 1999, 2000, 2001 Richard Guy Briggs.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: ipsec_esp.h,v 1.2 2004/03/22 21:53:18 as Exp $
+ */
+
+#include "freeswan/ipsec_md5h.h"
+#include "freeswan/ipsec_sha1.h"
+
+#include "crypto/des.h"
+
+#ifndef IPPROTO_ESP
+#define IPPROTO_ESP 50
+#endif /* IPPROTO_ESP */
+
+#define ESP_HEADER_LEN 8 /* 64 bits header (spi+rpl)*/
+
+#define EMT_ESPDESCBC_ULEN 20 /* coming from user mode */
+#define EMT_ESPDES_KMAX 64 /* 512 bit secret key enough? */
+#define EMT_ESPDES_KEY_SZ 8 /* 56 bit secret key with parity = 64 bits */
+#define EMT_ESP3DES_KEY_SZ 24 /* 168 bit secret key with parity = 192 bits */
+#define EMT_ESPDES_IV_SZ 8 /* IV size */
+#define ESP_DESCBC_BLKLEN 8 /* DES-CBC block size */
+
+#define ESP_IV_MAXSZ 16 /* This is _critical_ */
+#define ESP_IV_MAXSZ_INT (ESP_IV_MAXSZ/sizeof(int))
+
+#define DB_ES_PKTRX 0x0001
+#define DB_ES_PKTRX2 0x0002
+#define DB_ES_IPSA 0x0010
+#define DB_ES_XF 0x0020
+#define DB_ES_IPAD 0x0040
+#define DB_ES_INAU 0x0080
+#define DB_ES_OINFO 0x0100
+#define DB_ES_OINFO2 0x0200
+#define DB_ES_OH 0x0400
+#define DB_ES_REPLAY 0x0800
+
+#ifdef __KERNEL__
+struct des_eks {
+ des_key_schedule ks;
+};
+
+extern struct inet_protocol esp_protocol;
+
+struct options;
+
+extern int
+esp_rcv(struct sk_buff *skb,
+ struct device *dev,
+ struct options *opt,
+ __u32 daddr,
+ unsigned short len,
+ __u32 saddr,
+ int redo,
+ struct inet_protocol *protocol);
+
+/* Only for 64 bits IVs, eg. ESP_3DES :P */
+struct esphdr
+{
+ __u32 esp_spi; /* Security Parameters Index */
+ __u32 esp_rpl; /* Replay counter */
+ __u8 esp_iv[8]; /* iv */
+};
+
+#ifdef CONFIG_IPSEC_DEBUG
+extern int debug_esp;
+#endif /* CONFIG_IPSEC_DEBUG */
+#endif /* __KERNEL__ */
+
+/*
+ * $Log: ipsec_esp.h,v $
+ * Revision 1.2 2004/03/22 21:53:18 as
+ * merged alg-0.8.1 branch with HEAD
+ *
+ * Revision 1.1.4.1 2004/03/16 09:48:18 as
+ * alg-0.8.1rc12 patch merged
+ *
+ * Revision 1.1 2004/03/15 20:35:25 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.21 2003/02/06 02:21:34 rgb
+ *
+ * Moved "struct auth_alg" from ipsec_rcv.c to ipsec_ah.h .
+ * Changed "struct ah" to "struct ahhdr" and "struct esp" to "struct esphdr".
+ * Removed "#ifdef INBOUND_POLICY_CHECK_eroute" dead code.
+ *
+ * Revision 1.20 2002/05/14 02:37:02 rgb
+ * Change reference from _TDB to _IPSA.
+ *
+ * Revision 1.19 2002/04/24 07:55:32 mcr
+ * #include patches and Makefiles for post-reorg compilation.
+ *
+ * Revision 1.18 2002/04/24 07:36:46 mcr
+ * Moved from ./klips/net/ipsec/ipsec_esp.h,v
+ *
+ * Revision 1.17 2002/02/20 01:27:07 rgb
+ * Ditched a pile of structs only used by the old Netlink interface.
+ *
+ * Revision 1.16 2001/12/11 02:35:57 rgb
+ * Change "struct net_device" to "struct device" for 2.2 compatibility.
+ *
+ * Revision 1.15 2001/11/26 09:23:48 rgb
+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
+ *
+ * Revision 1.14.2.3 2001/10/23 04:16:42 mcr
+ * get definition of des_key_schedule from des.h
+ *
+ * Revision 1.14.2.2 2001/10/22 20:33:13 mcr
+ * use "des_key_schedule" structure instead of cooking our own.
+ *
+ * Revision 1.14.2.1 2001/09/25 02:18:25 mcr
+ * replace "struct device" with "struct netdevice"
+ *
+ * Revision 1.14 2001/06/14 19:35:08 rgb
+ * Update copyright date.
+ *
+ * Revision 1.13 2000/09/08 19:12:56 rgb
+ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
+ *
+ * Revision 1.12 2000/08/01 14:51:50 rgb
+ * Removed _all_ remaining traces of DES.
+ *
+ * Revision 1.11 2000/01/10 16:36:20 rgb
+ * Ditch last of EME option flags, including initiator.
+ *
+ * Revision 1.10 1999/12/07 18:16:22 rgb
+ * Fixed comments at end of #endif lines.
+ *
+ * Revision 1.9 1999/04/11 00:28:57 henry
+ * GPL boilerplate
+ *
+ * Revision 1.8 1999/04/06 04:54:25 rgb
+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+ * patch shell fixes.
+ *
+ * Revision 1.7 1999/01/26 02:06:00 rgb
+ * Removed CONFIG_IPSEC_ALGO_SWITCH macro.
+ *
+ * Revision 1.6 1999/01/22 15:22:05 rgb
+ * Re-enable IV in the espblkrply_edata structure to avoid breaking pluto
+ * until pluto can be fixed properly.
+ *
+ * Revision 1.5 1999/01/22 06:18:16 rgb
+ * Updated macro comments.
+ * Added key schedule types to support algorithm switch code.
+ *
+ * Revision 1.4 1998/08/12 00:07:32 rgb
+ * Added data structures for new xforms: null, {,3}dessha1.
+ *
+ * Revision 1.3 1998/07/14 15:57:01 rgb
+ * Add #ifdef __KERNEL__ to protect kernel-only structures.
+ *
+ * Revision 1.2 1998/06/25 19:33:46 rgb
+ * Add prototype for protocol receive function.
+ * Rearrange for more logical layout.
+ *
+ * Revision 1.1 1998/06/18 21:27:45 henry
+ * move sources from klips/src to klips/net/ipsec, to keep stupid
+ * kernel-build scripts happier in the presence of symlinks
+ *
+ * Revision 1.6 1998/06/05 02:28:08 rgb
+ * Minor comment fix.
+ *
+ * Revision 1.5 1998/05/27 22:34:00 rgb
+ * Changed structures to accomodate key separation.
+ *
+ * Revision 1.4 1998/05/18 22:28:43 rgb
+ * Disable key printing facilities from /proc/net/ipsec_*.
+ *
+ * Revision 1.3 1998/04/21 21:29:07 rgb
+ * Rearrange debug switches to change on the fly debug output from user
+ * space. Only kernel changes checked in at this time. radij.c was also
+ * changed to temporarily remove buggy debugging code in rj_delete causing
+ * an OOPS and hence, netlink device open errors.
+ *
+ * Revision 1.2 1998/04/12 22:03:20 rgb
+ * Updated ESP-3DES-HMAC-MD5-96,
+ * ESP-DES-HMAC-MD5-96,
+ * AH-HMAC-MD5-96,
+ * AH-HMAC-SHA1-96 since Henry started freeswan cvs repository
+ * from old standards (RFC182[5-9] to new (as of March 1998) drafts.
+ *
+ * Fixed eroute references in /proc/net/ipsec*.
+ *
+ * Started to patch module unloading memory leaks in ipsec_netlink and
+ * radij tree unloading.
+ *
+ * Revision 1.1 1998/04/09 03:06:00 henry
+ * sources moved up from linux/net/ipsec
+ *
+ * Revision 1.1.1.1 1998/04/08 05:35:02 henry
+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
+ *
+ * Revision 0.5 1997/06/03 04:24:48 ji
+ * Added ESP-3DES-MD5-96 transform.
+ *
+ * Revision 0.4 1997/01/15 01:28:15 ji
+ * Added definitions for new ESP transforms.
+ *
+ * Revision 0.3 1996/11/20 14:35:48 ji
+ * Minor Cleanup.
+ * Rationalized debugging code.
+ *
+ * Revision 0.2 1996/11/02 00:18:33 ji
+ * First limited release.
+ *
+ *
+ */
diff --git a/src/libfreeswan/ipsec_ipe4.h b/src/libfreeswan/ipsec_ipe4.h
new file mode 100644
index 000000000..73b6ae899
--- /dev/null
+++ b/src/libfreeswan/ipsec_ipe4.h
@@ -0,0 +1,68 @@
+/*
+ * IP-in-IP Header declarations
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 1999, 2000, 2001 Richard Guy Briggs.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: ipsec_ipe4.h,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+
+/* The packet header is an IP header! */
+
+struct ipe4_xdata /* transform table data */
+{
+ struct in_addr i4_src;
+ struct in_addr i4_dst;
+};
+
+#define EMT_IPE4_ULEN 8 /* coming from user mode */
+
+
+/*
+ * $Log: ipsec_ipe4.h,v $
+ * Revision 1.1 2004/03/15 20:35:25 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.5 2002/04/24 07:36:46 mcr
+ * Moved from ./klips/net/ipsec/ipsec_ipe4.h,v
+ *
+ * Revision 1.4 2001/06/14 19:35:08 rgb
+ * Update copyright date.
+ *
+ * Revision 1.3 1999/04/11 00:28:57 henry
+ * GPL boilerplate
+ *
+ * Revision 1.2 1999/04/06 04:54:25 rgb
+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+ * patch shell fixes.
+ *
+ * Revision 1.1 1998/06/18 21:27:47 henry
+ * move sources from klips/src to klips/net/ipsec, to keep stupid
+ * kernel-build scripts happier in the presence of symlinks
+ *
+ * Revision 1.1 1998/04/09 03:06:07 henry
+ * sources moved up from linux/net/ipsec
+ *
+ * Revision 1.1.1.1 1998/04/08 05:35:03 henry
+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
+ *
+ * Revision 0.4 1997/01/15 01:28:15 ji
+ * No changes.
+ *
+ * Revision 0.3 1996/11/20 14:48:53 ji
+ * Release update only.
+ *
+ * Revision 0.2 1996/11/02 00:18:33 ji
+ * First limited release.
+ *
+ *
+ */
diff --git a/src/libfreeswan/ipsec_kversion.h b/src/libfreeswan/ipsec_kversion.h
new file mode 100644
index 000000000..7bf56ac7f
--- /dev/null
+++ b/src/libfreeswan/ipsec_kversion.h
@@ -0,0 +1,227 @@
+#ifndef _FREESWAN_KVERSIONS_H
+/*
+ * header file for FreeS/WAN library functions
+ * Copyright (C) 1998, 1999, 2000 Henry Spencer.
+ * Copyright (C) 1999, 2000, 2001 Richard Guy Briggs
+ *
+ * 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.
+ *
+ * RCSID $Id: ipsec_kversion.h,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+#define _FREESWAN_KVERSIONS_H /* seen it, no need to see it again */
+
+/*
+ * this file contains a series of atomic defines that depend upon
+ * kernel version numbers. The kernel versions are arranged
+ * in version-order number (which is often not chronological)
+ * and each clause enables or disables a feature.
+ */
+
+/*
+ * First, assorted kernel-version-dependent trickery.
+ */
+#include <linux/version.h>
+#ifndef KERNEL_VERSION
+#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
+#define HEADER_CACHE_BIND_21
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
+#define SPINLOCK
+#define PROC_FS_21
+#define NETLINK_SOCK
+#define NET_21
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,19)
+#define net_device_stats enet_statistics
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+#define SPINLOCK_23
+#define NETDEV_23
+# ifndef CONFIG_IP_ALIAS
+# define CONFIG_IP_ALIAS
+# endif
+#include <linux/socket.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+# ifdef NETLINK_XFRM
+# define NETDEV_25
+# endif
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,25)
+#define PROC_FS_2325
+#undef PROC_FS_21
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,30)
+#define PROC_NO_DUMMY
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,35)
+#define SKB_COPY_EXPAND
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,37)
+#define IP_SELECT_IDENT
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,50)) && defined(CONFIG_NETFILTER)
+#define SKB_RESET_NFCT
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,2)
+#define IP_SELECT_IDENT_NEW
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4)
+#define IPH_is_SKB_PULLED
+#define SKB_COW_NEW
+#define PROTO_HANDLER_SINGLE_PARM
+#define IP_FRAGMENT_LINEARIZE 1
+#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4) */
+# ifdef REDHAT_BOGOSITY
+# define IP_SELECT_IDENT_NEW
+# define IPH_is_SKB_PULLED
+# define SKB_COW_NEW
+# define PROTO_HANDLER_SINGLE_PARM
+# endif /* REDHAT_BOGOSITY */
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4) */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,9)
+#define MALLOC_SLAB
+#define LINUX_KERNEL_HAS_SNPRINTF
+#endif
+
+#ifdef NET_21
+# include <linux/in6.h>
+#else
+ /* old kernel in.h has some IPv6 stuff, but not quite enough */
+# define s6_addr16 s6_addr
+# define AF_INET6 10
+# define uint8_t __u8
+# define uint16_t __u16
+# define uint32_t __u32
+# define uint64_t __u64
+#endif
+
+#ifdef NET_21
+# define ipsec_kfree_skb(a) kfree_skb(a)
+#else /* NET_21 */
+# define ipsec_kfree_skb(a) kfree_skb(a, FREE_WRITE)
+#endif /* NET_21 */
+
+#ifdef NETDEV_23
+# define device net_device
+# define ipsec_dev_get dev_get_by_name
+# define __ipsec_dev_get __dev_get_by_name
+# define ipsec_dev_put(x) dev_put(x)
+# define __ipsec_dev_put(x) __dev_put(x)
+# define ipsec_dev_hold(x) dev_hold(x)
+#else /* NETDEV_23 */
+# define ipsec_dev_get dev_get
+# define __ipsec_dev_put(x)
+# define ipsec_dev_put(x)
+# define ipsec_dev_hold(x)
+#endif /* NETDEV_23 */
+
+#ifndef SPINLOCK
+# include <linux/bios32.h>
+ /* simulate spin locks and read/write locks */
+ typedef struct {
+ volatile char lock;
+ } spinlock_t;
+
+ typedef struct {
+ volatile unsigned int lock;
+ } rwlock_t;
+
+# define spin_lock_init(x) { (x)->lock = 0;}
+# define rw_lock_init(x) { (x)->lock = 0; }
+
+# define spin_lock(x) { while ((x)->lock) barrier(); (x)->lock=1;}
+# define spin_lock_irq(x) { cli(); spin_lock(x);}
+# define spin_lock_irqsave(x,flags) { save_flags(flags); spin_lock_irq(x);}
+
+# define spin_unlock(x) { (x)->lock=0;}
+# define spin_unlock_irq(x) { spin_unlock(x); sti();}
+# define spin_unlock_irqrestore(x,flags) { spin_unlock(x); restore_flags(flags);}
+
+# define read_lock(x) spin_lock(x)
+# define read_lock_irq(x) spin_lock_irq(x)
+# define read_lock_irqsave(x,flags) spin_lock_irqsave(x,flags)
+
+# define read_unlock(x) spin_unlock(x)
+# define read_unlock_irq(x) spin_unlock_irq(x)
+# define read_unlock_irqrestore(x,flags) spin_unlock_irqrestore(x,flags)
+
+# define write_lock(x) spin_lock(x)
+# define write_lock_irq(x) spin_lock_irq(x)
+# define write_lock_irqsave(x,flags) spin_lock_irqsave(x,flags)
+
+# define write_unlock(x) spin_unlock(x)
+# define write_unlock_irq(x) spin_unlock_irq(x)
+# define write_unlock_irqrestore(x,flags) spin_unlock_irqrestore(x,flags)
+#endif /* !SPINLOCK */
+
+#ifndef SPINLOCK_23
+# define spin_lock_bh(x) spin_lock_irq(x)
+# define spin_unlock_bh(x) spin_unlock_irq(x)
+
+# define read_lock_bh(x) read_lock_irq(x)
+# define read_unlock_bh(x) read_unlock_irq(x)
+
+# define write_lock_bh(x) write_lock_irq(x)
+# define write_unlock_bh(x) write_unlock_irq(x)
+#endif /* !SPINLOCK_23 */
+
+#endif /* _FREESWAN_KVERSIONS_H */
+
+/*
+ * $Log: ipsec_kversion.h,v $
+ * Revision 1.1 2004/03/15 20:35:25 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.7 2003/07/31 22:48:08 mcr
+ * derive NET25-ness from presence of NETLINK_XFRM macro.
+ *
+ * Revision 1.6 2003/06/24 20:22:32 mcr
+ * added new global: ipsecdevices[] so that we can keep track of
+ * the ipsecX devices. They will be referenced with dev_hold(),
+ * so 2.2 may need this as well.
+ *
+ * Revision 1.5 2003/04/03 17:38:09 rgb
+ * Centralised ipsec_kfree_skb and ipsec_dev_{get,put}.
+ *
+ * Revision 1.4 2002/04/24 07:36:46 mcr
+ * Moved from ./klips/net/ipsec/ipsec_kversion.h,v
+ *
+ * Revision 1.3 2002/04/12 03:21:17 mcr
+ * three parameter version of ip_select_ident appears first
+ * in 2.4.2 (RH7.1) not 2.4.4.
+ *
+ * Revision 1.2 2002/03/08 21:35:22 rgb
+ * Defined LINUX_KERNEL_HAS_SNPRINTF to shut up compiler warnings after
+ * 2.4.9. (Andreas Piesk).
+ *
+ * Revision 1.1 2002/01/29 02:11:42 mcr
+ * removal of kversions.h - sources that needed it now use ipsec_param.h.
+ * updating of IPv6 structures to match latest in6.h version.
+ * removed dead code from freeswan.h that also duplicated kversions.h
+ * code.
+ *
+ *
+ */
diff --git a/src/libfreeswan/ipsec_life.h b/src/libfreeswan/ipsec_life.h
new file mode 100644
index 000000000..4cf270272
--- /dev/null
+++ b/src/libfreeswan/ipsec_life.h
@@ -0,0 +1,112 @@
+/*
+ * Definitions relevant to IPSEC lifetimes
+ * Copyright (C) 2001 Richard Guy Briggs <rgb@freeswan.org>
+ * and Michael Richardson <mcr@freeswan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: ipsec_life.h,v 1.1 2004/03/15 20:35:25 as Exp $
+ *
+ * This file derived from ipsec_xform.h on 2001/9/18 by mcr.
+ *
+ */
+
+/*
+ * This file describes the book keeping fields for the
+ * IPsec Security Association Structure. ("ipsec_sa")
+ *
+ * This structure is never allocated directly by kernel code,
+ * (it is always a static/auto or is part of a structure)
+ * so it does not have a reference count.
+ *
+ */
+
+#ifndef _IPSEC_LIFE_H_
+
+/*
+ * _count is total count.
+ * _hard is hard limit (kill SA after this number)
+ * _soft is soft limit (try to renew SA after this number)
+ * _last is used in some special cases.
+ *
+ */
+
+struct ipsec_lifetime64
+{
+ __u64 ipl_count;
+ __u64 ipl_soft;
+ __u64 ipl_hard;
+ __u64 ipl_last;
+};
+
+struct ipsec_lifetimes
+{
+ /* number of bytes processed */
+ struct ipsec_lifetime64 ipl_bytes;
+
+ /* number of packets processed */
+ struct ipsec_lifetime64 ipl_packets;
+
+ /* time since SA was added */
+ struct ipsec_lifetime64 ipl_addtime;
+
+ /* time since SA was first used */
+ struct ipsec_lifetime64 ipl_usetime;
+
+ /* from rfc2367:
+ * For CURRENT, the number of different connections,
+ * endpoints, or flows that the association has been
+ * allocated towards. For HARD and SOFT, the number of
+ * these the association may be allocated towards
+ * before it expires. The concept of a connection,
+ * flow, or endpoint is system specific.
+ *
+ * mcr(2001-9-18) it is unclear what purpose these serve for FreeSWAN.
+ * They are maintained for PF_KEY compatibility.
+ */
+ struct ipsec_lifetime64 ipl_allocations;
+};
+
+enum ipsec_life_alive {
+ ipsec_life_harddied = -1,
+ ipsec_life_softdied = 0,
+ ipsec_life_okay = 1
+};
+
+enum ipsec_life_type {
+ ipsec_life_timebased = 1,
+ ipsec_life_countbased= 0
+};
+
+#define _IPSEC_LIFE_H_
+#endif /* _IPSEC_LIFE_H_ */
+
+
+/*
+ * $Log: ipsec_life.h,v $
+ * Revision 1.1 2004/03/15 20:35:25 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.3 2002/04/24 07:36:46 mcr
+ * Moved from ./klips/net/ipsec/ipsec_life.h,v
+ *
+ * Revision 1.2 2001/11/26 09:16:14 rgb
+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
+ *
+ * Revision 1.1.2.1 2001/09/25 02:25:58 mcr
+ * lifetime structure created and common functions created.
+ *
+ *
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ *
+ */
diff --git a/src/libfreeswan/ipsec_md5h.h b/src/libfreeswan/ipsec_md5h.h
new file mode 100644
index 000000000..3fc54bc82
--- /dev/null
+++ b/src/libfreeswan/ipsec_md5h.h
@@ -0,0 +1,140 @@
+/*
+ * RCSID $Id: ipsec_md5h.h,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+
+/*
+ * The rest of this file is Copyright RSA DSI. See the following comments
+ * for the full Copyright notice.
+ */
+
+#ifndef _IPSEC_MD5H_H_
+#define _IPSEC_MD5H_H_
+
+/* GLOBAL.H - RSAREF types and constants
+ */
+
+/* PROTOTYPES should be set to one if and only if the compiler supports
+ function argument prototyping.
+ The following makes PROTOTYPES default to 0 if it has not already
+ been defined with C compiler flags.
+ */
+#ifndef PROTOTYPES
+#define PROTOTYPES 1
+#endif /* !PROTOTYPES */
+
+/* POINTER defines a generic pointer type */
+typedef __u8 *POINTER;
+
+/* UINT2 defines a two byte word */
+typedef __u16 UINT2;
+
+/* UINT4 defines a four byte word */
+typedef __u32 UINT4;
+
+/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
+ If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
+ returns an empty list.
+ */
+
+#if PROTOTYPES
+#define PROTO_LIST(list) list
+#else /* PROTOTYPES */
+#define PROTO_LIST(list) ()
+#endif /* PROTOTYPES */
+
+
+/* MD5.H - header file for MD5C.C
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+/* MD5 context. */
+typedef struct {
+ UINT4 state[4]; /* state (ABCD) */
+ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[64]; /* input buffer */
+} MD5_CTX;
+
+void MD5Init PROTO_LIST ((void *));
+void MD5Update PROTO_LIST
+ ((void *, unsigned char *, __u32));
+void MD5Final PROTO_LIST ((unsigned char [16], void *));
+
+#endif /* _IPSEC_MD5H_H_ */
+
+/*
+ * $Log: ipsec_md5h.h,v $
+ * Revision 1.1 2004/03/15 20:35:25 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.8 2002/09/10 01:45:09 mcr
+ * changed type of MD5_CTX and SHA1_CTX to void * so that
+ * the function prototypes would match, and could be placed
+ * into a pointer to a function.
+ *
+ * Revision 1.7 2002/04/24 07:36:46 mcr
+ * Moved from ./klips/net/ipsec/ipsec_md5h.h,v
+ *
+ * Revision 1.6 1999/12/13 13:59:13 rgb
+ * Quick fix to argument size to Update bugs.
+ *
+ * Revision 1.5 1999/12/07 18:16:23 rgb
+ * Fixed comments at end of #endif lines.
+ *
+ * Revision 1.4 1999/04/06 04:54:26 rgb
+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+ * patch shell fixes.
+ *
+ * Revision 1.3 1999/01/22 06:19:58 rgb
+ * 64-bit clean-up.
+ *
+ * Revision 1.2 1998/11/30 13:22:54 rgb
+ * Rationalised all the klips kernel file headers. They are much shorter
+ * now and won't conflict under RH5.2.
+ *
+ * Revision 1.1 1998/06/18 21:27:48 henry
+ * move sources from klips/src to klips/net/ipsec, to keep stupid
+ * kernel-build scripts happier in the presence of symlinks
+ *
+ * Revision 1.2 1998/04/23 20:54:03 rgb
+ * Fixed md5 and sha1 include file nesting issues, to be cleaned up when
+ * verified.
+ *
+ * Revision 1.1 1998/04/09 03:04:21 henry
+ * sources moved up from linux/net/ipsec
+ * these two include files modified not to include others except in kernel
+ *
+ * Revision 1.1.1.1 1998/04/08 05:35:03 henry
+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
+ *
+ * Revision 0.4 1997/01/15 01:28:15 ji
+ * No changes.
+ *
+ * Revision 0.3 1996/11/20 14:48:53 ji
+ * Release update only.
+ *
+ * Revision 0.2 1996/11/02 00:18:33 ji
+ * First limited release.
+ *
+ *
+ */
diff --git a/src/libfreeswan/ipsec_param.h b/src/libfreeswan/ipsec_param.h
new file mode 100644
index 000000000..02b36e6a3
--- /dev/null
+++ b/src/libfreeswan/ipsec_param.h
@@ -0,0 +1,226 @@
+/*
+ * @(#) FreeSWAN tunable paramaters
+ *
+ * Copyright (C) 2001 Richard Guy Briggs <rgb@freeswan.org>
+ * and Michael Richardson <mcr@freeswan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: ipsec_param.h,v 1.2 2004/04/28 08:07:11 as Exp $
+ *
+ */
+
+/*
+ * This file provides a set of #define's which may be tuned by various
+ * people/configurations. It keeps all compile-time tunables in one place.
+ *
+ * This file should be included before all other IPsec kernel-only files.
+ *
+ */
+
+#ifndef _IPSEC_PARAM_H_
+
+#ifdef __KERNEL__
+#include "ipsec_kversion.h"
+
+/* Set number of ipsecX virtual devices here. */
+/* This must be < exp(field width of IPSEC_DEV_FORMAT) */
+/* It must also be reasonable so as not to overload the memory and CPU */
+/* constraints of the host. */
+#define IPSEC_NUM_IF 4
+/* The field width must be < IF_NAM_SIZ - strlen("ipsec") - 1. */
+/* With "ipsec" being 5 characters, that means 10 is the max field width */
+/* but machine memory and CPU constraints are not likely to tollerate */
+/* more than 3 digits. The default is one digit. */
+/* Update: userland scripts get upset if they can't find "ipsec0", so */
+/* for now, no "0"-padding should be used (which would have been helpful */
+/* to make text-searches work */
+#define IPSEC_DEV_FORMAT "ipsec%d"
+/* For, say, 500 virtual ipsec devices, I would recommend: */
+/* #define IPSEC_NUM_IF 500 */
+/* #define IPSEC_DEV_FORMAT "ipsec%03d" */
+/* Note that the "interfaces=" line in /etc/ipsec.conf would be, um, challenging. */
+
+/* use dynamic ipsecX device allocation */
+#ifndef CONFIG_IPSEC_DYNDEV
+#define CONFIG_IPSEC_DYNDEV 1
+#endif /* CONFIG_IPSEC_DYNDEV */
+
+
+#ifdef CONFIG_IPSEC_BIGGATE
+# define SADB_HASHMOD 8069
+#else /* CONFIG_IPSEC_BIGGATE */
+# define SADB_HASHMOD 257
+#endif /* CONFIG_IPSEC_BIGGATE */
+#endif /* __KERNEL__ */
+
+/*
+ * This is for the SA reference table. This number is related to the
+ * maximum number of SAs that KLIPS can concurrently deal with, plus enough
+ * space for keeping expired SAs around.
+ *
+ * TABLE_MAX_WIDTH is the number of bits that we will use.
+ * MAIN_TABLE_WIDTH is the number of bits used for the primary index table.
+ *
+ */
+#ifndef IPSEC_SA_REF_TABLE_IDX_WIDTH
+# define IPSEC_SA_REF_TABLE_IDX_WIDTH 16
+#endif
+
+#ifndef IPSEC_SA_REF_MAINTABLE_IDX_WIDTH
+# define IPSEC_SA_REF_MAINTABLE_IDX_WIDTH 4
+#endif
+
+#ifndef IPSEC_SA_REF_FREELIST_NUM_ENTRIES
+# define IPSEC_SA_REF_FREELIST_NUM_ENTRIES 256
+#endif
+
+#ifndef IPSEC_SA_REF_CODE
+# define IPSEC_SA_REF_CODE 1
+#endif
+
+#ifdef __KERNEL__
+/* This is defined for 2.4, but not 2.2.... */
+#ifndef ARPHRD_VOID
+# define ARPHRD_VOID 0xFFFF
+#endif
+
+/*
+ * Worry about PROC_FS stuff
+ */
+#if defined(PROC_FS_2325)
+/* kernel 2.4 */
+# define IPSEC_PROC_LAST_ARG ,int *eof,void *data
+# define IPSEC_PROCFS_DEBUG_NO_STATIC
+# define IPSEC_PROC_SUBDIRS
+#else
+/* kernel <2.4 */
+# define IPSEC_PROCFS_DEBUG_NO_STATIC DEBUG_NO_STATIC
+
+# ifndef PROC_NO_DUMMY
+# define IPSEC_PROC_LAST_ARG , int dummy
+# else
+# define IPSEC_PROC_LAST_ARG
+# endif /* !PROC_NO_DUMMY */
+#endif /* PROC_FS_2325 */
+
+#if !defined(LINUX_KERNEL_HAS_SNPRINTF)
+/* GNU CPP specific! */
+# define snprintf(buf, len, fmt...) sprintf(buf, ##fmt)
+#endif /* !LINUX_KERNEL_HAS_SNPRINTF */
+
+#ifdef SPINLOCK
+# ifdef SPINLOCK_23
+# include <linux/spinlock.h> /* *lock* */
+# else /* SPINLOCK_23 */
+# include <asm/spinlock.h> /* *lock* */
+# endif /* SPINLOCK_23 */
+#endif /* SPINLOCK */
+
+#ifndef KLIPS_FIXES_DES_PARITY
+# define KLIPS_FIXES_DES_PARITY 1
+#endif /* !KLIPS_FIXES_DES_PARITY */
+
+/* we don't really want to print these unless there are really big problems */
+#ifndef KLIPS_DIVULGE_CYPHER_KEY
+# define KLIPS_DIVULGE_CYPHER_KEY 0
+#endif /* !KLIPS_DIVULGE_CYPHER_KEY */
+
+#ifndef KLIPS_DIVULGE_HMAC_KEY
+# define KLIPS_DIVULGE_HMAC_KEY 0
+#endif /* !KLIPS_DIVULGE_HMAC_KEY */
+
+#ifndef IPSEC_DISALLOW_IPOPTIONS
+# define IPSEC_DISALLOW_IPOPTIONS 1
+#endif /* !KLIPS_DIVULGE_HMAC_KEY */
+
+/* extra toggles for regression testing */
+#ifdef CONFIG_IPSEC_REGRESS
+
+/*
+ * should pfkey_acquire() become 100% lossy?
+ *
+ */
+extern int sysctl_ipsec_regress_pfkey_lossage;
+#ifndef KLIPS_PFKEY_ACQUIRE_LOSSAGE
+# ifdef CONFIG_IPSEC_PFKEY_ACQUIRE_LOSSAGE
+# define KLIPS_PFKEY_ACQUIRE_LOSSAGE 100
+# else /* CONFIG_IPSEC_PFKEY_ACQUIRE_LOSSAGE */
+/* not by default! */
+# define KLIPS_PFKEY_ACQUIRE_LOSSAGE 0
+# endif /* CONFIG_IPSEC_PFKEY_ACQUIRE_LOSSAGE */
+#endif /* KLIPS_PFKEY_ACQUIRE_LOSSAGE */
+
+#endif /* CONFIG_IPSEC_REGRESS */
+
+/*
+ * debugging routines.
+ */
+#ifdef CONFIG_IPSEC_DEBUG
+extern void ipsec_print_ip(struct iphdr *ip);
+
+ #define KLIPS_PRINT(flag, format, args...) \
+ ((flag) ? printk(KERN_INFO format , ## args) : 0)
+ #define KLIPS_PRINTMORE(flag, format, args...) \
+ ((flag) ? printk(format , ## args) : 0)
+ #define KLIPS_IP_PRINT(flag, ip) \
+ ((flag) ? ipsec_print_ip(ip) : 0)
+#else /* CONFIG_IPSEC_DEBUG */
+ #define KLIPS_PRINT(flag, format, args...) do ; while(0)
+ #define KLIPS_PRINTMORE(flag, format, args...) do ; while(0)
+ #define KLIPS_IP_PRINT(flag, ip) do ; while(0)
+#endif /* CONFIG_IPSEC_DEBUG */
+
+
+/*
+ * Stupid kernel API differences in APIs. Not only do some
+ * kernels not have ip_select_ident, but some have differing APIs,
+ * and SuSE has one with one parameter, but no way of checking to
+ * see what is really what.
+ */
+
+#ifdef SUSE_LINUX_2_4_19_IS_STUPID
+#define KLIPS_IP_SELECT_IDENT(iph, skb) ip_select_ident(iph)
+#else
+
+/* simplest case, nothing */
+#if !defined(IP_SELECT_IDENT)
+#define KLIPS_IP_SELECT_IDENT(iph, skb) do { iph->id = htons(ip_id_count++); } while(0)
+#endif
+
+/* kernels > 2.3.37-ish */
+#if defined(IP_SELECT_IDENT) && !defined(IP_SELECT_IDENT_NEW)
+#define KLIPS_IP_SELECT_IDENT(iph, skb) ip_select_ident(iph, skb->dst)
+#endif
+
+/* kernels > 2.4.2 */
+#if defined(IP_SELECT_IDENT) && defined(IP_SELECT_IDENT_NEW)
+#define KLIPS_IP_SELECT_IDENT(iph, skb) ip_select_ident(iph, skb->dst, NULL)
+#endif
+
+#endif /* SUSE_LINUX_2_4_19_IS_STUPID */
+
+/*
+ * make klips fail test:east-espiv-01.
+ * exploit is at testing/attacks/espiv
+ *
+ */
+#define KLIPS_IMPAIRMENT_ESPIV_CBC_ATTACK 0
+
+
+/* IP_FRAGMENT_LINEARIZE is set in freeswan.h if Kernel > 2.4.4 */
+#ifndef IP_FRAGMENT_LINEARIZE
+# define IP_FRAGMENT_LINEARIZE 0
+#endif /* IP_FRAGMENT_LINEARIZE */
+#endif /* __KERNEL__ */
+
+#define _IPSEC_PARAM_H_
+#endif /* _IPSEC_PARAM_H_ */
diff --git a/src/libfreeswan/ipsec_policy.h b/src/libfreeswan/ipsec_policy.h
new file mode 100644
index 000000000..671919e4b
--- /dev/null
+++ b/src/libfreeswan/ipsec_policy.h
@@ -0,0 +1,225 @@
+#ifndef _IPSEC_POLICY_H
+/*
+ * policy interface file between pluto and applications
+ * Copyright (C) 2003 Michael Richardson <mcr@freeswan.org>
+ *
+ * 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.
+ *
+ * RCSID $Id: ipsec_policy.h,v 1.4 2004/10/04 22:43:56 as Exp $
+ */
+#define _IPSEC_POLICY_H /* seen it, no need to see it again */
+
+
+/*
+ * this file defines an interface between an application (or rather an
+ * application library) and a key/policy daemon. It provides for inquiries
+ * as to the current state of a connected socket, as well as for general
+ * questions.
+ *
+ * In general, the interface is defined as a series of functional interfaces,
+ * and the policy messages should be internal. However, because this is in
+ * fact an ABI between pieces of the system that may get compiled and revised
+ * seperately, this ABI must be public and revision controlled.
+ *
+ * It is expected that the daemon will always support previous versions.
+ */
+
+#define IPSEC_POLICY_MSG_REVISION (unsigned)200305061
+
+enum ipsec_policy_command {
+ IPSEC_CMD_QUERY_FD = 1,
+ IPSEC_CMD_QUERY_HOSTPAIR = 2,
+ IPSEC_CMD_QUERY_DSTONLY = 3,
+};
+
+struct ipsec_policy_msg_head {
+ u_int32_t ipm_version;
+ u_int32_t ipm_msg_len;
+ u_int32_t ipm_msg_type;
+ u_int32_t ipm_msg_seq;
+};
+
+enum ipsec_privacy_quality {
+ IPSEC_PRIVACY_NONE = 0,
+ IPSEC_PRIVACY_INTEGRAL = 4, /* not private at all. AH-like */
+ IPSEC_PRIVACY_UNKNOWN = 8, /* something is claimed, but details unavail */
+ IPSEC_PRIVACY_ROT13 = 12, /* trivially breakable, i.e. 1DES */
+ IPSEC_PRIVACY_GAK = 16, /* known eavesdroppers */
+ IPSEC_PRIVACY_PRIVATE = 32, /* secure for at least a decade */
+ IPSEC_PRIVACY_STRONG = 64, /* ridiculously secure */
+ IPSEC_PRIVACY_TORTOISE = 192, /* even stronger, but very slow */
+ IPSEC_PRIVACY_OTP = 224, /* some kind of *true* one time pad */
+};
+
+enum ipsec_bandwidth_quality {
+ IPSEC_QOS_UNKNOWN = 0, /* unknown bandwidth */
+ IPSEC_QOS_INTERACTIVE = 16, /* reasonably moderate jitter, moderate fast.
+ Good enough for telnet/ssh. */
+ IPSEC_QOS_VOIP = 32, /* faster crypto, predicable jitter */
+ IPSEC_QOS_FTP = 64, /* higher throughput crypto, perhaps hardware
+ offloaded, but latency/jitter may be bad */
+ IPSEC_QOS_WIRESPEED = 128, /* expect to be able to fill your pipe */
+};
+
+/* moved from programs/pluto/constants.h */
+/* IPsec AH transform values
+ * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.4.3
+ * and in http://www.iana.org/assignments/isakmp-registry
+ */
+enum ipsec_authentication_algo {
+ AH_NONE = 0,
+ AH_MD5 = 2,
+ AH_SHA = 3,
+ AH_DES = 4,
+ AH_SHA2_256 = 5,
+ AH_SHA2_384 = 6,
+ AH_SHA2_512 = 7,
+ AH_RIPEMD = 8
+};
+
+/* IPsec ESP transform values
+ * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.4.4
+ * and from http://www.iana.org/assignments/isakmp-registry
+ */
+
+enum ipsec_cipher_algo {
+ ESP_NONE = 0,
+ ESP_DES_IV64 = 1,
+ ESP_DES = 2,
+ ESP_3DES = 3,
+ ESP_RC5 = 4,
+ ESP_IDEA = 5,
+ ESP_CAST = 6,
+ ESP_BLOWFISH = 7,
+ ESP_3IDEA = 8,
+ ESP_DES_IV32 = 9,
+ ESP_RC4 = 10,
+ ESP_NULL = 11,
+ ESP_AES = 12,
+ ESP_AES_CTR = 13,
+ ESP_AES_CCM_8 = 14,
+ ESP_AES_CCM_12 = 15,
+ ESP_AES_CCM_16 = 16,
+ ESP_SERPENT = 252,
+ ESP_TWOFISH = 253
+};
+
+/* IPCOMP transform values
+ * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.4.5
+ */
+
+enum ipsec_comp_algo {
+ IPSCOMP_NONE = 0,
+ IPCOMP_OUI = 1,
+ IPCOMP_DEFLATE = 2,
+ IPCOMP_LZS = 3,
+ IPCOMP_LZJH = 4
+};
+
+/* Identification type values
+ * RFC 2407 The Internet IP security Domain of Interpretation for ISAKMP 4.6.2.1
+ */
+
+enum ipsec_id_type {
+ ID_IMPOSSIBLE= (-2), /* private to Pluto */
+ ID_MYID= (-1), /* private to Pluto */
+ ID_NONE= 0, /* private to Pluto */
+ ID_IPV4_ADDR= 1,
+ ID_FQDN= 2,
+ ID_USER_FQDN= 3,
+ ID_IPV4_ADDR_SUBNET= 4,
+ ID_IPV6_ADDR= 5,
+ ID_IPV6_ADDR_SUBNET= 6,
+ ID_IPV4_ADDR_RANGE= 7,
+ ID_IPV6_ADDR_RANGE= 8,
+ ID_DER_ASN1_DN= 9,
+ ID_DER_ASN1_GN= 10,
+ ID_KEY_ID= 11
+};
+
+/* Certificate type values
+ * RFC 2408 ISAKMP, chapter 3.9
+ */
+enum ipsec_cert_type {
+ CERT_NONE= 0,
+ CERT_PKCS7_WRAPPED_X509= 1,
+ CERT_PGP= 2,
+ CERT_DNS_SIGNED_KEY= 3,
+ CERT_X509_SIGNATURE= 4,
+ CERT_X509_KEY_EXCHANGE= 5,
+ CERT_KERBEROS_TOKENS= 6,
+ CERT_CRL= 7,
+ CERT_ARL= 8,
+ CERT_SPKI= 9,
+ CERT_X509_ATTRIBUTE= 10,
+ CERT_RAW_RSA_KEY= 11
+};
+
+/* a SIG record in ASCII */
+struct ipsec_dns_sig {
+ char fqdn[256];
+ char dns_sig[768]; /* empty string if not signed */
+};
+
+struct ipsec_raw_key {
+ char id_name[256];
+ char fs_keyid[8];
+};
+
+struct ipsec_identity {
+ enum ipsec_id_type ii_type;
+ enum ipsec_cert_type ii_format;
+ union {
+ struct ipsec_dns_sig ipsec_dns_signed;
+ /* some thing for PGP */
+ /* some thing for PKIX */
+ struct ipsec_raw_key ipsec_raw_key;
+ } ii_credential;
+};
+
+#define IPSEC_MAX_CREDENTIALS 32
+
+struct ipsec_policy_cmd_query {
+ struct ipsec_policy_msg_head head;
+
+ /* Query section */
+ ip_address query_local; /* us */
+ ip_address query_remote; /* them */
+ u_short src_port, dst_port;
+
+ /* Answer section */
+ enum ipsec_privacy_quality strength;
+ enum ipsec_bandwidth_quality bandwidth;
+ enum ipsec_authentication_algo auth_detail;
+ enum ipsec_cipher_algo esp_detail;
+ enum ipsec_comp_algo comp_detail;
+
+ int credential_count;
+
+ struct ipsec_identity credentials[IPSEC_MAX_CREDENTIALS];
+};
+
+#define IPSEC_POLICY_SOCKET "/var/run/pluto.info"
+
+/* prototypes */
+extern err_t ipsec_policy_lookup(int fd, struct ipsec_policy_cmd_query *result);
+extern err_t ipsec_policy_init(void);
+extern err_t ipsec_policy_final(void);
+extern err_t ipsec_policy_readmsg(int policysock,
+ unsigned char *buf, size_t buflen);
+extern err_t ipsec_policy_sendrecv(unsigned char *buf, size_t buflen);
+extern err_t ipsec_policy_cgilookup(struct ipsec_policy_cmd_query *result);
+
+
+extern const char *ipsec_policy_version_code(void);
+extern const char *ipsec_policy_version_string(void);
+
+#endif /* _IPSEC_POLICY_H */
diff --git a/src/libfreeswan/ipsec_proto.h b/src/libfreeswan/ipsec_proto.h
new file mode 100644
index 000000000..55f947512
--- /dev/null
+++ b/src/libfreeswan/ipsec_proto.h
@@ -0,0 +1,111 @@
+/*
+ * @(#) prototypes for FreeSWAN functions
+ *
+ * Copyright (C) 2001 Richard Guy Briggs <rgb@freeswan.org>
+ * and Michael Richardson <mcr@freeswan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: ipsec_proto.h,v 1.3 2004/06/13 19:55:14 as Exp $
+ *
+ */
+
+#ifndef _IPSEC_PROTO_H_
+
+#include "ipsec_param.h"
+
+/*
+ * This file is a kernel only file that declares prototypes for
+ * all intra-module function calls and global data structures.
+ *
+ * Include this file last.
+ *
+ */
+
+/* ipsec_init.c */
+extern struct prng ipsec_prng;
+
+/* ipsec_sa.c */
+extern struct ipsec_sa *ipsec_sadb_hash[SADB_HASHMOD];
+extern spinlock_t tdb_lock;
+extern int ipsec_sadb_init(void);
+
+extern struct ipsec_sa *ipsec_sa_getbyid(struct sa_id*);
+extern int ipsec_sa_put(struct ipsec_sa *);
+extern /* void */ int ipsec_sa_del(struct ipsec_sa *);
+extern /* void */ int ipsec_sa_delchain(struct ipsec_sa *);
+extern /* void */ int ipsec_sa_add(struct ipsec_sa *);
+
+extern int ipsec_sadb_cleanup(__u8);
+extern int ipsec_sa_wipe(struct ipsec_sa *);
+
+/* debug declarations */
+
+/* ipsec_proc.c */
+extern int ipsec_proc_init(void);
+extern void ipsec_proc_cleanup(void);
+
+/* ipsec_radij.c */
+extern int ipsec_makeroute(struct sockaddr_encap *ea,
+ struct sockaddr_encap *em,
+ struct sa_id said,
+ uint32_t pid,
+ struct sk_buff *skb,
+ struct ident *ident_s,
+ struct ident *ident_d);
+
+extern int ipsec_breakroute(struct sockaddr_encap *ea,
+ struct sockaddr_encap *em,
+ struct sk_buff **first,
+ struct sk_buff **last);
+
+int ipsec_radijinit(void);
+int ipsec_cleareroutes(void);
+int ipsec_radijcleanup(void);
+
+/* ipsec_life.c */
+extern enum ipsec_life_alive ipsec_lifetime_check(struct ipsec_lifetime64 *il64,
+ const char *lifename,
+ const char *saname,
+ enum ipsec_life_type ilt,
+ enum ipsec_direction idir,
+ struct ipsec_sa *ips);
+
+
+extern int ipsec_lifetime_format(char *buffer,
+ int buflen,
+ char *lifename,
+ enum ipsec_life_type timebaselife,
+ struct ipsec_lifetime64 *lifetime);
+
+extern void ipsec_lifetime_update_hard(struct ipsec_lifetime64 *lifetime,
+ __u64 newvalue);
+
+extern void ipsec_lifetime_update_soft(struct ipsec_lifetime64 *lifetime,
+ __u64 newvalue);
+
+
+
+
+#ifdef CONFIG_IPSEC_DEBUG
+
+extern int debug_xform;
+extern int debug_eroute;
+extern int debug_spi;
+extern int debug_netlink;
+
+#endif /* CONFIG_IPSEC_DEBUG */
+
+
+
+
+#define _IPSEC_PROTO_H
+#endif /* _IPSEC_PROTO_H_ */
diff --git a/src/libfreeswan/ipsec_radij.h b/src/libfreeswan/ipsec_radij.h
new file mode 100644
index 000000000..7776dd8e4
--- /dev/null
+++ b/src/libfreeswan/ipsec_radij.h
@@ -0,0 +1,63 @@
+/*
+ * @(#) Definitions relevant to the IPSEC <> radij tree interfacing
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 1999, 2000, 2001 Richard Guy Briggs.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: ipsec_radij.h,v 1.3 2004/04/28 05:44:29 as Exp $
+ */
+
+#ifndef _IPSEC_RADIJ_H
+
+#include <freeswan.h>
+
+int ipsec_walk(char *);
+
+int ipsec_rj_walker_procprint(struct radij_node *, void *);
+int ipsec_rj_walker_delete(struct radij_node *, void *);
+
+/* This structure is used to pass information between
+ * ipsec_eroute_get_info and ipsec_rj_walker_procprint
+ * (through rj_walktree) and between calls of ipsec_rj_walker_procprint.
+ */
+struct wsbuf
+{
+ /* from caller of ipsec_eroute_get_info: */
+ char *const buffer; /* start of buffer provided */
+ const int length; /* length of buffer provided */
+ const off_t offset; /* file position of first character of interest */
+ /* accumulated by ipsec_rj_walker_procprint: */
+ int len; /* number of character filled into buffer */
+ off_t begin; /* file position contained in buffer[0] (<=offset) */
+};
+
+
+extern struct radij_node_head *rnh;
+extern spinlock_t eroute_lock;
+
+struct eroute * ipsec_findroute(struct sockaddr_encap *);
+
+#define O1(x) (int)(((x)>>24)&0xff)
+#define O2(x) (int)(((x)>>16)&0xff)
+#define O3(x) (int)(((x)>>8)&0xff)
+#define O4(x) (int)(((x))&0xff)
+
+#ifdef CONFIG_IPSEC_DEBUG
+extern int debug_radij;
+void rj_dumptrees(void);
+
+#define DB_RJ_DUMPTREES 0x0001
+#define DB_RJ_FINDROUTE 0x0002
+#endif /* CONFIG_IPSEC_DEBUG */
+
+#define _IPSEC_RADIJ_H
+#endif
diff --git a/src/libfreeswan/ipsec_rcv.h b/src/libfreeswan/ipsec_rcv.h
new file mode 100644
index 000000000..3ae239bf9
--- /dev/null
+++ b/src/libfreeswan/ipsec_rcv.h
@@ -0,0 +1,196 @@
+/*
+ *
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 1999, 2000, 2001 Richard Guy Briggs.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: ipsec_rcv.h,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+
+#define DB_RX_PKTRX 0x0001
+#define DB_RX_PKTRX2 0x0002
+#define DB_RX_DMP 0x0004
+#define DB_RX_IPSA 0x0010
+#define DB_RX_XF 0x0020
+#define DB_RX_IPAD 0x0040
+#define DB_RX_INAU 0x0080
+#define DB_RX_OINFO 0x0100
+#define DB_RX_OINFO2 0x0200
+#define DB_RX_OH 0x0400
+#define DB_RX_REPLAY 0x0800
+
+#ifdef __KERNEL__
+/* struct options; */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/config.h> /* for CONFIG_IP_FORWARD */
+#include <linux/version.h>
+#include <freeswan.h>
+
+#define IPSEC_BIRTH_TEMPLATE_MAXLEN 256
+
+struct ipsec_birth_reply {
+ int packet_template_len;
+ unsigned char packet_template[IPSEC_BIRTH_TEMPLATE_MAXLEN];
+};
+
+extern struct ipsec_birth_reply ipsec_ipv4_birth_packet;
+extern struct ipsec_birth_reply ipsec_ipv6_birth_packet;
+
+extern int
+#ifdef PROTO_HANDLER_SINGLE_PARM
+ipsec_rcv(struct sk_buff *skb);
+#else /* PROTO_HANDLER_SINGLE_PARM */
+ipsec_rcv(struct sk_buff *skb,
+#ifdef NET_21
+ unsigned short xlen);
+#else /* NET_21 */
+ struct device *dev,
+ struct options *opt,
+ __u32 daddr,
+ unsigned short len,
+ __u32 saddr,
+ int redo,
+ struct inet_protocol *protocol);
+#endif /* NET_21 */
+#endif /* PROTO_HANDLER_SINGLE_PARM */
+
+#ifdef CONFIG_IPSEC_DEBUG
+extern int debug_rcv;
+#endif /* CONFIG_IPSEC_DEBUG */
+extern int sysctl_ipsec_inbound_policy_check;
+#endif /* __KERNEL__ */
+
+/*
+ * $Log: ipsec_rcv.h,v $
+ * Revision 1.1 2004/03/15 20:35:25 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.17 2002/09/03 16:32:32 mcr
+ * definitions of ipsec_birth_reply.
+ *
+ * Revision 1.16 2002/05/14 02:36:00 rgb
+ * Change references to _TDB to _IPSA.
+ *
+ * Revision 1.15 2002/04/24 07:36:47 mcr
+ * Moved from ./klips/net/ipsec/ipsec_rcv.h,v
+ *
+ * Revision 1.14 2001/09/07 22:15:48 rgb
+ * Fix for removal of transport layer protocol handler arg in 2.4.4.
+ *
+ * Revision 1.13 2001/06/14 19:35:09 rgb
+ * Update copyright date.
+ *
+ * Revision 1.12 2001/03/16 07:36:44 rgb
+ * Fixed #endif comment to sate compiler.
+ *
+ * Revision 1.11 2000/09/21 04:34:21 rgb
+ * Moved declaration of sysctl_ipsec_inbound_policy_check outside
+ * CONFIG_IPSEC_DEBUG. (MB)
+ *
+ * Revision 1.10 2000/09/18 02:36:10 rgb
+ * Exported sysctl_ipsec_inbound_policy_check for skb_decompress().
+ *
+ * Revision 1.9 2000/09/08 19:12:56 rgb
+ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
+ *
+ * Revision 1.8 1999/11/18 04:09:19 rgb
+ * Replaced all kernel version macros to shorter, readable form.
+ *
+ * Revision 1.7 1999/05/25 01:45:37 rgb
+ * Fix version macros for 2.0.x as a module.
+ *
+ * Revision 1.6 1999/05/08 21:24:27 rgb
+ * Add includes for 2.2.x include into net/ipv4/protocol.c
+ *
+ * Revision 1.5 1999/05/05 22:02:32 rgb
+ * Add a quick and dirty port to 2.2 kernels by Marc Boucher <marc@mbsi.ca>.
+ *
+ * Revision 1.4 1999/04/11 00:28:59 henry
+ * GPL boilerplate
+ *
+ * Revision 1.3 1999/04/06 04:54:27 rgb
+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+ * patch shell fixes.
+ *
+ * Revision 1.2 1999/01/22 20:06:59 rgb
+ * Fixed cut-and-paste error from ipsec_esp.h.
+ *
+ * Revision 1.1 1999/01/21 20:29:12 rgb
+ * Converted from transform switching to algorithm switching.
+ *
+ * Log: ipsec_esp.h,v
+ * Revision 1.4 1998/08/12 00:07:32 rgb
+ * Added data structures for new xforms: null, {,3}dessha1.
+ *
+ * Revision 1.3 1998/07/14 15:57:01 rgb
+ * Add #ifdef __KERNEL__ to protect kernel-only structures.
+ *
+ * Revision 1.2 1998/06/25 19:33:46 rgb
+ * Add prototype for protocol receive function.
+ * Rearrange for more logical layout.
+ *
+ * Revision 1.1 1998/06/18 21:27:45 henry
+ * move sources from klips/src to klips/net/ipsec, to keep stupid
+ * kernel-build scripts happier in the presence of symlinks
+ *
+ * Revision 1.6 1998/06/05 02:28:08 rgb
+ * Minor comment fix.
+ *
+ * Revision 1.5 1998/05/27 22:34:00 rgb
+ * Changed structures to accomodate key separation.
+ *
+ * Revision 1.4 1998/05/18 22:28:43 rgb
+ * Disable key printing facilities from /proc/net/ipsec_*.
+ *
+ * Revision 1.3 1998/04/21 21:29:07 rgb
+ * Rearrange debug switches to change on the fly debug output from user
+ * space. Only kernel changes checked in at this time. radij.c was also
+ * changed to temporarily remove buggy debugging code in rj_delete causing
+ * an OOPS and hence, netlink device open errors.
+ *
+ * Revision 1.2 1998/04/12 22:03:20 rgb
+ * Updated ESP-3DES-HMAC-MD5-96,
+ * ESP-DES-HMAC-MD5-96,
+ * AH-HMAC-MD5-96,
+ * AH-HMAC-SHA1-96 since Henry started freeswan cvs repository
+ * from old standards (RFC182[5-9] to new (as of March 1998) drafts.
+ *
+ * Fixed eroute references in /proc/net/ipsec*.
+ *
+ * Started to patch module unloading memory leaks in ipsec_netlink and
+ * radij tree unloading.
+ *
+ * Revision 1.1 1998/04/09 03:06:00 henry
+ * sources moved up from linux/net/ipsec
+ *
+ * Revision 1.1.1.1 1998/04/08 05:35:02 henry
+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
+ *
+ * Revision 0.5 1997/06/03 04:24:48 ji
+ * Added ESP-3DES-MD5-96 transform.
+ *
+ * Revision 0.4 1997/01/15 01:28:15 ji
+ * Added definitions for new ESP transforms.
+ *
+ * Revision 0.3 1996/11/20 14:35:48 ji
+ * Minor Cleanup.
+ * Rationalized debugging code.
+ *
+ * Revision 0.2 1996/11/02 00:18:33 ji
+ * First limited release.
+ *
+ *
+ */
+
+
diff --git a/src/libfreeswan/ipsec_sa.h b/src/libfreeswan/ipsec_sa.h
new file mode 100644
index 000000000..555df42d3
--- /dev/null
+++ b/src/libfreeswan/ipsec_sa.h
@@ -0,0 +1,338 @@
+/*
+ * @(#) Definitions of IPsec Security Association (ipsec_sa)
+ *
+ * Copyright (C) 2001, 2002, 2003
+ * Richard Guy Briggs <rgb@freeswan.org>
+ * and Michael Richardson <mcr@freeswan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: ipsec_sa.h,v 1.3 2004/04/28 08:07:11 as Exp $
+ *
+ * This file derived from ipsec_xform.h on 2001/9/18 by mcr.
+ *
+ */
+
+/*
+ * This file describes the IPsec Security Association Structure.
+ *
+ * This structure keeps track of a single transform that may be done
+ * to a set of packets. It can describe applying the transform or
+ * apply the reverse. (e.g. compression vs expansion). However, it
+ * only describes one at a time. To describe both, two structures would
+ * be used, but since the sides of the transform are performed
+ * on different machines typically it is usual to have only one side
+ * of each association.
+ *
+ */
+
+#ifndef _IPSEC_SA_H_
+
+#ifdef __KERNEL__
+#include "ipsec_stats.h"
+#include "ipsec_life.h"
+#include "ipsec_eroute.h"
+#endif /* __KERNEL__ */
+#include "ipsec_param.h"
+
+
+/* SAs are held in a table.
+ * Entries in this table are referenced by IPsecSAref_t values.
+ * IPsecSAref_t values are conceptually subscripts. Because
+ * we want to allocate the table piece-meal, the subscripting
+ * is implemented with two levels, a bit like paged virtual memory.
+ * This representation mechanism is known as an Iliffe Vector.
+ *
+ * The Main table (AKA the refTable) consists of 2^IPSEC_SA_REF_MAINTABLE_IDX_WIDTH
+ * pointers to subtables.
+ * Each subtable has 2^IPSEC_SA_REF_SUBTABLE_IDX_WIDTH entries, each of which
+ * is a pointer to an SA.
+ *
+ * An IPsecSAref_t contains either an exceptional value (signified by the
+ * high-order bit being on) or a reference to a table entry. A table entry
+ * reference has the subtable subscript in the low-order
+ * IPSEC_SA_REF_SUBTABLE_IDX_WIDTH bits and the Main table subscript
+ * in the next lowest IPSEC_SA_REF_MAINTABLE_IDX_WIDTH bits.
+ *
+ * The Maintable entry for an IPsecSAref_t x, a pointer to its subtable, is
+ * IPsecSAref2table(x). It is of type struct IPsecSArefSubTable *.
+ *
+ * The pointer to the SA for x is IPsecSAref2SA(x). It is of type
+ * struct ipsec_sa*. The macro definition clearly shows the two-level
+ * access needed to find the SA pointer.
+ *
+ * The Maintable is allocated when IPsec is initialized.
+ * Each subtable is allocated when needed, but the first is allocated
+ * when IPsec is initialized.
+ *
+ * IPsecSAref_t is designed to be smaller than an NFmark so that
+ * they can be stored in NFmarks and still leave a few bits for other
+ * purposes. The spare bits are in the low order of the NFmark
+ * but in the high order of the IPsecSAref_t, so conversion is required.
+ * We pick the upper bits of NFmark on the theory that they are less likely to
+ * interfere with more pedestrian uses of nfmark.
+ */
+
+
+typedef unsigned short int IPsecRefTableUnusedCount;
+
+#define IPSEC_SA_REF_TABLE_NUM_ENTRIES (1 << IPSEC_SA_REF_TABLE_IDX_WIDTH)
+
+#ifdef __KERNEL__
+#if ((IPSEC_SA_REF_TABLE_IDX_WIDTH - (1 + IPSEC_SA_REF_MAINTABLE_IDX_WIDTH)) < 0)
+#error "IPSEC_SA_REF_TABLE_IDX_WIDTH("IPSEC_SA_REF_TABLE_IDX_WIDTH") MUST be < 1 + IPSEC_SA_REF_MAINTABLE_IDX_WIDTH("IPSEC_SA_REF_MAINTABLE_IDX_WIDTH")"
+#endif
+
+#define IPSEC_SA_REF_SUBTABLE_IDX_WIDTH (IPSEC_SA_REF_TABLE_IDX_WIDTH - IPSEC_SA_REF_MAINTABLE_IDX_WIDTH)
+
+#define IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES (1 << IPSEC_SA_REF_MAINTABLE_IDX_WIDTH)
+#define IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES (1 << IPSEC_SA_REF_SUBTABLE_IDX_WIDTH)
+
+#ifdef CONFIG_NETFILTER
+#define IPSEC_SA_REF_HOST_FIELD(x) ((struct sk_buff*)(x))->nfmark
+#define IPSEC_SA_REF_HOST_FIELD_TYPE typeof(IPSEC_SA_REF_HOST_FIELD(NULL))
+#else /* CONFIG_NETFILTER */
+/* just make it work for now, it doesn't matter, since there is no nfmark */
+#define IPSEC_SA_REF_HOST_FIELD_TYPE unsigned long
+#endif /* CONFIG_NETFILTER */
+#define IPSEC_SA_REF_HOST_FIELD_WIDTH (8 * sizeof(IPSEC_SA_REF_HOST_FIELD_TYPE))
+#define IPSEC_SA_REF_FIELD_WIDTH (8 * sizeof(IPsecSAref_t))
+
+#define IPSEC_SA_REF_MASK (IPSEC_SAREF_NULL >> (IPSEC_SA_REF_FIELD_WIDTH - IPSEC_SA_REF_TABLE_IDX_WIDTH))
+#define IPSEC_SA_REF_TABLE_MASK ((IPSEC_SAREF_NULL >> (IPSEC_SA_REF_FIELD_WIDTH - IPSEC_SA_REF_MAINTABLE_IDX_WIDTH)) << IPSEC_SA_REF_SUBTABLE_IDX_WIDTH)
+#define IPSEC_SA_REF_ENTRY_MASK (IPSEC_SAREF_NULL >> (IPSEC_SA_REF_FIELD_WIDTH - IPSEC_SA_REF_SUBTABLE_IDX_WIDTH))
+
+#define IPsecSAref2table(x) (((x) & IPSEC_SA_REF_TABLE_MASK) >> IPSEC_SA_REF_SUBTABLE_IDX_WIDTH)
+#define IPsecSAref2entry(x) ((x) & IPSEC_SA_REF_ENTRY_MASK)
+#define IPsecSArefBuild(x,y) (((x) << IPSEC_SA_REF_SUBTABLE_IDX_WIDTH) + (y))
+
+#define IPsecSAref2SA(x) (ipsec_sadb.refTable[IPsecSAref2table(x)]->entry[IPsecSAref2entry(x)])
+#define IPsecSA2SAref(x) ((x)->ips_ref)
+
+#define EMT_INBOUND 0x01 /* SA direction, 1=inbound */
+
+/* 'struct ipsec_sa' should be 64bit aligned when allocated. */
+struct ipsec_sa
+{
+ IPsecSAref_t ips_ref; /* reference table entry number */
+ atomic_t ips_refcount; /* reference count for this struct */
+ struct ipsec_sa *ips_hnext; /* next in hash chain */
+ struct ipsec_sa *ips_inext; /* pointer to next xform */
+ struct ipsec_sa *ips_onext; /* pointer to prev xform */
+
+ struct ifnet *ips_rcvif; /* related rcv encap interface */
+
+ struct sa_id ips_said; /* SA ID */
+
+ __u32 ips_seq; /* seq num of msg that initiated this SA */
+ __u32 ips_pid; /* PID of process that initiated this SA */
+ __u8 ips_authalg; /* auth algorithm for this SA */
+ __u8 ips_encalg; /* enc algorithm for this SA */
+
+ struct ipsec_stats ips_errs;
+
+ __u8 ips_replaywin; /* replay window size */
+ __u8 ips_state; /* state of SA */
+ __u32 ips_replaywin_lastseq; /* last pkt sequence num */
+ __u64 ips_replaywin_bitmap; /* bitmap of received pkts */
+ __u32 ips_replaywin_maxdiff; /* max pkt sequence difference */
+
+ __u32 ips_flags; /* generic xform flags */
+
+
+ struct ipsec_lifetimes ips_life; /* lifetime records */
+
+ /* selector information */
+ struct sockaddr*ips_addr_s; /* src sockaddr */
+ struct sockaddr*ips_addr_d; /* dst sockaddr */
+ struct sockaddr*ips_addr_p; /* proxy sockaddr */
+ __u16 ips_addr_s_size;
+ __u16 ips_addr_d_size;
+ __u16 ips_addr_p_size;
+ ip_address ips_flow_s;
+ ip_address ips_flow_d;
+ ip_address ips_mask_s;
+ ip_address ips_mask_d;
+
+ __u16 ips_key_bits_a; /* size of authkey in bits */
+ __u16 ips_auth_bits; /* size of authenticator in bits */
+ __u16 ips_key_bits_e; /* size of enckey in bits */
+ __u16 ips_iv_bits; /* size of IV in bits */
+ __u8 ips_iv_size;
+ __u16 ips_key_a_size;
+ __u16 ips_key_e_size;
+
+ caddr_t ips_key_a; /* authentication key */
+ caddr_t ips_key_e; /* encryption key */
+ caddr_t ips_iv; /* Initialisation Vector */
+
+ struct ident ips_ident_s; /* identity src */
+ struct ident ips_ident_d; /* identity dst */
+
+#ifdef CONFIG_IPSEC_IPCOMP
+ __u16 ips_comp_adapt_tries; /* ipcomp self-adaption tries */
+ __u16 ips_comp_adapt_skip; /* ipcomp self-adaption to-skip */
+ __u64 ips_comp_ratio_cbytes; /* compressed bytes */
+ __u64 ips_comp_ratio_dbytes; /* decompressed (or uncompressed) bytes */
+#endif /* CONFIG_IPSEC_IPCOMP */
+
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ __u8 ips_natt_type;
+ __u8 ips_natt_reserved[3];
+ __u16 ips_natt_sport;
+ __u16 ips_natt_dport;
+
+ struct sockaddr *ips_natt_oa;
+ __u16 ips_natt_oa_size;
+ __u16 ips_natt_reserved2;
+#endif
+
+#if 0
+ __u32 ips_sens_dpd;
+ __u8 ips_sens_sens_level;
+ __u8 ips_sens_sens_len;
+ __u64* ips_sens_sens_bitmap;
+ __u8 ips_sens_integ_level;
+ __u8 ips_sens_integ_len;
+ __u64* ips_sens_integ_bitmap;
+#endif
+ struct ipsec_alg_enc *ips_alg_enc;
+ struct ipsec_alg_auth *ips_alg_auth;
+ IPsecSAref_t ips_ref_rel;
+};
+
+struct IPsecSArefSubTable
+{
+ struct ipsec_sa* entry[IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES];
+};
+
+struct ipsec_sadb {
+ struct IPsecSArefSubTable* refTable[IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES];
+ IPsecSAref_t refFreeList[IPSEC_SA_REF_FREELIST_NUM_ENTRIES];
+ int refFreeListHead;
+ int refFreeListTail;
+ IPsecSAref_t refFreeListCont;
+ IPsecSAref_t said_hash[SADB_HASHMOD];
+ spinlock_t sadb_lock;
+};
+
+extern struct ipsec_sadb ipsec_sadb;
+
+extern int ipsec_SAref_recycle(void);
+extern int ipsec_SArefSubTable_alloc(unsigned table);
+extern int ipsec_saref_freelist_init(void);
+extern int ipsec_sadb_init(void);
+extern struct ipsec_sa *ipsec_sa_alloc(int*error); /* pass in error var by pointer */
+extern IPsecSAref_t ipsec_SAref_alloc(int*erorr); /* pass in error var by pointer */
+extern int ipsec_sa_free(struct ipsec_sa* ips);
+extern struct ipsec_sa *ipsec_sa_getbyid(struct sa_id *said);
+extern int ipsec_sa_put(struct ipsec_sa *ips);
+extern int ipsec_sa_add(struct ipsec_sa *ips);
+extern int ipsec_sa_del(struct ipsec_sa *ips);
+extern int ipsec_sa_delchain(struct ipsec_sa *ips);
+extern int ipsec_sadb_cleanup(__u8 proto);
+extern int ipsec_sadb_free(void);
+extern int ipsec_sa_wipe(struct ipsec_sa *ips);
+#endif /* __KERNEL__ */
+
+enum ipsec_direction {
+ ipsec_incoming = 1,
+ ipsec_outgoing = 2
+};
+
+#define _IPSEC_SA_H_
+#endif /* _IPSEC_SA_H_ */
+
+/*
+ * $Log: ipsec_sa.h,v $
+ * Revision 1.3 2004/04/28 08:07:11 as
+ * added dhr's freeswan-2.06 changes
+ *
+ * Revision 1.2 2004/03/22 21:53:18 as
+ * merged alg-0.8.1 branch with HEAD
+ *
+ * Revision 1.1.2.1.2.1 2004/03/16 09:48:18 as
+ * alg-0.8.1rc12 patch merged
+ *
+ * Revision 1.1.2.1 2004/03/15 22:30:06 as
+ * nat-0.6c patch merged
+ *
+ * Revision 1.1 2004/03/15 20:35:25 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.15 2003/05/11 00:53:09 mcr
+ * IPsecSAref_t and macros were moved to freeswan.h.
+ *
+ * Revision 1.14 2003/02/12 19:31:55 rgb
+ * Fixed bug in "file seen" machinery.
+ * Updated copyright year.
+ *
+ * Revision 1.13 2003/01/30 02:31:52 rgb
+ *
+ * Re-wrote comments describing SAref system for accuracy.
+ * Rename SAref table macro names for clarity.
+ * Convert IPsecSAref_t from signed to unsigned to fix apparent SAref exhaustion bug.
+ * Transmit error code through to caller from callee for better diagnosis of problems.
+ * Enclose all macro arguments in parens to avoid any possible obscrure bugs.
+ *
+ * Revision 1.12 2002/10/07 18:31:19 rgb
+ * Change comment to reflect the flexible nature of the main and sub-table widths.
+ * Added a counter for the number of unused entries in each subtable.
+ * Further break up host field type macro to host field.
+ * Move field width sanity checks to ipsec_sa.c
+ * Define a mask for an entire saref.
+ *
+ * Revision 1.11 2002/09/20 15:40:33 rgb
+ * Re-write most of the SAref macros and types to eliminate any pointer references to Entrys.
+ * Fixed SAref/nfmark macros.
+ * Rework saref freeslist.
+ * Place all ipsec sadb globals into one struct.
+ * Restrict some bits to kernel context for use to klips utils.
+ *
+ * Revision 1.10 2002/09/20 05:00:34 rgb
+ * Update copyright date.
+ *
+ * Revision 1.9 2002/09/17 17:19:29 mcr
+ * make it compile even if there is no netfilter - we lost
+ * functionality, but it works, especially on 2.2.
+ *
+ * Revision 1.8 2002/07/28 22:59:53 mcr
+ * clarified/expanded one comment.
+ *
+ * Revision 1.7 2002/07/26 08:48:31 rgb
+ * Added SA ref table code.
+ *
+ * Revision 1.6 2002/05/31 17:27:48 rgb
+ * Comment fix.
+ *
+ * Revision 1.5 2002/05/27 18:55:03 rgb
+ * Remove final vistiges of tdb references via IPSEC_KLIPS1_COMPAT.
+ *
+ * Revision 1.4 2002/05/23 07:13:36 rgb
+ * Convert "usecount" to "refcount" to remove ambiguity.
+ *
+ * Revision 1.3 2002/04/24 07:36:47 mcr
+ * Moved from ./klips/net/ipsec/ipsec_sa.h,v
+ *
+ * Revision 1.2 2001/11/26 09:16:15 rgb
+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
+ *
+ * Revision 1.1.2.1 2001/09/25 02:24:58 mcr
+ * struct tdb -> struct ipsec_sa.
+ * sa(tdb) manipulation functions renamed and moved to ipsec_sa.c
+ * ipsec_xform.c removed. header file still contains useful things.
+ *
+ *
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ *
+ */
diff --git a/src/libfreeswan/ipsec_sha1.h b/src/libfreeswan/ipsec_sha1.h
new file mode 100644
index 000000000..116170e6b
--- /dev/null
+++ b/src/libfreeswan/ipsec_sha1.h
@@ -0,0 +1,79 @@
+/*
+ * RCSID $Id: ipsec_sha1.h,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+
+/*
+ * Here is the original comment from the distribution:
+
+SHA-1 in C
+By Steve Reid <steve@edmweb.com>
+100% Public Domain
+
+ * Adapted for use by the IPSEC code by John Ioannidis
+ */
+
+
+#ifndef _IPSEC_SHA1_H_
+#define _IPSEC_SHA1_H_
+
+typedef struct
+{
+ __u32 state[5];
+ __u32 count[2];
+ __u8 buffer[64];
+} SHA1_CTX;
+
+void SHA1Transform(__u32 state[5], __u8 buffer[64]);
+void SHA1Init(void *context);
+void SHA1Update(void *context, unsigned char *data, __u32 len);
+void SHA1Final(unsigned char digest[20], void *context);
+
+
+#endif /* _IPSEC_SHA1_H_ */
+
+/*
+ * $Log: ipsec_sha1.h,v $
+ * Revision 1.1 2004/03/15 20:35:25 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.7 2002/09/10 01:45:09 mcr
+ * changed type of MD5_CTX and SHA1_CTX to void * so that
+ * the function prototypes would match, and could be placed
+ * into a pointer to a function.
+ *
+ * Revision 1.6 2002/04/24 07:36:47 mcr
+ * Moved from ./klips/net/ipsec/ipsec_sha1.h,v
+ *
+ * Revision 1.5 1999/12/13 13:59:13 rgb
+ * Quick fix to argument size to Update bugs.
+ *
+ * Revision 1.4 1999/12/07 18:16:23 rgb
+ * Fixed comments at end of #endif lines.
+ *
+ * Revision 1.3 1999/04/06 04:54:27 rgb
+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+ * patch shell fixes.
+ *
+ * Revision 1.2 1998/11/30 13:22:54 rgb
+ * Rationalised all the klips kernel file headers. They are much shorter
+ * now and won't conflict under RH5.2.
+ *
+ * Revision 1.1 1998/06/18 21:27:50 henry
+ * move sources from klips/src to klips/net/ipsec, to keep stupid
+ * kernel-build scripts happier in the presence of symlinks
+ *
+ * Revision 1.2 1998/04/23 20:54:05 rgb
+ * Fixed md5 and sha1 include file nesting issues, to be cleaned up when
+ * verified.
+ *
+ * Revision 1.1 1998/04/09 03:04:21 henry
+ * sources moved up from linux/net/ipsec
+ * these two include files modified not to include others except in kernel
+ *
+ * Revision 1.1.1.1 1998/04/08 05:35:04 henry
+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
+ *
+ * Revision 0.4 1997/01/15 01:28:15 ji
+ * New transform
+ *
+ */
diff --git a/src/libfreeswan/ipsec_stats.h b/src/libfreeswan/ipsec_stats.h
new file mode 100644
index 000000000..e4be11d29
--- /dev/null
+++ b/src/libfreeswan/ipsec_stats.h
@@ -0,0 +1,38 @@
+/*
+ * @(#) definition of ipsec_stats structure
+ *
+ * Copyright (C) 2001 Richard Guy Briggs <rgb@freeswan.org>
+ * and Michael Richardson <mcr@freeswan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: ipsec_stats.h,v 1.2 2004/03/30 19:33:52 as Exp $
+ *
+ */
+
+/*
+ * This file describes the errors/statistics that FreeSWAN collects.
+ */
+
+#ifndef _IPSEC_STATS_H_
+
+struct ipsec_stats {
+ __u32 ips_alg_errs; /* number of algorithm errors */
+ __u32 ips_auth_errs; /* # of authentication errors */
+ __u32 ips_encsize_errs; /* # of encryption size errors*/
+ __u32 ips_encpad_errs; /* # of encryption pad errors*/
+ __u32 ips_replaywin_errs; /* # of pkt sequence errors */
+};
+
+extern int ipsec_snprintf(char * buf, ssize_t size, const char *fmt, ...);
+
+#define _IPSEC_STATS_H_
+#endif /* _IPSEC_STATS_H_ */
diff --git a/src/libfreeswan/ipsec_tunnel.h b/src/libfreeswan/ipsec_tunnel.h
new file mode 100644
index 000000000..3b25e95e1
--- /dev/null
+++ b/src/libfreeswan/ipsec_tunnel.h
@@ -0,0 +1,265 @@
+/*
+ * IPSEC tunneling code
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Richard Guy Briggs.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: ipsec_tunnel.h,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+
+
+#ifdef NET_21
+# define DEV_QUEUE_XMIT(skb, device, pri) {\
+ skb->dev = device; \
+ neigh_compat_output(skb); \
+ /* skb->dst->output(skb); */ \
+ }
+# define ICMP_SEND(skb_in, type, code, info, dev) \
+ icmp_send(skb_in, type, code, htonl(info))
+# define IP_SEND(skb, dev) \
+ ip_send(skb);
+#else /* NET_21 */
+# define DEV_QUEUE_XMIT(skb, device, pri) {\
+ dev_queue_xmit(skb, device, pri); \
+ }
+# define ICMP_SEND(skb_in, type, code, info, dev) \
+ icmp_send(skb_in, type, code, info, dev)
+# define IP_SEND(skb, dev) \
+ if(ntohs(iph->tot_len) > physmtu) { \
+ ip_fragment(NULL, skb, dev, 0); \
+ ipsec_kfree_skb(skb); \
+ } else { \
+ dev_queue_xmit(skb, dev, SOPRI_NORMAL); \
+ }
+#endif /* NET_21 */
+
+
+/*
+ * Heavily based on drivers/net/new_tunnel.c. Lots
+ * of ideas also taken from the 2.1.x version of drivers/net/shaper.c
+ */
+
+struct ipsectunnelconf
+{
+ __u32 cf_cmd;
+ union
+ {
+ char cfu_name[12];
+ } cf_u;
+#define cf_name cf_u.cfu_name
+};
+
+#define IPSEC_SET_DEV (SIOCDEVPRIVATE)
+#define IPSEC_DEL_DEV (SIOCDEVPRIVATE + 1)
+#define IPSEC_CLR_DEV (SIOCDEVPRIVATE + 2)
+
+#ifdef __KERNEL__
+#include <linux/version.h>
+#ifndef KERNEL_VERSION
+# define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
+#endif
+struct ipsecpriv
+{
+ struct sk_buff_head sendq;
+ struct device *dev;
+ struct wait_queue *wait_queue;
+ char locked;
+ int (*hard_start_xmit) (struct sk_buff *skb,
+ struct device *dev);
+ int (*hard_header) (struct sk_buff *skb,
+ struct device *dev,
+ unsigned short type,
+ void *daddr,
+ void *saddr,
+ unsigned len);
+#ifdef NET_21
+ int (*rebuild_header)(struct sk_buff *skb);
+#else /* NET_21 */
+ int (*rebuild_header)(void *buff, struct device *dev,
+ unsigned long raddr, struct sk_buff *skb);
+#endif /* NET_21 */
+ int (*set_mac_address)(struct device *dev, void *addr);
+#ifndef NET_21
+ void (*header_cache_bind)(struct hh_cache **hhp, struct device *dev,
+ unsigned short htype, __u32 daddr);
+#endif /* !NET_21 */
+ void (*header_cache_update)(struct hh_cache *hh, struct device *dev, unsigned char * haddr);
+ struct net_device_stats *(*get_stats)(struct device *dev);
+ struct net_device_stats mystats;
+ int mtu; /* What is the desired MTU? */
+};
+
+extern char ipsec_tunnel_c_version[];
+
+extern struct device *ipsecdevices[IPSEC_NUM_IF];
+
+int ipsec_tunnel_init_devices(void);
+
+/* void */ int ipsec_tunnel_cleanup_devices(void);
+
+extern /* void */ int ipsec_init(void);
+
+extern int ipsec_tunnel_start_xmit(struct sk_buff *skb, struct device *dev);
+
+#ifdef CONFIG_IPSEC_DEBUG
+extern int debug_tunnel;
+extern int sysctl_ipsec_debug_verbose;
+#endif /* CONFIG_IPSEC_DEBUG */
+#endif /* __KERNEL__ */
+
+#ifdef CONFIG_IPSEC_DEBUG
+#define DB_TN_INIT 0x0001
+#define DB_TN_PROCFS 0x0002
+#define DB_TN_XMIT 0x0010
+#define DB_TN_OHDR 0x0020
+#define DB_TN_CROUT 0x0040
+#define DB_TN_OXFS 0x0080
+#define DB_TN_REVEC 0x0100
+#endif /* CONFIG_IPSEC_DEBUG */
+
+/*
+ * $Log: ipsec_tunnel.h,v $
+ * Revision 1.1 2004/03/15 20:35:25 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.28 2003/06/24 20:22:32 mcr
+ * added new global: ipsecdevices[] so that we can keep track of
+ * the ipsecX devices. They will be referenced with dev_hold(),
+ * so 2.2 may need this as well.
+ *
+ * Revision 1.27 2003/04/03 17:38:09 rgb
+ * Centralised ipsec_kfree_skb and ipsec_dev_{get,put}.
+ *
+ * Revision 1.26 2003/02/12 19:32:20 rgb
+ * Updated copyright year.
+ *
+ * Revision 1.25 2002/05/27 18:56:07 rgb
+ * Convert to dynamic ipsec device allocation.
+ *
+ * Revision 1.24 2002/04/24 07:36:48 mcr
+ * Moved from ./klips/net/ipsec/ipsec_tunnel.h,v
+ *
+ * Revision 1.23 2001/11/06 19:50:44 rgb
+ * Moved IP_SEND, ICMP_SEND, DEV_QUEUE_XMIT macros to ipsec_tunnel.h for
+ * use also by pfkey_v2_parser.c
+ *
+ * Revision 1.22 2001/09/15 16:24:05 rgb
+ * Re-inject first and last HOLD packet when an eroute REPLACE is done.
+ *
+ * Revision 1.21 2001/06/14 19:35:10 rgb
+ * Update copyright date.
+ *
+ * Revision 1.20 2000/09/15 11:37:02 rgb
+ * Merge in heavily modified Svenning Soerensen's <svenning@post5.tele.dk>
+ * IPCOMP zlib deflate code.
+ *
+ * Revision 1.19 2000/09/08 19:12:56 rgb
+ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
+ *
+ * Revision 1.18 2000/07/28 13:50:54 rgb
+ * Changed enet_statistics to net_device_stats and added back compatibility
+ * for pre-2.1.19.
+ *
+ * Revision 1.17 1999/11/19 01:12:15 rgb
+ * Purge unneeded proc_info prototypes, now that static linking uses
+ * dynamic proc_info registration.
+ *
+ * Revision 1.16 1999/11/18 18:51:00 rgb
+ * Changed all device registrations for static linking to
+ * dynamic to reduce the number and size of patches.
+ *
+ * Revision 1.15 1999/11/18 04:14:21 rgb
+ * Replaced all kernel version macros to shorter, readable form.
+ * Added CONFIG_PROC_FS compiler directives in case it is shut off.
+ * Added Marc Boucher's 2.3.25 proc patches.
+ *
+ * Revision 1.14 1999/05/25 02:50:10 rgb
+ * Fix kernel version macros for 2.0.x static linking.
+ *
+ * Revision 1.13 1999/05/25 02:41:06 rgb
+ * Add ipsec_klipsdebug support for static linking.
+ *
+ * Revision 1.12 1999/05/05 22:02:32 rgb
+ * Add a quick and dirty port to 2.2 kernels by Marc Boucher <marc@mbsi.ca>.
+ *
+ * Revision 1.11 1999/04/29 15:19:50 rgb
+ * Add return values to init and cleanup functions.
+ *
+ * Revision 1.10 1999/04/16 16:02:39 rgb
+ * Bump up macro to 4 ipsec I/Fs.
+ *
+ * Revision 1.9 1999/04/15 15:37:25 rgb
+ * Forward check changes from POST1_00 branch.
+ *
+ * Revision 1.5.2.1 1999/04/02 04:26:14 rgb
+ * Backcheck from HEAD, pre1.0.
+ *
+ * Revision 1.8 1999/04/11 00:29:01 henry
+ * GPL boilerplate
+ *
+ * Revision 1.7 1999/04/06 04:54:28 rgb
+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+ * patch shell fixes.
+ *
+ * Revision 1.6 1999/03/31 05:44:48 rgb
+ * Keep PMTU reduction private.
+ *
+ * Revision 1.5 1999/02/10 22:31:20 rgb
+ * Change rebuild_header member to reflect generality of link layer.
+ *
+ * Revision 1.4 1998/12/01 13:22:04 rgb
+ * Added support for debug printing of version info.
+ *
+ * Revision 1.3 1998/07/29 20:42:46 rgb
+ * Add a macro for clearing all tunnel devices.
+ * Rearrange structures and declarations for sharing with userspace.
+ *
+ * Revision 1.2 1998/06/25 20:01:45 rgb
+ * Make prototypes available for ipsec_init and ipsec proc_dir_entries
+ * for static linking.
+ *
+ * Revision 1.1 1998/06/18 21:27:50 henry
+ * move sources from klips/src to klips/net/ipsec, to keep stupid
+ * kernel-build scripts happier in the presence of symlinks
+ *
+ * Revision 1.3 1998/05/18 21:51:50 rgb
+ * Added macros for num of I/F's and a procfs debug switch.
+ *
+ * Revision 1.2 1998/04/21 21:29:09 rgb
+ * Rearrange debug switches to change on the fly debug output from user
+ * space. Only kernel changes checked in at this time. radij.c was also
+ * changed to temporarily remove buggy debugging code in rj_delete causing
+ * an OOPS and hence, netlink device open errors.
+ *
+ * Revision 1.1 1998/04/09 03:06:13 henry
+ * sources moved up from linux/net/ipsec
+ *
+ * Revision 1.1.1.1 1998/04/08 05:35:05 henry
+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
+ *
+ * Revision 0.5 1997/06/03 04:24:48 ji
+ * Added transport mode.
+ * Changed the way routing is done.
+ * Lots of bug fixes.
+ *
+ * Revision 0.4 1997/01/15 01:28:15 ji
+ * No changes.
+ *
+ * Revision 0.3 1996/11/20 14:39:04 ji
+ * Minor cleanups.
+ * Rationalized debugging code.
+ *
+ * Revision 0.2 1996/11/02 00:18:33 ji
+ * First limited release.
+ *
+ *
+ */
diff --git a/src/libfreeswan/ipsec_xform.h b/src/libfreeswan/ipsec_xform.h
new file mode 100644
index 000000000..1dc6b6083
--- /dev/null
+++ b/src/libfreeswan/ipsec_xform.h
@@ -0,0 +1,274 @@
+/*
+ * Definitions relevant to IPSEC transformations
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 1999, 2000, 2001 Richard Guy Briggs.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: ipsec_xform.h,v 1.3 2004/09/29 22:26:13 as Exp $
+ */
+
+#ifndef _IPSEC_XFORM_H_
+
+#include <freeswan.h>
+#include "ipsec_policy.h"
+
+#define XF_NONE 0 /* No transform set */
+#define XF_IP4 1 /* IPv4 inside IPv4 */
+#define XF_AHMD5 2 /* AH MD5 */
+#define XF_AHSHA 3 /* AH SHA */
+#define XF_ESP3DES 5 /* ESP DES3-CBC */
+#define XF_AHHMACMD5 6 /* AH-HMAC-MD5 with opt replay prot */
+#define XF_AHHMACSHA1 7 /* AH-HMAC-SHA1 with opt replay prot */
+#define XF_ESP3DESMD5 9 /* triple DES, HMAC-MD-5, 128-bits of authentication */
+#define XF_ESP3DESMD596 10 /* triple DES, HMAC-MD-5, 96-bits of authentication */
+#define XF_ESPNULLMD596 12 /* NULL, HMAC-MD-5 with 96-bits of authentication */
+#define XF_ESPNULLSHA196 13 /* NULL, HMAC-SHA-1 with 96-bits of authentication */
+#define XF_ESP3DESSHA196 14 /* triple DES, HMAC-SHA-1, 96-bits of authentication */
+#define XF_IP6 15 /* IPv6 inside IPv6 */
+#define XF_COMPDEFLATE 16 /* IPCOMP deflate */
+
+#define XF_CLR 126 /* Clear SA table */
+#define XF_DEL 127 /* Delete SA */
+
+#define XFT_AUTH 0x0001
+#define XFT_CONF 0x0100
+
+/* available if CONFIG_IPSEC_DEBUG is defined */
+#define DB_XF_INIT 0x0001
+
+#define PROTO2TXT(x) \
+ (x) == IPPROTO_AH ? "AH" : \
+ (x) == IPPROTO_ESP ? "ESP" : \
+ (x) == IPPROTO_IPIP ? "IPIP" : \
+ (x) == IPPROTO_COMP ? "COMP" : \
+ "UNKNOWN_proto"
+static inline const char *enc_name_id (unsigned id) {
+ static char buf[16];
+ snprintf(buf, sizeof(buf), "_ID%d", id);
+ return buf;
+}
+static inline const char *auth_name_id (unsigned id) {
+ static char buf[16];
+ snprintf(buf, sizeof(buf), "_ID%d", id);
+ return buf;
+}
+#define IPS_XFORM_NAME(x) \
+ PROTO2TXT((x)->ips_said.proto), \
+ (x)->ips_said.proto == IPPROTO_COMP ? \
+ ((x)->ips_encalg == SADB_X_CALG_DEFLATE ? \
+ "_DEFLATE" : "_UNKNOWN_comp") : \
+ (x)->ips_encalg == ESP_NONE ? "" : \
+ (x)->ips_encalg == ESP_3DES ? "_3DES" : \
+ (x)->ips_encalg == ESP_AES ? "_AES" : \
+ (x)->ips_encalg == ESP_SERPENT ? "_SERPENT" : \
+ (x)->ips_encalg == ESP_TWOFISH ? "_TWOFISH" : \
+ enc_name_id(x->ips_encalg)/* "_UNKNOWN_encr" */, \
+ (x)->ips_authalg == AH_NONE ? "" : \
+ (x)->ips_authalg == AH_MD5 ? "_HMAC_MD5" : \
+ (x)->ips_authalg == AH_SHA ? "_HMAC_SHA1" : \
+ (x)->ips_authalg == AH_SHA2_256 ? "_HMAC_SHA2_256" : \
+ (x)->ips_authalg == AH_SHA2_384 ? "_HMAC_SHA2_384" : \
+ (x)->ips_authalg == AH_SHA2_512 ? "_HMAC_SHA2_512" : \
+ auth_name_id(x->ips_authalg) /* "_UNKNOWN_auth" */ \
+
+#define _IPSEC_XFORM_H_
+#endif /* _IPSEC_XFORM_H_ */
+
+/*
+ * $Log: ipsec_xform.h,v $
+ * Revision 1.3 2004/09/29 22:26:13 as
+ * included ipsec_policy.h
+ *
+ * Revision 1.2 2004/03/22 21:53:18 as
+ * merged alg-0.8.1 branch with HEAD
+ *
+ * Revision 1.1.4.1 2004/03/16 09:48:18 as
+ * alg-0.8.1rc12 patch merged
+ *
+ * Revision 1.1 2004/03/15 20:35:25 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.36 2002/04/24 07:36:48 mcr
+ * Moved from ./klips/net/ipsec/ipsec_xform.h,v
+ *
+ * Revision 1.35 2001/11/26 09:23:51 rgb
+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
+ *
+ * Revision 1.33.2.1 2001/09/25 02:24:58 mcr
+ * struct tdb -> struct ipsec_sa.
+ * sa(tdb) manipulation functions renamed and moved to ipsec_sa.c
+ * ipsec_xform.c removed. header file still contains useful things.
+ *
+ * Revision 1.34 2001/11/06 19:47:17 rgb
+ * Changed lifetime_packets to uint32 from uint64.
+ *
+ * Revision 1.33 2001/09/08 21:13:34 rgb
+ * Added pfkey ident extension support for ISAKMPd. (NetCelo)
+ *
+ * Revision 1.32 2001/07/06 07:40:01 rgb
+ * Reformatted for readability.
+ * Added inbound policy checking fields for use with IPIP SAs.
+ *
+ * Revision 1.31 2001/06/14 19:35:11 rgb
+ * Update copyright date.
+ *
+ * Revision 1.30 2001/05/30 08:14:03 rgb
+ * Removed vestiges of esp-null transforms.
+ *
+ * Revision 1.29 2001/01/30 23:42:47 rgb
+ * Allow pfkey msgs from pid other than user context required for ACQUIRE
+ * and subsequent ADD or UDATE.
+ *
+ * Revision 1.28 2000/11/06 04:30:40 rgb
+ * Add Svenning's adaptive content compression.
+ *
+ * Revision 1.27 2000/09/19 00:38:25 rgb
+ * Fixed algorithm name bugs introduced for ipcomp.
+ *
+ * Revision 1.26 2000/09/17 21:36:48 rgb
+ * Added proto2txt macro.
+ *
+ * Revision 1.25 2000/09/17 18:56:47 rgb
+ * Added IPCOMP support.
+ *
+ * Revision 1.24 2000/09/12 19:34:12 rgb
+ * Defined XF_IP6 from Gerhard for ipv6 tunnel support.
+ *
+ * Revision 1.23 2000/09/12 03:23:14 rgb
+ * Cleaned out now unused tdb_xform and tdb_xdata members of struct tdb.
+ *
+ * Revision 1.22 2000/09/08 19:12:56 rgb
+ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
+ *
+ * Revision 1.21 2000/09/01 18:32:43 rgb
+ * Added (disabled) sensitivity members to tdb struct.
+ *
+ * Revision 1.20 2000/08/30 05:31:01 rgb
+ * Removed all the rest of the references to tdb_spi, tdb_proto, tdb_dst.
+ * Kill remainder of tdb_xform, tdb_xdata, xformsw.
+ *
+ * Revision 1.19 2000/08/01 14:51:52 rgb
+ * Removed _all_ remaining traces of DES.
+ *
+ * Revision 1.18 2000/01/21 06:17:45 rgb
+ * Tidied up spacing.
+ *
+ * Revision 1.17 1999/11/17 15:53:40 rgb
+ * Changed all occurrences of #include "../../../lib/freeswan.h"
+ * to #include <freeswan.h> which works due to -Ilibfreeswan in the
+ * klips/net/ipsec/Makefile.
+ *
+ * Revision 1.16 1999/10/16 04:23:07 rgb
+ * Add stats for replaywin_errs, replaywin_max_sequence_difference,
+ * authentication errors, encryption size errors, encryption padding
+ * errors, and time since last packet.
+ *
+ * Revision 1.15 1999/10/16 00:29:11 rgb
+ * Added SA lifetime packet counting variables.
+ *
+ * Revision 1.14 1999/10/01 00:04:14 rgb
+ * Added tdb structure locking.
+ * Add function to initialize tdb hash table.
+ *
+ * Revision 1.13 1999/04/29 15:20:57 rgb
+ * dd return values to init and cleanup functions.
+ * Eliminate unnessessary usage of tdb_xform member to further switch
+ * away from the transform switch to the algorithm switch.
+ * Change gettdb parameter to a pointer to reduce stack loading and
+ * facilitate parameter sanity checking.
+ * Add a parameter to tdbcleanup to be able to delete a class of SAs.
+ *
+ * Revision 1.12 1999/04/15 15:37:25 rgb
+ * Forward check changes from POST1_00 branch.
+ *
+ * Revision 1.9.2.2 1999/04/13 20:35:57 rgb
+ * Fix spelling mistake in comment.
+ *
+ * Revision 1.9.2.1 1999/03/30 17:13:52 rgb
+ * Extend struct tdb to support pfkey.
+ *
+ * Revision 1.11 1999/04/11 00:29:01 henry
+ * GPL boilerplate
+ *
+ * Revision 1.10 1999/04/06 04:54:28 rgb
+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+ * patch shell fixes.
+ *
+ * Revision 1.9 1999/01/26 02:09:31 rgb
+ * Removed CONFIG_IPSEC_ALGO_SWITCH macro.
+ * Removed dead code.
+ *
+ * Revision 1.8 1999/01/22 06:29:35 rgb
+ * Added algorithm switch code.
+ * Cruft clean-out.
+ *
+ * Revision 1.7 1998/11/10 05:37:35 rgb
+ * Add support for SA direction flag.
+ *
+ * Revision 1.6 1998/10/19 14:44:29 rgb
+ * Added inclusion of freeswan.h.
+ * sa_id structure implemented and used: now includes protocol.
+ *
+ * Revision 1.5 1998/08/12 00:12:30 rgb
+ * Added macros for new xforms. Added prototypes for new xforms.
+ *
+ * Revision 1.4 1998/07/28 00:04:20 rgb
+ * Add macro for clearing the SA table.
+ *
+ * Revision 1.3 1998/07/14 18:06:46 rgb
+ * Added #ifdef __KERNEL__ directives to restrict scope of header.
+ *
+ * Revision 1.2 1998/06/23 03:02:19 rgb
+ * Created a prototype for ipsec_tdbcleanup when it was moved from
+ * ipsec_init.c.
+ *
+ * Revision 1.1 1998/06/18 21:27:51 henry
+ * move sources from klips/src to klips/net/ipsec, to keep stupid
+ * kernel-build scripts happier in the presence of symlinks
+ *
+ * Revision 1.4 1998/06/11 05:55:31 rgb
+ * Added transform version string pointer to xformsw structure definition.
+ * Added extern declarations for transform version strings.
+ *
+ * Revision 1.3 1998/05/18 22:02:54 rgb
+ * Modify the *_zeroize function prototypes to include one parameter.
+ *
+ * Revision 1.2 1998/04/21 21:29:08 rgb
+ * Rearrange debug switches to change on the fly debug output from user
+ * space. Only kernel changes checked in at this time. radij.c was also
+ * changed to temporarily remove buggy debugging code in rj_delete causing
+ * an OOPS and hence, netlink device open errors.
+ *
+ * Revision 1.1 1998/04/09 03:06:14 henry
+ * sources moved up from linux/net/ipsec
+ *
+ * Revision 1.1.1.1 1998/04/08 05:35:06 henry
+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
+ *
+ * Revision 0.5 1997/06/03 04:24:48 ji
+ * Added ESP-3DES-MD5-96
+ *
+ * Revision 0.4 1997/01/15 01:28:15 ji
+ * Added new transforms.
+ *
+ * Revision 0.3 1996/11/20 14:39:04 ji
+ * Minor cleanups.
+ * Rationalized debugging code.
+ *
+ * Revision 0.2 1996/11/02 00:18:33 ji
+ * First limited release.
+ *
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ *
+ */
diff --git a/src/libfreeswan/ipsec_xmit.h b/src/libfreeswan/ipsec_xmit.h
new file mode 100644
index 000000000..033984886
--- /dev/null
+++ b/src/libfreeswan/ipsec_xmit.h
@@ -0,0 +1,140 @@
+/*
+ * IPSEC tunneling code
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Richard Guy Briggs.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: ipsec_xmit.h,v 1.3 2004/06/13 19:37:07 as Exp $
+ */
+
+#include "freeswan/ipsec_sa.h"
+
+enum ipsec_xmit_value
+{
+ IPSEC_XMIT_STOLEN=2,
+ IPSEC_XMIT_PASS=1,
+ IPSEC_XMIT_OK=0,
+ IPSEC_XMIT_ERRMEMALLOC=-1,
+ IPSEC_XMIT_ESP_BADALG=-2,
+ IPSEC_XMIT_BADPROTO=-3,
+ IPSEC_XMIT_ESP_PUSHPULLERR=-4,
+ IPSEC_XMIT_BADLEN=-5,
+ IPSEC_XMIT_AH_BADALG=-6,
+ IPSEC_XMIT_SAIDNOTFOUND=-7,
+ IPSEC_XMIT_SAIDNOTLIVE=-8,
+ IPSEC_XMIT_REPLAYROLLED=-9,
+ IPSEC_XMIT_LIFETIMEFAILED=-10,
+ IPSEC_XMIT_CANNOTFRAG=-11,
+ IPSEC_XMIT_MSSERR=-12,
+ IPSEC_XMIT_ERRSKBALLOC=-13,
+ IPSEC_XMIT_ENCAPFAIL=-14,
+ IPSEC_XMIT_NODEV=-15,
+ IPSEC_XMIT_NOPRIVDEV=-16,
+ IPSEC_XMIT_NOPHYSDEV=-17,
+ IPSEC_XMIT_NOSKB=-18,
+ IPSEC_XMIT_NOIPV6=-19,
+ IPSEC_XMIT_NOIPOPTIONS=-20,
+ IPSEC_XMIT_TTLEXPIRED=-21,
+ IPSEC_XMIT_BADHHLEN=-22,
+ IPSEC_XMIT_PUSHPULLERR=-23,
+ IPSEC_XMIT_ROUTEERR=-24,
+ IPSEC_XMIT_RECURSDETECT=-25,
+ IPSEC_XMIT_IPSENDFAILURE=-26,
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ IPSEC_XMIT_ESPUDP=-27,
+#endif
+};
+
+struct ipsec_xmit_state
+{
+ struct sk_buff *skb; /* working skb pointer */
+ struct device *dev; /* working dev pointer */
+ struct ipsecpriv *prv; /* Our device' private space */
+ struct sk_buff *oskb; /* Original skb pointer */
+ struct net_device_stats *stats; /* This device's statistics */
+ struct iphdr *iph; /* Our new IP header */
+ __u32 newdst; /* The other SG's IP address */
+ __u32 orgdst; /* Original IP destination address */
+ __u32 orgedst; /* 1st SG's IP address */
+ __u32 newsrc; /* The new source SG's IP address */
+ __u32 orgsrc; /* Original IP source address */
+ __u32 innersrc; /* Innermost IP source address */
+ int iphlen; /* IP header length */
+ int pyldsz; /* upper protocol payload size */
+ int headroom;
+ int tailroom;
+ int max_headroom; /* The extra header space needed */
+ int max_tailroom; /* The extra stuffing needed */
+ int ll_headroom; /* The extra link layer hard_header space needed */
+ int tot_headroom; /* The total header space needed */
+ int tot_tailroom; /* The totalstuffing needed */
+ __u8 *saved_header; /* saved copy of the hard header */
+ unsigned short sport, dport;
+
+ struct sockaddr_encap matcher; /* eroute search key */
+ struct eroute *eroute;
+ struct ipsec_sa *ipsp, *ipsq; /* ipsec_sa pointers */
+ char sa_txt[SATOA_BUF];
+ size_t sa_len;
+ int hard_header_stripped; /* has the hard header been removed yet? */
+ int hard_header_len;
+ struct device *physdev;
+/* struct device *virtdev; */
+ short physmtu;
+ short mtudiff;
+#ifdef NET_21
+ struct rtable *route;
+#endif /* NET_21 */
+ struct sa_id outgoing_said;
+#ifdef NET_21
+ int pass;
+#endif /* NET_21 */
+ int error;
+ uint32_t eroute_pid;
+ struct ipsec_sa ips;
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ uint8_t natt_type;
+ uint8_t natt_head;
+ uint16_t natt_sport;
+ uint16_t natt_dport;
+#endif
+};
+
+#if 0 /* save for alg refactorisation */
+struct xform_functions
+{
+ enum ipsec_xmit_value (*checks)(struct ipsec_xmit_state *ixs,
+ struct sk_buff *skb);
+ enum ipsec_xmit_value (*encrypt)(struct ipsec_xmit_state *ixs);
+
+ enum ipsec_xmit_value (*setup_auth)(struct ipsec_xmit_state *ixs,
+ struct sk_buff *skb,
+ __u32 *replay,
+ unsigned char **authenticator);
+ enum ipsec_xmit_value (*calc_auth)(struct ipsec_xmit_state *ixs,
+ struct sk_buff *skb);
+};
+#endif
+
+enum ipsec_xmit_value
+ipsec_xmit_sanity_check_dev(struct ipsec_xmit_state *ixs);
+
+enum ipsec_xmit_value
+ipsec_xmit_sanity_check_skb(struct ipsec_xmit_state *ixs);
+
+enum ipsec_xmit_value
+ipsec_xmit_encap_bundle(struct ipsec_xmit_state *ixs);
+
+extern int ipsec_xmit_trap_count;
+extern int ipsec_xmit_trap_sendcount;
+
+extern void ipsec_extract_ports(struct iphdr * iph, struct sockaddr_encap * er);
diff --git a/src/libfreeswan/keyblobtoid.3 b/src/libfreeswan/keyblobtoid.3
new file mode 100644
index 000000000..be381531a
--- /dev/null
+++ b/src/libfreeswan/keyblobtoid.3
@@ -0,0 +1,103 @@
+.TH IPSEC_KEYBLOBTOID 3 "25 March 2002"
+.\" RCSID $Id: keyblobtoid.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec keyblobtoid, splitkeytoid \- generate key IDs from RSA keys
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "size_t keyblobtoid(const unsigned char *blob,"
+.ti +1c
+.B "size_t bloblen, char *dst, size_t dstlen);"
+.br
+.B "size_t splitkeytoid(const unsigned char *e, size_t elen,"
+.ti +1c
+.B "const unsigned char *m, size_t mlen, char *dst,
+.ti +1c
+.B "size_t dstlen);"
+.SH DESCRIPTION
+.I Keyblobtoid
+and
+.I splitkeytoid
+generate
+key IDs
+from RSA keys,
+for use in messages and reporting,
+writing the result to
+.IR dst .
+A
+.I key ID
+is a short ASCII string identifying a key;
+currently it is just the first nine characters of the base64
+encoding of the RFC 2537/3110 ``byte blob'' representation of the key.
+(Beware that no finite key ID can be collision-proof:
+there is always some small chance of two random keys having the
+same ID.)
+.PP
+.I Keyblobtoid
+generates a key ID from a key which is already in the form of an
+RFC 2537/3110 binary key
+.I blob
+(encoded exponent length, exponent, modulus).
+.PP
+.I Splitkeytoid
+generates a key ID from a key given in the form of a separate
+(binary) exponent
+.I e
+and modulus
+.IR m .
+.PP
+The
+.I dstlen
+parameter of either
+specifies the size of the
+.I dst
+parameter;
+under no circumstances are more than
+.I dstlen
+bytes written to
+.IR dst .
+A result which will not fit is truncated.
+.I Dstlen
+can be zero, in which case
+.I dst
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+.I freeswan.h
+header file defines a constant
+.B KEYID_BUF
+which is the size of a buffer large enough for worst-case results.
+.PP
+Both functions return
+.B 0
+for a failure, and otherwise
+always return the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+.P
+With keys generated by
+.IR ipsec_rsasigkey (3),
+the first two base64 digits are always the same,
+and the third carries only about one bit of information.
+It's worse with keys using longer fixed exponents,
+e.g. the 24-bit exponent that's common in X.509 certificates.
+However, being able to relate key IDs to the full
+base64 text form of keys by eye is sufficiently useful that this
+waste of space seems justifiable.
+The choice of nine digits is a compromise between bulk and
+probability of collision.
+.SH SEE ALSO
+RFC 3110,
+\fIRSA/SHA-1 SIGs and RSA KEYs in the Domain Name System (DNS)\fR,
+Eastlake, 2001
+(superseding the older but better-known RFC 2537).
+.SH DIAGNOSTICS
+Fatal errors are:
+key too short to supply enough bits to construct a complete key ID
+(almost certainly indicating a garbage key);
+exponent too long for its length to be representable.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
diff --git a/src/libfreeswan/keyblobtoid.c b/src/libfreeswan/keyblobtoid.c
new file mode 100644
index 000000000..7798601cf
--- /dev/null
+++ b/src/libfreeswan/keyblobtoid.c
@@ -0,0 +1,148 @@
+/*
+ * generate printable key IDs
+ * Copyright (C) 2002 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.
+ *
+ * RCSID $Id: keyblobtoid.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - keyblobtoid - generate a printable key ID from an RFC 2537/3110 key blob
+ * Current algorithm is just to use first nine base64 digits.
+ */
+size_t
+keyblobtoid(src, srclen, dst, dstlen)
+const unsigned char *src;
+size_t srclen;
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ char buf[KEYID_BUF];
+ size_t ret;
+# define NDIG 9
+
+ if (srclen < (NDIG*6 + 7)/8) {
+ strcpy(buf, "?len= ?");
+ buf[5] = '0' + srclen;
+ ret = 0;
+ } else {
+ (void) datatot(src, srclen, 64, buf, NDIG+1);
+ ret = NDIG+1;
+ }
+
+ if (dstlen > 0) {
+ if (strlen(buf)+1 > dstlen)
+ *(buf + dstlen - 1) = '\0';
+ strcpy(dst, buf);
+ }
+ return ret;
+}
+
+/*
+ - splitkeytoid - generate a printable key ID from exponent/modulus pair
+ * Just constructs the beginnings of a key blob and calls keyblobtoid().
+ */
+size_t
+splitkeytoid(e, elen, m, mlen, dst, dstlen)
+const unsigned char *e;
+size_t elen;
+const unsigned char *m;
+size_t mlen;
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ unsigned char buf[KEYID_BUF]; /* ample room */
+ unsigned char *bufend = buf + sizeof(buf);
+ unsigned char *p;
+ size_t n;
+
+ p = buf;
+ if (elen <= 255)
+ *p++ = elen;
+ else if ((elen &~ 0xffff) == 0) {
+ *p++ = 0;
+ *p++ = (elen>>8) & 0xff;
+ *p++ = elen & 0xff;
+ } else
+ return 0; /* unrepresentable exponent length */
+
+ n = bufend - p;
+ if (elen < n)
+ n = elen;
+ memcpy(p, e, n);
+ p += n;
+
+ n = bufend - p;
+ if (n > 0) {
+ if (mlen < n)
+ n = mlen;
+ memcpy(p, m, n);
+ p += n;
+ }
+
+ return keyblobtoid(buf, p - buf, dst, dstlen);
+}
+
+
+
+#ifdef KEYBLOBTOID_MAIN
+
+#include <stdio.h>
+
+void regress();
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ typedef unsigned char uc;
+ uc hexblob[] = "\x01\x03\x85\xf2\xd6\x76\x9b\x03\x59\xb6\x21\x52";
+ uc hexe[] = "\x03";
+ uc hexm[] = "\x85\xf2\xd6\x76\x9b\x03\x59\xb6\x21\x52\xef\x85";
+ char b64nine[] = "AQOF8tZ2m";
+ char b64six[] = "AQOF8t";
+ char buf[100];
+ size_t n;
+ char *b = b64nine;
+ size_t bl = strlen(b) + 1;
+ int st = 0;
+
+ n = keyblobtoid(hexblob, strlen(hexblob), buf, sizeof(buf));
+ if (n != bl) {
+ fprintf(stderr, "%s: keyblobtoid returned %d not %d\n",
+ argv[0], n, bl);
+ st = 1;
+ }
+ if (strcmp(buf, b) != 0) {
+ fprintf(stderr, "%s: keyblobtoid generated `%s' not `%s'\n",
+ argv[0], buf, b);
+ st = 1;
+ }
+ n = splitkeytoid(hexe, strlen(hexe), hexm, strlen(hexm), buf,
+ sizeof(buf));
+ if (n != bl) {
+ fprintf(stderr, "%s: splitkeytoid returned %d not %d\n",
+ argv[0], n, bl);
+ st = 1;
+ }
+ if (strcmp(buf, b) != 0) {
+ fprintf(stderr, "%s: splitkeytoid generated `%s' not `%s'\n",
+ argv[0], buf, b);
+ st = 1;
+ }
+ exit(st);
+}
+
+#endif /* KEYBLOBTOID_MAIN */
diff --git a/src/libfreeswan/optionsfrom.3 b/src/libfreeswan/optionsfrom.3
new file mode 100644
index 000000000..e270475bd
--- /dev/null
+++ b/src/libfreeswan/optionsfrom.3
@@ -0,0 +1,182 @@
+.TH IPSEC_OPTIONSFROM 3 "16 Oct 1998"
+.\" RCSID $Id: optionsfrom.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec optionsfrom \- read additional ``command-line'' options from file
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "const char *optionsfrom(char *filename, int *argcp,"
+.ti +1c
+.B "char ***argvp, int optind, FILE *errsto);"
+.SH DESCRIPTION
+.I Optionsfrom
+is called from within a
+.IR getopt_long (3)
+scan,
+as the result of the appearance of an option (preferably
+.BR \-\-optionsfrom )
+to insert additional ``command-line'' arguments
+into the scan immediately after
+the option.
+Typically this would be done to pick up options which are
+security-sensitive and should not be visible to
+.IR ps (1)
+and similar commands,
+and hence cannot be supplied as part
+of the actual command line or the environment.
+.PP
+.I Optionsfrom
+reads the additional arguments from the specified
+.IR filename ,
+allocates a new argument vector to hold pointers to the existing
+arguments plus the new ones,
+and amends
+.I argc
+and
+.I argv
+(via the pointers
+.I argcp
+and
+.IR argvp ,
+which must point to the
+.I argc
+and
+.I argv
+being supplied to
+.IR getopt_long (3))
+accordingly.
+.I Optind
+must be the index, in the original argument vector,
+of the next argument.
+.PP
+If
+.I errsto
+is NULL,
+.I optionsfrom
+returns NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+If
+.I errsto
+is non-NULL and an error occurs,
+.I optionsfrom
+prints a suitable complaint onto the
+.I errsto
+descriptor and invokes
+.I exit
+with an exit status of 2;
+this is a convenience for cases where more sophisticated
+responses are not required.
+.PP
+The text of existing arguments is not disturbed by
+.IR optionsfrom ,
+so pointers to them and into them remain valid.
+.PP
+The file of additional arguments is an ASCII text file.
+Lines consisting solely of white space,
+and lines beginning with
+.BR # ,
+are comments and are ignored.
+Otherwise, a line which does not begin with
+.BR \-
+is taken to be a single argument;
+if it both begins and ends with double-quote ("),
+those quotes are stripped off (note, no other processing is done within
+the line!).
+A line beginning with
+.B \-
+is considered to contain multiple arguments separated by white space.
+.PP
+Because
+.I optionsfrom
+reads its entire file before the
+.IR getopt_long (3)
+scan is resumed, an
+.I optionsfrom
+file can contain another
+.B \-\-optionsfrom
+option.
+Obviously, infinite loops are possible here.
+If
+.I errsto
+is non-NULL,
+.I optionsfrom
+considers it an error to be called more than 100 times.
+If
+.I errsto
+is NULL,
+loop detection is up to the caller
+(and the internal loop counter is zeroed out).
+.SH EXAMPLE
+A reasonable way to invoke
+.I optionsfrom
+would be like so:
+.PP
+.nf
+.ft B
+#include <getopt.h>
+
+struct option opts[] = {
+ /* ... */
+ "optionsfrom", 1, NULL, '+',
+ /* ... */
+};
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ int opt;
+ extern char *optarg;
+ extern int optind;
+
+ while ((opt = getopt_long(argc, argv, "", opts, NULL)) != EOF)
+ switch (opt) {
+ /* ... */
+ case '+': /* optionsfrom */
+ optionsfrom(optarg, &argc, &argv, optind, stderr);
+ /* does not return on error */
+ break;
+ /* ... */
+ }
+ /* ... */
+.ft
+.fi
+.SH SEE ALSO
+getopt_long(3)
+.SH DIAGNOSTICS
+Errors in
+.I optionsfrom
+are:
+unable to open file;
+attempt to allocate temporary storage for argument or
+argument vector failed;
+read error in file;
+line too long.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+The double-quote convention is rather simplistic.
+.PP
+Line length is currently limited to 1023 bytes,
+and there is no continuation convention.
+.PP
+The restriction of error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+.PP
+The error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+.PP
+There is a certain element of unwarranted chumminess with
+the insides of
+.IR getopt_long (3)
+here.
+No non-public interfaces are actually used, but
+.IR optionsfrom
+does rely on
+.IR getopt_long (3)
+being well-behaved in certain ways that are not actually
+promised by the specs.
diff --git a/src/libfreeswan/optionsfrom.c b/src/libfreeswan/optionsfrom.c
new file mode 100644
index 000000000..d96a3124d
--- /dev/null
+++ b/src/libfreeswan/optionsfrom.c
@@ -0,0 +1,301 @@
+/*
+ * pick up more options from a file, in the middle of an option scan
+ * Copyright (C) 1998, 1999 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.
+ *
+ * RCSID $Id: optionsfrom.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+#include <stdio.h>
+
+#define MAX 100 /* loop-detection limit */
+
+/* internal work area */
+struct work {
+# define LOTS 1024
+ char buf[LOTS];
+ char *line;
+ char *pending;
+};
+
+static const char *dowork(const char *, int *, char ***, int);
+static const char *getanarg(FILE *, struct work *, char **);
+static char *getline(FILE *, char *, size_t);
+
+/*
+ - optionsfrom - add some options, taken from a file, to argc/argv
+ * If errsto is non-NULL, does not return in event of error.
+ */
+const char * /* NULL for success, else string literal */
+optionsfrom(filename, argcp, argvp, optind, errsto)
+const char *filename;
+int *argcp; /* pointer to argc */
+char ***argvp; /* pointer to argv */
+int optind; /* current optind, number of next argument */
+FILE *errsto; /* where to report errors (NULL means return) */
+{
+ const char *e;
+ static int nuses = 0;
+
+ if (errsto != NULL) {
+ nuses++;
+ if (nuses >= MAX) {
+ fprintf(errsto,
+ "%s: optionsfrom called %d times, looping?\n",
+ (*argvp)[0], nuses);
+ exit(2);
+ }
+ } else
+ nuses = 0;
+
+ e = dowork(filename, argcp, argvp, optind);
+ if (e != NULL && errsto != NULL) {
+ fprintf(errsto, "%s: optionsfrom failed: %s\n", (*argvp)[0], e);
+ exit(2);
+ }
+ return e;
+}
+
+/*
+ - dowork - do all the real work of optionsfrom
+ * Does not alter the existing arguments, but does relocate and alter
+ * the argv pointer vector.
+ */
+static const char * /* NULL for success, else string literal */
+dowork(filename, argcp, argvp, optind)
+const char *filename;
+int *argcp; /* pointer to argc */
+char ***argvp; /* pointer to argv */
+int optind; /* current optind, number of next argument */
+{
+ char **newargv;
+ char **tmp;
+ int newargc;
+ int next; /* place for next argument */
+ int room; /* how many more new arguments we can hold */
+# define SOME 10 /* first guess at how many we'll need */
+ FILE *f;
+ int i;
+ const char *p;
+ struct work wa; /* for getanarg() */
+
+ f = fopen(filename, "r");
+ if (f == NULL)
+ return "unable to open file";
+
+ newargc = *argcp + SOME;
+ newargv = malloc((newargc+1) * sizeof(char *));
+ if (newargv == NULL)
+ return "unable to allocate memory";
+ memcpy(newargv, *argvp, optind * sizeof(char *));
+ room = SOME;
+ next = optind;
+
+ newargv[next] = NULL;
+ wa.pending = NULL;
+ while ((p = getanarg(f, &wa, &newargv[next])) == NULL) {
+ if (room == 0) {
+ newargc += SOME;
+ tmp = realloc(newargv, (newargc+1) * sizeof(char *));
+ if (tmp == NULL) {
+ p = "out of space for new argv";
+ break; /* NOTE BREAK OUT */
+ }
+ newargv = tmp;
+ room += SOME;
+ }
+ next++;
+ room--;
+ }
+ if (p != NULL && !feof(f)) { /* error of some kind */
+ for (i = optind+1; i <= next; i++)
+ if (newargv[i] != NULL)
+ free(newargv[i]);
+ free(newargv);
+ fclose(f);
+ return p;
+ }
+
+ fclose(f);
+ memcpy(newargv + next, *argvp + optind,
+ (*argcp+1-optind) * sizeof(char *));
+ *argcp += next - optind;
+ *argvp = newargv;
+ return NULL;
+}
+
+/*
+ - getanarg - get a malloced argument from the file
+ */
+static const char * /* NULL for success, else string literal */
+getanarg(f, w, linep)
+FILE *f;
+struct work *w;
+char **linep; /* where to store pointer if successful */
+{
+ size_t len;
+ char *p;
+ char *endp;
+
+ while (w->pending == NULL) { /* no pending line */
+ if ((w->line = getline(f, w->buf, sizeof(w->buf))) == NULL)
+ return "error in line read"; /* caller checks EOF */
+ if (w->line[0] != '#' &&
+ *(w->line + strspn(w->line, " \t")) != '\0')
+ w->pending = w->line;
+ }
+
+ if (w->pending == w->line && w->line[0] != '-') {
+ /* fresh plain line */
+ w->pending = NULL;
+ p = w->line;
+ endp = p + strlen(p);
+ if (*p == '"' && endp > p+1 && *(endp-1) == '"') {
+ p++;
+ endp--;
+ *endp = '\0';
+ }
+ if (w->line == w->buf) {
+ *linep = malloc(endp - p + 1);
+ if (*linep == NULL)
+ return "out of memory for new line";
+ strcpy(*linep, p);
+ } else /* getline already malloced it */
+ *linep = p;
+ return NULL;
+ }
+
+ /* chip off a piece of a pending line */
+ p = w->pending;
+ p += strspn(p, " \t");
+ endp = p + strcspn(p, " \t");
+ len = endp - p;
+ if (*endp != '\0') {
+ *endp++ = '\0';
+ endp += strspn(endp, " \t");
+ }
+ /* endp now points to next real character, or to line-end NUL */
+ *linep = malloc(len + 1);
+ if (*linep == NULL) {
+ if (w->line != w->buf)
+ free(w->line);
+ return "out of memory for new argument";
+ }
+ strcpy(*linep, p);
+ if (*endp == '\0') {
+ w->pending = NULL;
+ if (w->line != w->buf)
+ free(w->line);
+ } else
+ w->pending = endp;
+ return NULL;
+}
+
+/*
+ - getline - read a line from the file, trim newline off
+ */
+static char * /* pointer to line, NULL for eof/error */
+getline(f, buf, bufsize)
+FILE *f;
+char *buf; /* buffer to use, if convenient */
+size_t bufsize; /* size of buf */
+{
+ size_t len;
+
+ if (fgets(buf, bufsize, f) == NULL)
+ return NULL;
+ len = strlen(buf);
+
+ if (len < bufsize-1 || buf[bufsize-1] == '\n') {
+ /* it fit */
+ buf[len-1] = '\0';
+ return buf;
+ }
+
+ /* oh crud, buffer overflow */
+ /* for now, to hell with it */
+ return NULL;
+}
+
+
+
+#ifdef TEST
+
+#include <getopt.h>
+
+char usage[] = "Usage: tester [--foo] [--bar] [--optionsfrom file] arg ...";
+struct option opts[] = {
+ "foo", 0, NULL, 'f',
+ "bar", 0, NULL, 'b',
+ "builtin", 0, NULL, 'B',
+ "optionsfrom", 1, NULL, '+',
+ "help", 0, NULL, 'h',
+ "version", 0, NULL, 'v',
+ 0, 0, NULL, 0,
+};
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ int opt;
+ extern char *optarg;
+ extern int optind;
+ int errflg = 0;
+ const char *p;
+ int i;
+ FILE *errs = NULL;
+
+ while ((opt = getopt_long(argc, argv, "", opts, NULL)) != EOF)
+ switch (opt) {
+ case 'f':
+ case 'b':
+ break;
+ case 'B':
+ errs = stderr;
+ break;
+ case '+': /* optionsfrom */
+ p = optionsfrom(optarg, &argc, &argv, optind, errs);
+ if (p != NULL) {
+ fprintf(stderr, "%s: optionsfrom error: %s\n",
+ argv[0], p);
+ exit(1);
+ }
+ break;
+ case 'h': /* help */
+ printf("%s\n", usage);
+ exit(0);
+ break;
+ case 'v': /* version */
+ printf("1\n");
+ exit(0);
+ break;
+ case '?':
+ default:
+ errflg = 1;
+ break;
+ }
+ if (errflg) {
+ fprintf(stderr, "%s\n", usage);
+ exit(2);
+ }
+
+ for (i = 1; i < argc; i++)
+ printf("%d: `%s'\n", i, argv[i]);
+ exit(0);
+}
+
+
+#endif /* TEST */
diff --git a/src/libfreeswan/pfkey.h b/src/libfreeswan/pfkey.h
new file mode 100644
index 000000000..afa5ce032
--- /dev/null
+++ b/src/libfreeswan/pfkey.h
@@ -0,0 +1,498 @@
+/*
+ * FreeS/WAN specific PF_KEY headers
+ * Copyright (C) 1999, 2000, 2001 Richard Guy Briggs.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: pfkey.h,v 1.2 2004/03/22 21:53:18 as Exp $
+ */
+
+#ifndef __NET_IPSEC_PF_KEY_H
+#define __NET_IPSEC_PF_KEY_H
+#ifdef __KERNEL__
+extern struct proto_ops pfkey_proto_ops;
+typedef struct sock pfkey_sock;
+extern int debug_pfkey;
+
+extern /* void */ int pfkey_init(void);
+extern /* void */ int pfkey_cleanup(void);
+
+extern struct sock *pfkey_sock_list;
+struct socket_list
+{
+ struct socket *socketp;
+ struct socket_list *next;
+};
+extern int pfkey_list_insert_socket(struct socket*, struct socket_list**);
+extern int pfkey_list_remove_socket(struct socket*, struct socket_list**);
+extern struct socket_list *pfkey_open_sockets;
+extern struct socket_list *pfkey_registered_sockets[SADB_SATYPE_MAX+1];
+
+/*
+ * There is a field-by-field copy in klips/net/ipsec/ipsec_alg.h
+ * please keep in sync until we migrate all support stuff
+ * to ipsec_alg objects
+ */
+struct supported
+{
+ uint16_t supported_alg_exttype;
+ uint8_t supported_alg_id;
+ uint8_t supported_alg_ivlen;
+ uint16_t supported_alg_minbits;
+ uint16_t supported_alg_maxbits;
+};
+extern struct supported_list *pfkey_supported_list[SADB_SATYPE_MAX+1];
+struct supported_list
+{
+ struct supported *supportedp;
+ struct supported_list *next;
+};
+extern int pfkey_list_insert_supported(struct supported*, struct supported_list**);
+extern int pfkey_list_remove_supported(struct supported*, struct supported_list**);
+
+struct sockaddr_key
+{
+ uint16_t key_family; /* PF_KEY */
+ uint16_t key_pad; /* not used */
+ uint32_t key_pid; /* process ID */
+};
+
+struct pfkey_extracted_data
+{
+ struct ipsec_sa* ips;
+ struct ipsec_sa* ips2;
+ struct eroute *eroute;
+};
+
+extern int
+pfkey_alloc_eroute(struct eroute** eroute);
+
+extern int
+pfkey_sa_process(struct sadb_ext *pfkey_ext,
+ struct pfkey_extracted_data* extr);
+
+extern int
+pfkey_lifetime_process(struct sadb_ext *pfkey_ext,
+ struct pfkey_extracted_data* extr);
+
+extern int
+pfkey_address_process(struct sadb_ext *pfkey_ext,
+ struct pfkey_extracted_data* extr);
+
+extern int
+pfkey_key_process(struct sadb_ext *pfkey_ext,
+ struct pfkey_extracted_data* extr);
+
+extern int
+pfkey_ident_process(struct sadb_ext *pfkey_ext,
+ struct pfkey_extracted_data* extr);
+
+extern int
+pfkey_sens_process(struct sadb_ext *pfkey_ext,
+ struct pfkey_extracted_data* extr);
+
+extern int
+pfkey_prop_process(struct sadb_ext *pfkey_ext,
+ struct pfkey_extracted_data* extr);
+
+extern int
+pfkey_supported_process(struct sadb_ext *pfkey_ext,
+ struct pfkey_extracted_data* extr);
+
+extern int
+pfkey_spirange_process(struct sadb_ext *pfkey_ext,
+ struct pfkey_extracted_data* extr);
+
+extern int
+pfkey_x_kmprivate_process(struct sadb_ext *pfkey_ext,
+ struct pfkey_extracted_data* extr);
+
+extern int
+pfkey_x_satype_process(struct sadb_ext *pfkey_ext,
+ struct pfkey_extracted_data* extr);
+
+extern int
+pfkey_x_debug_process(struct sadb_ext *pfkey_ext,
+ struct pfkey_extracted_data* extr);
+
+extern int pfkey_register_reply(int satype, struct sadb_msg *);
+extern int pfkey_upmsg(struct socket *, struct sadb_msg *);
+extern int pfkey_expire(struct ipsec_sa *, int);
+extern int pfkey_acquire(struct ipsec_sa *);
+#else /* ! __KERNEL__ */
+
+extern void (*pfkey_debug_func)(const char *message, ...);
+
+#endif /* __KERNEL__ */
+
+extern uint8_t satype2proto(uint8_t satype);
+extern uint8_t proto2satype(uint8_t proto);
+extern char* satype2name(uint8_t satype);
+extern char* proto2name(uint8_t proto);
+
+struct key_opt
+{
+ uint32_t key_pid; /* process ID */
+ struct sock *sk;
+};
+
+#define key_pid(sk) ((struct key_opt*)&((sk)->protinfo))->key_pid
+
+#define IPSEC_PFKEYv2_ALIGN (sizeof(uint64_t)/sizeof(uint8_t))
+#define BITS_PER_OCTET 8
+#define OCTETBITS 8
+#define PFKEYBITS 64
+#define DIVUP(x,y) ((x + y -1) / y) /* divide, rounding upwards */
+#define ALIGN_N(x,y) (DIVUP(x,y) * y) /* align on y boundary */
+
+#define PFKEYv2_MAX_MSGSIZE 4096
+
+/*
+ * PF_KEYv2 permitted and required extensions in and out bitmaps
+ */
+struct pf_key_ext_parsers_def {
+ int (*parser)(struct sadb_ext*);
+ char *parser_name;
+};
+
+
+extern unsigned int extensions_bitmaps[2/*in/out*/][2/*perm/req*/][SADB_MAX + 1/*ext*/];
+#define EXT_BITS_IN 0
+#define EXT_BITS_OUT 1
+#define EXT_BITS_PERM 0
+#define EXT_BITS_REQ 1
+
+extern void pfkey_extensions_init(struct sadb_ext *extensions[SADB_EXT_MAX + 1]);
+extern void pfkey_extensions_free(struct sadb_ext *extensions[SADB_EXT_MAX + 1]);
+extern void pfkey_msg_free(struct sadb_msg **pfkey_msg);
+
+extern int pfkey_msg_parse(struct sadb_msg *pfkey_msg,
+ struct pf_key_ext_parsers_def *ext_parsers[],
+ struct sadb_ext **extensions,
+ int dir);
+
+/*
+ * PF_KEYv2 build function prototypes
+ */
+
+int
+pfkey_msg_hdr_build(struct sadb_ext** pfkey_ext,
+ uint8_t msg_type,
+ uint8_t satype,
+ uint8_t msg_errno,
+ uint32_t seq,
+ uint32_t pid);
+
+int
+pfkey_sa_ref_build(struct sadb_ext ** pfkey_ext,
+ uint16_t exttype,
+ uint32_t spi, /* in network order */
+ uint8_t replay_window,
+ uint8_t sa_state,
+ uint8_t auth,
+ uint8_t encrypt,
+ uint32_t flags,
+ uint32_t/*IPsecSAref_t*/ ref);
+
+int
+pfkey_sa_build(struct sadb_ext ** pfkey_ext,
+ uint16_t exttype,
+ uint32_t spi, /* in network order */
+ uint8_t replay_window,
+ uint8_t sa_state,
+ uint8_t auth,
+ uint8_t encrypt,
+ uint32_t flags);
+
+int
+pfkey_lifetime_build(struct sadb_ext ** pfkey_ext,
+ uint16_t exttype,
+ uint32_t allocations,
+ uint64_t bytes,
+ uint64_t addtime,
+ uint64_t usetime,
+ uint32_t packets);
+
+int
+pfkey_address_build(struct sadb_ext** pfkey_ext,
+ uint16_t exttype,
+ uint8_t proto,
+ uint8_t prefixlen,
+ struct sockaddr* address);
+
+int
+pfkey_key_build(struct sadb_ext** pfkey_ext,
+ uint16_t exttype,
+ uint16_t key_bits,
+ char* key);
+
+int
+pfkey_ident_build(struct sadb_ext** pfkey_ext,
+ uint16_t exttype,
+ uint16_t ident_type,
+ uint64_t ident_id,
+ uint8_t ident_len,
+ char* ident_string);
+
+#ifdef __KERNEL__
+extern int pfkey_nat_t_new_mapping(struct ipsec_sa *, struct sockaddr *, __u16);
+extern int pfkey_x_nat_t_type_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr);
+extern int pfkey_x_nat_t_port_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr);
+#endif /* __KERNEL__ */
+
+int
+pfkey_x_nat_t_type_build(struct sadb_ext** pfkey_ext,
+ uint8_t type);
+int
+pfkey_x_nat_t_port_build(struct sadb_ext** pfkey_ext,
+ uint16_t exttype,
+ uint16_t port);
+
+int
+pfkey_sens_build(struct sadb_ext** pfkey_ext,
+ uint32_t dpd,
+ uint8_t sens_level,
+ uint8_t sens_len,
+ uint64_t* sens_bitmap,
+ uint8_t integ_level,
+ uint8_t integ_len,
+ uint64_t* integ_bitmap);
+
+int
+pfkey_x_protocol_build(struct sadb_ext **, uint8_t);
+
+
+int
+pfkey_prop_build(struct sadb_ext** pfkey_ext,
+ uint8_t replay,
+ unsigned int comb_num,
+ struct sadb_comb* comb);
+
+int
+pfkey_supported_build(struct sadb_ext** pfkey_ext,
+ uint16_t exttype,
+ unsigned int alg_num,
+ struct sadb_alg* alg);
+
+int
+pfkey_spirange_build(struct sadb_ext** pfkey_ext,
+ uint16_t exttype,
+ uint32_t min,
+ uint32_t max);
+
+int
+pfkey_x_kmprivate_build(struct sadb_ext** pfkey_ext);
+
+int
+pfkey_x_satype_build(struct sadb_ext** pfkey_ext,
+ uint8_t satype);
+
+int
+pfkey_x_debug_build(struct sadb_ext** pfkey_ext,
+ uint32_t tunnel,
+ uint32_t netlink,
+ uint32_t xform,
+ uint32_t eroute,
+ uint32_t spi,
+ uint32_t radij,
+ uint32_t esp,
+ uint32_t ah,
+ uint32_t rcv,
+ uint32_t pfkey,
+ uint32_t ipcomp,
+ uint32_t verbose);
+
+int
+pfkey_msg_build(struct sadb_msg** pfkey_msg,
+ struct sadb_ext* extensions[],
+ int dir);
+
+/* in pfkey_v2_debug.c - routines to decode numbers -> strings */
+const char *
+pfkey_v2_sadb_ext_string(int extnum);
+
+const char *
+pfkey_v2_sadb_type_string(int sadb_type);
+
+
+#endif /* __NET_IPSEC_PF_KEY_H */
+
+/*
+ * $Log: pfkey.h,v $
+ * Revision 1.2 2004/03/22 21:53:18 as
+ * merged alg-0.8.1 branch with HEAD
+ *
+ * Revision 1.1.2.1.2.1 2004/03/16 09:48:18 as
+ * alg-0.8.1rc12 patch merged
+ *
+ * Revision 1.1.2.1 2004/03/15 22:30:06 as
+ * nat-0.6c patch merged
+ *
+ * Revision 1.1 2004/03/15 20:35:25 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.42 2003/08/25 22:08:19 mcr
+ * removed pfkey_proto_init() from pfkey.h for 2.6 support.
+ *
+ * Revision 1.41 2003/05/07 17:28:57 mcr
+ * new function pfkey_debug_func added for us in debugging from
+ * pfkey library.
+ *
+ * Revision 1.40 2003/01/30 02:31:34 rgb
+ *
+ * Convert IPsecSAref_t from signed to unsigned to fix apparent SAref exhaustion bug.
+ *
+ * Revision 1.39 2002/09/20 15:40:21 rgb
+ * Switch from pfkey_alloc_ipsec_sa() to ipsec_sa_alloc().
+ * Added ref parameter to pfkey_sa_build().
+ * Cleaned out unused cruft.
+ *
+ * Revision 1.38 2002/05/14 02:37:24 rgb
+ * Change all references to tdb, TDB or Tunnel Descriptor Block to ips,
+ * ipsec_sa or ipsec_sa.
+ * Added function prototypes for the functions moved to
+ * pfkey_v2_ext_process.c.
+ *
+ * Revision 1.37 2002/04/24 07:36:49 mcr
+ * Moved from ./lib/pfkey.h,v
+ *
+ * Revision 1.36 2002/01/20 20:34:49 mcr
+ * added pfkey_v2_sadb_type_string to decode sadb_type to string.
+ *
+ * Revision 1.35 2001/11/27 05:27:47 mcr
+ * pfkey parses are now maintained by a structure
+ * that includes their name for debug purposes.
+ *
+ * Revision 1.34 2001/11/26 09:23:53 rgb
+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
+ *
+ * Revision 1.33 2001/11/06 19:47:47 rgb
+ * Added packet parameter to lifetime and comb structures.
+ *
+ * Revision 1.32 2001/09/08 21:13:34 rgb
+ * Added pfkey ident extension support for ISAKMPd. (NetCelo)
+ *
+ * Revision 1.31 2001/06/14 19:35:16 rgb
+ * Update copyright date.
+ *
+ * Revision 1.30 2001/02/27 07:04:52 rgb
+ * Added satype2name prototype.
+ *
+ * Revision 1.29 2001/02/26 19:59:33 rgb
+ * Ditch unused sadb_satype2proto[], replaced by satype2proto().
+ *
+ * Revision 1.28 2000/10/10 20:10:19 rgb
+ * Added support for debug_ipcomp and debug_verbose to klipsdebug.
+ *
+ * Revision 1.27 2000/09/21 04:20:45 rgb
+ * Fixed array size off-by-one error. (Thanks Svenning!)
+ *
+ * Revision 1.26 2000/09/12 03:26:05 rgb
+ * Added pfkey_acquire prototype.
+ *
+ * Revision 1.25 2000/09/08 19:21:28 rgb
+ * Fix pfkey_prop_build() parameter to be only single indirection.
+ *
+ * Revision 1.24 2000/09/01 18:46:42 rgb
+ * Added a supported algorithms array lists, one per satype and registered
+ * existing algorithms.
+ * Fixed pfkey_list_{insert,remove}_{socket,support}() to allow change to
+ * list.
+ *
+ * Revision 1.23 2000/08/27 01:55:26 rgb
+ * Define OCTETBITS and PFKEYBITS to avoid using 'magic' numbers in code.
+ *
+ * Revision 1.22 2000/08/20 21:39:23 rgb
+ * Added kernel prototypes for kernel funcitions pfkey_upmsg() and
+ * pfkey_expire().
+ *
+ * Revision 1.21 2000/08/15 17:29:23 rgb
+ * Fixes from SZI to untested pfkey_prop_build().
+ *
+ * Revision 1.20 2000/05/10 20:14:19 rgb
+ * Fleshed out sensitivity, proposal and supported extensions.
+ *
+ * Revision 1.19 2000/03/16 14:07:23 rgb
+ * Renamed ALIGN macro to avoid fighting with others in kernel.
+ *
+ * Revision 1.18 2000/01/22 23:24:06 rgb
+ * Added prototypes for proto2satype(), satype2proto() and proto2name().
+ *
+ * Revision 1.17 2000/01/21 06:26:59 rgb
+ * Converted from double tdb arguments to one structure (extr)
+ * containing pointers to all temporary information structures.
+ * Added klipsdebug switching capability.
+ * Dropped unused argument to pfkey_x_satype_build().
+ *
+ * Revision 1.16 1999/12/29 21:17:41 rgb
+ * Changed pfkey_msg_build() I/F to include a struct sadb_msg**
+ * parameter for cleaner manipulation of extensions[] and to guard
+ * against potential memory leaks.
+ * Changed the I/F to pfkey_msg_free() for the same reason.
+ *
+ * Revision 1.15 1999/12/09 23:12:54 rgb
+ * Added macro for BITS_PER_OCTET.
+ * Added argument to pfkey_sa_build() to do eroutes.
+ *
+ * Revision 1.14 1999/12/08 20:33:25 rgb
+ * Changed sa_family_t to uint16_t for 2.0.xx compatibility.
+ *
+ * Revision 1.13 1999/12/07 19:53:40 rgb
+ * Removed unused first argument from extension parsers.
+ * Changed __u* types to uint* to avoid use of asm/types.h and
+ * sys/types.h in userspace code.
+ * Added function prototypes for pfkey message and extensions
+ * initialisation and cleanup.
+ *
+ * Revision 1.12 1999/12/01 22:19:38 rgb
+ * Change pfkey_sa_build to accept an SPI in network byte order.
+ *
+ * Revision 1.11 1999/11/27 11:55:26 rgb
+ * Added extern sadb_satype2proto to enable moving protocol lookup table
+ * to lib/pfkey_v2_parse.c.
+ * Delete unused, moved typedefs.
+ * Add argument to pfkey_msg_parse() for direction.
+ * Consolidated the 4 1-d extension bitmap arrays into one 4-d array.
+ *
+ * Revision 1.10 1999/11/23 22:29:21 rgb
+ * This file has been moved in the distribution from klips/net/ipsec to
+ * lib.
+ * Add macros for dealing with alignment and rounding up more opaquely.
+ * The uint<n>_t type defines have been moved to freeswan.h to avoid
+ * chicken-and-egg problems.
+ * Add macros for dealing with alignment and rounding up more opaque.
+ * Added prototypes for using extention header bitmaps.
+ * Added prototypes of all the build functions.
+ *
+ * Revision 1.9 1999/11/20 21:59:48 rgb
+ * Moved socketlist type declarations and prototypes for shared use.
+ * Slightly modified scope of sockaddr_key declaration.
+ *
+ * Revision 1.8 1999/11/17 14:34:25 rgb
+ * Protect sa_family_t from being used in userspace with GLIBC<2.
+ *
+ * Revision 1.7 1999/10/27 19:40:35 rgb
+ * Add a maximum PFKEY packet size macro.
+ *
+ * Revision 1.6 1999/10/26 16:58:58 rgb
+ * Created a sockaddr_key and key_opt socket extension structures.
+ *
+ * Revision 1.5 1999/06/10 05:24:41 rgb
+ * Renamed variables to reduce confusion.
+ *
+ * Revision 1.4 1999/04/29 15:21:11 rgb
+ * Add pfkey support to debugging.
+ * Add return values to init and cleanup functions.
+ *
+ * Revision 1.3 1999/04/15 17:58:07 rgb
+ * Add RCSID labels.
+ *
+ */
diff --git a/src/libfreeswan/pfkey_v2_build.c b/src/libfreeswan/pfkey_v2_build.c
new file mode 100644
index 000000000..340c12cfe
--- /dev/null
+++ b/src/libfreeswan/pfkey_v2_build.c
@@ -0,0 +1,1435 @@
+/*
+ * RFC2367 PF_KEYv2 Key management API message parser
+ * Copyright (C) 1999, 2000, 2001 Richard Guy Briggs.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: pfkey_v2_build.c,v 1.4 2005/04/07 19:43:52 as Exp $
+ */
+
+/*
+ * Template from klips/net/ipsec/ipsec/ipsec_parser.c.
+ */
+
+char pfkey_v2_build_c_version[] = "$Id: pfkey_v2_build.c,v 1.4 2005/04/07 19:43:52 as Exp $";
+
+/*
+ * Some ugly stuff to allow consistent debugging code for use in the
+ * kernel and in user space
+*/
+
+#ifdef __KERNEL__
+
+# include <linux/kernel.h> /* for printk */
+
+# include "freeswan/ipsec_kversion.h" /* for malloc switch */
+# ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+# else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+# endif /* MALLOC_SLAB */
+# include <linux/errno.h> /* error codes */
+# include <linux/types.h> /* size_t */
+# include <linux/interrupt.h> /* mark_bh */
+
+# include <linux/netdevice.h> /* struct device, and other headers */
+# include <linux/etherdevice.h> /* eth_type_trans */
+# include <linux/ip.h> /* struct iphdr */
+# if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+# include <linux/ipv6.h> /* struct ipv6hdr */
+# endif /* if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
+
+# define MALLOC(size) kmalloc(size, GFP_ATOMIC)
+# define FREE(obj) kfree(obj)
+# include <freeswan.h>
+#else /* __KERNEL__ */
+
+# include <sys/types.h>
+# include <linux/types.h>
+# include <linux/errno.h>
+# include <malloc.h>
+# include <string.h> /* memset */
+
+# include <freeswan.h>
+unsigned int pfkey_lib_debug = 0;
+
+void (*pfkey_debug_func)(const char *message, ...) PRINTF_LIKE(1);
+
+/* #define PLUTO */
+
+#define DEBUGGING(args...) if(pfkey_lib_debug) { \
+ if(pfkey_debug_func != NULL) { \
+ (*pfkey_debug_func)("pfkey_lib_debug:" args); \
+ } else { \
+ printf("pfkey_lib_debug:" args); \
+ } }
+# define MALLOC(size) malloc(size)
+# define FREE(obj) free(obj)
+#endif /* __KERNEL__ */
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#ifdef __KERNEL__
+
+#include "freeswan/radij.h" /* rd_nodes */
+#include "freeswan/ipsec_encap.h" /* sockaddr_encap */
+
+# define DEBUGGING(args...) \
+ KLIPS_PRINT(debug_pfkey, "klips_debug:" args)
+#endif /* __KERNEL__ */
+
+#include "ipsec_sa.h" /* IPSEC_SAREF_NULL, IPSEC_SA_REF_TABLE_IDX_WIDTH */
+
+#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
+
+void
+pfkey_extensions_init(struct sadb_ext *extensions[SADB_EXT_MAX + 1])
+{
+ int i;
+
+ for (i = 0; i != SADB_EXT_MAX + 1; i++) {
+ extensions[i] = NULL;
+ }
+}
+
+void
+pfkey_extensions_free(struct sadb_ext *extensions[SADB_EXT_MAX + 1])
+{
+ int i;
+
+ if (!extensions) {
+ return;
+ }
+
+ if (extensions[0]) {
+ memset(extensions[0], 0, sizeof(struct sadb_msg));
+ FREE(extensions[0]);
+ extensions[0] = NULL;
+ }
+
+ for (i = 1; i != SADB_EXT_MAX + 1; i++) {
+ if(extensions[i]) {
+ memset(extensions[i], 0, extensions[i]->sadb_ext_len * IPSEC_PFKEYv2_ALIGN);
+ FREE(extensions[i]);
+ extensions[i] = NULL;
+ }
+ }
+}
+
+void
+pfkey_msg_free(struct sadb_msg **pfkey_msg)
+{
+ if (*pfkey_msg) {
+ memset(*pfkey_msg, 0, (*pfkey_msg)->sadb_msg_len * IPSEC_PFKEYv2_ALIGN);
+ FREE(*pfkey_msg);
+ *pfkey_msg = NULL;
+ }
+}
+
+/* Default extension builders taken from the KLIPS code */
+
+int
+pfkey_msg_hdr_build(struct sadb_ext** pfkey_ext,
+ uint8_t msg_type,
+ uint8_t satype,
+ uint8_t msg_errno,
+ uint32_t seq,
+ uint32_t pid)
+{
+ int error = 0;
+ struct sadb_msg *pfkey_msg = (struct sadb_msg *)*pfkey_ext;
+
+ DEBUGGING(
+ "pfkey_msg_hdr_build:\n");
+ DEBUGGING(
+ "pfkey_msg_hdr_build: "
+ "on_entry &pfkey_ext=0p%p pfkey_ext=0p%p *pfkey_ext=0p%p.\n",
+ &pfkey_ext,
+ pfkey_ext,
+ *pfkey_ext);
+ /* sanity checks... */
+ if (pfkey_msg) {
+ DEBUGGING(
+ "pfkey_msg_hdr_build: "
+ "why is pfkey_msg already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ if (!msg_type) {
+ DEBUGGING(
+ "pfkey_msg_hdr_build: "
+ "msg type not set, must be non-zero..\n");
+ SENDERR(EINVAL);
+ }
+
+ if (msg_type > SADB_MAX) {
+ DEBUGGING(
+ "pfkey_msg_hdr_build: "
+ "msg type too large:%d.\n",
+ msg_type);
+ SENDERR(EINVAL);
+ }
+
+ if (satype > SADB_SATYPE_MAX) {
+ DEBUGGING(
+ "pfkey_msg_hdr_build: "
+ "satype %d > max %d\n",
+ satype, SADB_SATYPE_MAX);
+ SENDERR(EINVAL);
+ }
+
+ pfkey_msg = (struct sadb_msg*)MALLOC(sizeof(struct sadb_msg));
+ *pfkey_ext = (struct sadb_ext*)pfkey_msg;
+
+ if (pfkey_msg == NULL) {
+ DEBUGGING(
+ "pfkey_msg_hdr_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_msg, 0, sizeof(struct sadb_msg));
+
+ pfkey_msg->sadb_msg_len = sizeof(struct sadb_msg) / IPSEC_PFKEYv2_ALIGN;
+
+ pfkey_msg->sadb_msg_type = msg_type;
+ pfkey_msg->sadb_msg_satype = satype;
+
+ pfkey_msg->sadb_msg_version = PF_KEY_V2;
+ pfkey_msg->sadb_msg_errno = msg_errno;
+ pfkey_msg->sadb_msg_reserved = 0;
+ pfkey_msg->sadb_msg_seq = seq;
+ pfkey_msg->sadb_msg_pid = pid;
+ DEBUGGING(
+ "pfkey_msg_hdr_build: "
+ "on_exit &pfkey_ext=0p%p pfkey_ext=0p%p *pfkey_ext=0p%p.\n",
+ &pfkey_ext,
+ pfkey_ext,
+ *pfkey_ext);
+errlab:
+ return error;
+}
+
+int
+pfkey_sa_ref_build(struct sadb_ext ** pfkey_ext,
+ uint16_t exttype,
+ uint32_t spi,
+ uint8_t replay_window,
+ uint8_t sa_state,
+ uint8_t auth,
+ uint8_t encrypt,
+ uint32_t flags,
+ uint32_t/*IPsecSAref_t*/ ref)
+{
+ int error = 0;
+ struct sadb_sa *pfkey_sa = (struct sadb_sa *)*pfkey_ext;
+
+ DEBUGGING(
+ "pfkey_sa_build: "
+ "spi=%08x replay=%d sa_state=%d auth=%d encrypt=%d flags=%d\n",
+ ntohl(spi), /* in network order */
+ replay_window,
+ sa_state,
+ auth,
+ encrypt,
+ flags);
+ /* sanity checks... */
+ if (pfkey_sa) {
+ DEBUGGING(
+ "pfkey_sa_build: "
+ "why is pfkey_sa already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ if (exttype != SADB_EXT_SA
+ && exttype != SADB_X_EXT_SA2) {
+ DEBUGGING(
+ "pfkey_sa_build: "
+ "invalid exttype=%d.\n",
+ exttype);
+ SENDERR(EINVAL);
+ }
+
+ if (replay_window > 64) {
+ DEBUGGING(
+ "pfkey_sa_build: "
+ "replay window size: %d -- must be 0 <= size <= 64\n",
+ replay_window);
+ SENDERR(EINVAL);
+ }
+
+ if (auth > SADB_AALG_MAX) {
+ DEBUGGING(
+ "pfkey_sa_build: "
+ "auth=%d > SADB_AALG_MAX=%d.\n",
+ auth,
+ SADB_AALG_MAX);
+ SENDERR(EINVAL);
+ }
+
+ if (encrypt > SADB_EALG_MAX) {
+ DEBUGGING(
+ "pfkey_sa_build: "
+ "encrypt=%d > SADB_EALG_MAX=%d.\n",
+ encrypt,
+ SADB_EALG_MAX);
+ SENDERR(EINVAL);
+ }
+
+ if (sa_state > SADB_SASTATE_MAX) {
+ DEBUGGING(
+ "pfkey_sa_build: "
+ "sa_state=%d exceeds MAX=%d.\n",
+ sa_state,
+ SADB_SASTATE_MAX);
+ SENDERR(EINVAL);
+ }
+
+ if (sa_state == SADB_SASTATE_DEAD) {
+ DEBUGGING(
+ "pfkey_sa_build: "
+ "sa_state=%d is DEAD=%d is not allowed.\n",
+ sa_state,
+ SADB_SASTATE_DEAD);
+ SENDERR(EINVAL);
+ }
+
+ if ((IPSEC_SAREF_NULL != ref) && (ref >= (1 << IPSEC_SA_REF_TABLE_IDX_WIDTH))) {
+ DEBUGGING(
+ "pfkey_sa_build: "
+ "SAref=%d must be (SAref == IPSEC_SAREF_NULL(%d) || SAref < IPSEC_SA_REF_TABLE_NUM_ENTRIES(%d)).\n",
+ ref,
+ IPSEC_SAREF_NULL,
+ IPSEC_SA_REF_TABLE_NUM_ENTRIES);
+ SENDERR(EINVAL);
+ }
+
+ pfkey_sa = (struct sadb_sa*)MALLOC(sizeof(struct sadb_sa));
+ *pfkey_ext = (struct sadb_ext*)pfkey_sa;
+
+ if (pfkey_sa == NULL) {
+ DEBUGGING(
+ "pfkey_sa_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_sa, 0, sizeof(struct sadb_sa));
+
+ pfkey_sa->sadb_sa_len = sizeof(*pfkey_sa) / IPSEC_PFKEYv2_ALIGN;
+ pfkey_sa->sadb_sa_exttype = exttype;
+ pfkey_sa->sadb_sa_spi = spi;
+ pfkey_sa->sadb_sa_replay = replay_window;
+ pfkey_sa->sadb_sa_state = sa_state;
+ pfkey_sa->sadb_sa_auth = auth;
+ pfkey_sa->sadb_sa_encrypt = encrypt;
+ pfkey_sa->sadb_sa_flags = flags;
+ pfkey_sa->sadb_x_sa_ref = ref;
+
+errlab:
+ return error;
+}
+
+int
+pfkey_sa_build(struct sadb_ext ** pfkey_ext,
+ uint16_t exttype,
+ uint32_t spi,
+ uint8_t replay_window,
+ uint8_t sa_state,
+ uint8_t auth,
+ uint8_t encrypt,
+ uint32_t flags)
+{
+ return pfkey_sa_ref_build(pfkey_ext,
+ exttype,
+ spi,
+ replay_window,
+ sa_state,
+ auth,
+ encrypt,
+ flags,
+ IPSEC_SAREF_NULL);
+}
+
+int
+pfkey_lifetime_build(struct sadb_ext ** pfkey_ext,
+ uint16_t exttype,
+ uint32_t allocations,
+ uint64_t bytes,
+ uint64_t addtime,
+ uint64_t usetime,
+ uint32_t packets)
+{
+ int error = 0;
+ struct sadb_lifetime *pfkey_lifetime = (struct sadb_lifetime *)*pfkey_ext;
+
+ DEBUGGING(
+ "pfkey_lifetime_build:\n");
+ /* sanity checks... */
+ if (pfkey_lifetime) {
+ DEBUGGING(
+ "pfkey_lifetime_build: "
+ "why is pfkey_lifetime already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ if (exttype != SADB_EXT_LIFETIME_CURRENT
+ && exttype != SADB_EXT_LIFETIME_HARD
+ && exttype != SADB_EXT_LIFETIME_SOFT) {
+ DEBUGGING(
+ "pfkey_lifetime_build: "
+ "invalid exttype=%d.\n",
+ exttype);
+ SENDERR(EINVAL);
+ }
+
+ pfkey_lifetime = (struct sadb_lifetime*)MALLOC(sizeof(struct sadb_lifetime));
+ *pfkey_ext = (struct sadb_ext*)pfkey_lifetime;
+
+ if (pfkey_lifetime == NULL) {
+ DEBUGGING(
+ "pfkey_lifetime_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_lifetime, 0, sizeof(struct sadb_lifetime));
+
+ pfkey_lifetime->sadb_lifetime_len = sizeof(struct sadb_lifetime) / IPSEC_PFKEYv2_ALIGN;
+ pfkey_lifetime->sadb_lifetime_exttype = exttype;
+ pfkey_lifetime->sadb_lifetime_allocations = allocations;
+ pfkey_lifetime->sadb_lifetime_bytes = bytes;
+ pfkey_lifetime->sadb_lifetime_addtime = addtime;
+ pfkey_lifetime->sadb_lifetime_usetime = usetime;
+ pfkey_lifetime->sadb_x_lifetime_packets = packets;
+
+errlab:
+ return error;
+}
+
+int
+pfkey_address_build(struct sadb_ext** pfkey_ext,
+ uint16_t exttype,
+ uint8_t proto,
+ uint8_t prefixlen,
+ struct sockaddr* address)
+{
+ int error = 0;
+ int saddr_len = 0;
+ char ipaddr_txt[ADDRTOT_BUF + 6/*extra for port number*/];
+ struct sadb_address *pfkey_address = (struct sadb_address *)*pfkey_ext;
+
+ DEBUGGING(
+ "pfkey_address_build: "
+ "exttype=%d proto=%d prefixlen=%d\n",
+ exttype,
+ proto,
+ prefixlen);
+ /* sanity checks... */
+ if (pfkey_address) {
+ DEBUGGING(
+ "pfkey_address_build: "
+ "why is pfkey_address already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ if (!address) {
+ DEBUGGING("pfkey_address_build: "
+ "address is NULL\n");
+ SENDERR(EINVAL);
+ }
+
+ switch(exttype) {
+ case SADB_EXT_ADDRESS_SRC:
+ case SADB_EXT_ADDRESS_DST:
+ case SADB_EXT_ADDRESS_PROXY:
+ case SADB_X_EXT_ADDRESS_DST2:
+ case SADB_X_EXT_ADDRESS_SRC_FLOW:
+ case SADB_X_EXT_ADDRESS_DST_FLOW:
+ case SADB_X_EXT_ADDRESS_SRC_MASK:
+ case SADB_X_EXT_ADDRESS_DST_MASK:
+ case SADB_X_EXT_NAT_T_OA:
+ break;
+ default:
+ DEBUGGING(
+ "pfkey_address_build: "
+ "unrecognised ext_type=%d.\n",
+ exttype);
+ SENDERR(EINVAL);
+ }
+
+ switch (address->sa_family) {
+ case AF_INET:
+ DEBUGGING(
+ "pfkey_address_build: "
+ "found address family AF_INET.\n");
+ saddr_len = sizeof(struct sockaddr_in);
+ sprintf(ipaddr_txt, "%d.%d.%d.%d:%d"
+ , (((struct sockaddr_in*)address)->sin_addr.s_addr >> 0) & 0xFF
+ , (((struct sockaddr_in*)address)->sin_addr.s_addr >> 8) & 0xFF
+ , (((struct sockaddr_in*)address)->sin_addr.s_addr >> 16) & 0xFF
+ , (((struct sockaddr_in*)address)->sin_addr.s_addr >> 24) & 0xFF
+ , ntohs(((struct sockaddr_in*)address)->sin_port));
+ break;
+ case AF_INET6:
+ DEBUGGING(
+ "pfkey_address_build: "
+ "found address family AF_INET6.\n");
+ saddr_len = sizeof(struct sockaddr_in6);
+ sprintf(ipaddr_txt, "%x:%x:%x:%x:%x:%x:%x:%x-%x"
+ , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[0])
+ , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[1])
+ , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[2])
+ , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[3])
+ , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[4])
+ , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[5])
+ , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[6])
+ , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[7])
+ , ntohs(((struct sockaddr_in6*)address)->sin6_port));
+ break;
+ default:
+ DEBUGGING(
+ "pfkey_address_build: "
+ "address->sa_family=%d not supported.\n",
+ address->sa_family);
+ SENDERR(EPFNOSUPPORT);
+ }
+
+ DEBUGGING(
+ "pfkey_address_build: "
+ "found address=%s.\n",
+ ipaddr_txt);
+ if (prefixlen != 0) {
+ DEBUGGING(
+ "pfkey_address_build: "
+ "address prefixes not supported yet.\n");
+ SENDERR(EAFNOSUPPORT); /* not supported yet */
+ }
+
+ pfkey_address = (struct sadb_address*)
+ MALLOC(ALIGN_N(sizeof(struct sadb_address) + saddr_len, IPSEC_PFKEYv2_ALIGN));
+ *pfkey_ext = (struct sadb_ext*)pfkey_address;
+
+ if (pfkey_address == NULL) {
+ DEBUGGING(
+ "pfkey_lifetime_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_address,
+ 0,
+ ALIGN_N(sizeof(struct sadb_address) + saddr_len,
+ IPSEC_PFKEYv2_ALIGN));
+
+ pfkey_address->sadb_address_len = DIVUP(sizeof(struct sadb_address) + saddr_len,
+ IPSEC_PFKEYv2_ALIGN);
+
+ pfkey_address->sadb_address_exttype = exttype;
+ pfkey_address->sadb_address_proto = proto;
+ pfkey_address->sadb_address_prefixlen = prefixlen;
+ pfkey_address->sadb_address_reserved = 0;
+
+ memcpy((char*)pfkey_address + sizeof(struct sadb_address),
+ address,
+ saddr_len);
+
+#if 0
+ for (i = 0; i < sizeof(struct sockaddr_in) - offsetof(struct sockaddr_in, sin_zero); i++) {
+ pfkey_address_s_ska.sin_zero[i] = 0;
+ }
+#endif
+ DEBUGGING(
+ "pfkey_address_build: "
+ "successful.\n");
+
+ errlab:
+ return error;
+}
+
+int
+pfkey_key_build(struct sadb_ext** pfkey_ext,
+ uint16_t exttype,
+ uint16_t key_bits,
+ char* key)
+{
+ int error = 0;
+ struct sadb_key *pfkey_key = (struct sadb_key *)*pfkey_ext;
+
+ DEBUGGING(
+ "pfkey_key_build:\n");
+ /* sanity checks... */
+ if (pfkey_key) {
+ DEBUGGING(
+ "pfkey_key_build: "
+ "why is pfkey_key already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ if (!key_bits) {
+ DEBUGGING(
+ "pfkey_key_build: "
+ "key_bits is zero, it must be non-zero.\n");
+ SENDERR(EINVAL);
+ }
+
+ if ( !((exttype == SADB_EXT_KEY_AUTH) || (exttype == SADB_EXT_KEY_ENCRYPT))) {
+ DEBUGGING(
+ "pfkey_key_build: "
+ "unsupported extension type=%d.\n",
+ exttype);
+ SENDERR(EINVAL);
+ }
+
+ pfkey_key = (struct sadb_key*)
+ MALLOC(sizeof(struct sadb_key) +
+ DIVUP(key_bits, 64) * IPSEC_PFKEYv2_ALIGN);
+ *pfkey_ext = (struct sadb_ext*)pfkey_key;
+
+ if (pfkey_key == NULL) {
+ DEBUGGING(
+ "pfkey_key_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_key,
+ 0,
+ sizeof(struct sadb_key) +
+ DIVUP(key_bits, 64) * IPSEC_PFKEYv2_ALIGN);
+
+ pfkey_key->sadb_key_len = DIVUP(sizeof(struct sadb_key) * IPSEC_PFKEYv2_ALIGN + key_bits,
+ 64);
+ pfkey_key->sadb_key_exttype = exttype;
+ pfkey_key->sadb_key_bits = key_bits;
+ pfkey_key->sadb_key_reserved = 0;
+ memcpy((char*)pfkey_key + sizeof(struct sadb_key),
+ key,
+ DIVUP(key_bits, 8));
+
+errlab:
+ return error;
+}
+
+int
+pfkey_ident_build(struct sadb_ext** pfkey_ext,
+ uint16_t exttype,
+ uint16_t ident_type,
+ uint64_t ident_id,
+ uint8_t ident_len,
+ char* ident_string)
+{
+ int error = 0;
+ struct sadb_ident *pfkey_ident = (struct sadb_ident *)*pfkey_ext;
+ int data_len = ident_len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident);
+
+ DEBUGGING(
+ "pfkey_ident_build:\n");
+ /* sanity checks... */
+ if (pfkey_ident) {
+ DEBUGGING(
+ "pfkey_ident_build: "
+ "why is pfkey_ident already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ if ( !((exttype == SADB_EXT_IDENTITY_SRC) ||
+ (exttype == SADB_EXT_IDENTITY_DST))) {
+ DEBUGGING(
+ "pfkey_ident_build: "
+ "unsupported extension type=%d.\n",
+ exttype);
+ SENDERR(EINVAL);
+ }
+
+ if (ident_type == SADB_IDENTTYPE_RESERVED) {
+ DEBUGGING(
+ "pfkey_ident_build: "
+ "ident_type must be non-zero.\n");
+ SENDERR(EINVAL);
+ }
+
+ if (ident_type > SADB_IDENTTYPE_MAX) {
+ DEBUGGING(
+ "pfkey_ident_build: "
+ "identtype=%d out of range.\n",
+ ident_type);
+ SENDERR(EINVAL);
+ }
+
+ if ((ident_type == SADB_IDENTTYPE_PREFIX ||
+ ident_type == SADB_IDENTTYPE_FQDN) &&
+ !ident_string) {
+ DEBUGGING(
+ "pfkey_ident_build: "
+ "string required to allocate size of extension.\n");
+ SENDERR(EINVAL);
+ }
+
+#if 0
+ if (ident_type == SADB_IDENTTYPE_USERFQDN) {
+ }
+#endif
+
+ pfkey_ident = (struct sadb_ident*)
+ MALLOC(ident_len * IPSEC_PFKEYv2_ALIGN);
+ *pfkey_ext = (struct sadb_ext*)pfkey_ident;
+
+ if (pfkey_ident == NULL) {
+ DEBUGGING(
+ "pfkey_ident_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_ident, 0, ident_len * IPSEC_PFKEYv2_ALIGN);
+
+ pfkey_ident->sadb_ident_len = ident_len;
+ pfkey_ident->sadb_ident_exttype = exttype;
+ pfkey_ident->sadb_ident_type = ident_type;
+ pfkey_ident->sadb_ident_reserved = 0;
+ pfkey_ident->sadb_ident_id = ident_id;
+ memcpy((char*)pfkey_ident + sizeof(struct sadb_ident),
+ ident_string,
+ data_len);
+
+errlab:
+ return error;
+}
+
+int
+pfkey_sens_build(struct sadb_ext** pfkey_ext,
+ uint32_t dpd,
+ uint8_t sens_level,
+ uint8_t sens_len,
+ uint64_t* sens_bitmap,
+ uint8_t integ_level,
+ uint8_t integ_len,
+ uint64_t* integ_bitmap)
+{
+ int error = 0;
+ struct sadb_sens *pfkey_sens = (struct sadb_sens *)*pfkey_ext;
+ int i;
+ uint64_t* bitmap;
+
+ DEBUGGING(
+ "pfkey_sens_build:\n");
+ /* sanity checks... */
+ if (pfkey_sens) {
+ DEBUGGING(
+ "pfkey_sens_build: "
+ "why is pfkey_sens already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(
+ "pfkey_sens_build: "
+ "Sorry, I can't build exttype=%d yet.\n",
+ (*pfkey_ext)->sadb_ext_type);
+ SENDERR(EINVAL); /* don't process these yet */
+
+ pfkey_sens = (struct sadb_sens*)
+ MALLOC(sizeof(struct sadb_sens) +
+ (sens_len + integ_len) * sizeof(uint64_t));
+ *pfkey_ext = (struct sadb_ext*)pfkey_sens;
+
+ if (pfkey_sens == NULL) {
+ DEBUGGING(
+ "pfkey_sens_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_sens,
+ 0,
+ sizeof(struct sadb_sens) +
+ (sens_len + integ_len) * sizeof(uint64_t));
+
+ pfkey_sens->sadb_sens_len = (sizeof(struct sadb_sens) +
+ (sens_len + integ_len) * sizeof(uint64_t)) / IPSEC_PFKEYv2_ALIGN;
+ pfkey_sens->sadb_sens_exttype = SADB_EXT_SENSITIVITY;
+ pfkey_sens->sadb_sens_dpd = dpd;
+ pfkey_sens->sadb_sens_sens_level = sens_level;
+ pfkey_sens->sadb_sens_sens_len = sens_len;
+ pfkey_sens->sadb_sens_integ_level = integ_level;
+ pfkey_sens->sadb_sens_integ_len = integ_len;
+ pfkey_sens->sadb_sens_reserved = 0;
+
+ bitmap = (uint64_t*)((char*)pfkey_ext + sizeof(struct sadb_sens));
+ for (i = 0; i < sens_len; i++) {
+ *bitmap = sens_bitmap[i];
+ bitmap++;
+ }
+ for (i = 0; i < integ_len; i++) {
+ *bitmap = integ_bitmap[i];
+ bitmap++;
+ }
+
+errlab:
+ return error;
+}
+
+int
+pfkey_prop_build(struct sadb_ext** pfkey_ext,
+ uint8_t replay,
+ unsigned int comb_num,
+ struct sadb_comb* comb)
+{
+ int error = 0;
+ int i;
+ struct sadb_prop *pfkey_prop = (struct sadb_prop *)*pfkey_ext;
+ struct sadb_comb *combp;
+
+ DEBUGGING(
+ "pfkey_prop_build:\n");
+ /* sanity checks... */
+ if (pfkey_prop) {
+ DEBUGGING(
+ "pfkey_prop_build: "
+ "why is pfkey_prop already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ pfkey_prop = (struct sadb_prop*)
+ MALLOC(sizeof(struct sadb_prop) +
+ comb_num * sizeof(struct sadb_comb));
+
+ *pfkey_ext = (struct sadb_ext*)pfkey_prop;
+
+ if (pfkey_prop == NULL) {
+ DEBUGGING(
+ "pfkey_prop_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_prop,
+ 0,
+ sizeof(struct sadb_prop) +
+ comb_num * sizeof(struct sadb_comb));
+
+ pfkey_prop->sadb_prop_len = (sizeof(struct sadb_prop) +
+ comb_num * sizeof(struct sadb_comb)) / IPSEC_PFKEYv2_ALIGN;
+
+ pfkey_prop->sadb_prop_exttype = SADB_EXT_PROPOSAL;
+ pfkey_prop->sadb_prop_replay = replay;
+
+ for (i=0; i<3; i++) {
+ pfkey_prop->sadb_prop_reserved[i] = 0;
+ }
+
+ combp = (struct sadb_comb*)((char*)*pfkey_ext + sizeof(struct sadb_prop));
+ for (i = 0; i < comb_num; i++) {
+ memcpy (combp, &(comb[i]), sizeof(struct sadb_comb));
+ combp++;
+ }
+
+#if 0
+ uint8_t sadb_comb_auth;
+ uint8_t sadb_comb_encrypt;
+ uint16_t sadb_comb_flags;
+ uint16_t sadb_comb_auth_minbits;
+ uint16_t sadb_comb_auth_maxbits;
+ uint16_t sadb_comb_encrypt_minbits;
+ uint16_t sadb_comb_encrypt_maxbits;
+ uint32_t sadb_comb_reserved;
+ uint32_t sadb_comb_soft_allocations;
+ uint32_t sadb_comb_hard_allocations;
+ uint64_t sadb_comb_soft_bytes;
+ uint64_t sadb_comb_hard_bytes;
+ uint64_t sadb_comb_soft_addtime;
+ uint64_t sadb_comb_hard_addtime;
+ uint64_t sadb_comb_soft_usetime;
+ uint64_t sadb_comb_hard_usetime;
+ uint32_t sadb_comb_soft_packets;
+ uint32_t sadb_comb_hard_packets;
+#endif
+errlab:
+ return error;
+}
+
+int
+pfkey_supported_build(struct sadb_ext** pfkey_ext,
+ uint16_t exttype,
+ unsigned int alg_num,
+ struct sadb_alg* alg)
+{
+ int error = 0;
+ unsigned int i;
+ struct sadb_supported *pfkey_supported = (struct sadb_supported *)*pfkey_ext;
+ struct sadb_alg *pfkey_alg;
+
+ /* sanity checks... */
+ if (pfkey_supported) {
+ DEBUGGING(
+ "pfkey_supported_build: "
+ "why is pfkey_supported already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ if ( !((exttype == SADB_EXT_SUPPORTED_AUTH) || (exttype == SADB_EXT_SUPPORTED_ENCRYPT))) {
+ DEBUGGING(
+ "pfkey_supported_build: "
+ "unsupported extension type=%d.\n",
+ exttype);
+ SENDERR(EINVAL);
+ }
+
+ pfkey_supported = (struct sadb_supported*)
+ MALLOC(sizeof(struct sadb_supported) +
+ alg_num * sizeof(struct sadb_alg));
+
+ *pfkey_ext = (struct sadb_ext*)pfkey_supported;
+
+ if (pfkey_supported == NULL) {
+ DEBUGGING(
+ "pfkey_supported_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_supported,
+ 0,
+ sizeof(struct sadb_supported) +
+ alg_num *
+ sizeof(struct sadb_alg));
+
+ pfkey_supported->sadb_supported_len = (sizeof(struct sadb_supported) +
+ alg_num *
+ sizeof(struct sadb_alg)) /
+ IPSEC_PFKEYv2_ALIGN;
+ pfkey_supported->sadb_supported_exttype = exttype;
+ pfkey_supported->sadb_supported_reserved = 0;
+
+ pfkey_alg = (struct sadb_alg*)((char*)pfkey_supported + sizeof(struct sadb_supported));
+ for(i = 0; i < alg_num; i++) {
+ memcpy (pfkey_alg, &(alg[i]), sizeof(struct sadb_alg));
+ pfkey_alg->sadb_alg_reserved = 0;
+ pfkey_alg++;
+ }
+
+#if 0
+ DEBUGGING(
+ "pfkey_supported_build: "
+ "Sorry, I can't build exttype=%d yet.\n",
+ (*pfkey_ext)->sadb_ext_type);
+ SENDERR(EINVAL); /* don't process these yet */
+
+ uint8_t sadb_alg_id;
+ uint8_t sadb_alg_ivlen;
+ uint16_t sadb_alg_minbits;
+ uint16_t sadb_alg_maxbits;
+ uint16_t sadb_alg_reserved;
+#endif
+errlab:
+ return error;
+}
+
+int
+pfkey_spirange_build(struct sadb_ext** pfkey_ext,
+ uint16_t exttype,
+ uint32_t min, /* in network order */
+ uint32_t max) /* in network order */
+{
+ int error = 0;
+ struct sadb_spirange *pfkey_spirange = (struct sadb_spirange *)*pfkey_ext;
+
+ /* sanity checks... */
+ if (pfkey_spirange) {
+ DEBUGGING(
+ "pfkey_spirange_build: "
+ "why is pfkey_spirange already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ if (ntohl(max) < ntohl(min)) {
+ DEBUGGING(
+ "pfkey_spirange_build: "
+ "minspi=%08x must be < maxspi=%08x.\n",
+ ntohl(min),
+ ntohl(max));
+ SENDERR(EINVAL);
+ }
+
+ if (ntohl(min) <= 255) {
+ DEBUGGING(
+ "pfkey_spirange_build: "
+ "minspi=%08x must be > 255.\n",
+ ntohl(min));
+ SENDERR(EEXIST);
+ }
+
+ pfkey_spirange = (struct sadb_spirange*)
+ MALLOC(sizeof(struct sadb_spirange));
+ *pfkey_ext = (struct sadb_ext*)pfkey_spirange;
+
+ if (pfkey_spirange == NULL) {
+ DEBUGGING(
+ "pfkey_spirange_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_spirange,
+ 0,
+ sizeof(struct sadb_spirange));
+
+ pfkey_spirange->sadb_spirange_len = sizeof(struct sadb_spirange) / IPSEC_PFKEYv2_ALIGN;
+
+ pfkey_spirange->sadb_spirange_exttype = SADB_EXT_SPIRANGE;
+ pfkey_spirange->sadb_spirange_min = min;
+ pfkey_spirange->sadb_spirange_max = max;
+ pfkey_spirange->sadb_spirange_reserved = 0;
+ errlab:
+ return error;
+}
+
+int
+pfkey_x_kmprivate_build(struct sadb_ext** pfkey_ext)
+{
+ int error = 0;
+ struct sadb_x_kmprivate *pfkey_x_kmprivate = (struct sadb_x_kmprivate *)*pfkey_ext;
+
+ /* sanity checks... */
+ if (pfkey_x_kmprivate) {
+ DEBUGGING(
+ "pfkey_x_kmprivate_build: "
+ "why is pfkey_x_kmprivate already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ pfkey_x_kmprivate->sadb_x_kmprivate_reserved = 0;
+
+ DEBUGGING(
+ "pfkey_x_kmprivate_build: "
+ "Sorry, I can't build exttype=%d yet.\n",
+ (*pfkey_ext)->sadb_ext_type);
+ SENDERR(EINVAL); /* don't process these yet */
+
+ pfkey_x_kmprivate = (struct sadb_x_kmprivate*)
+ MALLOC(sizeof(struct sadb_x_kmprivate));
+ *pfkey_ext = (struct sadb_ext*)pfkey_x_kmprivate;
+
+ if (pfkey_x_kmprivate == NULL) {
+ DEBUGGING(
+ "pfkey_x_kmprivate_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_x_kmprivate,
+ 0,
+ sizeof(struct sadb_x_kmprivate));
+
+ pfkey_x_kmprivate->sadb_x_kmprivate_len =
+ sizeof(struct sadb_x_kmprivate) / IPSEC_PFKEYv2_ALIGN;
+
+ pfkey_x_kmprivate->sadb_x_kmprivate_exttype = SADB_X_EXT_KMPRIVATE;
+ pfkey_x_kmprivate->sadb_x_kmprivate_reserved = 0;
+errlab:
+ return error;
+}
+
+int
+pfkey_x_satype_build(struct sadb_ext** pfkey_ext,
+ uint8_t satype)
+{
+ int error = 0;
+ int i;
+ struct sadb_x_satype *pfkey_x_satype = (struct sadb_x_satype *)*pfkey_ext;
+
+ DEBUGGING(
+ "pfkey_x_satype_build:\n");
+ /* sanity checks... */
+ if (pfkey_x_satype) {
+ DEBUGGING(
+ "pfkey_x_satype_build: "
+ "why is pfkey_x_satype already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ if (!satype) {
+ DEBUGGING(
+ "pfkey_x_satype_build: "
+ "SA type not set, must be non-zero.\n");
+ SENDERR(EINVAL);
+ }
+
+ if (satype > SADB_SATYPE_MAX) {
+ DEBUGGING(
+ "pfkey_x_satype_build: "
+ "satype %d > max %d\n",
+ satype, SADB_SATYPE_MAX);
+ SENDERR(EINVAL);
+ }
+
+ pfkey_x_satype = (struct sadb_x_satype*)
+ MALLOC(sizeof(struct sadb_x_satype));
+
+ *pfkey_ext = (struct sadb_ext*)pfkey_x_satype;
+
+ if (pfkey_x_satype == NULL) {
+ DEBUGGING(
+ "pfkey_x_satype_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_x_satype,
+ 0,
+ sizeof(struct sadb_x_satype));
+
+ pfkey_x_satype->sadb_x_satype_len = sizeof(struct sadb_x_satype) / IPSEC_PFKEYv2_ALIGN;
+
+ pfkey_x_satype->sadb_x_satype_exttype = SADB_X_EXT_SATYPE2;
+ pfkey_x_satype->sadb_x_satype_satype = satype;
+ for (i=0; i<3; i++) {
+ pfkey_x_satype->sadb_x_satype_reserved[i] = 0;
+ }
+
+errlab:
+ return error;
+}
+
+int
+pfkey_x_debug_build(struct sadb_ext** pfkey_ext,
+ uint32_t tunnel,
+ uint32_t netlink,
+ uint32_t xform,
+ uint32_t eroute,
+ uint32_t spi,
+ uint32_t radij,
+ uint32_t esp,
+ uint32_t ah,
+ uint32_t rcv,
+ uint32_t pfkey,
+ uint32_t ipcomp,
+ uint32_t verbose)
+{
+ int error = 0;
+ int i;
+ struct sadb_x_debug *pfkey_x_debug = (struct sadb_x_debug *)*pfkey_ext;
+
+ DEBUGGING(
+ "pfkey_x_debug_build:\n");
+ /* sanity checks... */
+ if (pfkey_x_debug) {
+ DEBUGGING(
+ "pfkey_x_debug_build: "
+ "why is pfkey_x_debug already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(
+ "pfkey_x_debug_build: "
+ "tunnel=%x netlink=%x xform=%x eroute=%x spi=%x radij=%x esp=%x ah=%x rcv=%x pfkey=%x ipcomp=%x verbose=%x?\n",
+ tunnel, netlink, xform, eroute, spi, radij, esp, ah, rcv, pfkey, ipcomp, verbose);
+
+ pfkey_x_debug = (struct sadb_x_debug*)
+ MALLOC(sizeof(struct sadb_x_debug));
+ *pfkey_ext = (struct sadb_ext*)pfkey_x_debug;
+
+ if (pfkey_x_debug == NULL) {
+ DEBUGGING(
+ "pfkey_x_debug_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+#if 0
+ memset(pfkey_x_debug,
+ 0,
+ sizeof(struct sadb_x_debug));
+#endif
+
+ pfkey_x_debug->sadb_x_debug_len = sizeof(struct sadb_x_debug) / IPSEC_PFKEYv2_ALIGN;
+ pfkey_x_debug->sadb_x_debug_exttype = SADB_X_EXT_DEBUG;
+
+ pfkey_x_debug->sadb_x_debug_tunnel = tunnel;
+ pfkey_x_debug->sadb_x_debug_netlink = netlink;
+ pfkey_x_debug->sadb_x_debug_xform = xform;
+ pfkey_x_debug->sadb_x_debug_eroute = eroute;
+ pfkey_x_debug->sadb_x_debug_spi = spi;
+ pfkey_x_debug->sadb_x_debug_radij = radij;
+ pfkey_x_debug->sadb_x_debug_esp = esp;
+ pfkey_x_debug->sadb_x_debug_ah = ah;
+ pfkey_x_debug->sadb_x_debug_rcv = rcv;
+ pfkey_x_debug->sadb_x_debug_pfkey = pfkey;
+ pfkey_x_debug->sadb_x_debug_ipcomp = ipcomp;
+ pfkey_x_debug->sadb_x_debug_verbose = verbose;
+
+ for (i=0; i<4; i++) {
+ pfkey_x_debug->sadb_x_debug_reserved[i] = 0;
+ }
+
+errlab:
+ return error;
+}
+
+int
+pfkey_x_nat_t_type_build(struct sadb_ext** pfkey_ext,
+ uint8_t type)
+{
+ int error = 0;
+ int i;
+ struct sadb_x_nat_t_type *pfkey_x_nat_t_type = (struct sadb_x_nat_t_type *)*pfkey_ext;
+
+ DEBUGGING(
+ "pfkey_x_nat_t_type_build:\n");
+ /* sanity checks... */
+ if (pfkey_x_nat_t_type) {
+ DEBUGGING(
+ "pfkey_x_nat_t_type_build: "
+ "why is pfkey_x_nat_t_type already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(
+ "pfkey_x_nat_t_type_build: "
+ "type=%d\n", type);
+
+ pfkey_x_nat_t_type = (struct sadb_x_nat_t_type*)
+ MALLOC(sizeof(struct sadb_x_nat_t_type));
+
+ *pfkey_ext = (struct sadb_ext*)pfkey_x_nat_t_type;
+ if (pfkey_x_nat_t_type == NULL) {
+ DEBUGGING(
+ "pfkey_x_nat_t_type_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+
+ pfkey_x_nat_t_type->sadb_x_nat_t_type_len = sizeof(struct sadb_x_nat_t_type) / IPSEC_PFKEYv2_ALIGN;
+ pfkey_x_nat_t_type->sadb_x_nat_t_type_exttype = SADB_X_EXT_NAT_T_TYPE;
+ pfkey_x_nat_t_type->sadb_x_nat_t_type_type = type;
+ for (i=0; i<3; i++) {
+ pfkey_x_nat_t_type->sadb_x_nat_t_type_reserved[i] = 0;
+ }
+
+errlab:
+ return error;
+}
+
+int
+pfkey_x_nat_t_port_build(struct sadb_ext** pfkey_ext,
+ uint16_t exttype,
+ uint16_t port)
+{
+ int error = 0;
+ struct sadb_x_nat_t_port *pfkey_x_nat_t_port = (struct sadb_x_nat_t_port *)*pfkey_ext;
+
+ DEBUGGING(
+ "pfkey_x_nat_t_port_build:\n");
+ /* sanity checks... */
+ if (pfkey_x_nat_t_port) {
+ DEBUGGING(
+ "pfkey_x_nat_t_port_build: "
+ "why is pfkey_x_nat_t_port already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ switch (exttype) {
+ case SADB_X_EXT_NAT_T_SPORT:
+ case SADB_X_EXT_NAT_T_DPORT:
+ break;
+ default:
+ DEBUGGING(
+ "pfkey_nat_t_port_build: "
+ "unrecognised ext_type=%d.\n",
+ exttype);
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(
+ "pfkey_x_nat_t_port_build: "
+ "ext=%d, port=%d\n", exttype, port);
+
+ pfkey_x_nat_t_port = (struct sadb_x_nat_t_port*)
+ MALLOC(sizeof(struct sadb_x_nat_t_port));
+ *pfkey_ext = (struct sadb_ext*)pfkey_x_nat_t_port;
+
+ if (pfkey_x_nat_t_port == NULL) {
+ DEBUGGING(
+ "pfkey_x_nat_t_port_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+
+ pfkey_x_nat_t_port->sadb_x_nat_t_port_len = sizeof(struct sadb_x_nat_t_port) / IPSEC_PFKEYv2_ALIGN;
+ pfkey_x_nat_t_port->sadb_x_nat_t_port_exttype = exttype;
+ pfkey_x_nat_t_port->sadb_x_nat_t_port_port = port;
+ pfkey_x_nat_t_port->sadb_x_nat_t_port_reserved = 0;
+
+errlab:
+ return error;
+}
+
+int pfkey_x_protocol_build(struct sadb_ext **pfkey_ext,
+ uint8_t protocol)
+{
+ int error = 0;
+ struct sadb_protocol * p = (struct sadb_protocol *)*pfkey_ext;
+ DEBUGGING("pfkey_x_protocol_build: protocol=%u\n", protocol);
+ /* sanity checks... */
+ if (p != 0) {
+ DEBUGGING("pfkey_x_protocol_build: bogus protocol pointer\n");
+ SENDERR(EINVAL);
+ }
+ if ((p = (struct sadb_protocol*)MALLOC(sizeof(*p))) == 0) {
+ DEBUGGING("pfkey_build: memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ *pfkey_ext = (struct sadb_ext *)p;
+ p->sadb_protocol_len = sizeof(*p) / sizeof(uint64_t);
+ p->sadb_protocol_exttype = SADB_X_EXT_PROTOCOL;
+ p->sadb_protocol_proto = protocol;
+ p->sadb_protocol_flags = 0;
+ p->sadb_protocol_reserved2 = 0;
+ errlab:
+ return error;
+}
+
+
+#if I_DONT_THINK_THIS_WILL_BE_USEFUL
+int (*ext_default_builders[SADB_EXT_MAX +1])(struct sadb_msg*, struct sadb_ext*)
+ =
+{
+ NULL, /* pfkey_msg_build, */
+ pfkey_sa_build,
+ pfkey_lifetime_build,
+ pfkey_lifetime_build,
+ pfkey_lifetime_build,
+ pfkey_address_build,
+ pfkey_address_build,
+ pfkey_address_build,
+ pfkey_key_build,
+ pfkey_key_build,
+ pfkey_ident_build,
+ pfkey_ident_build,
+ pfkey_sens_build,
+ pfkey_prop_build,
+ pfkey_supported_build,
+ pfkey_supported_build,
+ pfkey_spirange_build,
+ pfkey_x_kmprivate_build,
+ pfkey_x_satype_build,
+ pfkey_sa_build,
+ pfkey_address_build,
+ pfkey_address_build,
+ pfkey_address_build,
+ pfkey_address_build,
+ pfkey_address_build,
+ pfkey_x_ext_debug_build
+};
+#endif
+
+int
+pfkey_msg_build(struct sadb_msg **pfkey_msg, struct sadb_ext *extensions[], int dir)
+{
+ int error = 0;
+ unsigned ext;
+ unsigned total_size;
+ struct sadb_ext *pfkey_ext;
+ int extensions_seen = 0;
+ struct sadb_ext *extensions_check[SADB_EXT_MAX + 1];
+
+ if (!extensions[0]) {
+ DEBUGGING(
+ "pfkey_msg_build: "
+ "extensions[0] must be specified (struct sadb_msg).\n");
+ SENDERR(EINVAL);
+ }
+
+ total_size = sizeof(struct sadb_msg) / IPSEC_PFKEYv2_ALIGN;
+ for (ext = 1; ext <= SADB_EXT_MAX; ext++) {
+ if(extensions[ext]) {
+ total_size += (extensions[ext])->sadb_ext_len;
+ }
+ }
+
+ if (!(*pfkey_msg = (struct sadb_msg*)MALLOC(total_size * IPSEC_PFKEYv2_ALIGN))) {
+ DEBUGGING(
+ "pfkey_msg_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+
+ DEBUGGING(
+ "pfkey_msg_build: "
+ "pfkey_msg=0p%p allocated %lu bytes, &(extensions[0])=0p%p\n",
+ *pfkey_msg,
+ (unsigned long)(total_size * IPSEC_PFKEYv2_ALIGN),
+ &(extensions[0]));
+ memcpy(*pfkey_msg,
+ extensions[0],
+ sizeof(struct sadb_msg));
+ (*pfkey_msg)->sadb_msg_len = total_size;
+ (*pfkey_msg)->sadb_msg_reserved = 0;
+ extensions_seen = 1 ;
+
+ pfkey_ext = (struct sadb_ext*)(((char*)(*pfkey_msg)) + sizeof(struct sadb_msg));
+
+ for (ext = 1; ext <= SADB_EXT_MAX; ext++) {
+ /* copy from extension[ext] to buffer */
+ if (extensions[ext]) {
+ /* Is this type of extension permitted for this type of message? */
+ if (!(extensions_bitmaps[dir][EXT_BITS_PERM][(*pfkey_msg)->sadb_msg_type] &
+ 1<<ext)) {
+ DEBUGGING(
+ "pfkey_msg_build: "
+ "ext type %d not permitted, exts_perm=%08x, 1<<type=%08x\n",
+ ext,
+ extensions_bitmaps[dir][EXT_BITS_PERM][(*pfkey_msg)->sadb_msg_type],
+ 1<<ext);
+ SENDERR(EINVAL);
+ }
+ DEBUGGING(
+ "pfkey_msg_build: "
+ "copying %lu bytes from extensions[%u]=0p%p to=0p%p\n",
+ (unsigned long)(extensions[ext]->sadb_ext_len * IPSEC_PFKEYv2_ALIGN),
+ ext,
+ extensions[ext],
+ pfkey_ext);
+ memcpy(pfkey_ext,
+ extensions[ext],
+ (extensions[ext])->sadb_ext_len * IPSEC_PFKEYv2_ALIGN);
+ {
+ char *pfkey_ext_c = (char *)pfkey_ext;
+
+ pfkey_ext_c += (extensions[ext])->sadb_ext_len * IPSEC_PFKEYv2_ALIGN;
+ pfkey_ext = (struct sadb_ext *)pfkey_ext_c;
+ }
+ /* Mark that we have seen this extension and remember the header location */
+ extensions_seen |= ( 1 << ext );
+ }
+ }
+
+ /* check required extensions */
+ DEBUGGING(
+ "pfkey_msg_build: "
+ "extensions permitted=%08x, seen=%08x, required=%08x.\n",
+ extensions_bitmaps[dir][EXT_BITS_PERM][(*pfkey_msg)->sadb_msg_type],
+ extensions_seen,
+ extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type]);
+
+ if ((extensions_seen &
+ extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type]) !=
+ extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type]) {
+ DEBUGGING(
+ "pfkey_msg_build: "
+ "required extensions missing:%08x.\n",
+ extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type] -
+ (extensions_seen &
+ extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type]) );
+ SENDERR(EINVAL);
+ }
+
+ error = pfkey_msg_parse(*pfkey_msg, NULL, extensions_check, dir);
+ if (error) {
+ DEBUGGING(
+ "pfkey_msg_build: "
+ "Trouble parsing newly built pfkey message, error=%d.\n",
+ error);
+ SENDERR(-error);
+ }
+
+errlab:
+
+ return error;
+}
diff --git a/src/libfreeswan/pfkey_v2_debug.c b/src/libfreeswan/pfkey_v2_debug.c
new file mode 100644
index 000000000..8430766aa
--- /dev/null
+++ b/src/libfreeswan/pfkey_v2_debug.c
@@ -0,0 +1,177 @@
+/*
+ * @(#) pfkey version 2 debugging messages
+ *
+ * Copyright (C) 2001 Richard Guy Briggs <rgb@freeswan.org>
+ * and Michael Richardson <mcr@freeswan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: pfkey_v2_debug.c,v 1.2 2004/03/22 21:53:18 as Exp $
+ *
+ */
+
+#ifdef __KERNEL__
+
+# include <linux/kernel.h> /* for printk */
+
+# include "freeswan/ipsec_kversion.h" /* for malloc switch */
+# ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+# else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+# endif /* MALLOC_SLAB */
+# include <linux/errno.h> /* error codes */
+# include <linux/types.h> /* size_t */
+# include <linux/interrupt.h> /* mark_bh */
+
+# include <linux/netdevice.h> /* struct device, and other headers */
+# include <linux/etherdevice.h> /* eth_type_trans */
+extern int debug_pfkey;
+
+#else /* __KERNEL__ */
+
+# include <sys/types.h>
+# include <linux/types.h>
+# include <linux/errno.h>
+
+#endif /* __KERNEL__ */
+
+#include "freeswan.h"
+#include "pfkeyv2.h"
+#include "pfkey.h"
+
+/*
+ * This file provides ASCII translations of PF_KEY magic numbers.
+ *
+ */
+
+static char *pfkey_sadb_ext_strings[]={
+ "reserved", /* SADB_EXT_RESERVED 0 */
+ "security-association", /* SADB_EXT_SA 1 */
+ "lifetime-current", /* SADB_EXT_LIFETIME_CURRENT 2 */
+ "lifetime-hard", /* SADB_EXT_LIFETIME_HARD 3 */
+ "lifetime-soft", /* SADB_EXT_LIFETIME_SOFT 4 */
+ "source-address", /* SADB_EXT_ADDRESS_SRC 5 */
+ "destination-address", /* SADB_EXT_ADDRESS_DST 6 */
+ "proxy-address", /* SADB_EXT_ADDRESS_PROXY 7 */
+ "authentication-key", /* SADB_EXT_KEY_AUTH 8 */
+ "cipher-key", /* SADB_EXT_KEY_ENCRYPT 9 */
+ "source-identity", /* SADB_EXT_IDENTITY_SRC 10 */
+ "destination-identity", /* SADB_EXT_IDENTITY_DST 11 */
+ "sensitivity-label", /* SADB_EXT_SENSITIVITY 12 */
+ "proposal", /* SADB_EXT_PROPOSAL 13 */
+ "supported-auth", /* SADB_EXT_SUPPORTED_AUTH 14 */
+ "supported-cipher", /* SADB_EXT_SUPPORTED_ENCRYPT 15 */
+ "spi-range", /* SADB_EXT_SPIRANGE 16 */
+ "X-kmpprivate", /* SADB_X_EXT_KMPRIVATE 17 */
+ "X-satype2", /* SADB_X_EXT_SATYPE2 18 */
+ "X-security-association", /* SADB_X_EXT_SA2 19 */
+ "X-destination-address2", /* SADB_X_EXT_ADDRESS_DST2 20 */
+ "X-source-flow-address", /* SADB_X_EXT_ADDRESS_SRC_FLOW 21 */
+ "X-dest-flow-address", /* SADB_X_EXT_ADDRESS_DST_FLOW 22 */
+ "X-source-mask", /* SADB_X_EXT_ADDRESS_SRC_MASK 23 */
+ "X-dest-mask", /* SADB_X_EXT_ADDRESS_DST_MASK 24 */
+ "X-set-debug", /* SADB_X_EXT_DEBUG 25 */
+ "X-NAT-T-type", /* SADB_X_EXT_NAT_T_TYPE 26 */
+ "X-NAT-T-sport", /* SADB_X_EXT_NAT_T_SPORT 27 */
+ "X-NAT-T-dport", /* SADB_X_EXT_NAT_T_DPORT 28 */
+ "X-NAT-T-OA", /* SADB_X_EXT_NAT_T_OA 29 */
+};
+
+const char *
+pfkey_v2_sadb_ext_string(int ext)
+{
+ if(ext <= SADB_EXT_MAX) {
+ return pfkey_sadb_ext_strings[ext];
+ } else {
+ return "unknown-ext";
+ }
+}
+
+
+static char *pfkey_sadb_type_strings[]={
+ "reserved", /* SADB_RESERVED */
+ "getspi", /* SADB_GETSPI */
+ "update", /* SADB_UPDATE */
+ "add", /* SADB_ADD */
+ "delete", /* SADB_DELETE */
+ "get", /* SADB_GET */
+ "acquire", /* SADB_ACQUIRE */
+ "register", /* SADB_REGISTER */
+ "expire", /* SADB_EXPIRE */
+ "flush", /* SADB_FLUSH */
+ "dump", /* SADB_DUMP */
+ "x-promisc", /* SADB_X_PROMISC */
+ "x-pchange", /* SADB_X_PCHANGE */
+ "x-groupsa", /* SADB_X_GRPSA */
+ "x-addflow(eroute)", /* SADB_X_ADDFLOW */
+ "x-delflow(eroute)", /* SADB_X_DELFLOW */
+ "x-debug", /* SADB_X_DEBUG */
+};
+
+const char *
+pfkey_v2_sadb_type_string(int sadb_type)
+{
+ if(sadb_type <= SADB_MAX) {
+ return pfkey_sadb_type_strings[sadb_type];
+ } else {
+ return "unknown-sadb-type";
+ }
+}
+
+
+
+
+/*
+ * $Log: pfkey_v2_debug.c,v $
+ * Revision 1.2 2004/03/22 21:53:18 as
+ * merged alg-0.8.1 branch with HEAD
+ *
+ * Revision 1.1.2.1 2004/03/15 22:30:06 as
+ * nat-0.6c patch merged
+ *
+ * Revision 1.1 2004/03/15 20:35:26 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.7 2002/09/20 05:01:26 rgb
+ * Fixed limit inclusion error in both type and ext string conversion.
+ *
+ * Revision 1.6 2002/04/24 07:55:32 mcr
+ * #include patches and Makefiles for post-reorg compilation.
+ *
+ * Revision 1.5 2002/04/24 07:36:40 mcr
+ * Moved from ./lib/pfkey_v2_debug.c,v
+ *
+ * Revision 1.4 2002/01/29 22:25:36 rgb
+ * Re-add ipsec_kversion.h to keep MALLOC happy.
+ *
+ * Revision 1.3 2002/01/29 01:59:09 mcr
+ * removal of kversions.h - sources that needed it now use ipsec_param.h.
+ * updating of IPv6 structures to match latest in6.h version.
+ * removed dead code from freeswan.h that also duplicated kversions.h
+ * code.
+ *
+ * Revision 1.2 2002/01/20 20:34:50 mcr
+ * added pfkey_v2_sadb_type_string to decode sadb_type to string.
+ *
+ * Revision 1.1 2001/11/27 05:30:06 mcr
+ * initial set of debug strings for pfkey debugging.
+ * this will eventually only be included for debug builds.
+ *
+ * Revision 1.1 2001/09/21 04:12:03 mcr
+ * first compilable version.
+ *
+ *
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ *
+ */
diff --git a/src/libfreeswan/pfkey_v2_ext_bits.c b/src/libfreeswan/pfkey_v2_ext_bits.c
new file mode 100644
index 000000000..b41941848
--- /dev/null
+++ b/src/libfreeswan/pfkey_v2_ext_bits.c
@@ -0,0 +1,789 @@
+/*
+ * RFC2367 PF_KEYv2 Key management API message parser
+ * Copyright (C) 1999, 2000, 2001 Richard Guy Briggs.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: pfkey_v2_ext_bits.c,v 1.2 2004/03/22 21:53:18 as Exp $
+ */
+
+/*
+ * Template from klips/net/ipsec/ipsec/ipsec_parse.c.
+ */
+
+char pfkey_v2_ext_bits_c_version[] = "$Id: pfkey_v2_ext_bits.c,v 1.2 2004/03/22 21:53:18 as Exp $";
+
+/*
+ * Some ugly stuff to allow consistent debugging code for use in the
+ * kernel and in user space
+*/
+
+#ifdef __KERNEL__
+
+# include <linux/kernel.h> /* for printk */
+
+# include "freeswan/ipsec_kversion.h" /* for malloc switch */
+# ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+# else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+# endif /* MALLOC_SLAB */
+# include <linux/errno.h> /* error codes */
+# include <linux/types.h> /* size_t */
+# include <linux/interrupt.h> /* mark_bh */
+
+# include <linux/netdevice.h> /* struct device, and other headers */
+# include <linux/etherdevice.h> /* eth_type_trans */
+# include <linux/ip.h> /* struct iphdr */
+# if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+# include <linux/ipv6.h>
+# endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
+
+#else /* __KERNEL__ */
+
+# include <sys/types.h>
+# include <linux/types.h>
+# include <linux/errno.h>
+#endif
+
+#include <freeswan.h>
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+unsigned int extensions_bitmaps[2/*in/out*/][2/*perm/req*/][SADB_MAX + 1/*ext*/] = {
+
+/* INBOUND EXTENSIONS */
+{
+
+/* PERMITTED IN */
+{
+/* SADB_RESERVED */
+0
+,
+/* SADB_GETSPI */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_SPIRANGE
+,
+/* SADB_UPDATE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+| 1<<SADB_X_EXT_NAT_T_SPORT
+| 1<<SADB_X_EXT_NAT_T_DPORT
+,
+/* SADB_ADD */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+| 1<<SADB_X_EXT_NAT_T_TYPE
+| 1<<SADB_X_EXT_NAT_T_SPORT
+| 1<<SADB_X_EXT_NAT_T_DPORT
+| 1<<SADB_X_EXT_NAT_T_OA
+,
+/* SADB_DELETE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_GET */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_ACQUIRE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+| 1<<SADB_EXT_PROPOSAL
+,
+/* SADB_REGISTER */
+1<<SADB_EXT_RESERVED
+,
+/* SADB_EXPIRE */
+0
+,
+/* SADB_FLUSH */
+1<<SADB_EXT_RESERVED
+,
+/* SADB_DUMP */
+1<<SADB_EXT_RESERVED
+,
+/* SADB_X_PROMISC */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+| 1<<SADB_EXT_PROPOSAL
+| 1<<SADB_EXT_SUPPORTED_AUTH
+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+| 1<<SADB_EXT_SPIRANGE
+| 1<<SADB_X_EXT_KMPRIVATE
+| 1<<SADB_X_EXT_SATYPE2
+| 1<<SADB_X_EXT_SA2
+| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_PCHANGE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+| 1<<SADB_EXT_PROPOSAL
+| 1<<SADB_EXT_SUPPORTED_AUTH
+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+| 1<<SADB_EXT_SPIRANGE
+| 1<<SADB_X_EXT_KMPRIVATE
+| 1<<SADB_X_EXT_SATYPE2
+| 1<<SADB_X_EXT_SA2
+| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_GRPSA */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_SATYPE2
+| 1<<SADB_X_EXT_SA2
+| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_ADDFLOW */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
+| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
+| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
+| 1<<SADB_X_EXT_ADDRESS_DST_MASK
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_X_EXT_PROTOCOL
+,
+/* SADB_X_DELFLOW */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
+| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
+| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
+| 1<<SADB_X_EXT_ADDRESS_DST_MASK
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_X_EXT_PROTOCOL
+,
+/* SADB_X_DEBUG */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_X_EXT_DEBUG
+,
+/* SADB_X_NAT_T_NEW_MAPPING */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_NAT_T_SPORT
+| 1<<SADB_X_EXT_NAT_T_DPORT
+},
+
+/* REQUIRED IN */
+{
+/* SADB_RESERVED */
+0
+,
+/* SADB_GETSPI */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_SPIRANGE
+,
+/* SADB_UPDATE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+/*| 1<<SADB_EXT_KEY_AUTH*/
+/*| 1<<SADB_EXT_KEY_ENCRYPT*/
+,
+/* SADB_ADD */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+/*| 1<<SADB_EXT_KEY_AUTH*/
+/*| 1<<SADB_EXT_KEY_ENCRYPT*/
+,
+/* SADB_DELETE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_GET */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_ACQUIRE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_PROPOSAL
+,
+/* SADB_REGISTER */
+1<<SADB_EXT_RESERVED
+,
+/* SADB_EXPIRE */
+0
+,
+/* SADB_FLUSH */
+1<<SADB_EXT_RESERVED
+,
+/* SADB_DUMP */
+1<<SADB_EXT_RESERVED
+,
+/* SADB_X_PROMISC */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+| 1<<SADB_EXT_PROPOSAL
+| 1<<SADB_EXT_SUPPORTED_AUTH
+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+| 1<<SADB_EXT_SPIRANGE
+| 1<<SADB_X_EXT_KMPRIVATE
+| 1<<SADB_X_EXT_SATYPE2
+| 1<<SADB_X_EXT_SA2
+| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_PCHANGE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+| 1<<SADB_EXT_PROPOSAL
+| 1<<SADB_EXT_SUPPORTED_AUTH
+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+| 1<<SADB_EXT_SPIRANGE
+| 1<<SADB_X_EXT_KMPRIVATE
+| 1<<SADB_X_EXT_SATYPE2
+| 1<<SADB_X_EXT_SA2
+| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_GRPSA */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_DST
+/*| 1<<SADB_X_EXT_SATYPE2*/
+/*| 1<<SADB_X_EXT_SA2*/
+/*| 1<<SADB_X_EXT_ADDRESS_DST2*/
+,
+/* SADB_X_ADDFLOW */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
+| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
+| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
+| 1<<SADB_X_EXT_ADDRESS_DST_MASK
+,
+/* SADB_X_DELFLOW */
+1<<SADB_EXT_RESERVED
+/*| 1<<SADB_EXT_SA*/
+#if 0 /* SADB_X_CLREROUTE doesn't need all these... */
+| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
+| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
+| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
+| 1<<SADB_X_EXT_ADDRESS_DST_MASK
+#endif
+,
+/* SADB_X_DEBUG */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_X_EXT_DEBUG
+,
+/* SADB_X_NAT_T_NEW_MAPPING */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_NAT_T_SPORT
+| 1<<SADB_X_EXT_NAT_T_DPORT
+}
+
+},
+
+/* OUTBOUND EXTENSIONS */
+{
+
+/* PERMITTED OUT */
+{
+/* SADB_RESERVED */
+0
+,
+/* SADB_GETSPI */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_UPDATE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+,
+/* SADB_ADD */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+| 1<<SADB_X_EXT_NAT_T_TYPE
+| 1<<SADB_X_EXT_NAT_T_SPORT
+| 1<<SADB_X_EXT_NAT_T_DPORT
+| 1<<SADB_X_EXT_NAT_T_OA
+,
+/* SADB_DELETE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_GET */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+,
+/* SADB_ACQUIRE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+| 1<<SADB_EXT_PROPOSAL
+,
+/* SADB_REGISTER */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SUPPORTED_AUTH
+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+,
+/* SADB_EXPIRE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_FLUSH */
+1<<SADB_EXT_RESERVED
+,
+/* SADB_DUMP */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+,
+/* SADB_X_PROMISC */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+| 1<<SADB_EXT_PROPOSAL
+| 1<<SADB_EXT_SUPPORTED_AUTH
+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+| 1<<SADB_EXT_SPIRANGE
+| 1<<SADB_X_EXT_KMPRIVATE
+| 1<<SADB_X_EXT_SATYPE2
+| 1<<SADB_X_EXT_SA2
+| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_PCHANGE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+| 1<<SADB_EXT_PROPOSAL
+| 1<<SADB_EXT_SUPPORTED_AUTH
+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+| 1<<SADB_EXT_SPIRANGE
+| 1<<SADB_X_EXT_KMPRIVATE
+| 1<<SADB_X_EXT_SATYPE2
+| 1<<SADB_X_EXT_SA2
+| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_GRPSA */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_SATYPE2
+| 1<<SADB_X_EXT_SA2
+| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_ADDFLOW */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
+| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
+| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
+| 1<<SADB_X_EXT_ADDRESS_DST_MASK
+| 1<<SADB_X_EXT_PROTOCOL
+,
+/* SADB_X_DELFLOW */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
+| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
+| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
+| 1<<SADB_X_EXT_ADDRESS_DST_MASK
+| 1<<SADB_X_EXT_PROTOCOL
+,
+/* SADB_X_DEBUG */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_X_EXT_DEBUG
+,
+/* SADB_X_NAT_T_NEW_MAPPING */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_NAT_T_SPORT
+| 1<<SADB_X_EXT_NAT_T_DPORT
+},
+
+/* REQUIRED OUT */
+{
+/* SADB_RESERVED */
+0
+,
+/* SADB_GETSPI */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_UPDATE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_ADD */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_DELETE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_GET */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+/* | 1<<SADB_EXT_KEY_AUTH */
+/* | 1<<SADB_EXT_KEY_ENCRYPT */
+,
+/* SADB_ACQUIRE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_PROPOSAL
+,
+/* SADB_REGISTER */
+1<<SADB_EXT_RESERVED
+/* | 1<<SADB_EXT_SUPPORTED_AUTH
+ | 1<<SADB_EXT_SUPPORTED_ENCRYPT */
+,
+/* SADB_EXPIRE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+/* | 1<<SADB_EXT_LIFETIME_HARD
+ | 1<<SADB_EXT_LIFETIME_SOFT */
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_FLUSH */
+1<<SADB_EXT_RESERVED
+,
+/* SADB_DUMP */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+,
+/* SADB_X_PROMISC */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+| 1<<SADB_EXT_PROPOSAL
+| 1<<SADB_EXT_SUPPORTED_AUTH
+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+| 1<<SADB_EXT_SPIRANGE
+| 1<<SADB_X_EXT_KMPRIVATE
+| 1<<SADB_X_EXT_SATYPE2
+| 1<<SADB_X_EXT_SA2
+| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_PCHANGE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+| 1<<SADB_EXT_PROPOSAL
+| 1<<SADB_EXT_SUPPORTED_AUTH
+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+| 1<<SADB_EXT_SPIRANGE
+| 1<<SADB_X_EXT_KMPRIVATE
+| 1<<SADB_X_EXT_SATYPE2
+| 1<<SADB_X_EXT_SA2
+| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_GRPSA */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_X_ADDFLOW */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
+| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
+| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
+| 1<<SADB_X_EXT_ADDRESS_DST_MASK
+,
+/* SADB_X_DELFLOW */
+1<<SADB_EXT_RESERVED
+/*| 1<<SADB_EXT_SA*/
+| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
+| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
+| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
+| 1<<SADB_X_EXT_ADDRESS_DST_MASK
+,
+/* SADB_X_DEBUG */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_X_EXT_DEBUG
+,
+/* SADB_X_NAT_T_NEW_MAPPING */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_NAT_T_SPORT
+| 1<<SADB_X_EXT_NAT_T_DPORT
+}
+}
+};
+
+/*
+ * $Log: pfkey_v2_ext_bits.c,v $
+ * Revision 1.2 2004/03/22 21:53:18 as
+ * merged alg-0.8.1 branch with HEAD
+ *
+ * Revision 1.1.2.1 2004/03/15 22:30:06 as
+ * nat-0.6c patch merged
+ *
+ * Revision 1.1 2004/03/15 20:35:26 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.15 2002/04/24 07:55:32 mcr
+ * #include patches and Makefiles for post-reorg compilation.
+ *
+ * Revision 1.14 2002/04/24 07:36:40 mcr
+ * Moved from ./lib/pfkey_v2_ext_bits.c,v
+ *
+ * Revision 1.13 2002/01/29 22:25:36 rgb
+ * Re-add ipsec_kversion.h to keep MALLOC happy.
+ *
+ * Revision 1.12 2002/01/29 01:59:10 mcr
+ * removal of kversions.h - sources that needed it now use ipsec_param.h.
+ * updating of IPv6 structures to match latest in6.h version.
+ * removed dead code from freeswan.h that also duplicated kversions.h
+ * code.
+ *
+ * Revision 1.11 2001/10/18 04:45:24 rgb
+ * 2.4.9 kernel deprecates linux/malloc.h in favour of linux/slab.h,
+ * lib/freeswan.h version macros moved to lib/kversions.h.
+ * Other compiler directive cleanups.
+ *
+ * Revision 1.10 2001/09/08 21:13:35 rgb
+ * Added pfkey ident extension support for ISAKMPd. (NetCelo)
+ *
+ * Revision 1.9 2001/06/14 19:35:16 rgb
+ * Update copyright date.
+ *
+ * Revision 1.8 2001/03/26 23:07:36 rgb
+ * Remove requirement for auth and enc key from UPDATE.
+ *
+ * Revision 1.7 2000/09/12 22:35:37 rgb
+ * Restructured to remove unused extensions from CLEARFLOW messages.
+ *
+ * Revision 1.6 2000/09/09 06:39:01 rgb
+ * Added comments for clarity.
+ *
+ * Revision 1.5 2000/06/02 22:54:14 rgb
+ * Added Gerhard Gessler's struct sockaddr_storage mods for IPv6 support.
+ *
+ * Revision 1.4 2000/01/21 06:27:56 rgb
+ * Added address cases for eroute flows.
+ * Added comments for each message type.
+ * Added klipsdebug switching capability.
+ * Fixed GRPSA bitfields.
+ *
+ * Revision 1.3 1999/12/01 22:20:27 rgb
+ * Remove requirement for a proxy address in an incoming getspi message.
+ *
+ * Revision 1.2 1999/11/27 11:57:06 rgb
+ * Consolidated the 4 1-d extension bitmap arrays into one 4-d array.
+ * Add CVS log entry to bottom of file.
+ * Cleaned out unused bits.
+ *
+ */
diff --git a/src/libfreeswan/pfkey_v2_parse.c b/src/libfreeswan/pfkey_v2_parse.c
new file mode 100644
index 000000000..440aa8c1d
--- /dev/null
+++ b/src/libfreeswan/pfkey_v2_parse.c
@@ -0,0 +1,1824 @@
+/*
+ * RFC2367 PF_KEYv2 Key management API message parser
+ * Copyright (C) 1999, 2000, 2001 Richard Guy Briggs.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: pfkey_v2_parse.c,v 1.4 2004/06/13 20:35:07 as Exp $
+ */
+
+/*
+ * Template from klips/net/ipsec/ipsec/ipsec_parser.c.
+ */
+
+char pfkey_v2_parse_c_version[] = "$Id: pfkey_v2_parse.c,v 1.4 2004/06/13 20:35:07 as Exp $";
+
+/*
+ * Some ugly stuff to allow consistent debugging code for use in the
+ * kernel and in user space
+*/
+
+#ifdef __KERNEL__
+
+# include <linux/kernel.h> /* for printk */
+
+#include "freeswan/ipsec_kversion.h" /* for malloc switch */
+
+# ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+# else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+# endif /* MALLOC_SLAB */
+# include <linux/errno.h> /* error codes */
+# include <linux/types.h> /* size_t */
+# include <linux/interrupt.h> /* mark_bh */
+
+# include <linux/netdevice.h> /* struct device, and other headers */
+# include <linux/etherdevice.h> /* eth_type_trans */
+# include <linux/ip.h> /* struct iphdr */
+# if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+# include <linux/ipv6.h> /* struct ipv6hdr */
+# endif /* if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
+extern int debug_pfkey;
+
+#include "freeswan.h"
+
+#include "ipsec_encap.h"
+
+#else /* __KERNEL__ */
+
+# include <sys/types.h>
+# include <linux/types.h>
+# include <linux/errno.h>
+
+# include <freeswan.h>
+# include <constants.h>
+# include <defs.h> /* for PRINTF_LIKE */
+# include <log.h> /* for debugging and DBG_log */
+
+/* #define PLUTO */
+
+# ifdef PLUTO
+# define DEBUGGING(level, args...) { DBG_log("pfkey_lib_debug:" args); }
+# else
+# define DEBUGGING(level, args...) if(pfkey_lib_debug & level) { printf("pfkey_lib_debug:" args); } else { ; }
+# endif
+
+#endif /* __KERNEL__ */
+
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#ifdef __KERNEL__
+extern int sysctl_ipsec_debug_verbose;
+# define DEBUGGING(level, args...) \
+ KLIPS_PRINT( \
+ ((debug_pfkey & level & (PF_KEY_DEBUG_PARSE_STRUCT | PF_KEY_DEBUG_PARSE_PROBLEM)) \
+ || (sysctl_ipsec_debug_verbose && (debug_pfkey & level & PF_KEY_DEBUG_PARSE_FLOW))) \
+ , "klips_debug:" args)
+#endif /* __KERNEL__ */
+#include "ipsec_sa.h" /* IPSEC_SAREF_NULL, IPSEC_SA_REF_TABLE_IDX_WIDTH */
+
+
+#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
+
+struct satype_tbl {
+ uint8_t proto;
+ uint8_t satype;
+ char* name;
+} static satype_tbl[] = {
+#ifdef __KERNEL__
+ { IPPROTO_ESP, SADB_SATYPE_ESP, "ESP" },
+ { IPPROTO_AH, SADB_SATYPE_AH, "AH" },
+ { IPPROTO_IPIP, SADB_X_SATYPE_IPIP, "IPIP" },
+#ifdef CONFIG_IPSEC_IPCOMP
+ { IPPROTO_COMP, SADB_X_SATYPE_COMP, "COMP" },
+#endif /* CONFIG_IPSEC_IPCOMP */
+ { IPPROTO_INT, SADB_X_SATYPE_INT, "INT" },
+#else /* __KERNEL__ */
+ { SA_ESP, SADB_SATYPE_ESP, "ESP" },
+ { SA_AH, SADB_SATYPE_AH, "AH" },
+ { SA_IPIP, SADB_X_SATYPE_IPIP, "IPIP" },
+ { SA_COMP, SADB_X_SATYPE_COMP, "COMP" },
+ { SA_INT, SADB_X_SATYPE_INT, "INT" },
+#endif /* __KERNEL__ */
+ { 0, 0, "UNKNOWN" }
+};
+
+uint8_t
+satype2proto(uint8_t satype)
+{
+ int i =0;
+
+ while(satype_tbl[i].satype != satype && satype_tbl[i].satype != 0) {
+ i++;
+ }
+ return satype_tbl[i].proto;
+}
+
+uint8_t
+proto2satype(uint8_t proto)
+{
+ int i = 0;
+
+ while(satype_tbl[i].proto != proto && satype_tbl[i].proto != 0) {
+ i++;
+ }
+ return satype_tbl[i].satype;
+}
+
+char*
+satype2name(uint8_t satype)
+{
+ int i = 0;
+
+ while(satype_tbl[i].satype != satype && satype_tbl[i].satype != 0) {
+ i++;
+ }
+ return satype_tbl[i].name;
+}
+
+char*
+proto2name(uint8_t proto)
+{
+ int i = 0;
+
+ while(satype_tbl[i].proto != proto && satype_tbl[i].proto != 0) {
+ i++;
+ }
+ return satype_tbl[i].name;
+}
+
+/* Default extension parsers taken from the KLIPS code */
+
+DEBUG_NO_STATIC int
+pfkey_sa_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ struct sadb_sa *pfkey_sa = (struct sadb_sa *)pfkey_ext;
+#if 0
+ struct sadb_sa sav2;
+#endif
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
+ "pfkey_sa_parse: entry\n");
+ /* sanity checks... */
+ if(!pfkey_sa) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_sa_parse: "
+ "NULL pointer passed in.\n");
+ SENDERR(EINVAL);
+ }
+
+#if 0
+ /* check if this structure is short, and if so, fix it up.
+ * XXX this is NOT the way to do things.
+ */
+ if(pfkey_sa->sadb_sa_len == sizeof(struct sadb_sa_v1)/IPSEC_PFKEYv2_ALIGN) {
+
+ /* yes, so clear out a temporary structure, and copy first */
+ memset(&sav2, 0, sizeof(sav2));
+ memcpy(&sav2, pfkey_sa, sizeof(struct sadb_sa_v1));
+ sav2.sadb_x_sa_ref=-1;
+ sav2.sadb_sa_len = sizeof(struct sadb_sa) / IPSEC_PFKEYv2_ALIGN;
+
+ pfkey_sa = &sav2;
+ }
+#endif
+
+
+ if(pfkey_sa->sadb_sa_len != sizeof(struct sadb_sa) / IPSEC_PFKEYv2_ALIGN) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_sa_parse: "
+ "length wrong pfkey_sa->sadb_sa_len=%d sizeof(struct sadb_sa)=%d.\n",
+ pfkey_sa->sadb_sa_len,
+ (int)sizeof(struct sadb_sa));
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_sa->sadb_sa_encrypt > SADB_EALG_MAX) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_sa_parse: "
+ "pfkey_sa->sadb_sa_encrypt=%d > SADB_EALG_MAX=%d.\n",
+ pfkey_sa->sadb_sa_encrypt,
+ SADB_EALG_MAX);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_sa->sadb_sa_auth > SADB_AALG_MAX) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_sa_parse: "
+ "pfkey_sa->sadb_sa_auth=%d > SADB_AALG_MAX=%d.\n",
+ pfkey_sa->sadb_sa_auth,
+ SADB_AALG_MAX);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_sa->sadb_sa_state > SADB_SASTATE_MAX) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_sa_parse: "
+ "state=%d exceeds MAX=%d.\n",
+ pfkey_sa->sadb_sa_state,
+ SADB_SASTATE_MAX);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_sa->sadb_sa_state == SADB_SASTATE_DEAD) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_sa_parse: "
+ "state=%d is DEAD=%d.\n",
+ pfkey_sa->sadb_sa_state,
+ SADB_SASTATE_DEAD);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_sa->sadb_sa_replay > 64) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_sa_parse: "
+ "replay window size: %d -- must be 0 <= size <= 64\n",
+ pfkey_sa->sadb_sa_replay);
+ SENDERR(EINVAL);
+ }
+
+ if(! ((pfkey_sa->sadb_sa_exttype == SADB_EXT_SA) ||
+ (pfkey_sa->sadb_sa_exttype == SADB_X_EXT_SA2)))
+ {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_sa_parse: "
+ "unknown exttype=%d, expecting SADB_EXT_SA=%d or SADB_X_EXT_SA2=%d.\n",
+ pfkey_sa->sadb_sa_exttype,
+ SADB_EXT_SA,
+ SADB_X_EXT_SA2);
+ SENDERR(EINVAL);
+ }
+
+ if((IPSEC_SAREF_NULL != pfkey_sa->sadb_x_sa_ref) && (pfkey_sa->sadb_x_sa_ref >= (1 << IPSEC_SA_REF_TABLE_IDX_WIDTH))) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_sa_parse: "
+ "SAref=%d must be (SAref == IPSEC_SAREF_NULL(%d) || SAref < IPSEC_SA_REF_TABLE_NUM_ENTRIES(%d)).\n",
+ pfkey_sa->sadb_x_sa_ref,
+ IPSEC_SAREF_NULL,
+ IPSEC_SA_REF_TABLE_NUM_ENTRIES);
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
+ "pfkey_sa_parse: "
+ "successfully found len=%d exttype=%d(%s) spi=%08lx replay=%d state=%d auth=%d encrypt=%d flags=%d ref=%d.\n",
+ pfkey_sa->sadb_sa_len,
+ pfkey_sa->sadb_sa_exttype,
+ pfkey_v2_sadb_ext_string(pfkey_sa->sadb_sa_exttype),
+ (long unsigned int)ntohl(pfkey_sa->sadb_sa_spi),
+ pfkey_sa->sadb_sa_replay,
+ pfkey_sa->sadb_sa_state,
+ pfkey_sa->sadb_sa_auth,
+ pfkey_sa->sadb_sa_encrypt,
+ pfkey_sa->sadb_sa_flags,
+ pfkey_sa->sadb_x_sa_ref);
+
+ errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_lifetime_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ struct sadb_lifetime *pfkey_lifetime = (struct sadb_lifetime *)pfkey_ext;
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
+ "pfkey_lifetime_parse:enter\n");
+ /* sanity checks... */
+ if(!pfkey_lifetime) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_lifetime_parse: "
+ "NULL pointer passed in.\n");
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_lifetime->sadb_lifetime_len !=
+ sizeof(struct sadb_lifetime) / IPSEC_PFKEYv2_ALIGN) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_lifetime_parse: "
+ "length wrong pfkey_lifetime->sadb_lifetime_len=%d sizeof(struct sadb_lifetime)=%d.\n",
+ pfkey_lifetime->sadb_lifetime_len,
+ (int)sizeof(struct sadb_lifetime));
+ SENDERR(EINVAL);
+ }
+
+ if((pfkey_lifetime->sadb_lifetime_exttype != SADB_EXT_LIFETIME_HARD) &&
+ (pfkey_lifetime->sadb_lifetime_exttype != SADB_EXT_LIFETIME_SOFT) &&
+ (pfkey_lifetime->sadb_lifetime_exttype != SADB_EXT_LIFETIME_CURRENT)) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_lifetime_parse: "
+ "unexpected ext_type=%d.\n",
+ pfkey_lifetime->sadb_lifetime_exttype);
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
+ "pfkey_lifetime_parse: "
+ "life_type=%d(%s) alloc=%u bytes=%u add=%u use=%u pkts=%u.\n",
+ pfkey_lifetime->sadb_lifetime_exttype,
+ pfkey_v2_sadb_ext_string(pfkey_lifetime->sadb_lifetime_exttype),
+ pfkey_lifetime->sadb_lifetime_allocations,
+ (unsigned)pfkey_lifetime->sadb_lifetime_bytes,
+ (unsigned)pfkey_lifetime->sadb_lifetime_addtime,
+ (unsigned)pfkey_lifetime->sadb_lifetime_usetime,
+ pfkey_lifetime->sadb_x_lifetime_packets);
+errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_address_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ int saddr_len = 0;
+ struct sadb_address *pfkey_address = (struct sadb_address *)pfkey_ext;
+ struct sockaddr* s = (struct sockaddr*)((char*)pfkey_address + sizeof(*pfkey_address));
+ char ipaddr_txt[ADDRTOT_BUF];
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
+ "pfkey_address_parse:enter\n");
+ /* sanity checks... */
+ if(!pfkey_address) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_address_parse: "
+ "NULL pointer passed in.\n");
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_address->sadb_address_len <
+ (sizeof(struct sadb_address) + sizeof(struct sockaddr))/
+ IPSEC_PFKEYv2_ALIGN) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_address_parse: "
+ "size wrong 1 ext_len=%d, adr_ext_len=%d, saddr_len=%d.\n",
+ pfkey_address->sadb_address_len,
+ (int)sizeof(struct sadb_address),
+ (int)sizeof(struct sockaddr));
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_address->sadb_address_reserved) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_address_parse: "
+ "res=%d, must be zero.\n",
+ pfkey_address->sadb_address_reserved);
+ SENDERR(EINVAL);
+ }
+
+ switch(pfkey_address->sadb_address_exttype) {
+ case SADB_EXT_ADDRESS_SRC:
+ case SADB_EXT_ADDRESS_DST:
+ case SADB_EXT_ADDRESS_PROXY:
+ case SADB_X_EXT_ADDRESS_DST2:
+ case SADB_X_EXT_ADDRESS_SRC_FLOW:
+ case SADB_X_EXT_ADDRESS_DST_FLOW:
+ case SADB_X_EXT_ADDRESS_SRC_MASK:
+ case SADB_X_EXT_ADDRESS_DST_MASK:
+ case SADB_X_EXT_NAT_T_OA:
+ break;
+ default:
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_address_parse: "
+ "unexpected ext_type=%d.\n",
+ pfkey_address->sadb_address_exttype);
+ SENDERR(EINVAL);
+ }
+
+ switch(s->sa_family) {
+ case AF_INET:
+ saddr_len = sizeof(struct sockaddr_in);
+ sprintf(ipaddr_txt, "%d.%d.%d.%d"
+ , (((struct sockaddr_in*)s)->sin_addr.s_addr >> 0) & 0xFF
+ , (((struct sockaddr_in*)s)->sin_addr.s_addr >> 8) & 0xFF
+ , (((struct sockaddr_in*)s)->sin_addr.s_addr >> 16) & 0xFF
+ , (((struct sockaddr_in*)s)->sin_addr.s_addr >> 24) & 0xFF);
+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
+ "pfkey_address_parse: "
+ "found exttype=%u(%s) family=%d(AF_INET) address=%s proto=%u port=%u.\n",
+ pfkey_address->sadb_address_exttype,
+ pfkey_v2_sadb_ext_string(pfkey_address->sadb_address_exttype),
+ s->sa_family,
+ ipaddr_txt,
+ pfkey_address->sadb_address_proto,
+ ntohs(((struct sockaddr_in*)s)->sin_port));
+ break;
+ case AF_INET6:
+ saddr_len = sizeof(struct sockaddr_in6);
+ sprintf(ipaddr_txt, "%x:%x:%x:%x:%x:%x:%x:%x"
+ , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[0])
+ , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[1])
+ , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[2])
+ , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[3])
+ , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[4])
+ , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[5])
+ , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[6])
+ , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[7]));
+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
+ "pfkey_address_parse: "
+ "found exttype=%u(%s) family=%d(AF_INET6) address=%s proto=%u port=%u.\n",
+ pfkey_address->sadb_address_exttype,
+ pfkey_v2_sadb_ext_string(pfkey_address->sadb_address_exttype),
+ s->sa_family,
+ ipaddr_txt,
+ pfkey_address->sadb_address_proto,
+ ((struct sockaddr_in6*)s)->sin6_port);
+ break;
+ default:
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_address_parse: "
+ "s->sa_family=%d not supported.\n",
+ s->sa_family);
+ SENDERR(EPFNOSUPPORT);
+ }
+
+ if(pfkey_address->sadb_address_len !=
+ DIVUP(sizeof(struct sadb_address) + saddr_len, IPSEC_PFKEYv2_ALIGN)) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_address_parse: "
+ "size wrong 2 ext_len=%d, adr_ext_len=%d, saddr_len=%d.\n",
+ pfkey_address->sadb_address_len,
+ (int)sizeof(struct sadb_address),
+ saddr_len);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_address->sadb_address_prefixlen != 0) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_address_parse: "
+ "address prefixes not supported yet.\n");
+ SENDERR(EAFNOSUPPORT); /* not supported yet */
+ }
+
+ /* XXX check if port!=0 */
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
+ "pfkey_address_parse: successful.\n");
+ errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_key_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ struct sadb_key *pfkey_key = (struct sadb_key *)pfkey_ext;
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
+ "pfkey_key_parse:enter\n");
+ /* sanity checks... */
+
+ if(!pfkey_key) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_key_parse: "
+ "NULL pointer passed in.\n");
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_key->sadb_key_len < sizeof(struct sadb_key) / IPSEC_PFKEYv2_ALIGN) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_key_parse: "
+ "size wrong ext_len=%d, key_ext_len=%d.\n",
+ pfkey_key->sadb_key_len,
+ (int)sizeof(struct sadb_key));
+ SENDERR(EINVAL);
+ }
+
+ if(!pfkey_key->sadb_key_bits) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_key_parse: "
+ "key length set to zero, must be non-zero.\n");
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_key->sadb_key_len !=
+ DIVUP(sizeof(struct sadb_key) * OCTETBITS + pfkey_key->sadb_key_bits,
+ PFKEYBITS)) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_key_parse: "
+ "key length=%d does not agree with extension length=%d.\n",
+ pfkey_key->sadb_key_bits,
+ pfkey_key->sadb_key_len);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_key->sadb_key_reserved) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_key_parse: "
+ "res=%d, must be zero.\n",
+ pfkey_key->sadb_key_reserved);
+ SENDERR(EINVAL);
+ }
+
+ if(! ( (pfkey_key->sadb_key_exttype == SADB_EXT_KEY_AUTH) ||
+ (pfkey_key->sadb_key_exttype == SADB_EXT_KEY_ENCRYPT))) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_key_parse: "
+ "expecting extension type AUTH or ENCRYPT, got %d.\n",
+ pfkey_key->sadb_key_exttype);
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
+ "pfkey_key_parse: "
+ "success, found len=%d exttype=%d(%s) bits=%d reserved=%d.\n",
+ pfkey_key->sadb_key_len,
+ pfkey_key->sadb_key_exttype,
+ pfkey_v2_sadb_ext_string(pfkey_key->sadb_key_exttype),
+ pfkey_key->sadb_key_bits,
+ pfkey_key->sadb_key_reserved);
+
+errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_ident_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ struct sadb_ident *pfkey_ident = (struct sadb_ident *)pfkey_ext;
+
+ /* sanity checks... */
+ if(pfkey_ident->sadb_ident_len < sizeof(struct sadb_ident) / IPSEC_PFKEYv2_ALIGN) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_ident_parse: "
+ "size wrong ext_len=%d, key_ext_len=%d.\n",
+ pfkey_ident->sadb_ident_len,
+ (int)sizeof(struct sadb_ident));
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_ident->sadb_ident_type > SADB_IDENTTYPE_MAX) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_ident_parse: "
+ "ident_type=%d out of range, must be less than %d.\n",
+ pfkey_ident->sadb_ident_type,
+ SADB_IDENTTYPE_MAX);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_ident->sadb_ident_reserved) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_ident_parse: "
+ "res=%d, must be zero.\n",
+ pfkey_ident->sadb_ident_reserved);
+ SENDERR(EINVAL);
+ }
+
+ /* string terminator/padding must be zero */
+ if(pfkey_ident->sadb_ident_len > sizeof(struct sadb_ident) / IPSEC_PFKEYv2_ALIGN) {
+ if(*((char*)pfkey_ident + pfkey_ident->sadb_ident_len * IPSEC_PFKEYv2_ALIGN - 1)) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_ident_parse: "
+ "string padding must be zero, last is 0x%02x.\n",
+ *((char*)pfkey_ident +
+ pfkey_ident->sadb_ident_len * IPSEC_PFKEYv2_ALIGN - 1));
+ SENDERR(EINVAL);
+ }
+ }
+
+ if( ! ((pfkey_ident->sadb_ident_exttype == SADB_EXT_IDENTITY_SRC) ||
+ (pfkey_ident->sadb_ident_exttype == SADB_EXT_IDENTITY_DST))) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_key_parse: "
+ "expecting extension type IDENTITY_SRC or IDENTITY_DST, got %d.\n",
+ pfkey_ident->sadb_ident_exttype);
+ SENDERR(EINVAL);
+ }
+
+errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_sens_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ struct sadb_sens *pfkey_sens = (struct sadb_sens *)pfkey_ext;
+
+ /* sanity checks... */
+ if(pfkey_sens->sadb_sens_len < sizeof(struct sadb_sens) / IPSEC_PFKEYv2_ALIGN) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_sens_parse: "
+ "size wrong ext_len=%d, key_ext_len=%d.\n",
+ pfkey_sens->sadb_sens_len,
+ (int)sizeof(struct sadb_sens));
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_sens_parse: "
+ "Sorry, I can't parse exttype=%d yet.\n",
+ pfkey_ext->sadb_ext_type);
+#if 0
+ SENDERR(EINVAL); /* don't process these yet */
+#endif
+
+errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_prop_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ int i, num_comb;
+ struct sadb_prop *pfkey_prop = (struct sadb_prop *)pfkey_ext;
+ struct sadb_comb *pfkey_comb = (struct sadb_comb *)((char*)pfkey_ext + sizeof(struct sadb_prop));
+
+ /* sanity checks... */
+ if((pfkey_prop->sadb_prop_len < sizeof(struct sadb_prop) / IPSEC_PFKEYv2_ALIGN) ||
+ (((pfkey_prop->sadb_prop_len * IPSEC_PFKEYv2_ALIGN) - sizeof(struct sadb_prop)) % sizeof(struct sadb_comb))) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "size wrong ext_len=%d, prop_ext_len=%d comb_ext_len=%d.\n",
+ pfkey_prop->sadb_prop_len,
+ (int)sizeof(struct sadb_prop),
+ (int)sizeof(struct sadb_comb));
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_prop->sadb_prop_replay > 64) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "replay window size: %d -- must be 0 <= size <= 64\n",
+ pfkey_prop->sadb_prop_replay);
+ SENDERR(EINVAL);
+ }
+
+ for(i=0; i<3; i++) {
+ if(pfkey_prop->sadb_prop_reserved[i]) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "res[%d]=%d, must be zero.\n",
+ i, pfkey_prop->sadb_prop_reserved[i]);
+ SENDERR(EINVAL);
+ }
+ }
+
+ num_comb = ((pfkey_prop->sadb_prop_len * IPSEC_PFKEYv2_ALIGN) - sizeof(struct sadb_prop)) / sizeof(struct sadb_comb);
+
+ for(i = 0; i < num_comb; i++) {
+ if(pfkey_comb->sadb_comb_auth > SADB_AALG_MAX) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_auth=%d > SADB_AALG_MAX=%d.\n",
+ i,
+ pfkey_comb->sadb_comb_auth,
+ SADB_AALG_MAX);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_comb->sadb_comb_auth) {
+ if(!pfkey_comb->sadb_comb_auth_minbits) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_auth_minbits=0, fatal.\n",
+ i);
+ SENDERR(EINVAL);
+ }
+ if(!pfkey_comb->sadb_comb_auth_maxbits) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_auth_maxbits=0, fatal.\n",
+ i);
+ SENDERR(EINVAL);
+ }
+ if(pfkey_comb->sadb_comb_auth_minbits > pfkey_comb->sadb_comb_auth_maxbits) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_auth_minbits=%d > maxbits=%d, fatal.\n",
+ i,
+ pfkey_comb->sadb_comb_auth_minbits,
+ pfkey_comb->sadb_comb_auth_maxbits);
+ SENDERR(EINVAL);
+ }
+ } else {
+ if(pfkey_comb->sadb_comb_auth_minbits) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_auth_minbits=%d != 0, fatal.\n",
+ i,
+ pfkey_comb->sadb_comb_auth_minbits);
+ SENDERR(EINVAL);
+ }
+ if(pfkey_comb->sadb_comb_auth_maxbits) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_auth_maxbits=%d != 0, fatal.\n",
+ i,
+ pfkey_comb->sadb_comb_auth_maxbits);
+ SENDERR(EINVAL);
+ }
+ }
+
+ if(pfkey_comb->sadb_comb_encrypt > SADB_EALG_MAX) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_comb_parse: "
+ "pfkey_comb[%d]->sadb_comb_encrypt=%d > SADB_EALG_MAX=%d.\n",
+ i,
+ pfkey_comb->sadb_comb_encrypt,
+ SADB_EALG_MAX);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_comb->sadb_comb_encrypt) {
+ if(!pfkey_comb->sadb_comb_encrypt_minbits) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_encrypt_minbits=0, fatal.\n",
+ i);
+ SENDERR(EINVAL);
+ }
+ if(!pfkey_comb->sadb_comb_encrypt_maxbits) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_encrypt_maxbits=0, fatal.\n",
+ i);
+ SENDERR(EINVAL);
+ }
+ if(pfkey_comb->sadb_comb_encrypt_minbits > pfkey_comb->sadb_comb_encrypt_maxbits) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_encrypt_minbits=%d > maxbits=%d, fatal.\n",
+ i,
+ pfkey_comb->sadb_comb_encrypt_minbits,
+ pfkey_comb->sadb_comb_encrypt_maxbits);
+ SENDERR(EINVAL);
+ }
+ } else {
+ if(pfkey_comb->sadb_comb_encrypt_minbits) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_encrypt_minbits=%d != 0, fatal.\n",
+ i,
+ pfkey_comb->sadb_comb_encrypt_minbits);
+ SENDERR(EINVAL);
+ }
+ if(pfkey_comb->sadb_comb_encrypt_maxbits) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_encrypt_maxbits=%d != 0, fatal.\n",
+ i,
+ pfkey_comb->sadb_comb_encrypt_maxbits);
+ SENDERR(EINVAL);
+ }
+ }
+
+ /* XXX do sanity check on flags */
+
+ if(pfkey_comb->sadb_comb_hard_allocations && pfkey_comb->sadb_comb_soft_allocations > pfkey_comb->sadb_comb_hard_allocations) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_soft_allocations=%d > hard_allocations=%d, fatal.\n",
+ i,
+ pfkey_comb->sadb_comb_soft_allocations,
+ pfkey_comb->sadb_comb_hard_allocations);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_comb->sadb_comb_hard_bytes && pfkey_comb->sadb_comb_soft_bytes > pfkey_comb->sadb_comb_hard_bytes) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_soft_bytes=%Ld > hard_bytes=%Ld, fatal.\n",
+ i,
+ (unsigned long long int)pfkey_comb->sadb_comb_soft_bytes,
+ (unsigned long long int)pfkey_comb->sadb_comb_hard_bytes);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_comb->sadb_comb_hard_addtime && pfkey_comb->sadb_comb_soft_addtime > pfkey_comb->sadb_comb_hard_addtime) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_soft_addtime=%Ld > hard_addtime=%Ld, fatal.\n",
+ i,
+ (unsigned long long int)pfkey_comb->sadb_comb_soft_addtime,
+ (unsigned long long int)pfkey_comb->sadb_comb_hard_addtime);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_comb->sadb_comb_hard_usetime && pfkey_comb->sadb_comb_soft_usetime > pfkey_comb->sadb_comb_hard_usetime) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_soft_usetime=%Ld > hard_usetime=%Ld, fatal.\n",
+ i,
+ (unsigned long long int)pfkey_comb->sadb_comb_soft_usetime,
+ (unsigned long long int)pfkey_comb->sadb_comb_hard_usetime);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_comb->sadb_x_comb_hard_packets && pfkey_comb->sadb_x_comb_soft_packets > pfkey_comb->sadb_x_comb_hard_packets) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_x_comb_soft_packets=%d > hard_packets=%d, fatal.\n",
+ i,
+ pfkey_comb->sadb_x_comb_soft_packets,
+ pfkey_comb->sadb_x_comb_hard_packets);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_comb->sadb_comb_reserved) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "comb[%d].res=%d, must be zero.\n",
+ i,
+ pfkey_comb->sadb_comb_reserved);
+ SENDERR(EINVAL);
+ }
+ pfkey_comb++;
+ }
+
+errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_supported_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ unsigned int i, num_alg;
+ struct sadb_supported *pfkey_supported = (struct sadb_supported *)pfkey_ext;
+ struct sadb_alg *pfkey_alg = (struct sadb_alg*)((char*)pfkey_ext + sizeof(struct sadb_supported));
+
+ /* sanity checks... */
+ if((pfkey_supported->sadb_supported_len <
+ sizeof(struct sadb_supported) / IPSEC_PFKEYv2_ALIGN) ||
+ (((pfkey_supported->sadb_supported_len * IPSEC_PFKEYv2_ALIGN) -
+ sizeof(struct sadb_supported)) % sizeof(struct sadb_alg))) {
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_supported_parse: "
+ "size wrong ext_len=%d, supported_ext_len=%d alg_ext_len=%d.\n",
+ pfkey_supported->sadb_supported_len,
+ (int)sizeof(struct sadb_supported),
+ (int)sizeof(struct sadb_alg));
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_supported->sadb_supported_reserved) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_supported_parse: "
+ "res=%d, must be zero.\n",
+ pfkey_supported->sadb_supported_reserved);
+ SENDERR(EINVAL);
+ }
+
+ num_alg = ((pfkey_supported->sadb_supported_len * IPSEC_PFKEYv2_ALIGN) - sizeof(struct sadb_supported)) / sizeof(struct sadb_alg);
+
+ for(i = 0; i < num_alg; i++) {
+ /* process algo description */
+ if(pfkey_alg->sadb_alg_reserved) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_supported_parse: "
+ "alg[%d], id=%d, ivlen=%d, minbits=%d, maxbits=%d, res=%d, must be zero.\n",
+ i,
+ pfkey_alg->sadb_alg_id,
+ pfkey_alg->sadb_alg_ivlen,
+ pfkey_alg->sadb_alg_minbits,
+ pfkey_alg->sadb_alg_maxbits,
+ pfkey_alg->sadb_alg_reserved);
+ SENDERR(EINVAL);
+ }
+
+ /* XXX can alg_id auth/enc be determined from info given?
+ Yes, but OpenBSD's method does not iteroperate with rfc2367.
+ rgb, 2000-04-06 */
+
+ switch(pfkey_supported->sadb_supported_exttype) {
+ case SADB_EXT_SUPPORTED_AUTH:
+ if(pfkey_alg->sadb_alg_id > SADB_AALG_MAX) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_supported_parse: "
+ "alg[%d], alg_id=%d > SADB_AALG_MAX=%d, fatal.\n",
+ i,
+ pfkey_alg->sadb_alg_id,
+ SADB_AALG_MAX);
+ SENDERR(EINVAL);
+ }
+ break;
+ case SADB_EXT_SUPPORTED_ENCRYPT:
+ if(pfkey_alg->sadb_alg_id > SADB_EALG_MAX) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_supported_parse: "
+ "alg[%d], alg_id=%d > SADB_EALG_MAX=%d, fatal.\n",
+ i,
+ pfkey_alg->sadb_alg_id,
+ SADB_EALG_MAX);
+ SENDERR(EINVAL);
+ }
+ break;
+ default:
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_supported_parse: "
+ "alg[%d], alg_id=%d > SADB_EALG_MAX=%d, fatal.\n",
+ i,
+ pfkey_alg->sadb_alg_id,
+ SADB_EALG_MAX);
+ SENDERR(EINVAL);
+ }
+ pfkey_alg++;
+ }
+
+ errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_spirange_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ struct sadb_spirange *pfkey_spirange = (struct sadb_spirange *)pfkey_ext;
+
+ /* sanity checks... */
+ if(pfkey_spirange->sadb_spirange_len !=
+ sizeof(struct sadb_spirange) / IPSEC_PFKEYv2_ALIGN) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_spirange_parse: "
+ "size wrong ext_len=%d, key_ext_len=%d.\n",
+ pfkey_spirange->sadb_spirange_len,
+ (int)sizeof(struct sadb_spirange));
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_spirange->sadb_spirange_reserved) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_spirange_parse: "
+ "reserved=%d must be set to zero.\n",
+ pfkey_spirange->sadb_spirange_reserved);
+ SENDERR(EINVAL);
+ }
+
+ if(ntohl(pfkey_spirange->sadb_spirange_max) < ntohl(pfkey_spirange->sadb_spirange_min)) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_spirange_parse: "
+ "minspi=%08x must be < maxspi=%08x.\n",
+ ntohl(pfkey_spirange->sadb_spirange_min),
+ ntohl(pfkey_spirange->sadb_spirange_max));
+ SENDERR(EINVAL);
+ }
+
+ if(ntohl(pfkey_spirange->sadb_spirange_min) <= 255) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_spirange_parse: "
+ "minspi=%08x must be > 255.\n",
+ ntohl(pfkey_spirange->sadb_spirange_min));
+ SENDERR(EEXIST);
+ }
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
+ "pfkey_spirange_parse: "
+ "ext_len=%u ext_type=%u(%s) min=%u max=%u res=%u.\n",
+ pfkey_spirange->sadb_spirange_len,
+ pfkey_spirange->sadb_spirange_exttype,
+ pfkey_v2_sadb_ext_string(pfkey_spirange->sadb_spirange_exttype),
+ pfkey_spirange->sadb_spirange_min,
+ pfkey_spirange->sadb_spirange_max,
+ pfkey_spirange->sadb_spirange_reserved);
+ errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_x_kmprivate_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ struct sadb_x_kmprivate *pfkey_x_kmprivate = (struct sadb_x_kmprivate *)pfkey_ext;
+
+ /* sanity checks... */
+ if(pfkey_x_kmprivate->sadb_x_kmprivate_len <
+ sizeof(struct sadb_x_kmprivate) / IPSEC_PFKEYv2_ALIGN) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_x_kmprivate_parse: "
+ "size wrong ext_len=%d, key_ext_len=%d.\n",
+ pfkey_x_kmprivate->sadb_x_kmprivate_len,
+ (int)sizeof(struct sadb_x_kmprivate));
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_x_kmprivate->sadb_x_kmprivate_reserved) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_x_kmprivate_parse: "
+ "reserved=%d must be set to zero.\n",
+ pfkey_x_kmprivate->sadb_x_kmprivate_reserved);
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_x_kmprivate_parse: "
+ "Sorry, I can't parse exttype=%d yet.\n",
+ pfkey_ext->sadb_ext_type);
+ SENDERR(EINVAL); /* don't process these yet */
+
+errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_x_satype_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ int i;
+ struct sadb_x_satype *pfkey_x_satype = (struct sadb_x_satype *)pfkey_ext;
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
+ "pfkey_x_satype_parse: enter\n");
+ /* sanity checks... */
+ if(pfkey_x_satype->sadb_x_satype_len !=
+ sizeof(struct sadb_x_satype) / IPSEC_PFKEYv2_ALIGN) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_x_satype_parse: "
+ "size wrong ext_len=%d, key_ext_len=%d.\n",
+ pfkey_x_satype->sadb_x_satype_len,
+ (int)sizeof(struct sadb_x_satype));
+ SENDERR(EINVAL);
+ }
+
+ if(!pfkey_x_satype->sadb_x_satype_satype) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_x_satype_parse: "
+ "satype is zero, must be non-zero.\n");
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_x_satype->sadb_x_satype_satype > SADB_SATYPE_MAX) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_x_satype_parse: "
+ "satype %d > max %d, invalid.\n",
+ pfkey_x_satype->sadb_x_satype_satype, SADB_SATYPE_MAX);
+ SENDERR(EINVAL);
+ }
+
+ if(!(satype2proto(pfkey_x_satype->sadb_x_satype_satype))) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_x_satype_parse: "
+ "proto lookup from satype=%d failed.\n",
+ pfkey_x_satype->sadb_x_satype_satype);
+ SENDERR(EINVAL);
+ }
+
+ for(i = 0; i < 3; i++) {
+ if(pfkey_x_satype->sadb_x_satype_reserved[i]) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_x_satype_parse: "
+ "reserved[%d]=%d must be set to zero.\n",
+ i, pfkey_x_satype->sadb_x_satype_reserved[i]);
+ SENDERR(EINVAL);
+ }
+ }
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
+ "pfkey_x_satype_parse: "
+ "len=%u ext=%u(%s) satype=%u(%s) res=%u,%u,%u.\n",
+ pfkey_x_satype->sadb_x_satype_len,
+ pfkey_x_satype->sadb_x_satype_exttype,
+ pfkey_v2_sadb_ext_string(pfkey_x_satype->sadb_x_satype_exttype),
+ pfkey_x_satype->sadb_x_satype_satype,
+ satype2name(pfkey_x_satype->sadb_x_satype_satype),
+ pfkey_x_satype->sadb_x_satype_reserved[0],
+ pfkey_x_satype->sadb_x_satype_reserved[1],
+ pfkey_x_satype->sadb_x_satype_reserved[2]);
+errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_x_ext_debug_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ int i;
+ struct sadb_x_debug *pfkey_x_debug = (struct sadb_x_debug *)pfkey_ext;
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
+ "pfkey_x_debug_parse: enter\n");
+ /* sanity checks... */
+ if(pfkey_x_debug->sadb_x_debug_len !=
+ sizeof(struct sadb_x_debug) / IPSEC_PFKEYv2_ALIGN) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_x_debug_parse: "
+ "size wrong ext_len=%d, key_ext_len=%d.\n",
+ pfkey_x_debug->sadb_x_debug_len,
+ (int)sizeof(struct sadb_x_debug));
+ SENDERR(EINVAL);
+ }
+
+ for(i = 0; i < 4; i++) {
+ if(pfkey_x_debug->sadb_x_debug_reserved[i]) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_x_debug_parse: "
+ "reserved[%d]=%d must be set to zero.\n",
+ i, pfkey_x_debug->sadb_x_debug_reserved[i]);
+ SENDERR(EINVAL);
+ }
+ }
+
+errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_x_ext_protocol_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ struct sadb_protocol *p = (struct sadb_protocol *)pfkey_ext;
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_x_protocol_parse:\n");
+ /* sanity checks... */
+
+ if (p->sadb_protocol_len != sizeof(*p)/IPSEC_PFKEYv2_ALIGN) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_x_protocol_parse: size wrong ext_len=%d, key_ext_len=%d.\n",
+ p->sadb_protocol_len, (int)sizeof(*p));
+ SENDERR(EINVAL);
+ }
+
+ if (p->sadb_protocol_reserved2 != 0) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_protocol_parse: res=%d, must be zero.\n",
+ p->sadb_protocol_reserved2);
+ SENDERR(EINVAL);
+ }
+
+ errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_x_ext_nat_t_type_parse(struct sadb_ext *pfkey_ext)
+{
+ return 0;
+}
+
+DEBUG_NO_STATIC int
+pfkey_x_ext_nat_t_port_parse(struct sadb_ext *pfkey_ext)
+{
+ return 0;
+}
+
+#define DEFINEPARSER(NAME) static struct pf_key_ext_parsers_def NAME##_def={NAME, #NAME};
+
+DEFINEPARSER(pfkey_sa_parse);
+DEFINEPARSER(pfkey_lifetime_parse);
+DEFINEPARSER(pfkey_address_parse);
+DEFINEPARSER(pfkey_key_parse);
+DEFINEPARSER(pfkey_ident_parse);
+DEFINEPARSER(pfkey_sens_parse);
+DEFINEPARSER(pfkey_prop_parse);
+DEFINEPARSER(pfkey_supported_parse);
+DEFINEPARSER(pfkey_spirange_parse);
+DEFINEPARSER(pfkey_x_kmprivate_parse);
+DEFINEPARSER(pfkey_x_satype_parse);
+DEFINEPARSER(pfkey_x_ext_debug_parse);
+DEFINEPARSER(pfkey_x_ext_protocol_parse);
+DEFINEPARSER(pfkey_x_ext_nat_t_type_parse);
+DEFINEPARSER(pfkey_x_ext_nat_t_port_parse);
+
+struct pf_key_ext_parsers_def *ext_default_parsers[]=
+{
+ NULL, /* pfkey_msg_parse, */
+ &pfkey_sa_parse_def,
+ &pfkey_lifetime_parse_def,
+ &pfkey_lifetime_parse_def,
+ &pfkey_lifetime_parse_def,
+ &pfkey_address_parse_def,
+ &pfkey_address_parse_def,
+ &pfkey_address_parse_def,
+ &pfkey_key_parse_def,
+ &pfkey_key_parse_def,
+ &pfkey_ident_parse_def,
+ &pfkey_ident_parse_def,
+ &pfkey_sens_parse_def,
+ &pfkey_prop_parse_def,
+ &pfkey_supported_parse_def,
+ &pfkey_supported_parse_def,
+ &pfkey_spirange_parse_def,
+ &pfkey_x_kmprivate_parse_def,
+ &pfkey_x_satype_parse_def,
+ &pfkey_sa_parse_def,
+ &pfkey_address_parse_def,
+ &pfkey_address_parse_def,
+ &pfkey_address_parse_def,
+ &pfkey_address_parse_def,
+ &pfkey_address_parse_def,
+ &pfkey_x_ext_debug_parse_def,
+ &pfkey_x_ext_protocol_parse_def ,
+ &pfkey_x_ext_nat_t_type_parse_def,
+ &pfkey_x_ext_nat_t_port_parse_def,
+ &pfkey_x_ext_nat_t_port_parse_def,
+ &pfkey_address_parse_def
+};
+
+int
+pfkey_msg_parse(struct sadb_msg *pfkey_msg,
+ struct pf_key_ext_parsers_def *ext_parsers[],
+ struct sadb_ext *extensions[],
+ int dir)
+{
+ int error = 0;
+ int remain;
+ struct sadb_ext *pfkey_ext;
+ int extensions_seen = 0;
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
+ "pfkey_msg_parse: "
+ "parsing message ver=%d, type=%d(%s), errno=%d, satype=%d(%s), len=%d, res=%d, seq=%d, pid=%d.\n",
+ pfkey_msg->sadb_msg_version,
+ pfkey_msg->sadb_msg_type,
+ pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type),
+ pfkey_msg->sadb_msg_errno,
+ pfkey_msg->sadb_msg_satype,
+ satype2name(pfkey_msg->sadb_msg_satype),
+ pfkey_msg->sadb_msg_len,
+ pfkey_msg->sadb_msg_reserved,
+ pfkey_msg->sadb_msg_seq,
+ pfkey_msg->sadb_msg_pid);
+
+ if(ext_parsers == NULL) ext_parsers = ext_default_parsers;
+
+ pfkey_extensions_init(extensions);
+
+ remain = pfkey_msg->sadb_msg_len;
+ remain -= sizeof(struct sadb_msg) / IPSEC_PFKEYv2_ALIGN;
+
+ pfkey_ext = (struct sadb_ext*)((char*)pfkey_msg +
+ sizeof(struct sadb_msg));
+
+ extensions[0] = (struct sadb_ext *) pfkey_msg;
+
+
+ if(pfkey_msg->sadb_msg_version != PF_KEY_V2) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "not PF_KEY_V2 msg, found %d, should be %d.\n",
+ pfkey_msg->sadb_msg_version,
+ PF_KEY_V2);
+ SENDERR(EINVAL);
+ }
+
+ if(!pfkey_msg->sadb_msg_type) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "msg type not set, must be non-zero..\n");
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_msg->sadb_msg_type > SADB_MAX) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "msg type=%d > max=%d.\n",
+ pfkey_msg->sadb_msg_type,
+ SADB_MAX);
+ SENDERR(EINVAL);
+ }
+
+ switch(pfkey_msg->sadb_msg_type) {
+ case SADB_GETSPI:
+ case SADB_UPDATE:
+ case SADB_ADD:
+ case SADB_DELETE:
+ case SADB_GET:
+ case SADB_X_GRPSA:
+ case SADB_X_ADDFLOW:
+ if(!satype2proto(pfkey_msg->sadb_msg_satype)) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "satype %d conversion to proto failed for msg_type %d (%s).\n",
+ pfkey_msg->sadb_msg_satype,
+ pfkey_msg->sadb_msg_type,
+ pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type));
+ SENDERR(EINVAL);
+ } else {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "satype %d(%s) conversion to proto gives %d for msg_type %d(%s).\n",
+ pfkey_msg->sadb_msg_satype,
+ satype2name(pfkey_msg->sadb_msg_satype),
+ satype2proto(pfkey_msg->sadb_msg_satype),
+ pfkey_msg->sadb_msg_type,
+ pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type));
+ }
+ case SADB_ACQUIRE:
+ case SADB_REGISTER:
+ case SADB_EXPIRE:
+ if(!pfkey_msg->sadb_msg_satype) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "satype is zero, must be non-zero for msg_type %d(%s).\n",
+ pfkey_msg->sadb_msg_type,
+ pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type));
+ SENDERR(EINVAL);
+ }
+ default:
+ break;
+ }
+
+ /* errno must not be set in downward messages */
+ /* this is not entirely true... a response to an ACQUIRE could return an error */
+ if((dir == EXT_BITS_IN) && (pfkey_msg->sadb_msg_type != SADB_ACQUIRE) && pfkey_msg->sadb_msg_errno) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "errno set to %d.\n",
+ pfkey_msg->sadb_msg_errno);
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
+ "pfkey_msg_parse: "
+ "remain=%d, ext_type=%d(%s), ext_len=%d.\n",
+ remain,
+ pfkey_ext->sadb_ext_type,
+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type),
+ pfkey_ext->sadb_ext_len);
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
+ "pfkey_msg_parse: "
+ "extensions permitted=%08x, required=%08x.\n",
+ extensions_bitmaps[dir][EXT_BITS_PERM][pfkey_msg->sadb_msg_type],
+ extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]);
+
+ extensions_seen = 1;
+
+ while( (remain * IPSEC_PFKEYv2_ALIGN) >= sizeof(struct sadb_ext) ) {
+ /* Is there enough message left to support another extension header? */
+ if(remain < pfkey_ext->sadb_ext_len) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "remain %d less than ext len %d.\n",
+ remain, pfkey_ext->sadb_ext_len);
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
+ "pfkey_msg_parse: "
+ "parsing ext type=%d(%s) remain=%d.\n",
+ pfkey_ext->sadb_ext_type,
+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type),
+ remain);
+
+ /* Is the extension header type valid? */
+ if((pfkey_ext->sadb_ext_type > SADB_EXT_MAX) || (!pfkey_ext->sadb_ext_type)) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "ext type %d(%s) invalid, SADB_EXT_MAX=%d.\n",
+ pfkey_ext->sadb_ext_type,
+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type),
+ SADB_EXT_MAX);
+ SENDERR(EINVAL);
+ }
+
+ /* Have we already seen this type of extension? */
+ if((extensions_seen & ( 1 << pfkey_ext->sadb_ext_type )) != 0)
+ {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "ext type %d(%s) already seen.\n",
+ pfkey_ext->sadb_ext_type,
+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type));
+ SENDERR(EINVAL);
+ }
+
+ /* Do I even know about this type of extension? */
+ if(ext_parsers[pfkey_ext->sadb_ext_type]==NULL) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "ext type %d(%s) unknown, ignoring.\n",
+ pfkey_ext->sadb_ext_type,
+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type));
+ goto next_ext;
+ }
+
+ /* Is this type of extension permitted for this type of message? */
+ if(!(extensions_bitmaps[dir][EXT_BITS_PERM][pfkey_msg->sadb_msg_type] &
+ 1<<pfkey_ext->sadb_ext_type)) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "ext type %d(%s) not permitted, exts_perm_in=%08x, 1<<type=%08x\n",
+ pfkey_ext->sadb_ext_type,
+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type),
+ extensions_bitmaps[dir][EXT_BITS_PERM][pfkey_msg->sadb_msg_type],
+ 1<<pfkey_ext->sadb_ext_type);
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
+ "pfkey_msg_parse: "
+ "remain=%d ext_type=%d(%s) ext_len=%d parsing ext 0p%p with parser %s.\n",
+ remain,
+ pfkey_ext->sadb_ext_type,
+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type),
+ pfkey_ext->sadb_ext_len,
+ pfkey_ext,
+ ext_parsers[pfkey_ext->sadb_ext_type]->parser_name);
+
+ /* Parse the extension */
+ if((error =
+ (*ext_parsers[pfkey_ext->sadb_ext_type]->parser)(pfkey_ext))) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "extension parsing for type %d(%s) failed with error %d.\n",
+ pfkey_ext->sadb_ext_type,
+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type),
+ error);
+ SENDERR(-error);
+ }
+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
+ "pfkey_msg_parse: "
+ "Extension %d(%s) parsed.\n",
+ pfkey_ext->sadb_ext_type,
+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type));
+
+ /* Mark that we have seen this extension and remember the header location */
+ extensions_seen |= ( 1 << pfkey_ext->sadb_ext_type );
+ extensions[pfkey_ext->sadb_ext_type] = pfkey_ext;
+
+ next_ext:
+ /* Calculate how much message remains */
+ remain -= pfkey_ext->sadb_ext_len;
+
+ if(!remain) {
+ break;
+ }
+ /* Find the next extension header */
+ pfkey_ext = (struct sadb_ext*)((char*)pfkey_ext +
+ pfkey_ext->sadb_ext_len * IPSEC_PFKEYv2_ALIGN);
+ }
+
+ if(remain) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "unexpected remainder of %d.\n",
+ remain);
+ /* why is there still something remaining? */
+ SENDERR(EINVAL);
+ }
+
+ /* check required extensions */
+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
+ "pfkey_msg_parse: "
+ "extensions permitted=%08x, seen=%08x, required=%08x.\n",
+ extensions_bitmaps[dir][EXT_BITS_PERM][pfkey_msg->sadb_msg_type],
+ extensions_seen,
+ extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]);
+
+ /* don't check further if it is an error return message since it
+ may not have a body */
+ if(pfkey_msg->sadb_msg_errno) {
+ SENDERR(-error);
+ }
+
+ if((extensions_seen &
+ extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]) !=
+ extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "required extensions missing:%08x.\n",
+ extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type] -
+ (extensions_seen &
+ extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]));
+ SENDERR(EINVAL);
+ }
+
+ if((dir == EXT_BITS_IN) && (pfkey_msg->sadb_msg_type == SADB_X_DELFLOW)
+ && ((extensions_seen & SADB_X_EXT_ADDRESS_DELFLOW)
+ != SADB_X_EXT_ADDRESS_DELFLOW)
+ && (((extensions_seen & (1<<SADB_EXT_SA)) != (1<<SADB_EXT_SA))
+ || ((((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_flags
+ & SADB_X_SAFLAGS_CLEARFLOW)
+ != SADB_X_SAFLAGS_CLEARFLOW))) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "required SADB_X_DELFLOW extensions missing: either %08x must be present or %08x must be present with SADB_X_SAFLAGS_CLEARFLOW set.\n",
+ SADB_X_EXT_ADDRESS_DELFLOW
+ - (extensions_seen & SADB_X_EXT_ADDRESS_DELFLOW),
+ (1<<SADB_EXT_SA) - (extensions_seen & (1<<SADB_EXT_SA)));
+ SENDERR(EINVAL);
+ }
+
+ switch(pfkey_msg->sadb_msg_type) {
+ case SADB_ADD:
+ case SADB_UPDATE:
+ /* check maturity */
+ if(((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state !=
+ SADB_SASTATE_MATURE) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "state=%d for add or update should be MATURE=%d.\n",
+ ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state,
+ SADB_SASTATE_MATURE);
+ SENDERR(EINVAL);
+ }
+
+ /* check AH and ESP */
+ switch(((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype) {
+ case SADB_SATYPE_AH:
+ if(!(((struct sadb_sa*)extensions[SADB_EXT_SA]) &&
+ ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_auth !=
+ SADB_AALG_NONE)) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "auth alg is zero, must be non-zero for AH SAs.\n");
+ SENDERR(EINVAL);
+ }
+ if(((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_encrypt !=
+ SADB_EALG_NONE) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "AH handed encalg=%d, must be zero.\n",
+ ((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_encrypt);
+ SENDERR(EINVAL);
+ }
+ break;
+ case SADB_SATYPE_ESP:
+ if(!(((struct sadb_sa*)extensions[SADB_EXT_SA]) &&
+ ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt !=
+ SADB_EALG_NONE)) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "encrypt alg=%d is zero, must be non-zero for ESP=%d SAs.\n",
+ ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype);
+ SENDERR(EINVAL);
+ }
+ if((((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_encrypt ==
+ SADB_EALG_NULL) &&
+ (((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_auth ==
+ SADB_AALG_NONE) ) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "ESP handed encNULL+authNONE, illegal combination.\n");
+ SENDERR(EINVAL);
+ }
+ break;
+ case SADB_X_SATYPE_COMP:
+ if(!(((struct sadb_sa*)extensions[SADB_EXT_SA]) &&
+ ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt !=
+ SADB_EALG_NONE)) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "encrypt alg=%d is zero, must be non-zero for COMP=%d SAs.\n",
+ ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype);
+ SENDERR(EINVAL);
+ }
+ if(((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_auth !=
+ SADB_AALG_NONE) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "COMP handed auth=%d, must be zero.\n",
+ ((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_auth);
+ SENDERR(EINVAL);
+ }
+ break;
+ default:
+ break;
+ }
+ if(ntohl(((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_spi) <= 255) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "spi=%08x must be > 255.\n",
+ ntohl(((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_spi));
+ SENDERR(EINVAL);
+ }
+ default:
+ break;
+ }
+errlab:
+
+ return error;
+}
+
+/*
+ * $Log: pfkey_v2_parse.c,v $
+ * Revision 1.4 2004/06/13 20:35:07 as
+ * removed references to ipsec_netlink.h
+ *
+ * Revision 1.3 2004/03/30 10:00:17 as
+ * 64 bit issues
+ *
+ * Revision 1.2 2004/03/22 21:53:18 as
+ * merged alg-0.8.1 branch with HEAD
+ *
+ * Revision 1.1.2.1 2004/03/15 22:30:06 as
+ * nat-0.6c patch merged
+ *
+ * Revision 1.1 2004/03/15 20:35:26 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.53 2003/01/30 02:32:09 rgb
+ *
+ * Rename SAref table macro names for clarity.
+ * Convert IPsecSAref_t from signed to unsigned to fix apparent SAref exhaustion bug.
+ *
+ * Revision 1.52 2002/12/30 06:53:07 mcr
+ * deal with short SA structures... #if 0 out for now. Probably
+ * not quite the right way.
+ *
+ * Revision 1.51 2002/12/13 18:16:02 mcr
+ * restored sa_ref code
+ *
+ * Revision 1.50 2002/12/13 18:06:52 mcr
+ * temporarily removed sadb_x_sa_ref reference for 2.xx
+ *
+ * Revision 1.49 2002/10/05 05:02:58 dhr
+ *
+ * C labels go on statements
+ *
+ * Revision 1.48 2002/09/20 15:40:45 rgb
+ * Added sadb_x_sa_ref to struct sadb_sa.
+ *
+ * Revision 1.47 2002/09/20 05:01:31 rgb
+ * Fixed usage of pfkey_lib_debug.
+ * Format for function declaration style consistency.
+ * Added text labels to elucidate numeric values presented.
+ * Re-organised debug output to reduce noise in output.
+ *
+ * Revision 1.46 2002/07/24 18:44:54 rgb
+ * Type fiddling to tame ia64 compiler.
+ *
+ * Revision 1.45 2002/05/23 07:14:11 rgb
+ * Cleaned up %p variants to 0p%p for test suite cleanup.
+ *
+ * Revision 1.44 2002/04/24 07:55:32 mcr
+ * #include patches and Makefiles for post-reorg compilation.
+ *
+ * Revision 1.43 2002/04/24 07:36:40 mcr
+ * Moved from ./lib/pfkey_v2_parse.c,v
+ *
+ * Revision 1.42 2002/01/29 22:25:36 rgb
+ * Re-add ipsec_kversion.h to keep MALLOC happy.
+ *
+ * Revision 1.41 2002/01/29 01:59:10 mcr
+ * removal of kversions.h - sources that needed it now use ipsec_param.h.
+ * updating of IPv6 structures to match latest in6.h version.
+ * removed dead code from freeswan.h that also duplicated kversions.h
+ * code.
+ *
+ * Revision 1.40 2002/01/20 20:34:50 mcr
+ * added pfkey_v2_sadb_type_string to decode sadb_type to string.
+ *
+ * Revision 1.39 2001/11/27 05:29:22 mcr
+ * pfkey parses are now maintained by a structure
+ * that includes their name for debug purposes.
+ * DEBUGGING() macro changed so that it takes a debug
+ * level so that pf_key() can use this to decode the
+ * structures without innundanting humans.
+ * Also uses pfkey_v2_sadb_ext_string() in messages.
+ *
+ * Revision 1.38 2001/11/06 19:47:47 rgb
+ * Added packet parameter to lifetime and comb structures.
+ *
+ * Revision 1.37 2001/10/18 04:45:24 rgb
+ * 2.4.9 kernel deprecates linux/malloc.h in favour of linux/slab.h,
+ * lib/freeswan.h version macros moved to lib/kversions.h.
+ * Other compiler directive cleanups.
+ *
+ * Revision 1.36 2001/06/14 19:35:16 rgb
+ * Update copyright date.
+ *
+ * Revision 1.35 2001/05/03 19:44:51 rgb
+ * Standardise on SENDERR() macro.
+ *
+ * Revision 1.34 2001/03/16 07:41:51 rgb
+ * Put freeswan.h include before pluto includes.
+ *
+ * Revision 1.33 2001/02/27 07:13:51 rgb
+ * Added satype2name() function.
+ * Added text to default satype_tbl entry.
+ * Added satype2name() conversions for most satype debug output.
+ *
+ * Revision 1.32 2001/02/26 20:01:09 rgb
+ * Added internal IP protocol 61 for magic SAs.
+ * Ditch unused sadb_satype2proto[], replaced by satype2proto().
+ * Re-formatted debug output (split lines, consistent spacing).
+ * Removed acquire, register and expire requirements for a known satype.
+ * Changed message type checking to a switch structure.
+ * Verify expected NULL auth for IPCOMP.
+ * Enforced spi > 0x100 requirement, now that pass uses a magic SA for
+ * appropriate message types.
+ *
+ * Revision 1.31 2000/12/01 07:09:00 rgb
+ * Added ipcomp sanity check to require encalgo is set.
+ *
+ * Revision 1.30 2000/11/17 18:10:30 rgb
+ * Fixed bugs mostly relating to spirange, to treat all spi variables as
+ * network byte order since this is the way PF_KEYv2 stored spis.
+ *
+ * Revision 1.29 2000/10/12 00:02:39 rgb
+ * Removed 'format, ##' nonsense from debug macros for RH7.0.
+ *
+ * Revision 1.28 2000/09/20 16:23:04 rgb
+ * Remove over-paranoid extension check in the presence of sadb_msg_errno.
+ *
+ * Revision 1.27 2000/09/20 04:04:21 rgb
+ * Changed static functions to DEBUG_NO_STATIC to reveal function names in
+ * oopsen.
+ *
+ * Revision 1.26 2000/09/15 11:37:02 rgb
+ * Merge in heavily modified Svenning Soerensen's <svenning@post5.tele.dk>
+ * IPCOMP zlib deflate code.
+ *
+ * Revision 1.25 2000/09/12 22:35:37 rgb
+ * Restructured to remove unused extensions from CLEARFLOW messages.
+ *
+ * Revision 1.24 2000/09/12 18:59:54 rgb
+ * Added Gerhard's IPv6 support to pfkey parts of libfreeswan.
+ *
+ * Revision 1.23 2000/09/12 03:27:00 rgb
+ * Moved DEBUGGING definition to compile kernel with debug off.
+ *
+ * Revision 1.22 2000/09/09 06:39:27 rgb
+ * Restrict pfkey errno check to downward messages only.
+ *
+ * Revision 1.21 2000/09/08 19:22:34 rgb
+ * Enabled pfkey_sens_parse().
+ * Added check for errno on downward acquire messages only.
+ *
+ * Revision 1.20 2000/09/01 18:48:23 rgb
+ * Fixed reserved check bug and added debug output in
+ * pfkey_supported_parse().
+ * Fixed debug output label bug in pfkey_ident_parse().
+ *
+ * Revision 1.19 2000/08/27 01:55:26 rgb
+ * Define OCTETBITS and PFKEYBITS to avoid using 'magic' numbers in code.
+ *
+ * Revision 1.18 2000/08/24 17:00:36 rgb
+ * Ignore unknown extensions instead of failing.
+ *
+ * Revision 1.17 2000/06/02 22:54:14 rgb
+ * Added Gerhard Gessler's struct sockaddr_storage mods for IPv6 support.
+ *
+ * Revision 1.16 2000/05/10 19:25:11 rgb
+ * Fleshed out proposal and supported extensions.
+ *
+ * Revision 1.15 2000/01/24 21:15:31 rgb
+ * Added disabled pluto pfkey lib debug flag.
+ * Added algo debugging reporting.
+ *
+ * Revision 1.14 2000/01/22 23:24:29 rgb
+ * Added new functions proto2satype() and satype2proto() and lookup
+ * table satype_tbl. Also added proto2name() since it was easy.
+ *
+ * Revision 1.13 2000/01/21 09:43:59 rgb
+ * Cast ntohl(spi) as (unsigned long int) to shut up compiler.
+ *
+ * Revision 1.12 2000/01/21 06:28:19 rgb
+ * Added address cases for eroute flows.
+ * Indented compiler directives for readability.
+ * Added klipsdebug switching capability.
+ *
+ * Revision 1.11 1999/12/29 21:14:59 rgb
+ * Fixed debug text cut and paste typo.
+ *
+ * Revision 1.10 1999/12/10 17:45:24 rgb
+ * Added address debugging.
+ *
+ * Revision 1.9 1999/12/09 23:11:42 rgb
+ * Ditched <string.h> include since we no longer use memset().
+ * Use new pfkey_extensions_init() instead of memset().
+ * Added check for SATYPE in pfkey_msg_build().
+ * Tidy up comments and debugging comments.
+ *
+ * Revision 1.8 1999/12/07 19:55:26 rgb
+ * Removed unused first argument from extension parsers.
+ * Removed static pluto debug flag.
+ * Moved message type and state checking to pfkey_msg_parse().
+ * Changed print[fk] type from lx to x to quiet compiler.
+ * Removed redundant remain check.
+ * Changed __u* types to uint* to avoid use of asm/types.h and
+ * sys/types.h in userspace code.
+ *
+ * Revision 1.7 1999/12/01 22:20:51 rgb
+ * Moved pfkey_lib_debug variable into the library.
+ * Added pfkey version check into header parsing.
+ * Added check for SATYPE only for those extensions that require a
+ * non-zero value.
+ *
+ * Revision 1.6 1999/11/27 11:58:05 rgb
+ * Added ipv6 headers.
+ * Moved sadb_satype2proto protocol lookup table from
+ * klips/net/ipsec/pfkey_v2_parser.c.
+ * Enable lifetime_current checking.
+ * Debugging error messages added.
+ * Add argument to pfkey_msg_parse() for direction.
+ * Consolidated the 4 1-d extension bitmap arrays into one 4-d array.
+ * Add CVS log entry to bottom of file.
+ * Moved auth and enc alg check to pfkey_msg_parse().
+ * Enable accidentally disabled spirange parsing.
+ * Moved protocol/algorithm checks from klips/net/ipsec/pfkey_v2_parser.c
+ *
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ *
+ */
diff --git a/src/libfreeswan/pfkeyv2.h b/src/libfreeswan/pfkeyv2.h
new file mode 100644
index 000000000..07126f1b8
--- /dev/null
+++ b/src/libfreeswan/pfkeyv2.h
@@ -0,0 +1,375 @@
+/*
+ * RCSID $Id: pfkeyv2.h,v 1.5 2004/10/04 22:43:56 as Exp $
+ */
+
+/*
+RFC 2367 PF_KEY Key Management API July 1998
+
+
+Appendix D: Sample Header File
+
+This file defines structures and symbols for the PF_KEY Version 2
+key management interface. It was written at the U.S. Naval Research
+Laboratory. This file is in the public domain. The authors ask that
+you leave this credit intact on any copies of this file.
+*/
+#ifndef __PFKEY_V2_H
+#define __PFKEY_V2_H 1
+
+#define PF_KEY_V2 2
+#define PFKEYV2_REVISION 199806L
+
+#define SADB_RESERVED 0
+#define SADB_GETSPI 1
+#define SADB_UPDATE 2
+#define SADB_ADD 3
+#define SADB_DELETE 4
+#define SADB_GET 5
+#define SADB_ACQUIRE 6
+#define SADB_REGISTER 7
+#define SADB_EXPIRE 8
+#define SADB_FLUSH 9
+#define SADB_DUMP 10
+#define SADB_X_PROMISC 11
+#define SADB_X_PCHANGE 12
+#define SADB_X_GRPSA 13
+#define SADB_X_ADDFLOW 14
+#define SADB_X_DELFLOW 15
+#define SADB_X_DEBUG 16
+#define SADB_X_NAT_T_NEW_MAPPING 17
+#define SADB_MAX 17
+
+struct sadb_msg {
+ uint8_t sadb_msg_version;
+ uint8_t sadb_msg_type;
+ uint8_t sadb_msg_errno;
+ uint8_t sadb_msg_satype;
+ uint16_t sadb_msg_len;
+ uint16_t sadb_msg_reserved;
+ uint32_t sadb_msg_seq;
+ uint32_t sadb_msg_pid;
+};
+
+struct sadb_ext {
+ uint16_t sadb_ext_len;
+ uint16_t sadb_ext_type;
+};
+
+struct sadb_sa {
+ uint16_t sadb_sa_len;
+ uint16_t sadb_sa_exttype;
+ uint32_t sadb_sa_spi;
+ uint8_t sadb_sa_replay;
+ uint8_t sadb_sa_state;
+ uint8_t sadb_sa_auth;
+ uint8_t sadb_sa_encrypt;
+ uint32_t sadb_sa_flags;
+ uint32_t /*IPsecSAref_t*/ sadb_x_sa_ref; /* 32 bits */
+ uint8_t sadb_x_reserved[4];
+};
+
+struct sadb_sa_v1 {
+ uint16_t sadb_sa_len;
+ uint16_t sadb_sa_exttype;
+ uint32_t sadb_sa_spi;
+ uint8_t sadb_sa_replay;
+ uint8_t sadb_sa_state;
+ uint8_t sadb_sa_auth;
+ uint8_t sadb_sa_encrypt;
+ uint32_t sadb_sa_flags;
+};
+
+struct sadb_lifetime {
+ uint16_t sadb_lifetime_len;
+ uint16_t sadb_lifetime_exttype;
+ uint32_t sadb_lifetime_allocations;
+ uint64_t sadb_lifetime_bytes;
+ uint64_t sadb_lifetime_addtime;
+ uint64_t sadb_lifetime_usetime;
+ uint32_t sadb_x_lifetime_packets;
+ uint32_t sadb_x_lifetime_reserved;
+};
+
+struct sadb_address {
+ uint16_t sadb_address_len;
+ uint16_t sadb_address_exttype;
+ uint8_t sadb_address_proto;
+ uint8_t sadb_address_prefixlen;
+ uint16_t sadb_address_reserved;
+};
+
+struct sadb_key {
+ uint16_t sadb_key_len;
+ uint16_t sadb_key_exttype;
+ uint16_t sadb_key_bits;
+ uint16_t sadb_key_reserved;
+};
+
+struct sadb_ident {
+ uint16_t sadb_ident_len;
+ uint16_t sadb_ident_exttype;
+ uint16_t sadb_ident_type;
+ uint16_t sadb_ident_reserved;
+ uint64_t sadb_ident_id;
+};
+
+struct sadb_sens {
+ uint16_t sadb_sens_len;
+ uint16_t sadb_sens_exttype;
+ uint32_t sadb_sens_dpd;
+ uint8_t sadb_sens_sens_level;
+ uint8_t sadb_sens_sens_len;
+ uint8_t sadb_sens_integ_level;
+ uint8_t sadb_sens_integ_len;
+ uint32_t sadb_sens_reserved;
+};
+
+struct sadb_prop {
+ uint16_t sadb_prop_len;
+ uint16_t sadb_prop_exttype;
+ uint8_t sadb_prop_replay;
+ uint8_t sadb_prop_reserved[3];
+};
+
+struct sadb_comb {
+ uint8_t sadb_comb_auth;
+ uint8_t sadb_comb_encrypt;
+ uint16_t sadb_comb_flags;
+ uint16_t sadb_comb_auth_minbits;
+ uint16_t sadb_comb_auth_maxbits;
+ uint16_t sadb_comb_encrypt_minbits;
+ uint16_t sadb_comb_encrypt_maxbits;
+ uint32_t sadb_comb_reserved;
+ uint32_t sadb_comb_soft_allocations;
+ uint32_t sadb_comb_hard_allocations;
+ uint64_t sadb_comb_soft_bytes;
+ uint64_t sadb_comb_hard_bytes;
+ uint64_t sadb_comb_soft_addtime;
+ uint64_t sadb_comb_hard_addtime;
+ uint64_t sadb_comb_soft_usetime;
+ uint64_t sadb_comb_hard_usetime;
+ uint32_t sadb_x_comb_soft_packets;
+ uint32_t sadb_x_comb_hard_packets;
+};
+
+struct sadb_supported {
+ uint16_t sadb_supported_len;
+ uint16_t sadb_supported_exttype;
+ uint32_t sadb_supported_reserved;
+};
+
+struct sadb_alg {
+ uint8_t sadb_alg_id;
+ uint8_t sadb_alg_ivlen;
+ uint16_t sadb_alg_minbits;
+ uint16_t sadb_alg_maxbits;
+ uint16_t sadb_alg_reserved;
+};
+
+struct sadb_spirange {
+ uint16_t sadb_spirange_len;
+ uint16_t sadb_spirange_exttype;
+ uint32_t sadb_spirange_min;
+ uint32_t sadb_spirange_max;
+ uint32_t sadb_spirange_reserved;
+};
+
+struct sadb_x_kmprivate {
+ uint16_t sadb_x_kmprivate_len;
+ uint16_t sadb_x_kmprivate_exttype;
+ uint32_t sadb_x_kmprivate_reserved;
+};
+
+struct sadb_x_satype {
+ uint16_t sadb_x_satype_len;
+ uint16_t sadb_x_satype_exttype;
+ uint8_t sadb_x_satype_satype;
+ uint8_t sadb_x_satype_reserved[3];
+};
+
+struct sadb_x_policy {
+ uint16_t sadb_x_policy_len;
+ uint16_t sadb_x_policy_exttype;
+ uint16_t sadb_x_policy_type;
+ uint8_t sadb_x_policy_dir;
+ uint8_t sadb_x_policy_reserved;
+ uint32_t sadb_x_policy_id;
+ uint32_t sadb_x_policy_reserved2;
+};
+
+struct sadb_x_debug {
+ uint16_t sadb_x_debug_len;
+ uint16_t sadb_x_debug_exttype;
+ uint32_t sadb_x_debug_tunnel;
+ uint32_t sadb_x_debug_netlink;
+ uint32_t sadb_x_debug_xform;
+ uint32_t sadb_x_debug_eroute;
+ uint32_t sadb_x_debug_spi;
+ uint32_t sadb_x_debug_radij;
+ uint32_t sadb_x_debug_esp;
+ uint32_t sadb_x_debug_ah;
+ uint32_t sadb_x_debug_rcv;
+ uint32_t sadb_x_debug_pfkey;
+ uint32_t sadb_x_debug_ipcomp;
+ uint32_t sadb_x_debug_verbose;
+ uint8_t sadb_x_debug_reserved[4];
+};
+
+struct sadb_x_nat_t_type {
+ uint16_t sadb_x_nat_t_type_len;
+ uint16_t sadb_x_nat_t_type_exttype;
+ uint8_t sadb_x_nat_t_type_type;
+ uint8_t sadb_x_nat_t_type_reserved[3];
+};
+struct sadb_x_nat_t_port {
+ uint16_t sadb_x_nat_t_port_len;
+ uint16_t sadb_x_nat_t_port_exttype;
+ uint16_t sadb_x_nat_t_port_port;
+ uint16_t sadb_x_nat_t_port_reserved;
+};
+
+/*
+ * A protocol structure for passing through the transport level
+ * protocol. It contains more fields than are actually used/needed
+ * but it is this way to be compatible with the structure used in
+ * OpenBSD (http://www.openbsd.org/cgi-bin/cvsweb/src/sys/net/pfkeyv2.h)
+ */
+struct sadb_protocol {
+ uint16_t sadb_protocol_len;
+ uint16_t sadb_protocol_exttype;
+ uint8_t sadb_protocol_proto;
+ uint8_t sadb_protocol_direction;
+ uint8_t sadb_protocol_flags;
+ uint8_t sadb_protocol_reserved2;
+};
+
+#define SADB_EXT_RESERVED 0
+#define SADB_EXT_SA 1
+#define SADB_EXT_LIFETIME_CURRENT 2
+#define SADB_EXT_LIFETIME_HARD 3
+#define SADB_EXT_LIFETIME_SOFT 4
+#define SADB_EXT_ADDRESS_SRC 5
+#define SADB_EXT_ADDRESS_DST 6
+#define SADB_EXT_ADDRESS_PROXY 7
+#define SADB_EXT_KEY_AUTH 8
+#define SADB_EXT_KEY_ENCRYPT 9
+#define SADB_EXT_IDENTITY_SRC 10
+#define SADB_EXT_IDENTITY_DST 11
+#define SADB_EXT_SENSITIVITY 12
+#define SADB_EXT_PROPOSAL 13
+#define SADB_EXT_SUPPORTED_AUTH 14
+#define SADB_EXT_SUPPORTED_ENCRYPT 15
+#define SADB_EXT_SPIRANGE 16
+#define SADB_X_EXT_KMPRIVATE 17
+#define SADB_X_EXT_SATYPE2 18
+#ifdef KERNEL26_HAS_KAME_DUPLICATES
+#define SADB_X_EXT_POLICY 18
+#endif
+#define SADB_X_EXT_SA2 19
+#define SADB_X_EXT_ADDRESS_DST2 20
+#define SADB_X_EXT_ADDRESS_SRC_FLOW 21
+#define SADB_X_EXT_ADDRESS_DST_FLOW 22
+#define SADB_X_EXT_ADDRESS_SRC_MASK 23
+#define SADB_X_EXT_ADDRESS_DST_MASK 24
+#define SADB_X_EXT_DEBUG 25
+#define SADB_X_EXT_PROTOCOL 26
+#define SADB_X_EXT_NAT_T_TYPE 27
+#define SADB_X_EXT_NAT_T_SPORT 28
+#define SADB_X_EXT_NAT_T_DPORT 29
+#define SADB_X_EXT_NAT_T_OA 30
+#define SADB_EXT_MAX 30
+
+/* SADB_X_DELFLOW required over and above SADB_X_SAFLAGS_CLEARFLOW */
+#define SADB_X_EXT_ADDRESS_DELFLOW \
+ ( (1<<SADB_X_EXT_ADDRESS_SRC_FLOW) \
+ | (1<<SADB_X_EXT_ADDRESS_DST_FLOW) \
+ | (1<<SADB_X_EXT_ADDRESS_SRC_MASK) \
+ | (1<<SADB_X_EXT_ADDRESS_DST_MASK))
+
+#define SADB_SATYPE_UNSPEC 0
+#define SADB_SATYPE_AH 2
+#define SADB_SATYPE_ESP 3
+#define SADB_SATYPE_RSVP 5
+#define SADB_SATYPE_OSPFV2 6
+#define SADB_SATYPE_RIPV2 7
+#define SADB_SATYPE_MIP 8
+#define SADB_X_SATYPE_IPIP 9
+#ifdef KERNEL26_HAS_KAME_DUPLICATES
+#define SADB_X_SATYPE_IPCOMP 9 /* ICK! */
+#endif
+#define SADB_X_SATYPE_COMP 10
+#define SADB_X_SATYPE_INT 11
+#define SADB_SATYPE_MAX 11
+
+#define SADB_SASTATE_LARVAL 0
+#define SADB_SASTATE_MATURE 1
+#define SADB_SASTATE_DYING 2
+#define SADB_SASTATE_DEAD 3
+#define SADB_SASTATE_MAX 3
+
+#define SADB_SAFLAGS_PFS 1
+#define SADB_X_SAFLAGS_REPLACEFLOW 2
+#define SADB_X_SAFLAGS_CLEARFLOW 4
+#define SADB_X_SAFLAGS_INFLOW 8
+
+/* not obvious, but these are the same values as used in isakmp,
+ * and in freeswan/ipsec_policy.h. If you need to add any, they
+ * should be added as according to
+ * http://www.iana.org/assignments/isakmp-registry
+ *
+ * and if not, then please try to use a private-use value, and
+ * consider asking IANA to assign a value.
+ */
+#define SADB_AALG_NONE 0
+#define SADB_AALG_MD5_HMAC 2
+#define SADB_AALG_SHA1_HMAC 3
+#define SADB_AALG_DES_MAC 4
+#define SADB_AALG_SHA2_256_HMAC 5
+#define SADB_AALG_SHA2_384_HMAC 6
+#define SADB_AALG_SHA2_512_HMAC 7
+#define SADB_AALG_RIPEMD_160_HMAC 8
+#define SADB_AALG_AES_XCBC_MAC 9
+#define SADB_X_AALG_NULL 251 /* kame */
+#define SADB_AALG_MAX 251
+
+#define SADB_EALG_NONE 0
+#define SADB_EALG_DES_CBC 2
+#define SADB_EALG_3DES_CBC 3
+#define SADB_EALG_RC5_CBC 4
+#define SADB_EALG_IDEA_CBC 5
+#define SADB_EALG_CAST_CBC 6
+#define SADB_EALG_BLOWFISH_CBC 7
+#define SADB_EALG_NULL 11
+#define SADB_EALG_AES_CBC 12
+#define SADB_EALG_AES_CTR 13
+#define SADB_X_EALG_SERPENT_CBC 252
+#define SADB_X_EALG_TWOFISH_CBC 253
+#define SADB_EALG_MAX 253
+
+#define SADB_X_CALG_NONE 0
+#define SADB_X_CALG_OUI 1
+#define SADB_X_CALG_DEFLATE 2
+#define SADB_X_CALG_LZS 3
+#define SADB_X_CALG_V42BIS 4
+#ifdef KERNEL26_HAS_KAME_DUPLICATES
+#define SADB_X_CALG_LZJH 4
+#endif
+#define SADB_X_CALG_MAX 4
+
+#define SADB_X_TALG_NONE 0
+#define SADB_X_TALG_IPv4_in_IPv4 1
+#define SADB_X_TALG_IPv6_in_IPv4 2
+#define SADB_X_TALG_IPv4_in_IPv6 3
+#define SADB_X_TALG_IPv6_in_IPv6 4
+#define SADB_X_TALG_MAX 4
+
+
+#define SADB_IDENTTYPE_RESERVED 0
+#define SADB_IDENTTYPE_PREFIX 1
+#define SADB_IDENTTYPE_FQDN 2
+#define SADB_IDENTTYPE_USERFQDN 3
+#define SADB_X_IDENTTYPE_CONNECTION 4
+#define SADB_IDENTTYPE_MAX 4
+
+#define SADB_KEY_FLAGS_MAX 0
+#endif /* __PFKEY_V2_H */
diff --git a/src/libfreeswan/portof.3 b/src/libfreeswan/portof.3
new file mode 100644
index 000000000..fac0d8bc3
--- /dev/null
+++ b/src/libfreeswan/portof.3
@@ -0,0 +1,70 @@
+.TH IPSEC_PORTOF 3 "8 Sept 2000"
+.\" RCSID $Id: portof.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec portof \- get port field of an ip_address
+.br
+ipsec setportof \- set port field of an ip_address
+.br
+ipsec sockaddrof \- get pointer to internal sockaddr of an ip_address
+.br
+ipsec sockaddrlenof \- get length of internal sockaddr of an ip_address
+.SH SYNOPSIS
+.B "#include <freeswan.h>"
+.sp
+.B "int portof(const ip_address *src);"
+.br
+.B "void setportof(int port, ip_address *dst);"
+.br
+.B "struct sockaddr *sockaddrof(ip_address *src);"
+.br
+.B "size_t sockaddrlenof(const ip_address *src);"
+.SH DESCRIPTION
+The
+.B <freeswan.h>
+internal type
+.I ip_address
+contains one of the
+.I sockaddr
+types internally.
+\fIReliance on this feature is discouraged\fR,
+but it may occasionally be necessary.
+These functions provide low-level tools for this purpose.
+.PP
+.I Portof
+and
+.I setportof
+respectively read and write the port-number field of the internal
+.IR sockaddr .
+The values are in network byte order.
+.PP
+.I Sockaddrof
+returns a pointer to the internal
+.IR sockaddr ,
+for passing to other functions.
+.PP
+.I Sockaddrlenof
+reports the size of the internal
+.IR sockaddr ,
+for use in storage allocation.
+.SH SEE ALSO
+inet(3), ipsec_initaddr(3)
+.SH DIAGNOSTICS
+.I Portof
+returns
+.BR \-1 ,
+.I sockaddrof
+returns
+.BR NULL ,
+and
+.I sockaddrlenof
+returns
+.B 0
+if an unknown address family is found within the
+.IR ip_address .
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+These functions all depend on low-level details of the
+.I ip_address
+type, which are in principle subject to change.
+Avoid using them unless really necessary.
diff --git a/src/libfreeswan/portof.c b/src/libfreeswan/portof.c
new file mode 100644
index 000000000..d028ea034
--- /dev/null
+++ b/src/libfreeswan/portof.c
@@ -0,0 +1,96 @@
+/*
+ * low-level ip_address ugliness
+ * 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.
+ *
+ * RCSID $Id: portof.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - portof - get the port field of an ip_address
+ */
+int /* network order */
+portof(src)
+const ip_address *src;
+{
+ switch (src->u.v4.sin_family) {
+ case AF_INET:
+ return src->u.v4.sin_port;
+ break;
+ case AF_INET6:
+ return src->u.v6.sin6_port;
+ break;
+ default:
+ return -1; /* "can't happen" */
+ break;
+ }
+}
+
+/*
+ - setportof - set the port field of an ip_address
+ */
+void
+setportof(port, dst)
+int port; /* network order */
+ip_address *dst;
+{
+ switch (dst->u.v4.sin_family) {
+ case AF_INET:
+ dst->u.v4.sin_port = port;
+ break;
+ case AF_INET6:
+ dst->u.v6.sin6_port = port;
+ break;
+ }
+}
+
+/*
+ - sockaddrof - get a pointer to the sockaddr hiding inside an ip_address
+ */
+struct sockaddr *
+sockaddrof(src)
+ip_address *src;
+{
+ switch (src->u.v4.sin_family) {
+ case AF_INET:
+ return (struct sockaddr *)&src->u.v4;
+ break;
+ case AF_INET6:
+ return (struct sockaddr *)&src->u.v6;
+ break;
+ default:
+ return NULL; /* "can't happen" */
+ break;
+ }
+}
+
+/*
+ - sockaddrlenof - get length of the sockaddr hiding inside an ip_address
+ */
+size_t /* 0 for error */
+sockaddrlenof(src)
+const ip_address *src;
+{
+ switch (src->u.v4.sin_family) {
+ case AF_INET:
+ return sizeof(src->u.v4);
+ break;
+ case AF_INET6:
+ return sizeof(src->u.v6);
+ break;
+ default:
+ return 0;
+ break;
+ }
+}
diff --git a/src/libfreeswan/prng.3 b/src/libfreeswan/prng.3
new file mode 100644
index 000000000..51f19364f
--- /dev/null
+++ b/src/libfreeswan/prng.3
@@ -0,0 +1,121 @@
+.TH IPSEC_PRNG 3 "1 April 2002"
+.\" RCSID $Id: prng.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec prng_init \- initialize IPsec pseudorandom-number generator
+.br
+ipsec prng_bytes \- get bytes from IPsec pseudorandom-number generator
+.br
+ipsec prng_final \- close down IPsec pseudorandom-number generator
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "void prng_init(struct prng *prng,"
+.ti +1c
+.B "const unsigned char *key, size_t keylen);"
+.br
+.B "void prng_bytes(struct prng *prng, char *dst,"
+.ti +1c
+.B "size_t dstlen);"
+.br
+.B "unsigned long prng_count(struct prng *prng);"
+.br
+.B "void prng_final(struct prng *prng);"
+.SH DESCRIPTION
+.I Prng_init
+initializes a crypto-quality pseudo-random-number generator from a key;
+.I prng_bytes
+obtains pseudo-random bytes from it;
+.I prng_count
+reports the number of bytes extracted from it to date;
+.I prng_final
+closes it down.
+It is the user's responsibility to initialize a PRNG before using it,
+and not to use it again after it is closed down.
+.PP
+.I Prng_init
+initializes,
+or re-initializes,
+the specified
+.I prng
+from the
+.IR key ,
+whose length is given by
+.IR keylen .
+The user must allocate the
+.B "struct prng"
+pointed to by
+.IR prng .
+There is no particular constraint on the length of the key,
+although a key longer than 256 bytes is unnecessary because
+only the first 256 would be used.
+Initialization requires on the order of 3000 integer operations,
+independent of key length.
+.PP
+.I Prng_bytes
+obtains
+.I dstlen
+pseudo-random bytes from the PRNG and puts them in
+.IR buf .
+This is quite fast,
+on the order of 10 integer operations per byte.
+.PP
+.I Prng_count
+reports the number of bytes obtained from the PRNG
+since it was (last) initialized.
+.PP
+.I Prng_final
+closes down a PRNG by
+zeroing its internal memory,
+obliterating all trace of the state used to generate its previous output.
+This requires on the order of 250 integer operations.
+.PP
+The
+.B <freeswan.h>
+header file supplies the definition of the
+.B prng
+structure.
+Examination of its innards is discouraged, as they may change.
+.PP
+The PRNG algorithm
+used by these functions is currently identical to that of RC4(TM).
+This algorithm is cryptographically strong,
+sufficiently unpredictable that even a hostile observer will
+have difficulty determining the next byte of output from past history,
+provided it is initialized from a reasonably large key composed of
+highly random bytes (see
+.IR random (4)).
+The usual run of software pseudo-random-number generators
+(e.g.
+.IR random (3))
+are
+.I not
+cryptographically strong.
+.PP
+The well-known attacks against RC4(TM),
+e.g. as found in 802.11b's WEP encryption system,
+apply only if multiple PRNGs are initialized with closely-related keys
+(e.g., using a counter appended to a base key).
+If such keys are used, the first few hundred pseudo-random bytes
+from each PRNG should be discarded,
+to give the PRNGs a chance to randomize their innards properly.
+No useful attacks are known if the key is well randomized to begin with.
+.SH SEE ALSO
+random(3), random(4)
+.br
+Bruce Schneier,
+\fIApplied Cryptography\fR, 2nd ed., 1996, ISBN 0-471-11709-9,
+pp. 397-8.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+If an attempt is made to obtain more than 4e9 bytes
+between initializations,
+the PRNG will continue to work but
+.IR prng_count 's
+output will stick at
+.BR 4000000000 .
+Fixing this would require a longer integer type and does
+not seem worth the trouble,
+since you should probably re-initialize before then anyway...
+.PP
+``RC4'' is a trademark of RSA Data Security, Inc.
diff --git a/src/libfreeswan/prng.c b/src/libfreeswan/prng.c
new file mode 100644
index 000000000..e31836783
--- /dev/null
+++ b/src/libfreeswan/prng.c
@@ -0,0 +1,202 @@
+/*
+ * crypto-class pseudorandom number generator
+ * currently uses same algorithm as RC4(TM), from Schneier 2nd ed p397
+ * Copyright (C) 2002 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.
+ *
+ * RCSID $Id: prng.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - prng_init - initialize PRNG from a key
+ */
+void
+prng_init(prng, key, keylen)
+struct prng *prng;
+const unsigned char *key;
+size_t keylen;
+{
+ unsigned char k[256];
+ int i, j;
+ unsigned const char *p;
+ unsigned const char *keyend = key + keylen;
+ unsigned char t;
+
+ for (i = 0; i <= 255; i++)
+ prng->sbox[i] = i;
+ p = key;
+ for (i = 0; i <= 255; i++) {
+ k[i] = *p++;
+ if (p >= keyend)
+ p = key;
+ }
+ j = 0;
+ for (i = 0; i <= 255; i++) {
+ j = (j + prng->sbox[i] + k[i]) & 0xff;
+ t = prng->sbox[i];
+ prng->sbox[i] = prng->sbox[j];
+ prng->sbox[j] = t;
+ k[i] = 0; /* clear out key memory */
+ }
+ prng->i = 0;
+ prng->j = 0;
+ prng->count = 0;
+}
+
+/*
+ - prng_bytes - get some pseudorandom bytes from PRNG
+ */
+void
+prng_bytes(prng, dst, dstlen)
+struct prng *prng;
+unsigned char *dst;
+size_t dstlen;
+{
+ int i, j, t;
+ unsigned char *p = dst;
+ size_t remain = dstlen;
+# define MAX 4000000000ul
+
+ while (remain > 0) {
+ i = (prng->i + 1) & 0xff;
+ prng->i = i;
+ j = (prng->j + prng->sbox[i]) & 0xff;
+ prng->j = j;
+ t = prng->sbox[i];
+ prng->sbox[i] = prng->sbox[j];
+ prng->sbox[j] = t;
+ t = (t + prng->sbox[i]) & 0xff;
+ *p++ = prng->sbox[t];
+ remain--;
+ }
+ if (prng->count < MAX - dstlen)
+ prng->count += dstlen;
+ else
+ prng->count = MAX;
+}
+
+/*
+ - prnt_count - how many bytes have been extracted from PRNG so far?
+ */
+unsigned long
+prng_count(prng)
+struct prng *prng;
+{
+ return prng->count;
+}
+
+/*
+ - prng_final - clear out PRNG to ensure nothing left in memory
+ */
+void
+prng_final(prng)
+struct prng *prng;
+{
+ int i;
+
+ for (i = 0; i <= 255; i++)
+ prng->sbox[i] = 0;
+ prng->i = 0;
+ prng->j = 0;
+ prng->count = 0; /* just for good measure */
+}
+
+
+
+#ifdef PRNG_MAIN
+
+#include <stdio.h>
+
+void regress();
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ struct prng pr;
+ unsigned char buf[100];
+ unsigned char *p;
+ size_t n;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s {key|-r}\n", argv[0]);
+ exit(2);
+ }
+
+ if (strcmp(argv[1], "-r") == 0) {
+ regress();
+ fprintf(stderr, "regress() returned?!?\n");
+ exit(1);
+ }
+
+ prng_init(&pr, argv[1], strlen(argv[1]));
+ prng_bytes(&pr, buf, 32);
+ printf("0x");
+ for (p = buf, n = 32; n > 0; p++, n--)
+ printf("%02x", *p);
+ printf("\n%lu bytes\n", prng_count(&pr));
+ prng_final(&pr);
+ exit(0);
+}
+
+void
+regress()
+{
+ struct prng pr;
+ unsigned char buf[100];
+ unsigned char *p;
+ size_t n;
+ /* somewhat non-random sample key */
+ unsigned char key[] = "here we go gathering nuts in May";
+ /* first thirty bytes of output from that key */
+ unsigned char good[] = "\x3f\x02\x8e\x4a\x2a\xea\x23\x18\x92\x7c"
+ "\x09\x52\x83\x61\xaa\x26\xce\xbb\x9d\x71"
+ "\x71\xe5\x10\x22\xaf\x60\x54\x8d\x5b\x28";
+ int nzero, none;
+ int show = 0;
+
+ prng_init(&pr, key, strlen(key));
+ prng_bytes(&pr, buf, sizeof(buf));
+ for (p = buf, n = sizeof(buf); n > 0; p++, n--) {
+ if (*p == 0)
+ nzero++;
+ if (*p == 255)
+ none++;
+ }
+ if (nzero > 3 || none > 3) {
+ fprintf(stderr, "suspiciously non-random output!\n");
+ show = 1;
+ }
+ if (memcmp(buf, good, strlen(good)) != 0) {
+ fprintf(stderr, "incorrect output!\n");
+ show = 1;
+ }
+ if (show) {
+ fprintf(stderr, "0x");
+ for (p = buf, n = sizeof(buf); n > 0; p++, n--)
+ fprintf(stderr, "%02x", *p);
+ fprintf(stderr, "\n");
+ exit(1);
+ }
+ if (prng_count(&pr) != sizeof(buf)) {
+ fprintf(stderr, "got %u bytes, but count is %lu\n",
+ sizeof(buf), prng_count(&pr));
+ exit(1);
+ }
+ prng_final(&pr);
+ exit(0);
+}
+
+#endif /* PRNG_MAIN */
diff --git a/src/libfreeswan/radij.h b/src/libfreeswan/radij.h
new file mode 100644
index 000000000..2a66093a0
--- /dev/null
+++ b/src/libfreeswan/radij.h
@@ -0,0 +1,280 @@
+/*
+ * RCSID $Id: radij.h,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+
+/*
+ * This file is defived from ${SRC}/sys/net/radix.h of BSD 4.4lite
+ *
+ * Variable and procedure names have been modified so that they don't
+ * conflict with the original BSD code, as a small number of modifications
+ * have been introduced and we may want to reuse this code in BSD.
+ *
+ * The `j' in `radij' is pronounced as a voiceless guttural (like a Greek
+ * chi or a German ch sound (as `doch', not as in `milch'), or even a
+ * spanish j as in Juan. It is not as far back in the throat like
+ * the corresponding Hebrew sound, nor is it a soft breath like the English h.
+ * It has nothing to do with the Dutch ij sound.
+ *
+ * Here is the appropriate copyright notice:
+ */
+
+/*
+ * Copyright (c) 1988, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)radix.h 8.1 (Berkeley) 6/10/93
+ */
+
+#ifndef _RADIJ_H_
+#define _RADIJ_H_
+
+/*
+#define RJ_DEBUG
+*/
+
+#ifdef __KERNEL__
+
+#ifndef __P
+#ifdef __STDC__
+#define __P(x) x
+#else
+#define __P(x) ()
+#endif
+#endif
+
+/*
+ * Radix search tree node layout.
+ */
+
+struct radij_node
+{
+ struct radij_mask *rj_mklist; /* list of masks contained in subtree */
+ struct radij_node *rj_p; /* parent */
+ short rj_b; /* bit offset; -1-index(netmask) */
+ char rj_bmask; /* node: mask for bit test*/
+ u_char rj_flags; /* enumerated next */
+#define RJF_NORMAL 1 /* leaf contains normal route */
+#define RJF_ROOT 2 /* leaf is root leaf for tree */
+#define RJF_ACTIVE 4 /* This node is alive (for rtfree) */
+ union {
+ struct { /* leaf only data: */
+ caddr_t rj_Key; /* object of search */
+ caddr_t rj_Mask; /* netmask, if present */
+ struct radij_node *rj_Dupedkey;
+ } rj_leaf;
+ struct { /* node only data: */
+ int rj_Off; /* where to start compare */
+ struct radij_node *rj_L;/* progeny */
+ struct radij_node *rj_R;/* progeny */
+ }rj_node;
+ } rj_u;
+#ifdef RJ_DEBUG
+ int rj_info;
+ struct radij_node *rj_twin;
+ struct radij_node *rj_ybro;
+#endif
+};
+
+#define rj_dupedkey rj_u.rj_leaf.rj_Dupedkey
+#define rj_key rj_u.rj_leaf.rj_Key
+#define rj_mask rj_u.rj_leaf.rj_Mask
+#define rj_off rj_u.rj_node.rj_Off
+#define rj_l rj_u.rj_node.rj_L
+#define rj_r rj_u.rj_node.rj_R
+
+/*
+ * Annotations to tree concerning potential routes applying to subtrees.
+ */
+
+extern struct radij_mask {
+ short rm_b; /* bit offset; -1-index(netmask) */
+ char rm_unused; /* cf. rj_bmask */
+ u_char rm_flags; /* cf. rj_flags */
+ struct radij_mask *rm_mklist; /* more masks to try */
+ caddr_t rm_mask; /* the mask */
+ int rm_refs; /* # of references to this struct */
+} *rj_mkfreelist;
+
+#define MKGet(m) {\
+ if (rj_mkfreelist) {\
+ m = rj_mkfreelist; \
+ rj_mkfreelist = (m)->rm_mklist; \
+ } else \
+ R_Malloc(m, struct radij_mask *, sizeof (*(m))); }\
+
+#define MKFree(m) { (m)->rm_mklist = rj_mkfreelist; rj_mkfreelist = (m);}
+
+struct radij_node_head {
+ struct radij_node *rnh_treetop;
+ int rnh_addrsize; /* permit, but not require fixed keys */
+ int rnh_pktsize; /* permit, but not require fixed keys */
+#if 0
+ struct radij_node *(*rnh_addaddr) /* add based on sockaddr */
+ __P((void *v, void *mask,
+ struct radij_node_head *head, struct radij_node nodes[]));
+#endif
+ int (*rnh_addaddr) /* add based on sockaddr */
+ __P((void *v, void *mask,
+ struct radij_node_head *head, struct radij_node nodes[]));
+ struct radij_node *(*rnh_addpkt) /* add based on packet hdr */
+ __P((void *v, void *mask,
+ struct radij_node_head *head, struct radij_node nodes[]));
+#if 0
+ struct radij_node *(*rnh_deladdr) /* remove based on sockaddr */
+ __P((void *v, void *mask, struct radij_node_head *head));
+#endif
+ int (*rnh_deladdr) /* remove based on sockaddr */
+ __P((void *v, void *mask, struct radij_node_head *head, struct radij_node **node));
+ struct radij_node *(*rnh_delpkt) /* remove based on packet hdr */
+ __P((void *v, void *mask, struct radij_node_head *head));
+ struct radij_node *(*rnh_matchaddr) /* locate based on sockaddr */
+ __P((void *v, struct radij_node_head *head));
+ struct radij_node *(*rnh_matchpkt) /* locate based on packet hdr */
+ __P((void *v, struct radij_node_head *head));
+ int (*rnh_walktree) /* traverse tree */
+ __P((struct radij_node_head *head, int (*f)(struct radij_node *rn, void *w), void *w));
+ struct radij_node rnh_nodes[3]; /* empty tree for common case */
+};
+
+
+#define Bcmp(a, b, n) memcmp(((caddr_t)(b)), ((caddr_t)(a)), (unsigned)(n))
+#define Bcopy(a, b, n) memmove(((caddr_t)(b)), ((caddr_t)(a)), (unsigned)(n))
+#define Bzero(p, n) memset((caddr_t)(p), 0, (unsigned)(n))
+#define R_Malloc(p, t, n) ((p = (t) kmalloc((size_t)(n), GFP_ATOMIC)), Bzero((p),(n)))
+#define Free(p) kfree((caddr_t)p);
+
+void rj_init __P((void));
+int rj_inithead __P((void **, int));
+int rj_refines __P((void *, void *));
+int rj_walktree __P((struct radij_node_head *head, int (*f)(struct radij_node *rn, void *w), void *w));
+struct radij_node
+ *rj_addmask __P((void *, int, int)) /* , rgb */ ;
+int /* * */ rj_addroute __P((void *, void *, struct radij_node_head *,
+ struct radij_node [2])) /* , rgb */ ;
+int /* * */ rj_delete __P((void *, void *, struct radij_node_head *, struct radij_node **)) /* , rgb */ ;
+struct radij_node /* rgb */
+ *rj_insert __P((void *, struct radij_node_head *, int *,
+ struct radij_node [2])),
+ *rj_match __P((void *, struct radij_node_head *)),
+ *rj_newpair __P((void *, int, struct radij_node[2])),
+ *rj_search __P((void *, struct radij_node *)),
+ *rj_search_m __P((void *, struct radij_node *, void *));
+
+void rj_deltree(struct radij_node_head *);
+void rj_delnodes(struct radij_node *);
+void rj_free_mkfreelist(void);
+int radijcleartree(void);
+int radijcleanup(void);
+
+extern struct radij_node_head *mask_rjhead;
+extern int maj_keylen;
+#endif /* __KERNEL__ */
+
+#endif /* _RADIJ_H_ */
+
+
+/*
+ * $Log: radij.h,v $
+ * Revision 1.1 2004/03/15 20:35:25 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.12 2002/04/24 07:36:48 mcr
+ * Moved from ./klips/net/ipsec/radij.h,v
+ *
+ * Revision 1.11 2001/09/20 15:33:00 rgb
+ * Min/max cleanup.
+ *
+ * Revision 1.10 1999/11/18 04:09:20 rgb
+ * Replaced all kernel version macros to shorter, readable form.
+ *
+ * Revision 1.9 1999/05/05 22:02:33 rgb
+ * Add a quick and dirty port to 2.2 kernels by Marc Boucher <marc@mbsi.ca>.
+ *
+ * Revision 1.8 1999/04/29 15:24:58 rgb
+ * Add check for existence of macros min/max.
+ *
+ * Revision 1.7 1999/04/11 00:29:02 henry
+ * GPL boilerplate
+ *
+ * Revision 1.6 1999/04/06 04:54:29 rgb
+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+ * patch shell fixes.
+ *
+ * Revision 1.5 1999/01/22 06:30:32 rgb
+ * 64-bit clean-up.
+ *
+ * Revision 1.4 1998/11/30 13:22:55 rgb
+ * Rationalised all the klips kernel file headers. They are much shorter
+ * now and won't conflict under RH5.2.
+ *
+ * Revision 1.3 1998/10/25 02:43:27 rgb
+ * Change return type on rj_addroute and rj_delete and add and argument
+ * to the latter to be able to transmit more infomation about errors.
+ *
+ * Revision 1.2 1998/07/14 18:09:51 rgb
+ * Add a routine to clear eroute table.
+ * Added #ifdef __KERNEL__ directives to restrict scope of header.
+ *
+ * Revision 1.1 1998/06/18 21:30:22 henry
+ * move sources from klips/src to klips/net/ipsec to keep stupid kernel
+ * build scripts happier about symlinks
+ *
+ * Revision 1.4 1998/05/25 20:34:16 rgb
+ * Remove temporary ipsec_walk, rj_deltree and rj_delnodes functions.
+ *
+ * Rename ipsec_rj_walker (ipsec_walk) to ipsec_rj_walker_procprint and
+ * add ipsec_rj_walker_delete.
+ *
+ * Recover memory for eroute table on unload of module.
+ *
+ * Revision 1.3 1998/04/22 16:51:37 rgb
+ * Tidy up radij debug code from recent rash of modifications to debug code.
+ *
+ * Revision 1.2 1998/04/14 17:30:38 rgb
+ * Fix up compiling errors for radij tree memory reclamation.
+ *
+ * Revision 1.1 1998/04/09 03:06:16 henry
+ * sources moved up from linux/net/ipsec
+ *
+ * Revision 1.1.1.1 1998/04/08 05:35:04 henry
+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
+ *
+ * Revision 0.4 1997/01/15 01:28:15 ji
+ * No changes.
+ *
+ * Revision 0.3 1996/11/20 14:44:45 ji
+ * Release update only.
+ *
+ * Revision 0.2 1996/11/02 00:18:33 ji
+ * First limited release.
+ *
+ *
+ */
diff --git a/src/libfreeswan/rangetoa.c b/src/libfreeswan/rangetoa.c
new file mode 100644
index 000000000..e63b432f8
--- /dev/null
+++ b/src/libfreeswan/rangetoa.c
@@ -0,0 +1,61 @@
+/*
+ * convert binary form of address range to ASCII
+ * Copyright (C) 1998, 1999 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.
+ *
+ * RCSID $Id: rangetoa.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - rangetoa - convert address range to ASCII
+ */
+size_t /* space needed for full conversion */
+rangetoa(addrs, format, dst, dstlen)
+struct in_addr addrs[2];
+int format; /* character */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ size_t len;
+ size_t rest;
+ int n;
+ char *p;
+
+ switch (format) {
+ case 0:
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ len = addrtoa(addrs[0], 0, dst, dstlen);
+ if (len < dstlen)
+ for (p = dst + len - 1, n = 3; len < dstlen && n > 0;
+ p++, len++, n--)
+ *p = '.';
+ else
+ p = NULL;
+ if (len < dstlen)
+ rest = dstlen - len;
+ else {
+ if (dstlen > 0)
+ *(dst + dstlen - 1) = '\0';
+ rest = 0;
+ }
+
+ len += addrtoa(addrs[1], 0, p, rest);
+
+ return len;
+}
diff --git a/src/libfreeswan/rangetosubnet.3 b/src/libfreeswan/rangetosubnet.3
new file mode 100644
index 000000000..7d707545e
--- /dev/null
+++ b/src/libfreeswan/rangetosubnet.3
@@ -0,0 +1,59 @@
+.TH IPSEC_RANGETOSUBNET 3 "8 Sept 2000"
+.\" RCSID $Id: rangetosubnet.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec rangetosubnet \- convert address range to subnet
+.SH SYNOPSIS
+.B "#include <freeswan.h>"
+.sp
+.B "const char *rangetosubnet(const ip_address *start,"
+.ti +1c
+.B "const ip_address *stop, ip_subnet *dst);"
+.SH DESCRIPTION
+.I Rangetosubnet
+accepts two IP addresses which define an address range,
+from
+.I start
+to
+.I stop
+inclusive,
+and converts this to a subnet if possible.
+The addresses must both be IPv4 or both be IPv6,
+and the address family of the resulting subnet is the same.
+.PP
+.I Rangetosubnet
+returns NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+.SH SEE ALSO
+ipsec_initsubnet(3), ipsec_ttosubnet(3)
+.SH DIAGNOSTICS
+Fatal errors in
+.I rangetosubnet
+are:
+mixed address families;
+unknown address family;
+.I start
+and
+.I stop
+do not define a subnet.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+The restriction of error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+.PP
+The error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+.PP
+.RS
+.nf
+.B "const char *error;"
+.sp
+.B "error = rangetosubnet( /* ... */ );"
+.B "if (error != NULL) {"
+.B " /* something went wrong */"
+.fi
+.RE
diff --git a/src/libfreeswan/rangetosubnet.c b/src/libfreeswan/rangetosubnet.c
new file mode 100644
index 000000000..048b10556
--- /dev/null
+++ b/src/libfreeswan/rangetosubnet.c
@@ -0,0 +1,226 @@
+/*
+ * express an address range as a subnet (if possible)
+ * 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.
+ *
+ * RCSID $Id: rangetosubnet.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - rangetosubnet - turn an address range into a subnet, if possible
+ *
+ * A range which is a valid subnet will have a network part which is the
+ * same in the from value and the to value, followed by a host part which
+ * is all 0 in the from value and all 1 in the to value.
+ */
+err_t
+rangetosubnet(from, to, dst)
+const ip_address *from;
+const ip_address *to;
+ip_subnet *dst;
+{
+ unsigned const char *fp;
+ unsigned const char *tp;
+ unsigned fb;
+ unsigned tb;
+ unsigned const char *f;
+ unsigned const char *t;
+ size_t n;
+ size_t n2;
+ int i;
+ int nnet;
+ unsigned m;
+
+ if (addrtypeof(from) != addrtypeof(to))
+ return "mismatched address types";
+ n = addrbytesptr(from, &fp);
+ if (n == 0)
+ return "unknown address type";
+ n2 = addrbytesptr(to, &tp);
+ if (n != n2)
+ return "internal size mismatch in rangetosubnet";
+
+ f = fp;
+ t = tp;
+ nnet = 0;
+ for (i = n; i > 0 && *f == *t; i--, f++, t++)
+ nnet += 8;
+ if (i > 0 && !(*f == 0x00 && *t == 0xff)) { /* mid-byte bdry. */
+ fb = *f++;
+ tb = *t++;
+ i--;
+ m = 0x80;
+ while ((fb&m) == (tb&m)) {
+ fb &= ~m;
+ tb |= m;
+ m >>= 1;
+ nnet++;
+ }
+ if (fb != 0x00 || tb != 0xff)
+ return "not a valid subnet";
+ }
+ for (; i > 0 && *f == 0x00 && *t == 0xff; i--, f++, t++)
+ continue;
+
+ if (i != 0)
+ return "invalid subnet";
+
+ return initsubnet(from, nnet, 'x', dst);
+}
+
+
+
+#ifdef RANGETOSUBNET_MAIN
+
+#include <stdio.h>
+
+void regress(void);
+
+int
+main(int argc, char *argv[])
+{
+ ip_address start;
+ ip_address stop;
+ ip_subnet sub;
+ char buf[100];
+ const char *oops;
+ size_t n;
+ int af;
+ int i;
+
+ if (argc == 2 && strcmp(argv[1], "-r") == 0) {
+ regress();
+ fprintf(stderr, "regress() returned?!?\n");
+ exit(1);
+ }
+
+ if (argc < 3) {
+ fprintf(stderr, "Usage: %s [-6] start stop\n", argv[0]);
+ fprintf(stderr, " or: %s -r\n", argv[0]);
+ exit(2);
+ }
+
+ af = AF_INET;
+ i = 1;
+ if (strcmp(argv[i], "-6") == 0) {
+ af = AF_INET6;
+ i++;
+ }
+
+ oops = ttoaddr(argv[i], 0, af, &start);
+ if (oops != NULL) {
+ fprintf(stderr, "%s: start conversion failed: %s\n", argv[0], oops);
+ exit(1);
+ }
+ oops = ttoaddr(argv[i+1], 0, af, &stop);
+ if (oops != NULL) {
+ fprintf(stderr, "%s: stop conversion failed: %s\n", argv[0], oops);
+ exit(1);
+ }
+ oops = rangetosubnet(&start, &stop, &sub);
+ if (oops != NULL) {
+ fprintf(stderr, "%s: rangetosubnet failed: %s\n", argv[0], oops);
+ exit(1);
+ }
+ n = subnettot(&sub, 0, buf, sizeof(buf));
+ if (n > sizeof(buf)) {
+ fprintf(stderr, "%s: reverse conversion", argv[0]);
+ fprintf(stderr, " failed: need %ld bytes, have only %ld\n",
+ (long)n, (long)sizeof(buf));
+ exit(1);
+ }
+ printf("%s\n", buf);
+
+ exit(0);
+}
+
+struct rtab {
+ int family;
+ char *start;
+ char *stop;
+ char *output; /* NULL means error expected */
+} rtab[] = {
+ {4, "1.2.3.0", "1.2.3.255", "1.2.3.0/24"},
+ {4, "1.2.3.0", "1.2.3.7", "1.2.3.0/29"},
+ {4, "1.2.3.240", "1.2.3.255", "1.2.3.240/28"},
+ {4, "0.0.0.0", "255.255.255.255", "0.0.0.0/0"},
+ {4, "1.2.3.4", "1.2.3.4", "1.2.3.4/32"},
+ {4, "1.2.3.0", "1.2.3.254", NULL},
+ {4, "1.2.3.0", "1.2.3.126", NULL},
+ {4, "1.2.3.0", "1.2.3.125", NULL},
+ {4, "1.2.0.0", "1.2.255.255", "1.2.0.0/16"},
+ {4, "1.2.0.0", "1.2.0.255", "1.2.0.0/24"},
+ {4, "1.2.255.0", "1.2.255.255", "1.2.255.0/24"},
+ {4, "1.2.255.0", "1.2.254.255", NULL},
+ {4, "1.2.255.1", "1.2.255.255", NULL},
+ {4, "1.2.0.1", "1.2.255.255", NULL},
+ {6, "1:2:3:4:5:6:7:0", "1:2:3:4:5:6:7:ffff", "1:2:3:4:5:6:7:0/112"},
+ {6, "1:2:3:4:5:6:7:0", "1:2:3:4:5:6:7:fff", "1:2:3:4:5:6:7:0/116"},
+ {6, "1:2:3:4:5:6:7:f0", "1:2:3:4:5:6:7:ff", "1:2:3:4:5:6:7:f0/124"},
+ {4, NULL, NULL, NULL},
+};
+
+void
+regress()
+{
+ struct rtab *r;
+ int status = 0;
+ ip_address start;
+ ip_address stop;
+ ip_subnet sub;
+ char buf[100];
+ const char *oops;
+ size_t n;
+ int af;
+
+ for (r = rtab; r->start != NULL; r++) {
+ af = (r->family == 4) ? AF_INET : AF_INET6;
+ oops = ttoaddr(r->start, 0, af, &start);
+ if (oops != NULL) {
+ printf("surprise failure converting `%s'\n", r->start);
+ exit(1);
+ }
+ oops = ttoaddr(r->stop, 0, af, &stop);
+ if (oops != NULL) {
+ printf("surprise failure converting `%s'\n", r->stop);
+ exit(1);
+ }
+ oops = rangetosubnet(&start, &stop, &sub);
+ if (oops != NULL && r->output == NULL)
+ {} /* okay, error expected */
+ else if (oops != NULL) {
+ printf("`%s'-`%s' rangetosubnet failed: %s\n",
+ r->start, r->stop, oops);
+ status = 1;
+ } else if (r->output == NULL) {
+ printf("`%s'-`%s' rangetosubnet succeeded unexpectedly\n",
+ r->start, r->stop);
+ status = 1;
+ } else {
+ n = subnettot(&sub, 0, buf, sizeof(buf));
+ if (n > sizeof(buf)) {
+ printf("`%s'-`%s' subnettot failed: need %ld\n",
+ r->start, r->stop, (long)n);
+ status = 1;
+ } else if (strcmp(r->output, buf) != 0) {
+ printf("`%s'-`%s' gave `%s', expected `%s'\n",
+ r->start, r->stop, buf, r->output);
+ status = 1;
+ }
+ }
+ }
+ exit(status);
+}
+
+#endif /* RANGETOSUBNET_MAIN */
diff --git a/src/libfreeswan/sameaddr.3 b/src/libfreeswan/sameaddr.3
new file mode 100644
index 000000000..71be10761
--- /dev/null
+++ b/src/libfreeswan/sameaddr.3
@@ -0,0 +1,165 @@
+.TH IPSEC_ANYADDR 3 "28 Nov 2000"
+.\" RCSID $Id: sameaddr.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec sameaddr \- are two addresses the same?
+.br
+ipsec addrcmp \- ordered comparison of addresses
+.br
+ipsec samesubnet \- are two subnets the same?
+.br
+ipsec addrinsubnet \- is an address within a subnet?
+.br
+ipsec subnetinsubnet \- is a subnet within another subnet?
+.br
+ipsec subnetishost \- is a subnet a single host?
+.br
+ipsec samesaid \- are two SA IDs the same?
+.br
+ipsec sameaddrtype \- are two addresses of the same address family?
+.br
+ipsec samesubnettype \- are two subnets of the same address family?
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "int sameaddr(const ip_address *a, const ip_address *b);"
+.br
+.B "int addrcmp(const ip_address *a, const ip_address *b);"
+.br
+.B "int samesubnet(const ip_subnet *a, const ip_subnet *b);"
+.br
+.B "int addrinsubnet(const ip_address *a, const ip_subnet *s);"
+.br
+.B "int subnetinsubnet(const ip_subnet *a, const ip_subnet *b);"
+.br
+.B "int subnetishost(const ip_subnet *s);"
+.br
+.B "int samesaid(const ip_said *a, const ip_said *b);"
+.br
+.B "int sameaddrtype(const ip_address *a, const ip_address *b);"
+.br
+.B "int samesubnettype(const ip_subnet *a, const ip_subnet *b);"
+.SH DESCRIPTION
+These functions do various comparisons and tests on the
+.I ip_address
+type and
+.I ip_subnet
+types.
+.PP
+.I Sameaddr
+returns
+non-zero
+if addresses
+.I a
+and
+.IR b
+are identical,
+and
+.B 0
+otherwise.
+Addresses of different families are never identical.
+.PP
+.I Addrcmp
+returns
+.BR \-1 ,
+.BR 0 ,
+or
+.BR 1
+respectively
+if address
+.I a
+is less than, equal to, or greater than
+.IR b .
+If they are not of the same address family,
+they are never equal;
+the ordering reported in this case is arbitrary
+(and probably not useful) but consistent.
+.PP
+.I Samesubnet
+returns
+non-zero
+if subnets
+.I a
+and
+.IR b
+are identical,
+and
+.B 0
+otherwise.
+Subnets of different address families are never identical.
+.PP
+.I Addrinsubnet
+returns
+non-zero
+if address
+.I a
+is within subnet
+.IR s
+and
+.B 0
+otherwise.
+An address is never within a
+subnet of a different address family.
+.PP
+.I Subnetinsubnet
+returns
+non-zero
+if subnet
+.I a
+is a subset of subnet
+.IR b
+and
+.B 0
+otherwise.
+A subnet is deemed to be a subset of itself.
+A subnet is never a subset of another
+subnet if their address families differ.
+.PP
+.I Subnetishost
+returns
+non-zero
+if subnet
+.I s
+is in fact only a single host,
+and
+.B 0
+otherwise.
+.PP
+.I Samesaid
+returns
+non-zero
+if SA IDs
+.I a
+and
+.IR b
+are identical,
+and
+.B 0
+otherwise.
+.PP
+.I Sameaddrtype
+returns
+non-zero
+if addresses
+.I a
+and
+.IR b
+are of the same address family,
+and
+.B 0
+otherwise.
+.PP
+.I Samesubnettype
+returns
+non-zero
+if subnets
+.I a
+and
+.IR b
+are of the same address family,
+and
+.B 0
+otherwise.
+.SH SEE ALSO
+inet(3), ipsec_initaddr(3)
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
diff --git a/src/libfreeswan/sameaddr.c b/src/libfreeswan/sameaddr.c
new file mode 100644
index 000000000..efc40796e
--- /dev/null
+++ b/src/libfreeswan/sameaddr.c
@@ -0,0 +1,190 @@
+/*
+ * comparisons
+ * 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.
+ *
+ * RCSID $Id: sameaddr.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+static int samenbits(const ip_address *a, const ip_address *b, int n);
+
+/*
+ - addrcmp - compare two addresses
+ * Caution, the order of the tests is subtle: doing type test before
+ * size test can yield cases where a<b, b<c, but a>c.
+ */
+int /* like memcmp */
+addrcmp(a, b)
+const ip_address *a;
+const ip_address *b;
+{
+ int at = addrtypeof(a);
+ int bt = addrtypeof(b);
+ const unsigned char *ap;
+ const unsigned char *bp;
+ size_t as = addrbytesptr(a, &ap);
+ size_t bs = addrbytesptr(b, &bp);
+ size_t n = (as < bs) ? as : bs; /* min(as, bs) */
+ int c = memcmp(ap, bp, n);
+
+ if (c != 0) /* bytes differ */
+ return (c < 0) ? -1 : 1;
+ if (as != bs) /* comparison incomplete: lexical order */
+ return (as < bs) ? -1 : 1;
+ if (at != bt) /* bytes same but not same type: break tie */
+ return (at < bt) ? -1 : 1;
+ return 0;
+}
+
+/*
+ - sameaddr - are two addresses the same?
+ */
+int
+sameaddr(a, b)
+const ip_address *a;
+const ip_address *b;
+{
+ return (addrcmp(a, b) == 0) ? 1 : 0;
+}
+
+/*
+ - samesubnet - are two subnets the same?
+ */
+int
+samesubnet(a, b)
+const ip_subnet *a;
+const ip_subnet *b;
+{
+ if (!sameaddr(&a->addr, &b->addr)) /* also does type check */
+ return 0;
+ if (a->maskbits != b->maskbits)
+ return 0;
+ return 1;
+}
+
+/*
+ - subnetishost - is a subnet in fact a single host?
+ */
+int
+subnetishost(a)
+const ip_subnet *a;
+{
+ return (a->maskbits == addrlenof(&a->addr)*8) ? 1 : 0;
+}
+
+/*
+ - samesaid - are two SA IDs the same?
+ */
+int
+samesaid(a, b)
+const ip_said *a;
+const ip_said *b;
+{
+ if (a->spi != b->spi) /* test first, most likely to be different */
+ return 0;
+ if (!sameaddr(&a->dst, &b->dst))
+ return 0;
+ if (a->proto != b->proto)
+ return 0;
+ return 1;
+}
+
+/*
+ - sameaddrtype - do two addresses have the same type?
+ */
+int
+sameaddrtype(a, b)
+const ip_address *a;
+const ip_address *b;
+{
+ return (addrtypeof(a) == addrtypeof(b)) ? 1 : 0;
+}
+
+/*
+ - samesubnettype - do two subnets have the same type?
+ */
+int
+samesubnettype(a, b)
+const ip_subnet *a;
+const ip_subnet *b;
+{
+ return (subnettypeof(a) == subnettypeof(b)) ? 1 : 0;
+}
+
+/*
+ - addrinsubnet - is this address in this subnet?
+ */
+int
+addrinsubnet(a, s)
+const ip_address *a;
+const ip_subnet *s;
+{
+ if (addrtypeof(a) != subnettypeof(s))
+ return 0;
+ if (!samenbits(a, &s->addr, s->maskbits))
+ return 0;
+ return 1;
+}
+
+/*
+ - subnetinsubnet - is one subnet within another?
+ */
+int
+subnetinsubnet(a, b)
+const ip_subnet *a;
+const ip_subnet *b;
+{
+ if (subnettypeof(a) != subnettypeof(b))
+ return 0;
+ if (a->maskbits < b->maskbits) /* a is bigger than b */
+ return 0;
+ if (!samenbits(&a->addr, &b->addr, b->maskbits))
+ return 0;
+ return 1;
+}
+
+/*
+ - samenbits - do two addresses have the same first n bits?
+ */
+static int
+samenbits(a, b, nbits)
+const ip_address *a;
+const ip_address *b;
+int nbits;
+{
+ const unsigned char *ap;
+ const unsigned char *bp;
+ size_t n;
+ int m;
+
+ if (addrtypeof(a) != addrtypeof(b))
+ return 0; /* arbitrary */
+ n = addrbytesptr(a, &ap);
+ if (n == 0)
+ return 0; /* arbitrary */
+ (void) addrbytesptr(b, &bp);
+ if (nbits > n*8)
+ return 0; /* "can't happen" */
+
+ for (; nbits >= 8 && *ap == *bp; nbits -= 8, ap++, bp++)
+ continue;
+ if (nbits >= 8)
+ return 0;
+ if (nbits > 0) { /* partial byte */
+ m = ~(0xff >> nbits);
+ if ((*ap & m) != (*bp & m))
+ return 0;
+ }
+ return 1;
+}
diff --git a/src/libfreeswan/satoa.c b/src/libfreeswan/satoa.c
new file mode 100644
index 000000000..410fb8437
--- /dev/null
+++ b/src/libfreeswan/satoa.c
@@ -0,0 +1,102 @@
+/*
+ * convert from binary form of SA ID to ASCII
+ * Copyright (C) 1998, 1999, 2001 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.
+ *
+ * RCSID $Id: satoa.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+static struct typename {
+ char type;
+ char *name;
+} typenames[] = {
+ { SA_AH, "ah" },
+ { SA_ESP, "esp" },
+ { SA_IPIP, "tun" },
+ { SA_COMP, "comp" },
+ { SA_INT, "int" },
+ { 0, NULL }
+};
+
+/*
+ - satoa - convert SA to ASCII "ah507@1.2.3.4"
+ */
+size_t /* space needed for full conversion */
+satoa(sa, format, dst, dstlen)
+struct sa_id sa;
+int format; /* character */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ size_t len = 0; /* 0 means not handled yet */
+ int base;
+ struct typename *tn;
+ char buf[30+ADDRTOA_BUF];
+
+ switch (format) {
+ case 0:
+ base = 16; /* temporarily at least */
+ break;
+ case 'd':
+ base = 10;
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ for (tn = typenames; tn->name != NULL; tn++)
+ if (sa.proto == tn->type)
+ break;
+ if (tn->name == NULL)
+ return 0;
+
+ if (strcmp(tn->name, PASSTHROUGHTYPE) == 0 &&
+ sa.spi == PASSTHROUGHSPI &&
+ sa.dst.s_addr == PASSTHROUGHDST) {
+ strcpy(buf, PASSTHROUGHNAME);
+ len = strlen(buf);
+ } else if (sa.proto == SA_INT && sa.dst.s_addr == 0) {
+ char *p;
+
+ switch (ntohl(sa.spi)) {
+ case SPI_PASS: p = "%pass"; break;
+ case SPI_DROP: p = "%drop"; break;
+ case SPI_REJECT: p = "%reject"; break;
+ case SPI_HOLD: p = "%hold"; break;
+ case SPI_TRAP: p = "%trap"; break;
+ case SPI_TRAPSUBNET: p = "%trapsubnet"; break;
+ default: p = NULL; break;
+ }
+ if (p != NULL) {
+ strcpy(buf, p);
+ len = strlen(buf);
+ }
+ }
+
+ if (len == 0) {
+ strcpy(buf, tn->name);
+ len = strlen(buf);
+ len += ultoa(ntohl(sa.spi), base, buf+len, sizeof(buf)-len);
+ *(buf+len-1) = '@';
+ len += addrtoa(sa.dst, 0, buf+len, sizeof(buf)-len);
+ }
+
+ if (dst != NULL) {
+ if (len > dstlen)
+ *(buf+dstlen-1) = '\0';
+ strcpy(dst, buf);
+ }
+ return len;
+}
diff --git a/src/libfreeswan/satot.c b/src/libfreeswan/satot.c
new file mode 100644
index 000000000..927f4ca1f
--- /dev/null
+++ b/src/libfreeswan/satot.c
@@ -0,0 +1,132 @@
+/*
+ * convert from binary form of SA ID to text
+ * Copyright (C) 2000, 2001 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.
+ *
+ * RCSID $Id: satot.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+static struct typename {
+ char type;
+ char *name;
+} typenames[] = {
+ { SA_AH, "ah" },
+ { SA_ESP, "esp" },
+ { SA_IPIP, "tun" },
+ { SA_COMP, "comp" },
+ { SA_INT, "int" },
+ { 0, NULL }
+};
+
+/*
+ - satot - convert SA to text "ah507@1.2.3.4"
+ */
+size_t /* space needed for full conversion */
+satot(sa, format, dst, dstlen)
+const ip_said *sa;
+int format; /* character */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ size_t len = 0; /* 0 means "not recognized yet" */
+ int base;
+ int showversion; /* use delimiter to show IP version? */
+ struct typename *tn;
+ char *p;
+ char *pre;
+ char buf[10+1+ULTOT_BUF+ADDRTOT_BUF];
+ char unk[10];
+
+ switch (format) {
+ case 0:
+ base = 16;
+ showversion = 1;
+ break;
+ case 'f':
+ base = 17;
+ showversion = 1;
+ break;
+ case 'x':
+ base = 'x';
+ showversion = 0;
+ break;
+ case 'd':
+ base = 10;
+ showversion = 0;
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ pre = NULL;
+ for (tn = typenames; tn->name != NULL; tn++)
+ if (sa->proto == tn->type) {
+ pre = tn->name;
+ break; /* NOTE BREAK OUT */
+ }
+ if (pre == NULL) { /* unknown protocol */
+ strcpy(unk, "unk");
+ (void) ultot((unsigned char)sa->proto, 10, unk+strlen(unk),
+ sizeof(unk)-strlen(unk));
+ pre = unk;
+ }
+
+ if (strcmp(pre, PASSTHROUGHTYPE) == 0 &&
+ sa->spi == PASSTHROUGHSPI &&
+ isunspecaddr(&sa->dst)) {
+ strcpy(buf, (addrtypeof(&sa->dst) == AF_INET) ?
+ PASSTHROUGH4NAME :
+ PASSTHROUGH6NAME);
+ len = strlen(buf);
+ }
+
+ if (sa->proto == SA_INT && addrtypeof(&sa->dst) == AF_INET &&
+ isunspecaddr(&sa->dst)) {
+ switch (ntohl(sa->spi)) {
+ case SPI_PASS: p = "%pass"; break;
+ case SPI_DROP: p = "%drop"; break;
+ case SPI_REJECT: p = "%reject"; break;
+ case SPI_HOLD: p = "%hold"; break;
+ case SPI_TRAP: p = "%trap"; break;
+ case SPI_TRAPSUBNET: p = "%trapsubnet"; break;
+ default: p = NULL; break;
+ }
+ if (p != NULL) {
+ strcpy(buf, p);
+ len = strlen(buf);
+ }
+ }
+
+ if (len == 0) { /* general case needed */
+ strcpy(buf, pre);
+ len = strlen(buf);
+ if (showversion) {
+ *(buf+len) = (addrtypeof(&sa->dst) == AF_INET) ? '.' :
+ ':';
+ len++;
+ *(buf+len) = '\0';
+ }
+ len += ultot(ntohl(sa->spi), base, buf+len, sizeof(buf)-len);
+ *(buf+len-1) = '@';
+ len += addrtot(&sa->dst, 0, buf+len, sizeof(buf)-len);
+ }
+
+ if (dst != NULL) {
+ if (len > dstlen)
+ *(buf+dstlen-1) = '\0';
+ strcpy(dst, buf);
+ }
+ return len;
+}
diff --git a/src/libfreeswan/subnetof.3 b/src/libfreeswan/subnetof.3
new file mode 100644
index 000000000..1911e499f
--- /dev/null
+++ b/src/libfreeswan/subnetof.3
@@ -0,0 +1,47 @@
+.TH IPSEC_SUBNETOF 3 "11 June 2001"
+.\" RCSID $Id: subnetof.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec subnetof \- given Internet address and subnet mask, return subnet number
+.br
+ipsec hostof \- given Internet address and subnet mask, return host part
+.br
+ipsec broadcastof \- given Internet address and subnet mask, return broadcast address
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "struct in_addr subnetof(struct in_addr addr,"
+.ti +1c
+.B "struct in_addr mask);"
+.br
+.B "struct in_addr hostof(struct in_addr addr,"
+.ti +1c
+.B "struct in_addr mask);"
+.br
+.B "struct in_addr broadcastof(struct in_addr addr,"
+.ti +1c
+.B "struct in_addr mask);"
+.SH DESCRIPTION
+These functions are obsolete; see
+.IR ipsec_networkof (3)
+for their replacements.
+.PP
+.I Subnetof
+takes an Internet
+.I address
+and a subnet
+.I mask
+and returns the network part of the address
+(all in network byte order).
+.I Hostof
+similarly returns the host part, and
+.I broadcastof
+returns the broadcast address (all-1s convention) for the network.
+.PP
+These functions are provided to hide the Internet bit-munging inside
+an API, in hopes of easing the eventual transition to IPv6.
+.SH SEE ALSO
+inet(3), ipsec_atosubnet(3)
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+Calling functions for this is more costly than doing it yourself.
diff --git a/src/libfreeswan/subnetof.c b/src/libfreeswan/subnetof.c
new file mode 100644
index 000000000..1b288c591
--- /dev/null
+++ b/src/libfreeswan/subnetof.c
@@ -0,0 +1,60 @@
+/*
+ * minor network-address manipulation utilities
+ * Copyright (C) 1998, 1999 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.
+ *
+ * RCSID $Id: subnetof.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - subnetof - given address and mask, return subnet part
+ */
+struct in_addr
+subnetof(addr, mask)
+struct in_addr addr;
+struct in_addr mask;
+{
+ struct in_addr result;
+
+ result.s_addr = addr.s_addr & mask.s_addr;
+ return result;
+}
+
+/*
+ - hostof - given address and mask, return host part
+ */
+struct in_addr
+hostof(addr, mask)
+struct in_addr addr;
+struct in_addr mask;
+{
+ struct in_addr result;
+
+ result.s_addr = addr.s_addr & ~mask.s_addr;
+ return result;
+}
+
+/*
+ - broadcastof - given (network) address and mask, return broadcast address
+ */
+struct in_addr
+broadcastof(addr, mask)
+struct in_addr addr;
+struct in_addr mask;
+{
+ struct in_addr result;
+
+ result.s_addr = addr.s_addr | ~mask.s_addr;
+ return result;
+}
diff --git a/src/libfreeswan/subnettoa.c b/src/libfreeswan/subnettoa.c
new file mode 100644
index 000000000..36cad8b88
--- /dev/null
+++ b/src/libfreeswan/subnettoa.c
@@ -0,0 +1,62 @@
+/*
+ * convert binary form of subnet description to ASCII
+ * Copyright (C) 1998, 1999 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.
+ *
+ * RCSID $Id: subnettoa.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - subnettoa - convert address and mask to ASCII "addr/mask"
+ * Output expresses the mask as a bit count if possible, else dotted decimal.
+ */
+size_t /* space needed for full conversion */
+subnettoa(addr, mask, format, dst, dstlen)
+struct in_addr addr;
+struct in_addr mask;
+int format; /* character */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ size_t len;
+ size_t rest;
+ int n;
+ char *p;
+
+ switch (format) {
+ case 0:
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ len = addrtoa(addr, 0, dst, dstlen);
+ if (len < dstlen) {
+ dst[len - 1] = '/';
+ p = dst + len;
+ rest = dstlen - len;
+ } else {
+ p = NULL;
+ rest = 0;
+ }
+
+ n = masktobits(mask);
+ if (n >= 0)
+ len += ultoa((unsigned long)n, 10, p, rest);
+ else
+ len += addrtoa(mask, 0, p, rest);
+
+ return len;
+}
diff --git a/src/libfreeswan/subnettot.c b/src/libfreeswan/subnettot.c
new file mode 100644
index 000000000..0385d25e5
--- /dev/null
+++ b/src/libfreeswan/subnettot.c
@@ -0,0 +1,56 @@
+/*
+ * convert binary form of subnet description to text
+ * 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.
+ *
+ * RCSID $Id: subnettot.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - subnettot - convert subnet to text "addr/bitcount"
+ */
+size_t /* space needed for full conversion */
+subnettot(sub, format, dst, dstlen)
+const ip_subnet *sub;
+int format; /* character */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ size_t len;
+ size_t rest;
+ char *p;
+
+ switch (format) {
+ case 0:
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ len = addrtot(&sub->addr, format, dst, dstlen);
+ if (len < dstlen) {
+ dst[len - 1] = '/';
+ p = dst + len;
+ rest = dstlen - len;
+ } else {
+ p = NULL;
+ rest = 0;
+ }
+
+
+ len += ultoa((unsigned long)sub->maskbits, 10, p, rest);
+
+ return len;
+}
diff --git a/src/libfreeswan/subnettypeof.c b/src/libfreeswan/subnettypeof.c
new file mode 100644
index 000000000..6f44b2e4b
--- /dev/null
+++ b/src/libfreeswan/subnettypeof.c
@@ -0,0 +1,109 @@
+/*
+ * extract parts of an ip_subnet, and related
+ * 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.
+ *
+ * RCSID $Id: subnettypeof.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - subnettypeof - get the address type of an ip_subnet
+ */
+int
+subnettypeof(src)
+const ip_subnet *src;
+{
+ return src->addr.u.v4.sin_family;
+}
+
+/*
+ - networkof - get the network address of a subnet
+ */
+void
+networkof(src, dst)
+const ip_subnet *src;
+ip_address *dst;
+{
+ *dst = src->addr;
+}
+
+/*
+ - maskof - get the mask of a subnet, as an address
+ */
+void
+maskof(src, dst)
+const ip_subnet *src;
+ip_address *dst;
+{
+ int b;
+ unsigned char buf[16];
+ size_t n = addrlenof(&src->addr);
+ unsigned char *p;
+
+ if (src->maskbits > n*8 || n > sizeof(buf))
+ return; /* "can't happen" */
+
+ p = buf;
+ for (b = src->maskbits; b >= 8; b -= 8)
+ *p++ = 0xff;
+ if (b != 0)
+ *p++ = (0xff << (8 - b)) & 0xff;
+ while (p - buf < n)
+ *p++ = 0;
+
+ (void) initaddr(buf, n, addrtypeof(&src->addr), dst);
+}
+
+/*
+ - masktocount - convert a mask, expressed as an address, to a bit count
+ */
+int /* -1 if not valid mask */
+masktocount(src)
+const ip_address *src;
+{
+ int b;
+ unsigned const char *bp;
+ size_t n;
+ unsigned const char *p;
+ unsigned const char *stop;
+
+ n = addrbytesptr(src, &bp);
+ if (n == 0)
+ return -1;
+
+ p = bp;
+ stop = bp + n;
+
+ n = 0;
+ while (p < stop && *p == 0xff) {
+ p++;
+ n += 8;
+ }
+ if (p < stop && *p != 0) { /* boundary in mid-byte */
+ b = *p++;
+ while (b&0x80) {
+ b <<= 1;
+ n++;
+ }
+ if ((b&0xff) != 0)
+ return -1; /* bits not contiguous */
+ }
+ while (p < stop && *p == 0)
+ p++;
+
+ if (p != stop)
+ return -1;
+
+ return n;
+}
diff --git a/src/libfreeswan/ttoaddr.3 b/src/libfreeswan/ttoaddr.3
new file mode 100644
index 000000000..5bf48d4b2
--- /dev/null
+++ b/src/libfreeswan/ttoaddr.3
@@ -0,0 +1,377 @@
+.TH IPSEC_TTOADDR 3 "28 Sept 2001"
+.\" RCSID $Id: ttoaddr.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec ttoaddr, tnatoaddr, addrtot \- convert Internet addresses to and from text
+.br
+ipsec ttosubnet, subnettot \- convert subnet/mask text form to and from addresses
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "const char *ttoaddr(const char *src, size_t srclen,"
+.ti +1c
+.B "int af, ip_address *addr);"
+.br
+.B "const char *tnatoaddr(const char *src, size_t srclen,"
+.ti +1c
+.B "int af, ip_address *addr);"
+.br
+.B "size_t addrtot(const ip_address *addr, int format,"
+.ti +1c
+.B "char *dst, size_t dstlen);"
+.sp
+.B "const char *ttosubnet(const char *src, size_t srclen,"
+.ti +1c
+.B "int af, ip_subnet *dst);"
+.br
+.B "size_t subnettot(const ip_subnet *sub, int format,"
+.ti +1c
+.B "char *dst, size_t dstlen);"
+.SH DESCRIPTION
+.I Ttoaddr
+converts a text-string name or numeric address into a binary address
+(in network byte order).
+.I Tnatoaddr
+does the same conversion,
+but the only text forms it accepts are
+the ``official'' forms of
+numeric address (dotted-decimal for IPv4, colon-hex for IPv6).
+.I Addrtot
+does the reverse conversion, from binary address back to a text form.
+.I Ttosubnet
+and
+.I subnettot
+do likewise for the ``address/mask'' form used to write a
+specification of a subnet.
+.PP
+An IPv4 address is specified in text as a
+dotted-decimal address (e.g.
+.BR 1.2.3.4 ),
+an eight-digit network-order hexadecimal number with the usual C prefix (e.g.
+.BR 0x01020304 ,
+which is synonymous with
+.BR 1.2.3.4 ),
+an eight-digit host-order hexadecimal number with a
+.B 0h
+prefix (e.g.
+.BR 0h01020304 ,
+which is synonymous with
+.B 1.2.3.4
+on a big-endian host and
+.B 4.3.2.1
+on a little-endian host),
+a DNS name to be looked up via
+.IR gethostbyname (3),
+or an old-style network name to be looked up via
+.IR getnetbyname (3).
+.PP
+A dotted-decimal address may be incomplete, in which case
+text-to-binary conversion implicitly appends
+as many instances of
+.B .0
+as necessary to bring it up to four components.
+The components of a dotted-decimal address are always taken as
+decimal, and leading zeros are ignored.
+For example,
+.B 10
+is synonymous with
+.BR 10.0.0.0 ,
+and
+.B 128.009.000.032
+is synonymous with
+.BR 128.9.0.32
+(the latter example is verbatim from RFC 1166).
+The result of applying
+.I addrtot
+to an IPv4 address is always complete and does not contain leading zeros.
+.PP
+Use of hexadecimal addresses is
+.B strongly
+.BR discouraged ;
+they are included only to save hassles when dealing with
+the handful of perverted programs which already print
+network addresses in hexadecimal.
+.PP
+An IPv6 address is specified in text with
+colon-hex notation (e.g.
+.BR 0:56:78ab:22:33:44:55:66 ),
+colon-hex with
+.B ::
+abbreviating at most one subsequence of multiple zeros (e.g.
+.BR 99:ab::54:068 ,
+which is synonymous with
+.BR 99:ab:0:0:0:0:54:68 ),
+or a DNS name to be looked up via
+.IR gethostbyname (3).
+The result of applying
+.I addrtot
+to an IPv6 address will use
+.B ::
+abbreviation if possible,
+and will not contain leading zeros.
+.PP
+The letters in hexadecimal
+may be uppercase or lowercase or any mixture thereof.
+.PP
+DNS names may be complete (optionally terminated with a ``.'')
+or incomplete, and are looked up as specified by local system configuration
+(see
+.IR resolver (5)).
+The
+.I h_addr
+value returned by
+.IR gethostbyname2 (3)
+is used,
+so with current DNS implementations,
+the result when the name corresponds to more than one address is
+difficult to predict.
+IPv4 name lookup resorts to
+.IR getnetbyname (3)
+only if
+.IR gethostbyname2 (3)
+fails.
+.PP
+A subnet specification is of the form \fInetwork\fB/\fImask\fR.
+The
+.I network
+and
+.I mask
+can be any form acceptable to
+.IR ttoaddr .
+In addition, and preferably, the
+.I mask
+can be a decimal integer (leading zeros ignored) giving a bit count,
+in which case
+it stands for a mask with that number of high bits on and all others off
+(e.g.,
+.B 24
+in IPv4 means
+.BR 255.255.255.0 ).
+In any case, the mask must be contiguous
+(a sequence of high bits on and all remaining low bits off).
+As a special case, the subnet specification
+.B %default
+is a synonym for
+.B 0.0.0.0/0
+or
+.B ::/0
+in IPv4 or IPv6 respectively.
+.PP
+.I Ttosubnet
+ANDs the mask with the address before returning,
+so that any non-network bits in the address are turned off
+(e.g.,
+.B 10.1.2.3/24
+is synonymous with
+.BR 10.1.2.0/24 ).
+.I Subnettot
+always generates the decimal-integer-bit-count
+form of the mask,
+with no leading zeros.
+.PP
+The
+.I srclen
+parameter of
+.I ttoaddr
+and
+.I ttosubnet
+specifies the length of the text string pointed to by
+.IR src ;
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+.I srclen
+value of
+.B 0
+is taken to mean
+.BR strlen(src) .
+.PP
+The
+.I af
+parameter of
+.I ttoaddr
+and
+.I ttosubnet
+specifies the address family of interest.
+It should be either
+.B AF_INET
+or
+.BR AF_INET6 .
+.PP
+The
+.I dstlen
+parameter of
+.I addrtot
+and
+.I subnettot
+specifies the size of the
+.I dst
+parameter;
+under no circumstances are more than
+.I dstlen
+bytes written to
+.IR dst .
+A result which will not fit is truncated.
+.I Dstlen
+can be zero, in which case
+.I dst
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+.I freeswan.h
+header file defines constants,
+.B ADDRTOT_BUF
+and
+.BR SUBNETTOT_BUF ,
+which are the sizes of buffers just large enough for worst-case results.
+.PP
+The
+.I format
+parameter of
+.I addrtot
+and
+.I subnettot
+specifies what format is to be used for the conversion.
+The value
+.B 0
+(not the character
+.BR '0' ,
+but a zero value)
+specifies a reasonable default,
+and is in fact the only format currently available in
+.IR subnettot .
+.I Addrtot
+also accepts format values
+.B 'r'
+(signifying a text form suitable for DNS reverse lookups,
+e.g.
+.B 4.3.2.1.IN-ADDR.ARPA.
+for IPv4 and
+RFC 2874 format for IPv6),
+and
+.B 'R'
+(signifying an alternate reverse-lookup form,
+an error for IPv4 and RFC 1886 format for IPv6).
+Reverse-lookup names always end with a ``.''.
+.PP
+The text-to-binary functions return NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+The binary-to-text functions return
+.B 0
+for a failure, and otherwise
+always return the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+.SH SEE ALSO
+inet(3)
+.SH DIAGNOSTICS
+Fatal errors in
+.I ttoaddr
+are:
+empty input;
+unknown address family;
+attempt to allocate temporary storage for a very long name failed;
+name lookup failed;
+syntax error in dotted-decimal or colon-hex form;
+dotted-decimal or colon-hex component too large.
+.PP
+Fatal errors in
+.I ttosubnet
+are:
+no
+.B /
+in
+.IR src ;
+.I ttoaddr
+error in conversion of
+.I network
+or
+.IR mask ;
+bit-count mask too big;
+mask non-contiguous.
+.PP
+Fatal errors in
+.I addrtot
+and
+.I subnettot
+are:
+unknown format.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+The interpretation of incomplete dotted-decimal addresses
+(e.g.
+.B 10/24
+means
+.BR 10.0.0.0/24 )
+differs from that of some older conversion
+functions, e.g. those of
+.IR inet (3).
+The behavior of the older functions has never been
+particularly consistent or particularly useful.
+.PP
+Ignoring leading zeros in dotted-decimal components and bit counts
+is arguably the most useful behavior in this application,
+but it might occasionally cause confusion with the historical use of leading
+zeros to denote octal numbers.
+.PP
+.I Ttoaddr
+does not support the mixed colon-hex-dotted-decimal
+convention used to embed an IPv4 address in an IPv6 address.
+.PP
+.I Addrtot
+always uses the
+.B ::
+abbreviation (which can appear only once in an address) for the
+.I first
+sequence of multiple zeros in an IPv6 address.
+One can construct addresses (unlikely ones) in which this is suboptimal.
+.PP
+.I Addrtot
+.B 'r'
+conversion of an IPv6 address uses lowercase hexadecimal,
+not the uppercase used in RFC 2874's examples.
+It takes careful reading of RFCs 2874, 2673, and 2234 to realize
+that lowercase is technically legitimate here,
+and there may be software which botches this
+and hence would have trouble with lowercase hex.
+.PP
+Possibly
+.I subnettot
+ought to recognize the
+.B %default
+case and generate that string as its output.
+Currently it doesn't.
+.PP
+It is barely possible that somebody, somewhere,
+might have a legitimate use for non-contiguous subnet masks.
+.PP
+.IR Getnetbyname (3)
+is a historical dreg.
+.PP
+.I Tnatoaddr
+probably should enforce completeness of dotted-decimal addresses.
+.PP
+The restriction of text-to-binary error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+.PP
+The text-to-binary error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+.PP
+.RS
+.nf
+.B "const char *error;"
+.sp
+.B "error = ttoaddr( /* ... */ );"
+.B "if (error != NULL) {"
+.B " /* something went wrong */"
+.fi
+.RE
diff --git a/src/libfreeswan/ttoaddr.c b/src/libfreeswan/ttoaddr.c
new file mode 100644
index 000000000..efcb33e9f
--- /dev/null
+++ b/src/libfreeswan/ttoaddr.c
@@ -0,0 +1,426 @@
+/*
+ * conversion from text forms of addresses to internal ones
+ * 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.
+ *
+ * RCSID $Id: ttoaddr.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ * Legal ASCII characters in a domain name. Underscore technically is not,
+ * but is a common misunderstanding. Non-ASCII characters are simply
+ * exempted from checking at the moment, to allow for UTF-8 encoded stuff;
+ * the purpose of this check is merely to catch blatant errors.
+ */
+static const char namechars[] = "abcdefghijklmnopqrstuvwxyz0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ-_.";
+#define ISASCII(c) (((c) & 0x80) == 0)
+
+static err_t tryname(const char *, size_t, int, int, ip_address *);
+static err_t tryhex(const char *, size_t, int, ip_address *);
+static err_t trydotted(const char *, size_t, ip_address *);
+static err_t getbyte(const char **, const char *, int *);
+static err_t colon(const char *, size_t, ip_address *);
+static err_t getpiece(const char **, const char *, unsigned *);
+
+/*
+ - ttoaddr - convert text name or dotted-decimal address to binary address
+ */
+err_t /* NULL for success, else string literal */
+ttoaddr(src, srclen, af, dst)
+const char *src;
+size_t srclen; /* 0 means "apply strlen" */
+int af; /* address family */
+ip_address *dst;
+{
+ err_t oops;
+# define HEXLEN 10 /* strlen("0x11223344") */
+ int nultermd;
+
+ if (srclen == 0) {
+ srclen = strlen(src);
+ if (srclen == 0)
+ return "empty string";
+ nultermd = 1;
+ } else
+ nultermd = 0; /* at least, not *known* to be terminated */
+
+ switch (af) {
+ case AF_INET:
+ case AF_INET6:
+ case 0: /* guess */
+ break;
+
+ default:
+ return "invalid address family";
+ }
+
+ if (af == AF_INET && srclen == HEXLEN && *src == '0') {
+ if (*(src+1) == 'x' || *(src+1) == 'X')
+ return tryhex(src+2, srclen-2, 'x', dst);
+ if (*(src+1) == 'h' || *(src+1) == 'H')
+ return tryhex(src+2, srclen-2, 'h', dst);
+ }
+
+ if (memchr(src, ':', srclen) != NULL) {
+ if(af == 0)
+ {
+ af = AF_INET6;
+ }
+
+ if (af != AF_INET6)
+ return "non-ipv6 address may not contain `:'";
+ return colon(src, srclen, dst);
+ }
+
+ if (af == 0 || af == AF_INET) {
+ oops = trydotted(src, srclen, dst);
+ if (oops == NULL)
+ return NULL; /* it worked */
+ if (*oops != '?')
+ return oops; /* probably meant as d-d */
+ }
+
+ return tryname(src, srclen, nultermd, af, dst);
+}
+
+/*
+ - tnatoaddr - convert text numeric address (only) to binary address
+ */
+err_t /* NULL for success, else string literal */
+tnatoaddr(src, srclen, af, dst)
+const char *src;
+size_t srclen; /* 0 means "apply strlen" */
+int af; /* address family */
+ip_address *dst;
+{
+ err_t oops;
+
+ if (srclen == 0) {
+ srclen = strlen(src);
+ if (srclen == 0)
+ return "empty string";
+ }
+
+ switch (af) {
+ case 0: /* guess */
+ oops = colon(src, srclen, dst);
+ if(oops == NULL)
+ {
+ return NULL;
+ }
+ oops = trydotted(src, srclen, dst);
+ if(oops == NULL)
+ {
+ return NULL;
+ }
+ return "does not appear to be either IPv4 or IPv6 numeric address";
+ break;
+
+ case AF_INET6:
+ return colon(src, srclen, dst);
+ break;
+ case AF_INET:
+ oops = trydotted(src, srclen, dst);
+ if (oops == NULL)
+ return NULL; /* it worked */
+ if (*oops != '?')
+ return oops; /* probably meant as d-d */
+ return "does not appear to be numeric address";
+ break;
+ default:
+ return "unknown address family in tnatoaddr";
+ break;
+ }
+}
+
+/*
+ - tryname - try it as a name
+ * Slightly complicated by lack of reliable NUL termination in source.
+ */
+static err_t
+tryname(src, srclen, nultermd, af, dst)
+const char *src;
+size_t srclen;
+int nultermd; /* is it known to be NUL-terminated? */
+int af;
+ip_address *dst;
+{
+ struct hostent *h;
+ struct netent *ne = NULL;
+ char namebuf[100]; /* enough for most DNS names */
+ const char *cp;
+ char *p = namebuf;
+ size_t n;
+
+ for (cp = src, n = srclen; n > 0; cp++, n--)
+ if (ISASCII(*cp) && strchr(namechars, *cp) == NULL)
+ return "illegal (non-DNS-name) character in name";
+
+ if (nultermd)
+ cp = src;
+ else {
+ if (srclen+1 > sizeof(namebuf)) {
+ p = (char *) MALLOC(srclen+1);
+ if (p == NULL)
+ return "unable to get temporary space for name";
+ }
+ p[0] = '\0'; /* strncpy semantics are wrong */
+ strncat(p, src, srclen);
+ cp = (const char *)p;
+ }
+
+ h = gethostbyname2(cp, af);
+ if (h == NULL && af == AF_INET)
+ ne = getnetbyname(cp);
+ if (p != namebuf)
+ FREE(p);
+ if (h == NULL && ne == NULL)
+ return "does not look numeric and name lookup failed";
+
+ if (h != NULL) {
+ if (h->h_addrtype != af)
+ return "address-type mismatch from gethostbyname2!!!";
+ return initaddr((unsigned char *)h->h_addr, h->h_length, af, dst);
+ } else {
+ if (ne->n_addrtype != af)
+ return "address-type mismatch from getnetbyname!!!";
+ ne->n_net = htonl(ne->n_net);
+ return initaddr((unsigned char *)&ne->n_net, sizeof(ne->n_net),
+ af, dst);
+ }
+}
+
+/*
+ - tryhex - try conversion as an eight-digit hex number (AF_INET only)
+ */
+static err_t
+tryhex(src, srclen, flavor, dst)
+const char *src;
+size_t srclen; /* should be 8 */
+int flavor; /* 'x' for network order, 'h' for host order */
+ip_address *dst;
+{
+ err_t oops;
+ unsigned long ul;
+ union {
+ uint32_t addr;
+ unsigned char buf[4];
+ } u;
+
+ if (srclen != 8)
+ return "internal error, tryhex called with bad length";
+
+ oops = ttoul(src, srclen, 16, &ul);
+ if (oops != NULL)
+ return oops;
+
+ u.addr = (flavor == 'h') ? ul : htonl(ul);
+ return initaddr(u.buf, sizeof(u.buf), AF_INET, dst);
+}
+
+/*
+ - trydotted - try conversion as dotted decimal (AF_INET only)
+ *
+ * If the first char of a complaint is '?', that means "didn't look like
+ * dotted decimal at all".
+ */
+static err_t
+trydotted(src, srclen, dst)
+const char *src;
+size_t srclen;
+ip_address *dst;
+{
+ const char *stop = src + srclen; /* just past end */
+ int byte;
+ err_t oops;
+# define NBYTES 4
+ unsigned char buf[NBYTES];
+ int i;
+
+ memset(buf, 0, sizeof(buf));
+ for (i = 0; i < NBYTES && src < stop; i++) {
+ oops = getbyte(&src, stop, &byte);
+ if (oops != NULL) {
+ if (*oops != '?')
+ return oops; /* bad number */
+ if (i > 1)
+ return oops+1; /* failed number */
+ return oops; /* with leading '?' */
+ }
+ buf[i] = byte;
+ if (i < 3 && src < stop && *src++ != '.') {
+ if (i == 0)
+ return "?syntax error in dotted-decimal address";
+ else
+ return "syntax error in dotted-decimal address";
+ }
+ }
+ if (src != stop)
+ return "extra garbage on end of dotted-decimal address";
+
+ return initaddr(buf, sizeof(buf), AF_INET, dst);
+}
+
+/*
+ - getbyte - try to scan a byte in dotted decimal
+ * A subtlety here is that all this arithmetic on ASCII digits really is
+ * highly portable -- ANSI C guarantees that digits 0-9 are contiguous.
+ * It's easier to just do it ourselves than set up for a call to ttoul().
+ *
+ * If the first char of a complaint is '?', that means "didn't look like a
+ * number at all".
+ */
+err_t
+getbyte(srcp, stop, retp)
+const char **srcp; /* *srcp is updated */
+const char *stop; /* first untouchable char */
+int *retp; /* return-value pointer */
+{
+ char c;
+ const char *p;
+ int no;
+
+ if (*srcp >= stop)
+ return "?empty number in dotted-decimal address";
+
+ no = 0;
+ p = *srcp;
+ while (p < stop && no <= 255 && (c = *p) >= '0' && c <= '9') {
+ no = no*10 + (c - '0');
+ p++;
+ }
+ if (p == *srcp)
+ return "?non-numeric component in dotted-decimal address";
+ *srcp = p;
+ if (no > 255)
+ return "byte overflow in dotted-decimal address";
+ *retp = no;
+ return NULL;
+}
+
+/*
+ - colon - convert IPv6 "numeric" address
+ */
+static err_t
+colon(src, srclen, dst)
+const char *src;
+size_t srclen; /* known to be >0 */
+ip_address *dst;
+{
+ const char *stop = src + srclen; /* just past end */
+ unsigned piece;
+ int gapat; /* where was empty piece seen */
+ err_t oops;
+# define NPIECES 8
+ unsigned char buf[NPIECES*2]; /* short may have wrong byte order */
+ int i;
+ int j;
+# define IT "IPv6 numeric address"
+ int naftergap;
+
+ /* leading or trailing :: becomes single empty field */
+ if (*src == ':') { /* legal only if leading :: */
+ if (srclen == 1 || *(src+1) != ':')
+ return "illegal leading `:' in " IT;
+ if (srclen == 2) {
+ unspecaddr(AF_INET6, dst);
+ return NULL;
+ }
+ src++; /* past first but not second */
+ srclen--;
+ }
+ if (*(stop-1) == ':') { /* legal only if trailing :: */
+ if (srclen == 1 || *(stop-2) != ':')
+ return "illegal trailing `:' in " IT;
+ srclen--; /* leave one */
+ }
+
+ gapat = -1;
+ for (i = 0; i < NPIECES && src < stop; i++) {
+ oops = getpiece(&src, stop, &piece);
+ if (oops != NULL && *oops == ':') { /* empty field */
+ if (gapat >= 0)
+ return "more than one :: in " IT;
+ gapat = i;
+ } else if (oops != NULL)
+ return oops;
+ buf[2*i] = piece >> 8;
+ buf[2*i + 1] = piece & 0xff;
+ if (i < NPIECES-1) { /* there should be more input */
+ if (src == stop && gapat < 0)
+ return IT " ends prematurely";
+ if (src != stop && *src++ != ':')
+ return "syntax error in " IT;
+ }
+ }
+ if (src != stop)
+ return "extra garbage on end of " IT;
+
+ if (gapat < 0 && i < NPIECES) /* should have been caught earlier */
+ return "incomplete " IT " (internal error)";
+ if (gapat >= 0 && i == NPIECES)
+ return "non-abbreviating empty field in " IT;
+ if (gapat >= 0) {
+ naftergap = i - (gapat + 1);
+ for (i--, j = NPIECES-1; naftergap > 0; i--, j--, naftergap--) {
+ buf[2*j] = buf[2*i];
+ buf[2*j + 1] = buf[2*i + 1];
+ }
+ for (; j >= gapat; j--)
+ buf[2*j] = buf[2*j + 1] = 0;
+ }
+
+ return initaddr(buf, sizeof(buf), AF_INET6, dst);
+}
+
+/*
+ - getpiece - try to scan one 16-bit piece of an IPv6 address
+ */
+err_t /* ":" means "empty field seen" */
+getpiece(srcp, stop, retp)
+const char **srcp; /* *srcp is updated */
+const char *stop; /* first untouchable char */
+unsigned *retp; /* return-value pointer */
+{
+ const char *p;
+# define NDIG 4
+ int d;
+ unsigned long ret;
+ err_t oops;
+
+ if (*srcp >= stop || **srcp == ':') { /* empty field */
+ *retp = 0;
+ return ":";
+ }
+
+ p = *srcp;
+ d = 0;
+ while (p < stop && d < NDIG && isxdigit(*p)) {
+ p++;
+ d++;
+ }
+ if (d == 0)
+ return "non-hex field in IPv6 numeric address";
+ if (p < stop && d == NDIG && isxdigit(*p))
+ return "field in IPv6 numeric address longer than 4 hex digits";
+
+ oops = ttoul(*srcp, d, 16, &ret);
+ if (oops != NULL) /* shouldn't happen, really... */
+ return oops;
+
+ *srcp = p;
+ *retp = ret;
+ return NULL;
+}
diff --git a/src/libfreeswan/ttodata.3 b/src/libfreeswan/ttodata.3
new file mode 100644
index 000000000..98bbe4ab3
--- /dev/null
+++ b/src/libfreeswan/ttodata.3
@@ -0,0 +1,281 @@
+.TH IPSEC_TTODATA 3 "16 August 2003"
+.\" RCSID $Id: ttodata.3,v 1.2 2005/07/18 20:13:42 as Exp $
+.SH NAME
+ipsec ttodata, datatot \- convert binary data bytes from and to text formats
+.SH SYNOPSIS
+.B "#include <freeswan.h>"
+.sp
+.B "const char *ttodata(const char *src, size_t srclen,"
+.ti +1c
+.B "int base, char *dst, size_t dstlen, size_t *lenp);"
+.br
+.B "const char *ttodatav(const char *src, size_t srclen,"
+.ti +1c
+.B "int base, char *dst, size_t dstlen, size_t *lenp,"
+.ti +1c
+.B "char *errp, size_t errlen, int flags);"
+.br
+.B "size_t datatot(const char *src, size_t srclen,"
+.ti +1c
+.B "int format, char *dst, size_t dstlen);"
+.SH DESCRIPTION
+.IR Ttodata ,
+.IR ttodatav ,
+and
+.I datatot
+convert arbitrary binary data (e.g. encryption or authentication keys)
+from and to more-or-less human-readable text formats.
+.PP
+Currently supported formats are hexadecimal, base64, and characters.
+.PP
+A hexadecimal text value begins with a
+.B 0x
+(or
+.BR 0X )
+prefix and continues with two-digit groups
+of hexadecimal digits (0-9, and a-f or A-F),
+each group encoding the value of one binary byte, high-order digit first.
+A single
+.B _
+(underscore)
+between consecutive groups is ignored, permitting punctuation to improve
+readability; doing this every eight digits seems about right.
+.PP
+A base64 text value begins with a
+.B 0s
+(or
+.BR 0S )
+prefix
+and continues with four-digit groups of base64 digits (A-Z, a-z, 0-9, +, and /),
+each group encoding the value of three binary bytes as described in
+section 6.8 of RFC 2045.
+If
+.B flags
+has the
+.B TTODATAV_IGNORESPACE
+bit on, blanks are ignore (after the prefix).
+Note that the last one or two digits of a base64 group can be
+.B =
+to indicate that fewer than three binary bytes are encoded.
+.PP
+A character text value begins with a
+.B 0t
+(or
+.BR 0T )
+prefix
+and continues with text characters, each being the value of one binary byte.
+.PP
+All these functions basically copy data from
+.I src
+(whose size is specified by
+.IR srclen )
+to
+.I dst
+(whose size is specified by
+.IR dstlen ),
+doing the conversion en route.
+If the result will not fit in
+.IR dst ,
+it is truncated;
+under no circumstances are more than
+.I dstlen
+bytes of result written to
+.IR dst .
+.I Dstlen
+can be zero, in which case
+.I dst
+need not be valid and no result bytes are written at all.
+.PP
+The
+.I base
+parameter of
+.I ttodata
+and
+.I ttodatav
+specifies what format the input is in;
+normally it should be
+.B 0
+to signify that this gets figured out from the prefix.
+Values of
+.BR 16 ,
+.BR 64 ,
+and
+.BR 256
+respectively signify hexadecimal, base64, and character-text formats
+without prefixes.
+.PP
+The
+.I format
+parameter of
+.IR datatot ,
+a single character used as a type code,
+specifies which text format is wanted.
+The value
+.B 0
+(not ASCII
+.BR '0' ,
+but a zero value) specifies a reasonable default.
+Other currently-supported values are:
+.RS 2
+.TP 4
+.B 'x'
+continuous lower-case hexadecimal with a
+.B 0x
+prefix
+.TP
+.B 'h'
+lower-case hexadecimal with a
+.B 0x
+prefix and a
+.B _
+every eight digits
+.TP
+.B ':'
+lower-case hexadecimal with no prefix and a
+.B :
+(colon) every two digits
+.TP
+.B 16
+lower-case hexadecimal with no prefix or
+.B _
+.TP
+.B 's'
+continuous base64 with a
+.B 0s
+prefix
+.TP
+.B 64
+continuous base64 with no prefix
+.RE
+.PP
+The default format is currently
+.BR 'h' .
+.PP
+.I Ttodata
+returns NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+On success,
+if and only if
+.I lenp
+is non-NULL,
+.B *lenp
+is set to the number of bytes required to contain the full untruncated result.
+It is the caller's responsibility to check this against
+.I dstlen
+to determine whether he has obtained a complete result.
+The
+.B *lenp
+value is correct even if
+.I dstlen
+is zero, which offers a way to determine how much space would be needed
+before having to allocate any.
+.PP
+.I Ttodatav
+is just like
+.I ttodata
+except that in certain cases,
+if
+.I errp
+is non-NULL,
+the buffer pointed to by
+.I errp
+(whose length is given by
+.IR errlen )
+is used to hold a more detailed error message.
+The return value is NULL for success,
+and is either
+.I errp
+or a pointer to a string literal for failure.
+If the size of the error-message buffer is
+inadequate for the desired message,
+.I ttodatav
+will fall back on returning a pointer to a literal string instead.
+The
+.I freeswan.h
+header file defines a constant
+.B TTODATAV_BUF
+which is the size of a buffer large enough for worst-case results.
+.PP
+The normal return value of
+.IR datatot
+is the number of bytes required
+to contain the full untruncated result.
+It is the caller's responsibility to check this against
+.I dstlen
+to determine whether he has obtained a complete result.
+The return value is correct even if
+.I dstlen
+is zero, which offers a way to determine how much space would be needed
+before having to allocate any.
+A return value of
+.B 0
+signals a fatal error of some kind
+(see DIAGNOSTICS).
+.PP
+A zero value for
+.I srclen
+in
+.I ttodata
+(but not
+.IR datatot !)
+is synonymous with
+.BR strlen(src) .
+A non-zero
+.I srclen
+in
+.I ttodata
+must not include the terminating NUL.
+.PP
+Unless
+.I dstlen
+is zero,
+the result supplied by
+.I datatot
+is always NUL-terminated,
+and its needed-size return value includes space for the terminating NUL.
+.PP
+Several obsolete variants of these functions
+.RI ( atodata ,
+.IR datatoa ,
+.IR atobytes ,
+and
+.IR bytestoa )
+are temporarily also supported.
+.SH SEE ALSO
+sprintf(3), ipsec_atoaddr(3)
+.SH DIAGNOSTICS
+Fatal errors in
+.I ttodata
+and
+.I ttodatav
+are:
+unknown characters in the input;
+unknown or missing prefix;
+unknown base;
+incomplete digit group;
+non-zero padding in a base64 less-than-three-bytes digit group;
+zero-length input.
+.PP
+Fatal errors in
+.I datatot
+are:
+unknown format code;
+zero-length input.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+.I Datatot
+should have a format code to produce character-text output.
+.PP
+The
+.B 0s
+and
+.B 0t
+prefixes are the author's inventions and are not a standard
+of any kind.
+They have been chosen to avoid collisions with existing practice
+(some C implementations use
+.B 0b
+for binary)
+and possible confusion with unprefixed hexadecimal.
diff --git a/src/libfreeswan/ttodata.c b/src/libfreeswan/ttodata.c
new file mode 100644
index 000000000..e1bf7606a
--- /dev/null
+++ b/src/libfreeswan/ttodata.c
@@ -0,0 +1,722 @@
+/*
+ * 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.
+ *
+ * RCSID $Id: ttodata.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.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;
+}
+
+
+
+#ifdef TTODATA_MAIN
+
+#include <stdio.h>
+
+struct artab;
+static void check(struct artab *r, char *buf, size_t n, err_t oops, int *status);
+static void regress(char *pgm);
+static void hexout(const char *s, size_t len, FILE *f);
+
+/*
+ - main - convert first argument to hex, or run regression
+ */
+int
+main(int argc, char *argv[])
+{
+ char buf[1024];
+ char buf2[1024];
+ char err[512];
+ size_t n;
+ size_t i;
+ char *p = buf;
+ char *p2 = buf2;
+ char *pgm = argv[0];
+ const char *oops;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s {0x<hex>|0s<base64>|-r}\n", pgm);
+ exit(2);
+ }
+
+ if (strcmp(argv[1], "-r") == 0) {
+ regress(pgm); /* should not return */
+ fprintf(stderr, "%s: regress() returned?!?\n", pgm);
+ exit(1);
+ }
+
+ oops = ttodatav(argv[1], 0, 0, buf, sizeof(buf), &n,
+ err, sizeof(err), TTODATAV_IGNORESPACE);
+ if (oops != NULL) {
+ fprintf(stderr, "%s: ttodata error `%s' in `%s'\n", pgm,
+ oops, argv[1]);
+ exit(1);
+ }
+
+ if (n > sizeof(buf)) {
+ p = (char *)malloc((size_t)n);
+ if (p == NULL) {
+ fprintf(stderr,
+ "%s: unable to malloc %d bytes for result\n",
+ pgm, n);
+ exit(1);
+ }
+ oops = ttodata(argv[1], 0, 0, p, n, &n);
+ if (oops != NULL) {
+ fprintf(stderr, "%s: error `%s' in ttodata retry?!?\n",
+ pgm, oops);
+ exit(1);
+ }
+ }
+
+ hexout(p, n, stdout);
+ printf("\n");
+
+ i = datatot(buf, n, 'h', buf2, sizeof(buf2));
+ if (i == 0) {
+ fprintf(stderr, "%s: datatot reports error in `%s'\n", pgm,
+ argv[1]);
+ exit(1);
+ }
+
+ if (i > sizeof(buf2)) {
+ p2 = (char *)malloc((size_t)i);
+ if (p == NULL) {
+ fprintf(stderr,
+ "%s: unable to malloc %d bytes for result\n",
+ pgm, i);
+ exit(1);
+ }
+ i = datatot(buf, n, 'h', p2, i);
+ if (i == 0) {
+ fprintf(stderr, "%s: error in datatoa retry?!?\n", pgm);
+ exit(1);
+ }
+ }
+
+ printf("%s\n", p2);
+
+ exit(0);
+}
+
+/*
+ - hexout - output an arbitrary-length string in hex
+ */
+static void
+hexout(s, len, f)
+const char *s;
+size_t len;
+FILE *f;
+{
+ size_t i;
+
+ fprintf(f, "0x");
+ for (i = 0; i < len; i++)
+ fprintf(f, "%02x", (unsigned char)s[i]);
+}
+
+struct artab {
+ int base;
+# define IGNORESPACE_BIAS 1000
+ char *ascii; /* NULL for end */
+ char *data; /* NULL for error expected */
+} atodatatab[] = {
+ { 0, "", NULL, },
+ { 0, "0", NULL, },
+ { 0, "0x", NULL, },
+ { 0, "0xa", NULL, },
+ { 0, "0xab", "\xab", },
+ { 0, "0xabc", NULL, },
+ { 0, "0xabcd", "\xab\xcd", },
+ { 0, "0x0123456789", "\x01\x23\x45\x67\x89", },
+ { 0, "0x01x", NULL, },
+ { 0, "0xabcdef", "\xab\xcd\xef", },
+ { 0, "0xABCDEF", "\xab\xcd\xef", },
+ { 0, "0XaBc0eEd81f", "\xab\xc0\xee\xd8\x1f", },
+ { 0, "0XaBc0_eEd8", "\xab\xc0\xee\xd8", },
+ { 0, "0XaBc0_", NULL, },
+ { 0, "0X_aBc0", NULL, },
+ { 0, "0Xa_Bc0", NULL, },
+ { 16, "aBc0eEd8", "\xab\xc0\xee\xd8", },
+ { 0, "0s", NULL, },
+ { 0, "0sA", NULL, },
+ { 0, "0sBA", NULL, },
+ { 0, "0sCBA", NULL, },
+ { 0, "0sDCBA", "\x0c\x20\x40", },
+ { 0, "0SDCBA", "\x0c\x20\x40", },
+ { 0, "0sDA==", "\x0c", },
+ { 0, "0sDC==", NULL, },
+ { 0, "0sDCA=", "\x0c\x20", },
+ { 0, "0sDCB=", NULL, },
+ { 0, "0sDCAZ", "\x0c\x20\x19", },
+ { 0, "0sDCAa", "\x0c\x20\x1a", },
+ { 0, "0sDCAz", "\x0c\x20\x33", },
+ { 0, "0sDCA0", "\x0c\x20\x34", },
+ { 0, "0sDCA9", "\x0c\x20\x3d", },
+ { 0, "0sDCA+", "\x0c\x20\x3e", },
+ { 0, "0sDCA/", "\x0c\x20\x3f", },
+ { 0, "0sAbraCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0s AbraCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sA braCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sAb raCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sAbr aCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sAbra Cadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sAbraC adabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sAbraCa dabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sAbraCad abra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sAbraCada bra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sAbraCadab ra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sAbraCadabr a+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sAbraCadabra +", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sAbraCadabra+ ", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { 0, "0t", NULL, },
+ { 0, "0tabc_xyz", "abc_xyz", },
+ { 256, "abc_xyz", "abc_xyz", },
+ { 0, NULL, NULL, },
+};
+
+struct drtab {
+ char *data; /* input; NULL for end */
+ char format;
+ int buflen; /* -1 means big buffer */
+ int outlen; /* -1 means strlen(ascii)+1 */
+ char *ascii; /* NULL for error expected */
+} datatoatab[] = {
+ { "", 'x', -1, -1, NULL, },
+ { "", 'X', -1, -1, NULL, },
+ { "", 'n', -1, -1, NULL, },
+ { "0", 'x', -1, -1, "0x30", },
+ { "0", 'x', 0, 5, "---", },
+ { "0", 'x', 1, 5, "", },
+ { "0", 'x', 2, 5, "0", },
+ { "0", 'x', 3, 5, "0x", },
+ { "0", 'x', 4, 5, "0x3", },
+ { "0", 'x', 5, 5, "0x30", },
+ { "0", 'x', 6, 5, "0x30", },
+ { "\xab\xcd", 'x', -1, -1, "0xabcd", },
+ { "\x01\x23\x45\x67\x89", 'x', -1, -1, "0x0123456789", },
+ { "\xab\xcd\xef", 'x', -1, -1, "0xabcdef", },
+ { "\xab\xc0\xee\xd8\x1f", 'x', -1, -1, "0xabc0eed81f", },
+ { "\x01\x02", 'h', -1, -1, "0x0102", },
+ { "\x01\x02\x03\x04\x05\x06", 'h', -1, -1, "0x01020304_0506", },
+ { "\xab\xc0\xee\xd8\x1f", 16, -1, -1, "abc0eed81f", },
+ { "\x0c\x20\x40", 's', -1, -1, "0sDCBA", },
+ { "\x0c\x20\x40", 's', 0, 7, "---", },
+ { "\x0c\x20\x40", 's', 1, 7, "", },
+ { "\x0c\x20\x40", 's', 2, 7, "0", },
+ { "\x0c\x20\x40", 's', 3, 7, "0s", },
+ { "\x0c\x20\x40", 's', 4, 7, "0sD", },
+ { "\x0c\x20\x40", 's', 5, 7, "0sDC", },
+ { "\x0c\x20\x40", 's', 6, 7, "0sDCB", },
+ { "\x0c\x20\x40", 's', 7, 7, "0sDCBA", },
+ { "\x0c\x20\x40", 's', 8, 7, "0sDCBA", },
+ { "\x0c", 's', -1, -1, "0sDA==", },
+ { "\x0c\x20", 's', -1, -1, "0sDCA=", },
+ { "\x0c\x20\x19", 's', -1, -1, "0sDCAZ", },
+ { "\x0c\x20\x1a", 's', -1, -1, "0sDCAa", },
+ { "\x0c\x20\x33", 's', -1, -1, "0sDCAz", },
+ { "\x0c\x20\x34", 's', -1, -1, "0sDCA0", },
+ { "\x0c\x20\x3d", 's', -1, -1, "0sDCA9", },
+ { "\x0c\x20\x3e", 's', -1, -1, "0sDCA+", },
+ { "\x0c\x20\x3f", 's', -1, -1, "0sDCA/", },
+ { "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", 's', -1, -1, "0sAbraCadabra+", },
+ { "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", 64, -1, -1, "AbraCadabra+", },
+ { NULL, 'x', -1, -1, NULL, },
+};
+
+/*
+ - regress - regression-test ttodata() and datatot()
+ */
+static void
+check(r, buf, n, oops, status)
+struct artab *r;
+char *buf;
+size_t n;
+err_t oops;
+int *status;
+{
+ if (oops != NULL && r->data == NULL)
+ {} /* error expected */
+ else if (oops != NULL) {
+ printf("`%s' gave error `%s', expecting %d `", r->ascii,
+ oops, strlen(r->data));
+ hexout(r->data, strlen(r->data), stdout);
+ printf("'\n");
+ *status = 1;
+ } else if (r->data == NULL) {
+ printf("`%s' gave %d `", r->ascii, n);
+ hexout(buf, n, stdout);
+ printf("', expecting error\n");
+ *status = 1;
+ } else if (n != strlen(r->data)) {
+ printf("length wrong in `%s': got %d `", r->ascii, n);
+ hexout(buf, n, stdout);
+ printf("', expecting %d `", strlen(r->data));
+ hexout(r->data, strlen(r->data), stdout);
+ printf("'\n");
+ *status = 1;
+ } else if (memcmp(buf, r->data, n) != 0) {
+ printf("`%s' gave %d `", r->ascii, n);
+ hexout(buf, n, stdout);
+ printf("', expecting %d `", strlen(r->data));
+ hexout(r->data, strlen(r->data), stdout);
+ printf("'\n");
+ *status = 1;
+ }
+ fflush(stdout);
+}
+
+static void /* should not return at all, in fact */
+regress(pgm)
+char *pgm;
+{
+ struct artab *r;
+ struct drtab *dr;
+ char buf[100];
+ size_t n;
+ int status = 0;
+
+ for (r = atodatatab; r->ascii != NULL; r++) {
+ int base = r->base;
+ int xbase = 0;
+
+ if ((base == 0 || base == IGNORESPACE_BIAS + 0) && r->ascii[0] == '0') {
+ switch (r->ascii[1]) {
+ case 'x':
+ case 'X':
+ xbase = 16;
+ break;
+ case 's':
+ case 'S':
+ xbase = 64;
+ break;
+ case 't':
+ case 'T':
+ xbase = 256;
+ break;
+ }
+ }
+
+ if (base >= IGNORESPACE_BIAS) {
+ base = base - IGNORESPACE_BIAS;
+ check(r, buf, n, ttodatav(r->ascii, 0, base, buf, sizeof(buf), &n, NULL, 0, TTODATAV_IGNORESPACE), &status);
+ if (xbase != 0)
+ check(r, buf, n, ttodatav(r->ascii+2, 0, xbase, buf, sizeof(buf), &n, NULL, 0, TTODATAV_IGNORESPACE), &status);
+ } else {
+ check(r, buf, n, ttodata(r->ascii, 0, base, buf, sizeof(buf), &n), &status);
+ if (base == 64 || xbase == 64)
+ check(r, buf, n, ttodatav(r->ascii, 0, base, buf, sizeof(buf), &n, NULL, 0, TTODATAV_IGNORESPACE), &status);
+ if (xbase != 0) {
+ check(r, buf, n, ttodata(r->ascii+2, 0, xbase, buf, sizeof(buf), &n), &status);
+ if (base == 64 || xbase == 64)
+ check(r, buf, n, ttodatav(r->ascii+2, 0, xbase, buf, sizeof(buf), &n, NULL, 0, TTODATAV_IGNORESPACE), &status);
+ }
+ }
+ }
+ for (dr = datatoatab; dr->data != NULL; dr++) {
+ size_t should;
+
+ strcpy(buf, "---");
+ n = datatot(dr->data, strlen(dr->data), dr->format, buf,
+ (dr->buflen == -1) ? sizeof(buf) : dr->buflen);
+ should = (dr->ascii == NULL) ? 0 : strlen(dr->ascii) + 1;
+ if (dr->outlen != -1)
+ should = dr->outlen;
+ if (n == 0 && dr->ascii == NULL)
+ {} /* error expected */
+ else if (n == 0) {
+ printf("`");
+ hexout(dr->data, strlen(dr->data), stdout);
+ printf("' %c gave error, expecting %d `%s'\n",
+ dr->format, should, dr->ascii);
+ status = 1;
+ } else if (dr->ascii == NULL) {
+ printf("`");
+ hexout(dr->data, strlen(dr->data), stdout);
+ printf("' %c gave %d `%.*s', expecting error\n",
+ dr->format, n, (int)n, buf);
+ status = 1;
+ } else if (n != should) {
+ printf("length wrong in `");
+ hexout(dr->data, strlen(dr->data), stdout);
+ printf("': got %d `%s'", n, buf);
+ printf(", expecting %d `%s'\n", should, dr->ascii);
+ status = 1;
+ } else if (strcmp(buf, dr->ascii) != 0) {
+ printf("`");
+ hexout(dr->data, strlen(dr->data), stdout);
+ printf("' gave %d `%s'", n, buf);
+ printf(", expecting %d `%s'\n", should, dr->ascii);
+ status = 1;
+ }
+ fflush(stdout);
+ }
+ exit(status);
+}
+
+#endif /* TTODATA_MAIN */
diff --git a/src/libfreeswan/ttoprotoport.c b/src/libfreeswan/ttoprotoport.c
new file mode 100644
index 000000000..46321838c
--- /dev/null
+++ b/src/libfreeswan/ttoprotoport.c
@@ -0,0 +1,103 @@
+/*
+ * conversion from protocol/port string to protocol and port
+ * Copyright (C) 2002 Mario Strasser <mast@gmx.net>,
+ * 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.
+ *
+ * RCSID $Id: ttoprotoport.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ * ttoprotoport - converts from protocol/port string to protocol and port
+ */
+err_t
+ttoprotoport(src, src_len, proto, port, has_port_wildcard)
+char *src; /* input string */
+size_t src_len; /* length of input string, use strlen() if 0 */
+u_int8_t *proto; /* extracted protocol number */
+u_int16_t *port; /* extracted port number if it exists */
+int *has_port_wildcard; /* set if port is %any */
+{
+ char *end, *service_name;
+ char proto_name[16];
+ int proto_len;
+ long int l;
+ struct protoent *protocol;
+ struct servent *service;
+
+ /* get the length of the string */
+ if (!src_len) src_len = strlen(src);
+
+ /* locate delimiter '/' between protocol and port */
+ end = strchr(src, '/');
+ if (end != NULL) {
+ proto_len = end - src;
+ service_name = end + 1;
+ } else {
+ proto_len = src_len;
+ service_name = src + src_len;
+ }
+
+ /* copy protocol name*/
+ memset(proto_name, '\0', sizeof(proto_name));
+ memcpy(proto_name, src, proto_len);
+
+ /* extract protocol by trying to resolve it by name */
+ protocol = getprotobyname(proto_name);
+ if (protocol != NULL) {
+ *proto = protocol->p_proto;
+ }
+ else /* failed, now try it by number */
+ {
+ l = strtol(proto_name, &end, 0);
+
+ if (*proto_name && *end)
+ return "<protocol> is neither a number nor a valid name";
+
+ if (l < 0 || l > 0xff)
+ return "<protocol> must be between 0 and 255";
+
+ *proto = (u_int8_t)l;
+ }
+
+ /* is there a port wildcard? */
+ *has_port_wildcard = (strcmp(service_name, "%any") == 0);
+
+ if (*has_port_wildcard)
+ {
+ *port = 0;
+ return NULL;
+ }
+
+ /* extract port by trying to resolve it by name */
+ service = getservbyname(service_name, NULL);
+ if (service != NULL) {
+ *port = ntohs(service->s_port);
+ }
+ else /* failed, now try it by number */
+ {
+ l = strtol(service_name, &end, 0);
+
+ if (*service_name && *end)
+ return "<port> is neither a number nor a valid name";
+
+ if (l < 0 || l > 0xffff)
+ return "<port> must be between 0 and 65535";
+
+ *port = (u_int16_t)l;
+ }
+ return NULL;
+}
+
diff --git a/src/libfreeswan/ttosa.3 b/src/libfreeswan/ttosa.3
new file mode 100644
index 000000000..bf918e108
--- /dev/null
+++ b/src/libfreeswan/ttosa.3
@@ -0,0 +1,288 @@
+.TH IPSEC_TTOSA 3 "26 Nov 2001"
+.\" RCSID $Id: ttosa.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec ttosa, satot \- convert IPsec Security Association IDs to and from text
+.br
+ipsec initsaid \- initialize an SA ID
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "typedef struct {"
+.ti +1c
+.B "ip_address dst;"
+.ti +1c
+.B "ipsec_spi_t spi;"
+.ti +1c
+.B "int proto;"
+.br
+.B "} ip_said;"
+.sp
+.B "const char *ttosa(const char *src, size_t srclen,"
+.ti +1c
+.B "ip_said *sa);
+.br
+.B "size_t satot(const ip_said *sa, int format,"
+.ti +1c
+.B "char *dst, size_t dstlen);"
+.br
+.B "void initsaid(const ip_address *addr, ipsec_spi_t spi,"
+.ti +1c
+.B "int proto, ip_said *dst);"
+.SH DESCRIPTION
+.I Ttosa
+converts an ASCII Security Association (SA) specifier into an
+.B ip_said
+structure (containing
+a destination-host address
+in network byte order,
+an SPI number in network byte order, and
+a protocol code).
+.I Satot
+does the reverse conversion, back to a text SA specifier.
+.I Initsaid
+initializes an
+.B ip_said
+from separate items of information.
+.PP
+An SA is specified in text with a mail-like syntax, e.g.
+.BR esp.5a7@1.2.3.4 .
+An SA specifier contains
+a protocol prefix (currently
+.BR ah ,
+.BR esp ,
+.BR tun ,
+.BR comp ,
+or
+.BR int ),
+a single character indicating the address family
+.RB ( .
+for IPv4,
+.B :
+for IPv6),
+an unsigned integer SPI number in hexadecimal (with no
+.B 0x
+prefix),
+and an IP address.
+The IP address can be any form accepted by
+.IR ipsec_ttoaddr (3),
+e.g. dotted-decimal IPv4 address,
+colon-hex IPv6 address,
+or DNS name.
+.PP
+As a special case, the SA specifier
+.B %passthrough4
+or
+.B %passthrough6
+signifies the special SA used to indicate that packets should be
+passed through unaltered.
+(At present, these are synonyms for
+.B tun.0@0.0.0.0
+and
+.B tun:0@::
+respectively,
+but that is subject to change without notice.)
+.B %passthrough
+is a historical synonym for
+.BR %passthrough4 .
+These forms are known to both
+.I ttosa
+and
+.IR satot ,
+so the internal representation is never visible.
+.PP
+Similarly, the SA specifiers
+.BR %pass ,
+.BR %drop ,
+.BR %reject ,
+.BR %hold ,
+.BR %trap ,
+and
+.BR %trapsubnet
+signify special ``magic'' SAs used to indicate that packets should be
+passed, dropped, rejected (dropped with ICMP notification),
+held,
+and trapped (sent up to
+.IR ipsec_pluto (8),
+with either of two forms of
+.B %hold
+automatically installed)
+respectively.
+These forms too are known to both routines,
+so the internal representation of the magic SAs should never be visible.
+.PP
+The
+.B <freeswan.h>
+header file supplies the
+.B ip_said
+structure, as well as a data type
+.B ipsec_spi_t
+which is an unsigned 32-bit integer.
+(There is no consistency between kernel and user on what such a type
+is called, hence the header hides the differences.)
+.PP
+The protocol code uses the same numbers that IP does.
+For user convenience, given the difficulty in acquiring the exact set of
+protocol names used by the kernel,
+.B <freeswan.h>
+defines the names
+.BR SA_ESP ,
+.BR SA_AH ,
+.BR SA_IPIP ,
+and
+.BR SA_COMP
+to have the same values as the kernel names
+.BR IPPROTO_ESP ,
+.BR IPPROTO_AH ,
+.BR IPPROTO_IPIP ,
+and
+.BR IPPROTO_COMP .
+.PP
+.B <freeswan.h>
+also defines
+.BR SA_INT
+to have the value
+.BR 61
+(reserved by IANA for ``any host internal protocol'')
+and
+.BR SPI_PASS ,
+.BR SPI_DROP ,
+.BR SPI_REJECT ,
+.BR SPI_HOLD ,
+and
+.B SPI_TRAP
+to have the values 256-260 (in \fIhost\fR byte order) respectively.
+These are used in constructing the magic SAs
+(which always have address
+.BR 0.0.0.0 ).
+.PP
+If
+.I satot
+encounters an unknown protocol code, e.g. 77,
+it yields output using a prefix
+showing the code numerically, e.g. ``unk77''.
+This form is
+.I not
+recognized by
+.IR ttosa .
+.PP
+The
+.I srclen
+parameter of
+.I ttosa
+specifies the length of the string pointed to by
+.IR src ;
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+.I srclen
+value of
+.B 0
+is taken to mean
+.BR strlen(src) .
+.PP
+The
+.I dstlen
+parameter of
+.I satot
+specifies the size of the
+.I dst
+parameter;
+under no circumstances are more than
+.I dstlen
+bytes written to
+.IR dst .
+A result which will not fit is truncated.
+.I Dstlen
+can be zero, in which case
+.I dst
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+.B <freeswan.h>
+header file defines a constant,
+.BR SATOT_BUF ,
+which is the size of a buffer just large enough for worst-case results.
+.PP
+The
+.I format
+parameter of
+.I satot
+specifies what format is to be used for the conversion.
+The value
+.B 0
+(not the ASCII character
+.BR '0' ,
+but a zero value)
+specifies a reasonable default
+(currently
+lowercase protocol prefix, lowercase hexadecimal SPI,
+dotted-decimal or colon-hex address).
+The value
+.B 'f'
+is similar except that the SPI is padded with
+.BR 0 s
+to a fixed 32-bit width, to ease aligning displayed tables.
+.PP
+.I Ttosa
+returns
+.B NULL
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+.I Satot
+returns
+.B 0
+for a failure, and otherwise
+always returns the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+.PP
+There is also, temporarily, support for some obsolete
+forms of SA specifier which lack the address-family indicator.
+.SH SEE ALSO
+ipsec_ttoul(3), ipsec_ttoaddr(3), ipsec_samesaid(3), inet(3)
+.SH DIAGNOSTICS
+Fatal errors in
+.I ttosa
+are:
+empty input;
+input too small to be a legal SA specifier;
+no
+.B @
+in input;
+unknown protocol prefix;
+conversion error in
+.I ttoul
+or
+.IR ttoaddr .
+.PP
+Fatal errors in
+.I satot
+are:
+unknown format.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+The restriction of text-to-binary error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+.PP
+The text-to-binary error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+.PP
+.RS
+.nf
+.B "const char *error;"
+.sp
+.B "error = ttosa( /* ... */ );"
+.B "if (error != NULL) {"
+.B " /* something went wrong */"
+.fi
+.RE
diff --git a/src/libfreeswan/ttosa.c b/src/libfreeswan/ttosa.c
new file mode 100644
index 000000000..aa2283694
--- /dev/null
+++ b/src/libfreeswan/ttosa.c
@@ -0,0 +1,280 @@
+/*
+ * convert from text form of SA ID to binary
+ * Copyright (C) 2000, 2001 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.
+ *
+ * RCSID $Id: ttosa.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+static struct satype {
+ char *prefix;
+ size_t prelen; /* strlen(prefix) */
+ int proto;
+} satypes[] = {
+ { "ah", 2, SA_AH },
+ { "esp", 3, SA_ESP },
+ { "tun", 3, SA_IPIP },
+ { "comp", 4, SA_COMP },
+ { "int", 3, SA_INT },
+ { NULL, 0, 0, }
+};
+
+static struct magic {
+ char *name;
+ char *really;
+} magic[] = {
+ { PASSTHROUGHNAME, PASSTHROUGH4IS },
+ { PASSTHROUGH4NAME, PASSTHROUGH4IS },
+ { PASSTHROUGH6NAME, PASSTHROUGH6IS },
+ { "%pass", "int256@0.0.0.0" },
+ { "%drop", "int257@0.0.0.0" },
+ { "%reject", "int258@0.0.0.0" },
+ { "%hold", "int259@0.0.0.0" },
+ { "%trap", "int260@0.0.0.0" },
+ { "%trapsubnet", "int261@0.0.0.0" },
+ { NULL, NULL }
+};
+
+/*
+ - ttosa - convert text "ah507@10.0.0.1" to SA identifier
+ */
+err_t /* NULL for success, else string literal */
+ttosa(src, srclen, sa)
+const char *src;
+size_t srclen; /* 0 means "apply strlen" */
+ip_said *sa;
+{
+ const char *at;
+ const char *addr;
+ size_t alen;
+ const char *spi = NULL;
+ struct satype *sat;
+ unsigned long ul;
+ const char *oops;
+ struct magic *mp;
+ size_t nlen;
+# define MINLEN 5 /* ah0@0 is as short as it can get */
+ int af;
+ int base;
+
+ if (srclen == 0)
+ srclen = strlen(src);
+ if (srclen == 0)
+ return "empty string";
+ if (srclen < MINLEN)
+ return "string too short to be SA identifier";
+ if (*src == '%') {
+ for (mp = magic; mp->name != NULL; mp++) {
+ nlen = strlen(mp->name);
+ if (srclen == nlen && memcmp(src, mp->name, nlen) == 0)
+ break;
+ }
+ if (mp->name == NULL)
+ return "unknown % keyword";
+ src = mp->really;
+ srclen = strlen(src);
+ }
+
+ at = memchr(src, '@', srclen);
+ if (at == NULL)
+ return "no @ in SA specifier";
+
+ for (sat = satypes; sat->prefix != NULL; sat++)
+ if (sat->prelen < srclen &&
+ strncmp(src, sat->prefix, sat->prelen) == 0) {
+ sa->proto = sat->proto;
+ spi = src + sat->prelen;
+ break; /* NOTE BREAK OUT */
+ }
+ if (sat->prefix == NULL)
+ return "SA specifier lacks valid protocol prefix";
+
+ if (spi >= at)
+ return "no SPI in SA specifier";
+ switch (*spi) {
+ case '.':
+ af = AF_INET;
+ spi++;
+ base = 16;
+ break;
+ case ':':
+ af = AF_INET6;
+ spi++;
+ base = 16;
+ break;
+ default:
+ af = AF_UNSPEC; /* not known yet */
+ base = 0;
+ break;
+ }
+ if (spi >= at)
+ return "no SPI found in SA specifier";
+ oops = ttoul(spi, at - spi, base, &ul);
+ if (oops != NULL)
+ return oops;
+ sa->spi = htonl(ul);
+
+ addr = at + 1;
+ alen = srclen - (addr - src);
+ if (af == AF_UNSPEC)
+ af = (memchr(addr, ':', alen) != NULL) ? AF_INET6 : AF_INET;
+ oops = ttoaddr(addr, alen, af, &sa->dst);
+ if (oops != NULL)
+ return oops;
+
+ return NULL;
+}
+
+
+
+#ifdef TTOSA_MAIN
+
+#include <stdio.h>
+
+void regress(void);
+
+int
+main(int argc, char *argv[])
+{
+ ip_said sa;
+ char buf[100];
+ char buf2[100];
+ const char *oops;
+ size_t n;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s {ahnnn@aaa|-r}\n", argv[0]);
+ exit(2);
+ }
+
+ if (strcmp(argv[1], "-r") == 0) {
+ regress();
+ fprintf(stderr, "regress() returned?!?\n");
+ exit(1);
+ }
+
+ oops = ttosa(argv[1], 0, &sa);
+ if (oops != NULL) {
+ fprintf(stderr, "%s: conversion failed: %s\n", argv[0], oops);
+ exit(1);
+ }
+ n = satot(&sa, 0, buf, sizeof(buf));
+ if (n > sizeof(buf)) {
+ fprintf(stderr, "%s: reverse conv of `%d'", argv[0], sa.proto);
+ fprintf(stderr, "%lx@", (long unsigned int)sa.spi);
+ (void) addrtot(&sa.dst, 0, buf2, sizeof(buf2));
+ fprintf(stderr, "%s", buf2);
+ fprintf(stderr, " failed: need %ld bytes, have only %ld\n",
+ (long)n, (long)sizeof(buf));
+ exit(1);
+ }
+ printf("%s\n", buf);
+
+ exit(0);
+}
+
+struct rtab {
+ int format;
+# define FUDGE 0x1000
+ char *input;
+ char *output; /* NULL means error expected */
+} rtab[] = {
+ {0, "esp257@1.2.3.0", "esp.101@1.2.3.0"},
+ {0, "ah0x20@1.2.3.4", "ah.20@1.2.3.4"},
+ {0, "tun20@1.2.3.4", "tun.14@1.2.3.4"},
+ {0, "comp20@1.2.3.4", "comp.14@1.2.3.4"},
+ {0, "esp257@::1", "esp:101@::1"},
+ {0, "esp257@0bc:12de::1", "esp:101@bc:12de::1"},
+ {0, "esp78@1049:1::8007:2040", "esp:4e@1049:1::8007:2040"},
+ {0, "esp0x78@1049:1::8007:2040", "esp:78@1049:1::8007:2040"},
+ {0, "ah78@1049:1::8007:2040", "ah:4e@1049:1::8007:2040"},
+ {0, "ah0x78@1049:1::8007:2040", "ah:78@1049:1::8007:2040"},
+ {0, "tun78@1049:1::8007:2040", "tun:4e@1049:1::8007:2040"},
+ {0, "tun0x78@1049:1::8007:2040", "tun:78@1049:1::8007:2040"},
+ {0, "duk99@3ffe:370:400:ff::9001:3001", NULL},
+ {0, "esp78x@1049:1::8007:2040", NULL},
+ {0, "esp0x78@1049:1:0xfff::8007:2040", NULL},
+ {0, "es78@1049:1::8007:2040", NULL},
+ {0, "", NULL},
+ {0, "_", NULL},
+ {0, "ah2.2", NULL},
+ {0, "goo2@1.2.3.4", NULL},
+ {0, "esp9@1.2.3.4", "esp.9@1.2.3.4"},
+ {'f', "esp0xa9@1.2.3.4", "esp.000000a9@1.2.3.4"},
+ {0, "espp9@1.2.3.4", NULL},
+ {0, "es9@1.2.3.4", NULL},
+ {0, "ah@1.2.3.4", NULL},
+ {0, "esp7x7@1.2.3.4", NULL},
+ {0, "esp77@1.0x2.3.4", NULL},
+ {0, PASSTHROUGHNAME, PASSTHROUGH4NAME},
+ {0, PASSTHROUGH6NAME, PASSTHROUGH6NAME},
+ {0, "%pass", "%pass"},
+ {0, "int256@0.0.0.0", "%pass"},
+ {0, "%drop", "%drop"},
+ {0, "int257@0.0.0.0", "%drop"},
+ {0, "%reject", "%reject"},
+ {0, "int258@0.0.0.0", "%reject"},
+ {0, "%hold", "%hold"},
+ {0, "int259@0.0.0.0", "%hold"},
+ {0, "%trap", "%trap"},
+ {0, "int260@0.0.0.0", "%trap"},
+ {0, "%trapsubnet", "%trapsubnet"},
+ {0, "int261@0.0.0.0", "%trapsubnet"},
+ {0, "int262@0.0.0.0", "int.106@0.0.0.0"},
+ {FUDGE, "esp9@1.2.3.4", "unk77.9@1.2.3.4"},
+ {0, NULL, NULL}
+};
+
+void
+regress(void)
+{
+ struct rtab *r;
+ int status = 0;
+ ip_said sa;
+ char in[100];
+ char buf[100];
+ const char *oops;
+ size_t n;
+
+ for (r = rtab; r->input != NULL; r++) {
+ strcpy(in, r->input);
+ oops = ttosa(in, 0, &sa);
+ if (oops != NULL && r->output == NULL)
+ {} /* okay, error expected */
+ else if (oops != NULL) {
+ printf("`%s' ttosa failed: %s\n", r->input, oops);
+ status = 1;
+ } else if (r->output == NULL) {
+ printf("`%s' ttosa succeeded unexpectedly\n",
+ r->input);
+ status = 1;
+ } else {
+ if (r->format&FUDGE)
+ sa.proto = 77;
+ n = satot(&sa, (char)r->format, buf, sizeof(buf));
+ if (n > sizeof(buf)) {
+ printf("`%s' satot failed: need %ld\n",
+ r->input, (long)n);
+ status = 1;
+ } else if (strcmp(r->output, buf) != 0) {
+ printf("`%s' gave `%s', expected `%s'\n",
+ r->input, buf, r->output);
+ status = 1;
+ }
+ }
+ }
+ exit(status);
+}
+
+#endif /* TTOSA_MAIN */
diff --git a/src/libfreeswan/ttosubnet.c b/src/libfreeswan/ttosubnet.c
new file mode 100644
index 000000000..7f5cddb82
--- /dev/null
+++ b/src/libfreeswan/ttosubnet.c
@@ -0,0 +1,296 @@
+/*
+ * convert from text form of subnet specification 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.
+ *
+ * RCSID $Id: ttosubnet.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+#ifndef DEFAULTSUBNET
+#define DEFAULTSUBNET "%default"
+#endif
+
+/*
+ - ttosubnet - convert text "addr/mask" to address and mask
+ * Mask can be integer bit count.
+ */
+err_t
+ttosubnet(src, srclen, af, dst)
+const char *src;
+size_t srclen; /* 0 means "apply strlen" */
+int af; /* AF_INET or AF_INET6 */
+ip_subnet *dst;
+{
+ const char *slash;
+ const char *colon;
+ const char *mask;
+ size_t mlen;
+ const char *oops;
+ unsigned long bc;
+ static char def[] = DEFAULTSUBNET;
+# define DEFLEN (sizeof(def) - 1) /* -1 for NUL */
+ static char defis4[] = "0/0";
+# define DEFIS4LEN (sizeof(defis4) - 1)
+ static char defis6[] = "::/0";
+# define DEFIS6LEN (sizeof(defis6) - 1)
+ ip_address addrtmp;
+ ip_address masktmp;
+ int nbits;
+ int i;
+
+ if (srclen == 0)
+ srclen = strlen(src);
+ if (srclen == 0)
+ return "empty string";
+
+ switch (af) {
+ case AF_INET:
+ nbits = 32;
+ break;
+ case AF_INET6:
+ nbits = 128;
+ break;
+ default:
+ return "unknown address family in ttosubnet";
+ break;
+ }
+
+ if (srclen == DEFLEN && strncmp(src, def, srclen) == 0) {
+ src = (af == AF_INET) ? defis4 : defis6;
+ srclen = (af == AF_INET) ? DEFIS4LEN : DEFIS6LEN;
+ }
+
+ slash = memchr(src, '/', srclen);
+ if (slash == NULL)
+ return "no / in subnet specification";
+ mask = slash + 1;
+ mlen = srclen - (mask - src);
+
+ oops = ttoaddr(src, slash-src, af, &addrtmp);
+ if (oops != NULL)
+ return oops;
+
+ /* extract port */
+ colon = memchr(mask, ':', mlen);
+ if (colon == 0)
+ {
+ setportof(0, &addrtmp);
+ }
+ else
+ {
+ long port;
+
+ oops = ttoul(colon+1, mlen-(colon-mask+1), 10, &port);
+ if (oops != NULL)
+ return oops;
+ setportof(htons(port), &addrtmp);
+ mlen = colon - mask;
+ }
+
+ /*extract mask */
+ oops = ttoul(mask, mlen, 10, &bc);
+ if (oops == NULL) {
+ /* ttoul succeeded, it's a bit-count mask */
+ if (bc > nbits)
+ return "subnet mask bit count too large";
+ i = bc;
+ } else {
+ oops = ttoaddr(mask, mlen, af, &masktmp);
+ if (oops != NULL)
+ return oops;
+ i = masktocount(&masktmp);
+ if (i < 0)
+ return "non-contiguous or otherwise erroneous mask";
+ }
+
+ return initsubnet(&addrtmp, i, '0', dst);
+}
+
+
+
+#ifdef TTOSUBNET_MAIN
+
+#include <stdio.h>
+
+void regress(void);
+
+int main(int argc, char *argv[])
+{
+ ip_subnet s;
+ char buf[100];
+ char buf2[100];
+ const char *oops;
+ size_t n;
+ int af;
+ char *p;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s [-6] addr/mask\n", argv[0]);
+ fprintf(stderr, " or: %s -r\n", argv[0]);
+ exit(2);
+ }
+
+ if (strcmp(argv[1], "-r") == 0) {
+ regress();
+ fprintf(stderr, "regress() returned?!?\n");
+ exit(1);
+ }
+
+ af = AF_INET;
+ p = argv[1];
+ if (strcmp(argv[1], "-6") == 0) {
+ af = AF_INET6;
+ p = argv[2];
+ } else if (strchr(argv[1], ':') != NULL)
+ af = AF_INET6;
+
+ oops = ttosubnet(p, 0, af, &s);
+ if (oops != NULL) {
+ fprintf(stderr, "%s: conversion failed: %s\n", argv[0], oops);
+ exit(1);
+ }
+ n = subnettot(&s, 0, buf, sizeof(buf));
+ if (n > sizeof(buf)) {
+ fprintf(stderr, "%s: reverse conversion of ", argv[0]);
+ (void) addrtot(&s.addr, 0, buf2, sizeof(buf2));
+ fprintf(stderr, "%s/", buf2);
+ fprintf(stderr, "%d", s.maskbits);
+ fprintf(stderr, " failed: need %ld bytes, have only %ld\n",
+ (long)n, (long)sizeof(buf));
+ exit(1);
+ }
+ printf("%s\n", buf);
+
+ exit(0);
+}
+
+struct rtab {
+ int family;
+ char *input;
+ char *output; /* NULL means error expected */
+} rtab[] = {
+ {4, "1.2.3.0/255.255.255.0", "1.2.3.0/24"},
+ {4, "1.2.3.0/24", "1.2.3.0/24"},
+ {4, "1.2.3.0/24:10", "1.2.3.0/24:10"},
+ {4, "1.2.3.0/24:-1", NULL},
+ {4, "1.2.3.0/24:none", NULL},
+ {4, "1.2.3.0/24:", NULL},
+ {4, "1.2.3.0/24:0x10", "1.2.3.0/24:16"},
+ {4, "1.2.3.0/24:0X10", "1.2.3.0/24:16"},
+ {4, "1.2.3.0/24:010", "1.2.3.0/24:8"},
+ {4, "1.2.3.1/255.255.255.240", "1.2.3.0/28"},
+ {4, "1.2.3.1/32", "1.2.3.1/32"},
+ {4, "1.2.3.1/0", "0.0.0.0/0"},
+/* {4, "1.2.3.1/255.255.127.0", "1.2.3.0/255.255.127.0"}, */
+ {4, "1.2.3.1/255.255.127.0", NULL},
+ {4, "128.009.000.032/32", "128.9.0.32/32"},
+ {4, "128.0x9.0.32/32", NULL},
+ {4, "0x80090020/32", "128.9.0.32/32"},
+ {4, "0x800x0020/32", NULL},
+ {4, "128.9.0.32/0xffFF0000", "128.9.0.0/16"},
+ {4, "128.9.0.32/0xff0000FF", NULL},
+ {4, "128.9.0.32/0x0000ffFF", NULL},
+ {4, "128.9.0.32/0x00ffFF0000", NULL},
+ {4, "128.9.0.32/0xffFF", NULL},
+ {4, "128.9.0.32.27/32", NULL},
+ {4, "128.9.0k32/32", NULL},
+ {4, "328.9.0.32/32", NULL},
+ {4, "128.9..32/32", NULL},
+ {4, "10/8", "10.0.0.0/8"},
+ {4, "10.0/8", "10.0.0.0/8"},
+ {4, "10.0.0/8", "10.0.0.0/8"},
+ {4, "10.0.1/24", "10.0.1.0/24"},
+ {4, "_", NULL},
+ {4, "_/_", NULL},
+ {4, "1.2.3.1", NULL},
+ {4, "1.2.3.1/_", NULL},
+ {4, "1.2.3.1/24._", NULL},
+ {4, "1.2.3.1/99", NULL},
+ {4, "localhost/32", "127.0.0.1/32"},
+ {4, "%default", "0.0.0.0/0"},
+ {6, "3049:1::8007:2040/0", "::/0"},
+ {6, "3049:1::8007:2040/128", "3049:1::8007:2040/128"},
+ {6, "3049:1::192.168.0.1/128", NULL}, /*"3049:1::c0a8:1/128",*/
+ {6, "3049:1::8007::2040/128", NULL},
+ {6, "3049:1::8007:2040/ffff::0", "3049::/16"},
+ {6, "3049:1::8007:2040/64", "3049:1::/64"},
+ {6, "3049:1::8007:2040/ffff::", "3049::/16"},
+ {6, "3049:1::8007:2040/0000:ffff::0", NULL},
+ {6, "3049:1::8007:2040/ff1f::0", NULL},
+ {6, "3049:1::8007:x:2040/128", NULL},
+ {6, "3049:1t::8007:2040/128", NULL},
+ {6, "3049:1::80071:2040/128", NULL},
+ {6, "::/21", "::/21"},
+ {6, "::1/128", "::1/128"},
+ {6, "1::/21", "1::/21"},
+ {6, "1::2/128", "1::2/128"},
+ {6, "1:0:0:0:0:0:0:2/128", "1::2/128"},
+ {6, "1:0:0:0:3:0:0:2/128", "1::3:0:0:2/128"},
+ {6, "1:0:0:3:0:0:0:2/128", "1::3:0:0:0:2/128"},
+ {6, "1:0:3:0:0:0:0:2/128", "1:0:3::2/128"},
+ {6, "abcd:ef01:2345:6789:0:00a:000:20/128", "abcd:ef01:2345:6789:0:a:0:20/128"},
+ {6, "3049:1::8007:2040/ffff:ffff:", NULL},
+ {6, "3049:1::8007:2040/ffff:88::", NULL},
+ {6, "3049:12::9000:3200/ffff:fff0::", "3049:10::/28"},
+ {6, "3049:12::9000:3200/28", "3049:10::/28"},
+ {6, "3049:12::9000:3200/ff00:::", NULL},
+ {6, "3049:12::9000:3200/ffff:::", NULL},
+ {6, "3049:12::9000:3200/128_", NULL},
+ {6, "3049:12::9000:3200/", NULL},
+ {6, "%default", "::/0"},
+ {4, NULL, NULL}
+};
+
+void
+regress(void)
+{
+ struct rtab *r;
+ int status = 0;
+ ip_subnet s;
+ char in[100];
+ char buf[100];
+ const char *oops;
+ size_t n;
+ int af;
+
+ for (r = rtab; r->input != NULL; r++) {
+ af = (r->family == 4) ? AF_INET : AF_INET6;
+ strcpy(in, r->input);
+ oops = ttosubnet(in, 0, af, &s);
+ if (oops != NULL && r->output == NULL)
+ {} /* okay, error expected */
+ else if (oops != NULL) {
+ printf("`%s' ttosubnet failed: %s\n", r->input, oops);
+ status = 1;
+ } else if (r->output == NULL) {
+ printf("`%s' ttosubnet succeeded unexpectedly\n",
+ r->input);
+ status = 1;
+ } else {
+ n = subnettot(&s, 0, buf, sizeof(buf));
+ if (n > sizeof(buf)) {
+ printf("`%s' subnettot failed: need %ld\n",
+ r->input, (long)n);
+ status = 1;
+ } else if (strcmp(r->output, buf) != 0) {
+ printf("`%s' gave `%s', expected `%s'\n",
+ r->input, buf, r->output);
+ status = 1;
+ }
+ }
+ }
+ exit(status);
+}
+
+#endif /* TTOSUBNET_MAIN */
diff --git a/src/libfreeswan/ttoul.3 b/src/libfreeswan/ttoul.3
new file mode 100644
index 000000000..67d4bd34f
--- /dev/null
+++ b/src/libfreeswan/ttoul.3
@@ -0,0 +1,192 @@
+.TH IPSEC_TTOUL 3 "16 Aug 2000"
+.\" RCSID $Id: ttoul.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec ttoul, ultot \- convert unsigned-long numbers to and from text
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "const char *ttoul(const char *src, size_t srclen,"
+.ti +1c
+.B "int base, unsigned long *n);"
+.br
+.B "size_t ultot(unsigned long n, int format, char *dst,"
+.ti +1c
+.B "size_t dstlen);"
+.SH DESCRIPTION
+.I Ttoul
+converts a text-string number into a binary
+.B "unsigned long"
+value.
+.I Ultot
+does the reverse conversion, back to a text version.
+.PP
+Numbers are specified in text as
+decimal (e.g.
+.BR 123 ),
+octal with a leading zero (e.g.
+.BR 012 ,
+which has value 10),
+or hexadecimal with a leading
+.B 0x
+(e.g.
+.BR 0x1f ,
+which has value 31)
+in either upper or lower case.
+.PP
+The
+.I srclen
+parameter of
+.I ttoul
+specifies the length of the string pointed to by
+.IR src ;
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+.I srclen
+value of
+.B 0
+is taken to mean
+.BR strlen(src) .
+.PP
+The
+.I base
+parameter of
+.I ttoul
+can be
+.BR 8 ,
+.BR 10 ,
+or
+.BR 16 ,
+in which case the number supplied is assumed to be of that form
+(and in the case of
+.BR 16 ,
+to lack any
+.B 0x
+prefix).
+It can also be
+.BR 0 ,
+in which case the number is examined for a leading zero
+or a leading
+.B 0x
+to determine its base.
+.PP
+The
+.I dstlen
+parameter of
+.I ultot
+specifies the size of the
+.I dst
+parameter;
+under no circumstances are more than
+.I dstlen
+bytes written to
+.IR dst .
+A result which will not fit is truncated.
+.I Dstlen
+can be zero, in which case
+.I dst
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+.I freeswan.h
+header file defines a constant,
+.BR ULTOT_BUF ,
+which is the size of a buffer just large enough for worst-case results.
+.PP
+The
+.I format
+parameter of
+.I ultot
+must be one of:
+.RS
+.IP \fB'o'\fR 4
+octal conversion with leading
+.B 0
+.IP \fB\ 8\fR
+octal conversion with no leading
+.B 0
+.IP \fB'd'\fR
+decimal conversion
+.IP \fB10\fR
+same as
+.B d
+.IP \fB'x'\fR
+hexadecimal conversion, including leading
+.B 0x
+.IP \fB16\fR
+hexadecimal conversion with no leading
+.B 0x
+.IP \fB17\fR
+like
+.B 16
+except padded on left with
+.BR 0 s
+to eight digits (full width of a 32-bit number)
+.RE
+.PP
+.I Ttoul
+returns NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+.I Ultot
+returns
+.B 0
+for a failure, and otherwise
+returns the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL
+(it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred).
+.SH SEE ALSO
+atol(3), strtoul(3)
+.SH DIAGNOSTICS
+Fatal errors in
+.I ttoul
+are:
+empty input;
+unknown
+.IR base ;
+non-digit character found;
+number too large for an
+.BR "unsigned long" .
+.PP
+Fatal errors in
+.I ultot
+are:
+unknown
+.IR format .
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+Conversion of
+.B 0
+with format
+.B o
+yields
+.BR 00 .
+.PP
+.I Ultot
+format
+.B 17
+is a bit of a kludge.
+.PP
+The restriction of error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+.PP
+The error-reporting convention lends itself to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+.PP
+.RS
+.nf
+.B "const char *error;"
+.sp
+.B "error = ttoul( /* ... */ );"
+.B "if (error != NULL) {"
+.B " /* something went wrong */"
+.fi
+.RE
diff --git a/src/libfreeswan/ttoul.c b/src/libfreeswan/ttoul.c
new file mode 100644
index 000000000..9c6193c68
--- /dev/null
+++ b/src/libfreeswan/ttoul.c
@@ -0,0 +1,91 @@
+/*
+ * convert from text form of unsigned long 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.
+ *
+ * RCSID $Id: ttoul.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - ttoul - convert text substring to unsigned long number
+ */
+const char * /* NULL for success, else string literal */
+ttoul(src, srclen, base, resultp)
+const char *src;
+size_t srclen; /* 0 means strlen(src) */
+int base; /* 0 means figure it out */
+unsigned long *resultp;
+{
+ const char *stop;
+ static char hex[] = "0123456789abcdef";
+ static char uchex[] = "0123456789ABCDEF";
+ int d;
+ char c;
+ char *p;
+ unsigned long r;
+ unsigned long rlimit;
+ int dlimit;
+
+ if (srclen == 0)
+ srclen = strlen(src);
+ if (srclen == 0)
+ return "empty string";
+
+ if (base == 0) {
+ if (srclen > 2 && *src == '0' &&
+ (*(src+1) == 'x' || *(src+1) == 'X'))
+ return ttoul(src+2, srclen-2, 16, resultp);
+ if (srclen > 1 && *src == '0')
+ return ttoul(src+1, srclen-1, 8, resultp);
+ return ttoul(src, srclen, 10, resultp);
+ }
+ if (base != 8 && base != 10 && base != 16)
+ return "unsupported number base";
+
+ r = 0;
+ stop = src + srclen;
+ if (base == 16) {
+ while (src < stop) {
+ c = *src++;
+ p = strchr(hex, c);
+ if (p != NULL)
+ d = p - hex;
+ else {
+ p = strchr(uchex, c);
+ if (p == NULL)
+ return "non-hex digit in hex number";
+ d = p - uchex;
+ }
+ r = (r << 4) | d;
+ }
+ /* defer length check to catch invalid digits first */
+ if (srclen > sizeof(unsigned long) * 2)
+ return "hex number too long";
+ } else {
+ rlimit = ULONG_MAX / base;
+ dlimit = (int)(ULONG_MAX - rlimit*base);
+ while (src < stop) {
+ c = *src++;
+ d = c - '0';
+ if (d < 0 || d >= base)
+ return "non-digit in number";
+ if (r > rlimit || (r == rlimit && d > dlimit))
+ return "unsigned-long overflow";
+ r = r*base + d;
+ }
+ }
+
+ *resultp = r;
+ return NULL;
+}
diff --git a/src/libfreeswan/ultoa.c b/src/libfreeswan/ultoa.c
new file mode 100644
index 000000000..2c2644826
--- /dev/null
+++ b/src/libfreeswan/ultoa.c
@@ -0,0 +1,67 @@
+/*
+ * convert unsigned long to ASCII
+ * Copyright (C) 1998, 1999 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.
+ *
+ * RCSID $Id: ultoa.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - ultoa - convert unsigned long to decimal ASCII
+ */
+size_t /* length required for full conversion */
+ultoa(n, base, dst, dstlen)
+unsigned long n;
+int base;
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ char buf[3*sizeof(unsigned long) + 1];
+ char *bufend = buf + sizeof(buf);
+ size_t len;
+ char *p;
+ static char hex[] = "0123456789abcdef";
+
+ p = bufend;
+ *--p = '\0';
+ if (base == 10) {
+ do {
+ *--p = n%10 + '0';
+ n /= 10;
+ } while (n != 0);
+ } else if (base == 16) {
+ do {
+ *--p = hex[n&0xf];
+ n >>= 4;
+ } while (n != 0);
+ *--p = 'x';
+ *--p = '0';
+ } else if (base == 8) {
+ do {
+ *--p = (n&07) + '0';
+ n >>= 3;
+ } while (n != 0);
+ *--p = '0';
+ } else
+ *--p = '?';
+
+ len = bufend - p;
+
+ if (dstlen > 0) {
+ if (len > dstlen)
+ *(p + dstlen - 1) = '\0';
+ strcpy(dst, p);
+ }
+ return len;
+}
diff --git a/src/libfreeswan/ultot.c b/src/libfreeswan/ultot.c
new file mode 100644
index 000000000..edffa4a2d
--- /dev/null
+++ b/src/libfreeswan/ultot.c
@@ -0,0 +1,83 @@
+/*
+ * convert unsigned long to text
+ * 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.
+ *
+ * RCSID $Id: ultot.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - ultot - convert unsigned long to text
+ */
+size_t /* length required for full conversion */
+ultot(n, base, dst, dstlen)
+unsigned long n;
+int base;
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ char buf[3*sizeof(unsigned long) + 1];
+ char *bufend = buf + sizeof(buf);
+ size_t len;
+ char *p;
+ static char hex[] = "0123456789abcdef";
+# define HEX32 (32/4)
+
+ p = bufend;
+ *--p = '\0';
+ switch (base) {
+ case 10:
+ case 'd':
+ do {
+ *--p = n%10 + '0';
+ n /= 10;
+ } while (n != 0);
+ break;
+ case 16:
+ case 17:
+ case 'x':
+ do {
+ *--p = hex[n&0xf];
+ n >>= 4;
+ } while (n != 0);
+ if (base == 17)
+ while (bufend - p < HEX32 + 1)
+ *--p = '0';
+ if (base == 'x') {
+ *--p = 'x';
+ *--p = '0';
+ }
+ break;
+ case 8:
+ case 'o':
+ do {
+ *--p = (n&07) + '0';
+ n >>= 3;
+ } while (n != 0);
+ if (base == 'o')
+ *--p = '0';
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ len = bufend - p;
+ if (dstlen > 0) {
+ if (len > dstlen)
+ *(p + dstlen - 1) = '\0';
+ strcpy(dst, p);
+ }
+ return len;
+}
diff --git a/src/libfreeswan/version.3 b/src/libfreeswan/version.3
new file mode 100644
index 000000000..06c5f01e3
--- /dev/null
+++ b/src/libfreeswan/version.3
@@ -0,0 +1,44 @@
+.TH IPSEC_VERSION 3 "21 Nov 2001"
+.\" RCSID $Id: version.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec ipsec_version_code \- get IPsec version code
+.br
+ipsec ipsec_version_string \- get full IPsec version string
+.br
+ipsec ipsec_copyright_notice \- get IPsec copyright notice
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "const char *ipsec_version_code(void);"
+.br
+.B "const char *ipsec_version_string(void);"
+.br
+.B "const char **ipsec_copyright_notice(void);"
+.SH DESCRIPTION
+These functions provide information on version numbering and copyright
+of the Linux FreeS/WAN IPsec implementation.
+.PP
+.I Ipsec_version_code
+returns a pointer to a string constant
+containing the current IPsec version code,
+such as ``1.92'' or ``snap2001Nov19b''.
+.PP
+.I Ipsec_version_string
+returns a pointer to a string constant giving a full version identification,
+consisting of the version code preceded by a prefix identifying the software,
+e.g. ``Linux FreeS/WAN 1.92''.
+.PP
+.I Ipsec_copyright_notice
+returns a pointer to a vector of pointers,
+terminated by a
+.BR NULL ,
+which is the text of a suitable copyright notice.
+Each pointer points to a string constant (possibly empty) which is one line
+of the somewhat-verbose copyright notice.
+The strings are NUL-terminated and do not contain a newline;
+supplying suitable line termination for the output device is
+the caller's responsibility.
+.SH SEE ALSO
+ipsec(8)
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
diff --git a/src/libfreeswan/version.c b/src/libfreeswan/version.c
new file mode 100644
index 000000000..3a947b1b9
--- /dev/null
+++ b/src/libfreeswan/version.c
@@ -0,0 +1,43 @@
+/*
+ * return IPsec version information
+ * Copyright (C) 2001 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.
+ *
+ * RCSID $Id: version.in.c,v 1.2 2004/03/16 12:26:32 as Exp $
+ */
+
+#ifdef __KERNEL__
+#include <linux/netdevice.h>
+#endif
+
+#include "freeswan.h"
+
+static const char strongswan_number[] = VERSION;
+static const char strongswan_string[] = "Linux strongSwan " VERSION;
+
+/*
+ - ipsec_version_code - return IPsec version number/code, as string
+ */
+const char *
+ipsec_version_code()
+{
+ return strongswan_number;
+}
+
+/*
+ - ipsec_version_string - return full version string
+ */
+const char *
+ipsec_version_string()
+{
+ return strongswan_string;
+}
diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am
new file mode 100644
index 000000000..b103be193
--- /dev/null
+++ b/src/libstrongswan/Makefile.am
@@ -0,0 +1,69 @@
+lib_LTLIBRARIES = libstrongswan.la
+
+libstrongswan_la_SOURCES = \
+credential_store.h \
+library.c library.h \
+chunk.c chunk.h \
+debug.c debug.h \
+enum.c enum.h \
+printf_hook.c printf_hook.h \
+asn1/asn1.c asn1/asn1.h \
+asn1/oid.c asn1/oid.h \
+asn1/pem.c asn1/pem.h \
+asn1/ttodata.c asn1/ttodata.h \
+crypto/ca.c crypto/ca.h \
+crypto/certinfo.c crypto/certinfo.h \
+crypto/crl.c crypto/crl.h \
+crypto/crypters/crypter.c crypto/crypters/crypter.h \
+crypto/crypters/aes_cbc_crypter.c crypto/crypters/aes_cbc_crypter.h\
+crypto/crypters/des_crypter.c crypto/crypters/des_crypter.h\
+crypto/diffie_hellman.c crypto/diffie_hellman.h \
+crypto/hashers/hasher.h crypto/hashers/hasher.c \
+crypto/hashers/sha1_hasher.c crypto/hashers/sha1_hasher.h \
+crypto/hashers/sha2_hasher.c crypto/hashers/sha2_hasher.h \
+crypto/hashers/md5_hasher.c crypto/hashers/md5_hasher.h \
+crypto/hmac.c crypto/hmac.h \
+crypto/ocsp.c crypto/ocsp.h \
+crypto/prfs/fips_prf.c crypto/prfs/fips_prf.h \
+crypto/prfs/hmac_prf.c crypto/prfs/hmac_prf.h \
+crypto/prfs/prf.c crypto/prfs/prf.h \
+crypto/prf_plus.h crypto/prf_plus.c \
+crypto/rsa/rsa_private_key.c crypto/rsa/rsa_private_key.h \
+crypto/rsa/rsa_public_key.h crypto/rsa/rsa_public_key.c \
+crypto/signers/hmac_signer.c crypto/signers/hmac_signer.h \
+crypto/signers/signer.c crypto/signers/signer.h \
+crypto/x509.c crypto/x509.h \
+utils/fetcher.c utils/fetcher.h \
+utils/host.c utils/host.h \
+utils/identification.c utils/identification.h \
+utils/iterator.h \
+utils/leak_detective.c utils/leak_detective.h \
+utils/lexparser.c utils/lexparser.h \
+utils/linked_list.c utils/linked_list.h \
+utils/randomizer.c utils/randomizer.h
+
+libstrongswan_la_LIBADD = -lgmp -lpthread
+
+INCLUDES = -I$(top_srcdir)/src/libstrongswan
+EXTRA_DIST = asn1/oid.txt asn1/oid.pl
+BUILT_SOURCES = asn1/oid.c asn1/oid.h
+MAINTAINERCLEANFILES = asn1/oid.c asn1/oid.h
+
+if USE_LEAK_DETECTIVE
+ libstrongswan_la_LIBADD += -ldl
+ AM_CFLAGS = -DLEAK_DETECTIVE
+endif
+
+if USE_LIBCURL
+ libstrongswan_la_LIBADD += -lcurl
+endif
+
+if USE_LIBLDAP
+ libstrongswan_la_LIBADD += -lldap -llber
+endif
+
+asn1/oid.c : asn1/oid.txt asn1/oid.pl
+ cd asn1 && $(PERL) oid.pl
+
+asn1/oid.h : asn1/oid.txt asn1/oid.pl
+ cd asn1 && $(PERL) oid.pl
diff --git a/src/libstrongswan/Makefile.in b/src/libstrongswan/Makefile.in
new file mode 100644
index 000000000..e5c5c758e
--- /dev/null
+++ b/src/libstrongswan/Makefile.in
@@ -0,0 +1,820 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@USE_LEAK_DETECTIVE_TRUE@am__append_1 = -ldl
+@USE_LIBCURL_TRUE@am__append_2 = -lcurl
+@USE_LIBLDAP_TRUE@am__append_3 = -lldap -llber
+subdir = src/libstrongswan
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_CLEAN_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(libdir)"
+libLTLIBRARIES_INSTALL = $(INSTALL)
+LTLIBRARIES = $(lib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libstrongswan_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am_libstrongswan_la_OBJECTS = library.lo chunk.lo debug.lo enum.lo \
+ printf_hook.lo asn1.lo oid.lo pem.lo ttodata.lo ca.lo \
+ certinfo.lo crl.lo crypter.lo aes_cbc_crypter.lo \
+ des_crypter.lo diffie_hellman.lo hasher.lo sha1_hasher.lo \
+ sha2_hasher.lo md5_hasher.lo hmac.lo ocsp.lo fips_prf.lo \
+ hmac_prf.lo prf.lo prf_plus.lo rsa_private_key.lo \
+ rsa_public_key.lo hmac_signer.lo signer.lo x509.lo fetcher.lo \
+ host.lo identification.lo leak_detective.lo lexparser.lo \
+ linked_list.lo randomizer.lo
+libstrongswan_la_OBJECTS = $(am_libstrongswan_la_OBJECTS)
+DEFAULT_INCLUDES = -I. -I$(srcdir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libstrongswan_la_SOURCES)
+DIST_SOURCES = $(libstrongswan_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_EAP_SIM_FALSE = @BUILD_EAP_SIM_FALSE@
+BUILD_EAP_SIM_TRUE = @BUILD_EAP_SIM_TRUE@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GPERF = @GPERF@
+GREP = @GREP@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+USE_CISCO_QUIRKS_FALSE = @USE_CISCO_QUIRKS_FALSE@
+USE_CISCO_QUIRKS_TRUE = @USE_CISCO_QUIRKS_TRUE@
+USE_LEAK_DETECTIVE_FALSE = @USE_LEAK_DETECTIVE_FALSE@
+USE_LEAK_DETECTIVE_TRUE = @USE_LEAK_DETECTIVE_TRUE@
+USE_LIBCURL_FALSE = @USE_LIBCURL_FALSE@
+USE_LIBCURL_TRUE = @USE_LIBCURL_TRUE@
+USE_LIBLDAP_FALSE = @USE_LIBLDAP_FALSE@
+USE_LIBLDAP_TRUE = @USE_LIBLDAP_TRUE@
+USE_NAT_TRANSPORT_FALSE = @USE_NAT_TRANSPORT_FALSE@
+USE_NAT_TRANSPORT_TRUE = @USE_NAT_TRANSPORT_TRUE@
+USE_SMARTCARD_FALSE = @USE_SMARTCARD_FALSE@
+USE_SMARTCARD_TRUE = @USE_SMARTCARD_TRUE@
+USE_VENDORID_FALSE = @USE_VENDORID_FALSE@
+USE_VENDORID_TRUE = @USE_VENDORID_TRUE@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+confdir = @confdir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+eapdir = @eapdir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+ipsecdir = @ipsecdir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+piddir = @piddir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+lib_LTLIBRARIES = libstrongswan.la
+libstrongswan_la_SOURCES = \
+credential_store.h \
+library.c library.h \
+chunk.c chunk.h \
+debug.c debug.h \
+enum.c enum.h \
+printf_hook.c printf_hook.h \
+asn1/asn1.c asn1/asn1.h \
+asn1/oid.c asn1/oid.h \
+asn1/pem.c asn1/pem.h \
+asn1/ttodata.c asn1/ttodata.h \
+crypto/ca.c crypto/ca.h \
+crypto/certinfo.c crypto/certinfo.h \
+crypto/crl.c crypto/crl.h \
+crypto/crypters/crypter.c crypto/crypters/crypter.h \
+crypto/crypters/aes_cbc_crypter.c crypto/crypters/aes_cbc_crypter.h\
+crypto/crypters/des_crypter.c crypto/crypters/des_crypter.h\
+crypto/diffie_hellman.c crypto/diffie_hellman.h \
+crypto/hashers/hasher.h crypto/hashers/hasher.c \
+crypto/hashers/sha1_hasher.c crypto/hashers/sha1_hasher.h \
+crypto/hashers/sha2_hasher.c crypto/hashers/sha2_hasher.h \
+crypto/hashers/md5_hasher.c crypto/hashers/md5_hasher.h \
+crypto/hmac.c crypto/hmac.h \
+crypto/ocsp.c crypto/ocsp.h \
+crypto/prfs/fips_prf.c crypto/prfs/fips_prf.h \
+crypto/prfs/hmac_prf.c crypto/prfs/hmac_prf.h \
+crypto/prfs/prf.c crypto/prfs/prf.h \
+crypto/prf_plus.h crypto/prf_plus.c \
+crypto/rsa/rsa_private_key.c crypto/rsa/rsa_private_key.h \
+crypto/rsa/rsa_public_key.h crypto/rsa/rsa_public_key.c \
+crypto/signers/hmac_signer.c crypto/signers/hmac_signer.h \
+crypto/signers/signer.c crypto/signers/signer.h \
+crypto/x509.c crypto/x509.h \
+utils/fetcher.c utils/fetcher.h \
+utils/host.c utils/host.h \
+utils/identification.c utils/identification.h \
+utils/iterator.h \
+utils/leak_detective.c utils/leak_detective.h \
+utils/lexparser.c utils/lexparser.h \
+utils/linked_list.c utils/linked_list.h \
+utils/randomizer.c utils/randomizer.h
+
+libstrongswan_la_LIBADD = -lgmp -lpthread $(am__append_1) \
+ $(am__append_2) $(am__append_3)
+INCLUDES = -I$(top_srcdir)/src/libstrongswan
+EXTRA_DIST = asn1/oid.txt asn1/oid.pl
+BUILT_SOURCES = asn1/oid.c asn1/oid.h
+MAINTAINERCLEANFILES = asn1/oid.c asn1/oid.h
+@USE_LEAK_DETECTIVE_TRUE@AM_CFLAGS = -DLEAK_DETECTIVE
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libstrongswan/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/libstrongswan/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)"
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ if test -f $$p; then \
+ f=$(am__strip_dir) \
+ echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @set -x; list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ p=$(am__strip_dir) \
+ echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \
+ $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libstrongswan.la: $(libstrongswan_la_OBJECTS) $(libstrongswan_la_DEPENDENCIES)
+ $(LINK) -rpath $(libdir) $(libstrongswan_la_LDFLAGS) $(libstrongswan_la_OBJECTS) $(libstrongswan_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aes_cbc_crypter.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ca.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/certinfo.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chunk.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crypter.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/debug.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/des_crypter.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/diffie_hellman.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/enum.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fetcher.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fips_prf.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hasher.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hmac.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hmac_prf.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hmac_signer.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/host.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/identification.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/leak_detective.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lexparser.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/library.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/linked_list.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5_hasher.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ocsp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oid.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pem.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/prf.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/prf_plus.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/printf_hook.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/randomizer.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rsa_private_key.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rsa_public_key.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha1_hasher.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha2_hasher.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/signer.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ttodata.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/x509.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+asn1.lo: asn1/asn1.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT asn1.lo -MD -MP -MF "$(DEPDIR)/asn1.Tpo" -c -o asn1.lo `test -f 'asn1/asn1.c' || echo '$(srcdir)/'`asn1/asn1.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/asn1.Tpo" "$(DEPDIR)/asn1.Plo"; else rm -f "$(DEPDIR)/asn1.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='asn1/asn1.c' object='asn1.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o asn1.lo `test -f 'asn1/asn1.c' || echo '$(srcdir)/'`asn1/asn1.c
+
+oid.lo: asn1/oid.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT oid.lo -MD -MP -MF "$(DEPDIR)/oid.Tpo" -c -o oid.lo `test -f 'asn1/oid.c' || echo '$(srcdir)/'`asn1/oid.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/oid.Tpo" "$(DEPDIR)/oid.Plo"; else rm -f "$(DEPDIR)/oid.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='asn1/oid.c' object='oid.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o oid.lo `test -f 'asn1/oid.c' || echo '$(srcdir)/'`asn1/oid.c
+
+pem.lo: asn1/pem.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT pem.lo -MD -MP -MF "$(DEPDIR)/pem.Tpo" -c -o pem.lo `test -f 'asn1/pem.c' || echo '$(srcdir)/'`asn1/pem.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/pem.Tpo" "$(DEPDIR)/pem.Plo"; else rm -f "$(DEPDIR)/pem.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='asn1/pem.c' object='pem.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o pem.lo `test -f 'asn1/pem.c' || echo '$(srcdir)/'`asn1/pem.c
+
+ttodata.lo: asn1/ttodata.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ttodata.lo -MD -MP -MF "$(DEPDIR)/ttodata.Tpo" -c -o ttodata.lo `test -f 'asn1/ttodata.c' || echo '$(srcdir)/'`asn1/ttodata.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ttodata.Tpo" "$(DEPDIR)/ttodata.Plo"; else rm -f "$(DEPDIR)/ttodata.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='asn1/ttodata.c' object='ttodata.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ttodata.lo `test -f 'asn1/ttodata.c' || echo '$(srcdir)/'`asn1/ttodata.c
+
+ca.lo: crypto/ca.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ca.lo -MD -MP -MF "$(DEPDIR)/ca.Tpo" -c -o ca.lo `test -f 'crypto/ca.c' || echo '$(srcdir)/'`crypto/ca.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ca.Tpo" "$(DEPDIR)/ca.Plo"; else rm -f "$(DEPDIR)/ca.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='crypto/ca.c' object='ca.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ca.lo `test -f 'crypto/ca.c' || echo '$(srcdir)/'`crypto/ca.c
+
+certinfo.lo: crypto/certinfo.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT certinfo.lo -MD -MP -MF "$(DEPDIR)/certinfo.Tpo" -c -o certinfo.lo `test -f 'crypto/certinfo.c' || echo '$(srcdir)/'`crypto/certinfo.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/certinfo.Tpo" "$(DEPDIR)/certinfo.Plo"; else rm -f "$(DEPDIR)/certinfo.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='crypto/certinfo.c' object='certinfo.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o certinfo.lo `test -f 'crypto/certinfo.c' || echo '$(srcdir)/'`crypto/certinfo.c
+
+crl.lo: crypto/crl.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT crl.lo -MD -MP -MF "$(DEPDIR)/crl.Tpo" -c -o crl.lo `test -f 'crypto/crl.c' || echo '$(srcdir)/'`crypto/crl.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/crl.Tpo" "$(DEPDIR)/crl.Plo"; else rm -f "$(DEPDIR)/crl.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='crypto/crl.c' object='crl.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o crl.lo `test -f 'crypto/crl.c' || echo '$(srcdir)/'`crypto/crl.c
+
+crypter.lo: crypto/crypters/crypter.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT crypter.lo -MD -MP -MF "$(DEPDIR)/crypter.Tpo" -c -o crypter.lo `test -f 'crypto/crypters/crypter.c' || echo '$(srcdir)/'`crypto/crypters/crypter.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/crypter.Tpo" "$(DEPDIR)/crypter.Plo"; else rm -f "$(DEPDIR)/crypter.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='crypto/crypters/crypter.c' object='crypter.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o crypter.lo `test -f 'crypto/crypters/crypter.c' || echo '$(srcdir)/'`crypto/crypters/crypter.c
+
+aes_cbc_crypter.lo: crypto/crypters/aes_cbc_crypter.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT aes_cbc_crypter.lo -MD -MP -MF "$(DEPDIR)/aes_cbc_crypter.Tpo" -c -o aes_cbc_crypter.lo `test -f 'crypto/crypters/aes_cbc_crypter.c' || echo '$(srcdir)/'`crypto/crypters/aes_cbc_crypter.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/aes_cbc_crypter.Tpo" "$(DEPDIR)/aes_cbc_crypter.Plo"; else rm -f "$(DEPDIR)/aes_cbc_crypter.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='crypto/crypters/aes_cbc_crypter.c' object='aes_cbc_crypter.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o aes_cbc_crypter.lo `test -f 'crypto/crypters/aes_cbc_crypter.c' || echo '$(srcdir)/'`crypto/crypters/aes_cbc_crypter.c
+
+des_crypter.lo: crypto/crypters/des_crypter.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT des_crypter.lo -MD -MP -MF "$(DEPDIR)/des_crypter.Tpo" -c -o des_crypter.lo `test -f 'crypto/crypters/des_crypter.c' || echo '$(srcdir)/'`crypto/crypters/des_crypter.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/des_crypter.Tpo" "$(DEPDIR)/des_crypter.Plo"; else rm -f "$(DEPDIR)/des_crypter.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='crypto/crypters/des_crypter.c' object='des_crypter.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o des_crypter.lo `test -f 'crypto/crypters/des_crypter.c' || echo '$(srcdir)/'`crypto/crypters/des_crypter.c
+
+diffie_hellman.lo: crypto/diffie_hellman.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT diffie_hellman.lo -MD -MP -MF "$(DEPDIR)/diffie_hellman.Tpo" -c -o diffie_hellman.lo `test -f 'crypto/diffie_hellman.c' || echo '$(srcdir)/'`crypto/diffie_hellman.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/diffie_hellman.Tpo" "$(DEPDIR)/diffie_hellman.Plo"; else rm -f "$(DEPDIR)/diffie_hellman.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='crypto/diffie_hellman.c' object='diffie_hellman.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o diffie_hellman.lo `test -f 'crypto/diffie_hellman.c' || echo '$(srcdir)/'`crypto/diffie_hellman.c
+
+hasher.lo: crypto/hashers/hasher.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT hasher.lo -MD -MP -MF "$(DEPDIR)/hasher.Tpo" -c -o hasher.lo `test -f 'crypto/hashers/hasher.c' || echo '$(srcdir)/'`crypto/hashers/hasher.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/hasher.Tpo" "$(DEPDIR)/hasher.Plo"; else rm -f "$(DEPDIR)/hasher.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='crypto/hashers/hasher.c' object='hasher.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o hasher.lo `test -f 'crypto/hashers/hasher.c' || echo '$(srcdir)/'`crypto/hashers/hasher.c
+
+sha1_hasher.lo: crypto/hashers/sha1_hasher.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sha1_hasher.lo -MD -MP -MF "$(DEPDIR)/sha1_hasher.Tpo" -c -o sha1_hasher.lo `test -f 'crypto/hashers/sha1_hasher.c' || echo '$(srcdir)/'`crypto/hashers/sha1_hasher.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/sha1_hasher.Tpo" "$(DEPDIR)/sha1_hasher.Plo"; else rm -f "$(DEPDIR)/sha1_hasher.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='crypto/hashers/sha1_hasher.c' object='sha1_hasher.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sha1_hasher.lo `test -f 'crypto/hashers/sha1_hasher.c' || echo '$(srcdir)/'`crypto/hashers/sha1_hasher.c
+
+sha2_hasher.lo: crypto/hashers/sha2_hasher.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sha2_hasher.lo -MD -MP -MF "$(DEPDIR)/sha2_hasher.Tpo" -c -o sha2_hasher.lo `test -f 'crypto/hashers/sha2_hasher.c' || echo '$(srcdir)/'`crypto/hashers/sha2_hasher.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/sha2_hasher.Tpo" "$(DEPDIR)/sha2_hasher.Plo"; else rm -f "$(DEPDIR)/sha2_hasher.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='crypto/hashers/sha2_hasher.c' object='sha2_hasher.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sha2_hasher.lo `test -f 'crypto/hashers/sha2_hasher.c' || echo '$(srcdir)/'`crypto/hashers/sha2_hasher.c
+
+md5_hasher.lo: crypto/hashers/md5_hasher.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT md5_hasher.lo -MD -MP -MF "$(DEPDIR)/md5_hasher.Tpo" -c -o md5_hasher.lo `test -f 'crypto/hashers/md5_hasher.c' || echo '$(srcdir)/'`crypto/hashers/md5_hasher.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/md5_hasher.Tpo" "$(DEPDIR)/md5_hasher.Plo"; else rm -f "$(DEPDIR)/md5_hasher.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='crypto/hashers/md5_hasher.c' object='md5_hasher.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o md5_hasher.lo `test -f 'crypto/hashers/md5_hasher.c' || echo '$(srcdir)/'`crypto/hashers/md5_hasher.c
+
+hmac.lo: crypto/hmac.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT hmac.lo -MD -MP -MF "$(DEPDIR)/hmac.Tpo" -c -o hmac.lo `test -f 'crypto/hmac.c' || echo '$(srcdir)/'`crypto/hmac.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/hmac.Tpo" "$(DEPDIR)/hmac.Plo"; else rm -f "$(DEPDIR)/hmac.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='crypto/hmac.c' object='hmac.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o hmac.lo `test -f 'crypto/hmac.c' || echo '$(srcdir)/'`crypto/hmac.c
+
+ocsp.lo: crypto/ocsp.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ocsp.lo -MD -MP -MF "$(DEPDIR)/ocsp.Tpo" -c -o ocsp.lo `test -f 'crypto/ocsp.c' || echo '$(srcdir)/'`crypto/ocsp.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ocsp.Tpo" "$(DEPDIR)/ocsp.Plo"; else rm -f "$(DEPDIR)/ocsp.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='crypto/ocsp.c' object='ocsp.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ocsp.lo `test -f 'crypto/ocsp.c' || echo '$(srcdir)/'`crypto/ocsp.c
+
+fips_prf.lo: crypto/prfs/fips_prf.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fips_prf.lo -MD -MP -MF "$(DEPDIR)/fips_prf.Tpo" -c -o fips_prf.lo `test -f 'crypto/prfs/fips_prf.c' || echo '$(srcdir)/'`crypto/prfs/fips_prf.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/fips_prf.Tpo" "$(DEPDIR)/fips_prf.Plo"; else rm -f "$(DEPDIR)/fips_prf.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='crypto/prfs/fips_prf.c' object='fips_prf.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fips_prf.lo `test -f 'crypto/prfs/fips_prf.c' || echo '$(srcdir)/'`crypto/prfs/fips_prf.c
+
+hmac_prf.lo: crypto/prfs/hmac_prf.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT hmac_prf.lo -MD -MP -MF "$(DEPDIR)/hmac_prf.Tpo" -c -o hmac_prf.lo `test -f 'crypto/prfs/hmac_prf.c' || echo '$(srcdir)/'`crypto/prfs/hmac_prf.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/hmac_prf.Tpo" "$(DEPDIR)/hmac_prf.Plo"; else rm -f "$(DEPDIR)/hmac_prf.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='crypto/prfs/hmac_prf.c' object='hmac_prf.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o hmac_prf.lo `test -f 'crypto/prfs/hmac_prf.c' || echo '$(srcdir)/'`crypto/prfs/hmac_prf.c
+
+prf.lo: crypto/prfs/prf.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT prf.lo -MD -MP -MF "$(DEPDIR)/prf.Tpo" -c -o prf.lo `test -f 'crypto/prfs/prf.c' || echo '$(srcdir)/'`crypto/prfs/prf.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/prf.Tpo" "$(DEPDIR)/prf.Plo"; else rm -f "$(DEPDIR)/prf.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='crypto/prfs/prf.c' object='prf.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o prf.lo `test -f 'crypto/prfs/prf.c' || echo '$(srcdir)/'`crypto/prfs/prf.c
+
+prf_plus.lo: crypto/prf_plus.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT prf_plus.lo -MD -MP -MF "$(DEPDIR)/prf_plus.Tpo" -c -o prf_plus.lo `test -f 'crypto/prf_plus.c' || echo '$(srcdir)/'`crypto/prf_plus.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/prf_plus.Tpo" "$(DEPDIR)/prf_plus.Plo"; else rm -f "$(DEPDIR)/prf_plus.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='crypto/prf_plus.c' object='prf_plus.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o prf_plus.lo `test -f 'crypto/prf_plus.c' || echo '$(srcdir)/'`crypto/prf_plus.c
+
+rsa_private_key.lo: crypto/rsa/rsa_private_key.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rsa_private_key.lo -MD -MP -MF "$(DEPDIR)/rsa_private_key.Tpo" -c -o rsa_private_key.lo `test -f 'crypto/rsa/rsa_private_key.c' || echo '$(srcdir)/'`crypto/rsa/rsa_private_key.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/rsa_private_key.Tpo" "$(DEPDIR)/rsa_private_key.Plo"; else rm -f "$(DEPDIR)/rsa_private_key.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='crypto/rsa/rsa_private_key.c' object='rsa_private_key.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rsa_private_key.lo `test -f 'crypto/rsa/rsa_private_key.c' || echo '$(srcdir)/'`crypto/rsa/rsa_private_key.c
+
+rsa_public_key.lo: crypto/rsa/rsa_public_key.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rsa_public_key.lo -MD -MP -MF "$(DEPDIR)/rsa_public_key.Tpo" -c -o rsa_public_key.lo `test -f 'crypto/rsa/rsa_public_key.c' || echo '$(srcdir)/'`crypto/rsa/rsa_public_key.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/rsa_public_key.Tpo" "$(DEPDIR)/rsa_public_key.Plo"; else rm -f "$(DEPDIR)/rsa_public_key.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='crypto/rsa/rsa_public_key.c' object='rsa_public_key.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rsa_public_key.lo `test -f 'crypto/rsa/rsa_public_key.c' || echo '$(srcdir)/'`crypto/rsa/rsa_public_key.c
+
+hmac_signer.lo: crypto/signers/hmac_signer.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT hmac_signer.lo -MD -MP -MF "$(DEPDIR)/hmac_signer.Tpo" -c -o hmac_signer.lo `test -f 'crypto/signers/hmac_signer.c' || echo '$(srcdir)/'`crypto/signers/hmac_signer.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/hmac_signer.Tpo" "$(DEPDIR)/hmac_signer.Plo"; else rm -f "$(DEPDIR)/hmac_signer.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='crypto/signers/hmac_signer.c' object='hmac_signer.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o hmac_signer.lo `test -f 'crypto/signers/hmac_signer.c' || echo '$(srcdir)/'`crypto/signers/hmac_signer.c
+
+signer.lo: crypto/signers/signer.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT signer.lo -MD -MP -MF "$(DEPDIR)/signer.Tpo" -c -o signer.lo `test -f 'crypto/signers/signer.c' || echo '$(srcdir)/'`crypto/signers/signer.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/signer.Tpo" "$(DEPDIR)/signer.Plo"; else rm -f "$(DEPDIR)/signer.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='crypto/signers/signer.c' object='signer.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o signer.lo `test -f 'crypto/signers/signer.c' || echo '$(srcdir)/'`crypto/signers/signer.c
+
+x509.lo: crypto/x509.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT x509.lo -MD -MP -MF "$(DEPDIR)/x509.Tpo" -c -o x509.lo `test -f 'crypto/x509.c' || echo '$(srcdir)/'`crypto/x509.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/x509.Tpo" "$(DEPDIR)/x509.Plo"; else rm -f "$(DEPDIR)/x509.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='crypto/x509.c' object='x509.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o x509.lo `test -f 'crypto/x509.c' || echo '$(srcdir)/'`crypto/x509.c
+
+fetcher.lo: utils/fetcher.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fetcher.lo -MD -MP -MF "$(DEPDIR)/fetcher.Tpo" -c -o fetcher.lo `test -f 'utils/fetcher.c' || echo '$(srcdir)/'`utils/fetcher.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/fetcher.Tpo" "$(DEPDIR)/fetcher.Plo"; else rm -f "$(DEPDIR)/fetcher.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='utils/fetcher.c' object='fetcher.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fetcher.lo `test -f 'utils/fetcher.c' || echo '$(srcdir)/'`utils/fetcher.c
+
+host.lo: utils/host.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT host.lo -MD -MP -MF "$(DEPDIR)/host.Tpo" -c -o host.lo `test -f 'utils/host.c' || echo '$(srcdir)/'`utils/host.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/host.Tpo" "$(DEPDIR)/host.Plo"; else rm -f "$(DEPDIR)/host.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='utils/host.c' object='host.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o host.lo `test -f 'utils/host.c' || echo '$(srcdir)/'`utils/host.c
+
+identification.lo: utils/identification.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT identification.lo -MD -MP -MF "$(DEPDIR)/identification.Tpo" -c -o identification.lo `test -f 'utils/identification.c' || echo '$(srcdir)/'`utils/identification.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/identification.Tpo" "$(DEPDIR)/identification.Plo"; else rm -f "$(DEPDIR)/identification.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='utils/identification.c' object='identification.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o identification.lo `test -f 'utils/identification.c' || echo '$(srcdir)/'`utils/identification.c
+
+leak_detective.lo: utils/leak_detective.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT leak_detective.lo -MD -MP -MF "$(DEPDIR)/leak_detective.Tpo" -c -o leak_detective.lo `test -f 'utils/leak_detective.c' || echo '$(srcdir)/'`utils/leak_detective.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/leak_detective.Tpo" "$(DEPDIR)/leak_detective.Plo"; else rm -f "$(DEPDIR)/leak_detective.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='utils/leak_detective.c' object='leak_detective.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o leak_detective.lo `test -f 'utils/leak_detective.c' || echo '$(srcdir)/'`utils/leak_detective.c
+
+lexparser.lo: utils/lexparser.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lexparser.lo -MD -MP -MF "$(DEPDIR)/lexparser.Tpo" -c -o lexparser.lo `test -f 'utils/lexparser.c' || echo '$(srcdir)/'`utils/lexparser.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/lexparser.Tpo" "$(DEPDIR)/lexparser.Plo"; else rm -f "$(DEPDIR)/lexparser.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='utils/lexparser.c' object='lexparser.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lexparser.lo `test -f 'utils/lexparser.c' || echo '$(srcdir)/'`utils/lexparser.c
+
+linked_list.lo: utils/linked_list.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT linked_list.lo -MD -MP -MF "$(DEPDIR)/linked_list.Tpo" -c -o linked_list.lo `test -f 'utils/linked_list.c' || echo '$(srcdir)/'`utils/linked_list.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/linked_list.Tpo" "$(DEPDIR)/linked_list.Plo"; else rm -f "$(DEPDIR)/linked_list.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='utils/linked_list.c' object='linked_list.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o linked_list.lo `test -f 'utils/linked_list.c' || echo '$(srcdir)/'`utils/linked_list.c
+
+randomizer.lo: utils/randomizer.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT randomizer.lo -MD -MP -MF "$(DEPDIR)/randomizer.Tpo" -c -o randomizer.lo `test -f 'utils/randomizer.c' || echo '$(srcdir)/'`utils/randomizer.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/randomizer.Tpo" "$(DEPDIR)/randomizer.Plo"; else rm -f "$(DEPDIR)/randomizer.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='utils/randomizer.c' object='randomizer.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o randomizer.lo `test -f 'utils/randomizer.c' || echo '$(srcdir)/'`utils/randomizer.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ $(mkdir_p) $(distdir)/asn1
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-libLTLIBRARIES
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libLTLIBRARIES clean-libtool ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am \
+ install-libLTLIBRARIES install-man install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-info-am \
+ uninstall-libLTLIBRARIES
+
+
+asn1/oid.c : asn1/oid.txt asn1/oid.pl
+ cd asn1 && $(PERL) oid.pl
+
+asn1/oid.h : asn1/oid.txt asn1/oid.pl
+ cd asn1 && $(PERL) oid.pl
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/libstrongswan/asn1/asn1.c b/src/libstrongswan/asn1/asn1.c
new file mode 100644
index 000000000..91a6621d4
--- /dev/null
+++ b/src/libstrongswan/asn1/asn1.c
@@ -0,0 +1,733 @@
+/* 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 <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "asn1.h"
+
+#include <library.h>
+#include <debug.h>
+
+/* 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_empty;
+ }
+}
+
+/**
+ * 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)
+ {
+ DBG2("number of length octets is larger than ASN.1 object");
+ return ASN1_INVALID_LENGTH;
+ }
+
+ if (n > sizeof(len))
+ {
+ DBG2("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;
+}
+
+/**
+ * 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, bool private)
+{
+ ctx->blobs[0] = blob;
+ ctx->level0 = level0;
+ ctx->implicit = implicit;
+ ctx->private = private;
+ 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, bool private)
+{
+ int oid;
+
+ switch (type)
+ {
+ case ASN1_OID:
+ oid = known_oid(object);
+ if (oid != OID_UNKNOWN)
+ {
+ DBG2(" '%s'", oid_names[oid].name);
+ return;
+ }
+ break;
+ case ASN1_UTF8STRING:
+ case ASN1_IA5STRING:
+ case ASN1_PRINTABLESTRING:
+ case ASN1_T61STRING:
+ case ASN1_VISIBLESTRING:
+ DBG2(" '%.*s'", (int)object.len, object.ptr);
+ return;
+ case ASN1_UTCTIME:
+ case ASN1_GENERALIZEDTIME:
+ {
+ time_t time = asn1totime(&object, type);
+
+ DBG2(" '%T'", &time);
+ }
+ return;
+ default:
+ break;
+ }
+ if (private)
+ {
+ DBG4("%B", &object);
+ }
+ else
+ {
+ DBG3("%B", &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_empty;
+
+ 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 */
+ DBG2("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)
+ {
+ DBG2("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)
+ {
+ DBG2("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)
+ {
+ DBG2("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))
+ {
+ DBG1("L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x",
+ *level, obj.name, obj.type, *start_ptr);
+ DBG3("%b", start_ptr, (u_int)(blob->ptr - start_ptr));
+ return FALSE;
+ }
+
+ DBG2("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);
+ if (ctx->private)
+ {
+ DBG4("%B", object);
+ }
+ else
+ {
+ DBG3("%B", object);
+ }
+ }
+ else if (obj.flags & ASN1_BODY)
+ {
+ *object = *blob1;
+ debug_asn1_simple_object(*object, obj.type, ctx->private);
+ }
+ 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)
+ {
+ DBG2("L%d - %s: ASN.1 object smaller than 2 octets", level, name);
+ return FALSE;
+ }
+
+ if (*object->ptr != type)
+ {
+ DBG2("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)
+ {
+ DBG2("L%d - %s: length of ASN.1 object invalid or too large",
+ level, name);
+ return FALSE;
+ }
+
+ DBG2("L%d - %s:", level, name);
+ debug_asn1_simple_object(*object, type, FALSE);
+ 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, 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)
+ {
+ DBG2(" file content is not binary ASN.1");
+ return FALSE;
+ }
+ len = asn1_length(&blob);
+ if (len != blob.len)
+ {
+ DBG2(" 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[32];
+ 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;
+ }
+ snprintf(buf, sizeof(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/src/libstrongswan/asn1/asn1.h b/src/libstrongswan/asn1/asn1.h
new file mode 100644
index 000000000..5ab519ec8
--- /dev/null
+++ b/src/libstrongswan/asn1/asn1.h
@@ -0,0 +1,135 @@
+/* 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 <library.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;
+ bool private;
+ 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;
+
+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, bool private);
+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, ...);
+
+#endif /* _ASN1_H */
diff --git a/src/libstrongswan/asn1/oid.c b/src/libstrongswan/asn1/oid.c
new file mode 100644
index 000000000..4b0632de2
--- /dev/null
+++ b/src/libstrongswan/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/src/libstrongswan/asn1/oid.h b/src/libstrongswan/asn1/oid.h
new file mode 100644
index 000000000..f85997159
--- /dev/null
+++ b/src/libstrongswan/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/src/libstrongswan/asn1/oid.pl b/src/libstrongswan/asn1/oid.pl
new file mode 100644
index 000000000..5db619755
--- /dev/null
+++ b/src/libstrongswan/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))/4), $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/src/libstrongswan/asn1/oid.txt b/src/libstrongswan/asn1/oid.txt
new file mode 100644
index 000000000..eed46d59d
--- /dev/null
+++ b/src/libstrongswan/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/src/libstrongswan/asn1/pem.c b/src/libstrongswan/asn1/pem.c
new file mode 100755
index 000000000..e88db249d
--- /dev/null
+++ b/src/libstrongswan/asn1/pem.c
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 2001-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.
+ */
+
+#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 <library.h>
+#include <debug.h>
+#include <asn1/asn1.h>
+#include <asn1/ttodata.h>
+
+#include <utils/lexparser.h>
+#include <crypto/hashers/hasher.h>
+#include <crypto/crypters/crypter.h>
+
+#define PKCS5_SALT_LEN 8 /* bytes */
+
+/**
+ * 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;
+}
+
+/**
+ * find a boundary of the form -----tag name-----
+ */
+static bool find_boundary(const char* tag, chunk_t *line)
+{
+ chunk_t name = chunk_empty;
+
+ 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))
+ {
+ DBG2(" -----%s %.*s-----", tag, (int)name.len, name.ptr);
+ return TRUE;
+ }
+ line->ptr++; line->len--; name.len++;
+ }
+ return FALSE;
+}
+
+/*
+ * decrypts a passphrase protected encrypted data block
+ */
+static err_t pem_decrypt(chunk_t *blob, encryption_algorithm_t alg, size_t key_size,
+ chunk_t *iv, chunk_t *passphrase)
+{
+ hasher_t *hasher;
+ crypter_t *crypter;
+ chunk_t salt = { iv->ptr, PKCS5_SALT_LEN };
+ chunk_t hash;
+ chunk_t decrypted;
+ chunk_t key = {alloca(key_size), key_size};
+ u_int8_t padding, *last_padding_pos, *first_padding_pos;
+
+ if (passphrase == NULL || passphrase->len == 0)
+ return "missing passphrase";
+
+ /* build key from passphrase and IV */
+ hasher = hasher_create(HASH_MD5);
+ hash.len = hasher->get_hash_size(hasher);
+ hash.ptr = alloca(hash.len);
+ hasher->get_hash(hasher, *passphrase, NULL);
+ hasher->get_hash(hasher, salt, hash.ptr);
+ memcpy(key.ptr, hash.ptr, hash.len);
+
+ if (key.len > hash.len)
+ {
+ hasher->get_hash(hasher, hash, NULL);
+ hasher->get_hash(hasher, *passphrase, NULL);
+ hasher->get_hash(hasher, salt, hash.ptr);
+ memcpy(key.ptr + hash.len, hash.ptr, key.len - hash.len);
+ }
+ hasher->destroy(hasher);
+
+ /* decrypt blob */
+ crypter = crypter_create(alg, key_size);
+ crypter->set_key(crypter, key);
+ if (crypter->decrypt(crypter, *blob, *iv, &decrypted) != SUCCESS)
+ {
+ return "data size is not multiple of block size";
+ }
+ 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 "invalid passphrase";
+ }
+ /* remove padding */
+ blob->len -= padding;
+ return NULL;
+}
+
+/* Converts a PEM encoded file into its binary form
+ *
+ * RFC 1421 Privacy Enhancement for Electronic Mail, February 1993
+ * RFC 934 Message Encapsulation, January 1985
+ */
+err_t pem_to_bin(chunk_t *blob, chunk_t *passphrase, bool *pgp)
+{
+ typedef enum {
+ PEM_PRE = 0,
+ PEM_MSG = 1,
+ PEM_HEADER = 2,
+ PEM_BODY = 3,
+ PEM_POST = 4,
+ PEM_ABORT = 5
+ } state_t;
+
+ encryption_algorithm_t alg = ENCR_UNDEFINED;
+ size_t key_size = 0;
+
+ bool encrypted = FALSE;
+
+ state_t state = PEM_PRE;
+
+ chunk_t src = *blob;
+ chunk_t dst = *blob;
+ chunk_t line = chunk_empty;
+ chunk_t iv = chunk_empty;
+
+ 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)
+ {
+ err_t ugh = NULL;
+ chunk_t name = chunk_empty;
+ chunk_t value = chunk_empty;
+
+ /* an empty line separates HEADER and BODY */
+ if (line.len == 0)
+ {
+ state = PEM_BODY;
+ continue;
+ }
+
+ /* we are looking for a parameter: value pair */
+ DBG2(" %.*s", (int)line.len, line.ptr);
+ ugh = extract_parameter_value(&name, &value, &line);
+ if (ugh != NULL)
+ continue;
+
+ if (match("Proc-Type", &name) && *value.ptr == '4')
+ encrypted = TRUE;
+ else if (match("DEK-Info", &name))
+ {
+ size_t len = 0;
+ chunk_t dek;
+
+ if (!extract_token(&dek, ',', &value))
+ dek = value;
+
+ if (match("DES-EDE3-CBC", &dek))
+ {
+ alg = ENCR_3DES;
+ key_size = 24;
+ }
+ else if (match("AES-128-CBC", &dek))
+ {
+ alg = ENCR_AES_CBC;
+ key_size = 16;
+ }
+ else if (match("AES-192-CBC", &dek))
+ {
+ alg = ENCR_AES_CBC;
+ key_size = 24;
+ }
+ else if (match("AES-256-CBC", &dek))
+ {
+ alg = ENCR_AES_CBC;
+ key_size = 32;
+ }
+ else
+ {
+ return "encryption algorithm not supported";
+ }
+
+ eat_whitespace(&value);
+ ugh = ttodata(value.ptr, value.len, 16, iv.ptr, 16, &len);
+ if (ugh)
+ return "error in IV";
+
+ 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;
+ }
+
+ /* check for PGP armor checksum */
+ if (*data.ptr == '=')
+ {
+ *pgp = TRUE;
+ data.ptr++;
+ data.len--;
+ DBG2(" Armor checksum: %.*s", (int)data.len, data.ptr);
+ continue;
+ }
+
+ 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 "file coded in unknown format, discarded";
+
+ return (encrypted)? pem_decrypt(blob, alg, key_size, &iv, passphrase) : NULL;
+}
+
+/* load a coded key or certificate file with autodetection
+ * of binary DER or base64 PEM ASN.1 formats and armored PGP format
+ */
+bool pem_asn1_load_file(const char *filename, chunk_t *passphrase,
+ const char *type, chunk_t *blob, bool *pgp)
+{
+ err_t ugh = NULL;
+
+ FILE *fd = fopen(filename, "r");
+
+ if (fd)
+ {
+ int bytes;
+ fseek(fd, 0, SEEK_END );
+ blob->len = ftell(fd);
+ rewind(fd);
+ blob->ptr = malloc(blob->len);
+ bytes = fread(blob->ptr, 1, blob->len, fd);
+ fclose(fd);
+ DBG1(" loading %s file '%s' (%d bytes)", type, filename, bytes);
+
+ *pgp = FALSE;
+
+ /* try DER format */
+ if (is_asn1(*blob))
+ {
+ DBG2(" file coded in DER format");
+ return TRUE;
+ }
+
+ if (passphrase != NULL)
+ DBG4(" passphrase:", passphrase->ptr, passphrase->len);
+
+ /* try PEM format */
+ ugh = pem_to_bin(blob, passphrase, pgp);
+
+ if (ugh == NULL)
+ {
+ if (*pgp)
+ {
+ DBG2(" file coded in armored PGP format");
+ return TRUE;
+ }
+ if (is_asn1(*blob))
+ {
+ DBG2(" file coded in PEM format");
+ return TRUE;
+ }
+ ugh = "file coded in unknown format, discarded";
+ }
+
+ /* a conversion error has occured */
+ DBG1(" %s", ugh);
+ chunk_free(blob);
+ }
+ else
+ {
+ DBG1(" could not open %s file '%s'", type, filename);
+ }
+ return FALSE;
+}
diff --git a/src/libstrongswan/asn1/pem.h b/src/libstrongswan/asn1/pem.h
new file mode 100755
index 000000000..0f4b7202c
--- /dev/null
+++ b/src/libstrongswan/asn1/pem.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2001-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.
+ */
+
+#ifndef PEM_H_
+#define PEM_H_
+
+#include <stdio.h>
+
+#include <library.h>
+
+err_t pem_to_bin(chunk_t *blob, chunk_t *passphrase, bool *pgp);
+
+bool pem_asn1_load_file(const char *filename, chunk_t *passphrase,
+ const char *type, chunk_t *blob, bool *pgp);
+
+#endif /*PEM_H_*/
diff --git a/src/libstrongswan/asn1/ttodata.c b/src/libstrongswan/asn1/ttodata.c
new file mode 100644
index 000000000..8114b12c5
--- /dev/null
+++ b/src/libstrongswan/asn1/ttodata.c
@@ -0,0 +1,378 @@
+/*
+ * 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))
+
+/**
+ * @brief 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.
+ *
+ * @param src
+ * @param srclen 0 means apply strlen()
+ * @param base 0 means figure it out
+ * @param dst need not be valid if dstlen is 0
+ * @param dstlen
+ * @param lenp where to record length (NULL is nowhere)
+ * @param errp error buffer
+ * @param flags
+ * @return NULL on success, else literal or errp
+ */
+const char *ttodatav(const char *src, size_t srclen, int base, char *dst, size_t dstlen, size_t *lenp, char *errp, 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;
+}
+
+/**
+ * @brief ttodata - convert text to data
+ *
+ * @param src
+ * @param srclen 0 means apply strlen()
+ * @param base 0 means figure it out
+ * @param dst need not be valid if dstlen is 0
+ * @param dstlen
+ * @param lenp where to record length (NULL is nowhere)
+ * @return NULL on success, else literal
+ */
+const char *ttodata(const char *src, size_t srclen, int base, char *dst, size_t dstlen, size_t *lenp)
+{
+ return ttodatav(src, srclen, base, dst, dstlen, lenp, (char *)NULL,
+ (size_t)0, TTODATAV_SPACECOUNTS);
+}
+
+/**
+ * @brief atodata - convert ASCII to data
+ *
+ * backward-compatibility interface
+ *
+ * @param src
+ * @param srclen
+ * @param dst
+ * @param dstlen
+ * @return 0 for failure, true length for success
+ */
+size_t atodata(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;
+}
+
+/**
+ * @brief atobytes - convert ASCII to data bytes
+ *
+ * another backward-compatibility interface
+ */
+const char *atobytes(const char *src, size_t srclen, char *dst, size_t dstlen, size_t *lenp)
+{
+ return ttodata(src, srclen, 0, dst, dstlen, lenp);
+}
+
+/**
+ * @brief unhex - convert two ASCII hex digits to byte
+ *
+ * @param src known to be full length
+ * @param dstnumber of result bytes, or error code
+ * @param dstlen not large enough is a failure
+ * @return
+ */
+static int unhex(const char *src, char *dst, size_t dstlen)
+{
+ 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;
+}
+
+/**
+ * @brief 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.
+ *
+ * @param src known to be full length
+ * @param dst
+ * @param dstlen
+ * @return number of result bytes, or error code
+ */
+static int unb64(const char *src, 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;
+}
+
+/**
+ * @brief untext - convert one ASCII character to byte
+ *
+ * @param src known to be full length
+ * @param dst
+ * @param dstlen not large enough is a failure
+ * @return number of result bytes, or error code
+ */
+static int untext(const char *src, char *dst, size_t dstlen)
+{
+ if (dstlen < 1)
+ return SHORT;
+
+ *dst = *src;
+ return 1;
+}
+
+/**
+ * @brief 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.
+ *
+ * @param src
+ * @param errcode
+ * @param errp might be NULL
+ * @param errlen
+ * @return literal or errp
+ */
+static const char *badch(const char *src, int errcode, char *errp, 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/src/libstrongswan/asn1/ttodata.h b/src/libstrongswan/asn1/ttodata.h
new file mode 100644
index 000000000..6125c6b82
--- /dev/null
+++ b/src/libstrongswan/asn1/ttodata.h
@@ -0,0 +1,28 @@
+/*
+ * 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 <library.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 */
+
+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/src/libstrongswan/chunk.c b/src/libstrongswan/chunk.c
new file mode 100644
index 000000000..cba823c22
--- /dev/null
+++ b/src/libstrongswan/chunk.c
@@ -0,0 +1,410 @@
+/**
+ * @file chunk.c
+ *
+ * @brief Pointer/lenght abstraction and its functions.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 "chunk.h"
+
+#include <debug.h>
+#include <printf_hook.h>
+
+/**
+ * Empty chunk.
+ */
+chunk_t chunk_empty = { NULL, 0 };
+
+/**
+ * Described in header.
+ */
+chunk_t chunk_create(u_char *ptr, size_t len)
+{
+ chunk_t chunk = {ptr, len};
+ return chunk;
+}
+
+/**
+ * Described in header.
+ */
+chunk_t chunk_create_clone(u_char *ptr, chunk_t chunk)
+{
+ chunk_t clone = chunk_empty;
+
+ if (chunk.ptr && chunk.len > 0)
+ {
+ clone.ptr = ptr;
+ clone.len = chunk.len;
+ memcpy(clone.ptr, chunk.ptr, chunk.len);
+ }
+
+ return clone;
+}
+
+/**
+ * Decribed in header.
+ */
+size_t chunk_length(const char* mode, ...)
+{
+ va_list chunks;
+ size_t length = 0;
+
+ va_start(chunks, mode);
+ while (TRUE)
+ {
+ switch (*mode++)
+ {
+ case 'm':
+ case 'c':
+ {
+ chunk_t ch = va_arg(chunks, chunk_t);
+ length += ch.len;
+ continue;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ va_end(chunks);
+ return length;
+}
+
+/**
+ * Decribed in header.
+ */
+chunk_t chunk_create_cat(u_char *ptr, const char* mode, ...)
+{
+ va_list chunks;
+ chunk_t construct = chunk_create(ptr, 0);
+
+ va_start(chunks, mode);
+ while (TRUE)
+ {
+ bool free_chunk = FALSE;
+ switch (*mode++)
+ {
+ case 'm':
+ {
+ free_chunk = TRUE;
+ }
+ case 'c':
+ {
+ chunk_t ch = va_arg(chunks, chunk_t);
+ memcpy(ptr, ch.ptr, ch.len);
+ ptr += ch.len;
+ construct.len += ch.len;
+ if (free_chunk)
+ {
+ free(ch.ptr);
+ }
+ continue;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ va_end(chunks);
+
+ return construct;
+}
+
+/**
+ * Decribed in header.
+ */
+void chunk_split(chunk_t chunk, const char *mode, ...)
+{
+ va_list chunks;
+ size_t len;
+ chunk_t *ch;
+
+ va_start(chunks, mode);
+ while (TRUE)
+ {
+ if (*mode == '\0')
+ {
+ break;
+ }
+ len = va_arg(chunks, size_t);
+ ch = va_arg(chunks, chunk_t*);
+ /* a null chunk means skip len bytes */
+ if (ch == NULL)
+ {
+ chunk = chunk_skip(chunk, len);
+ continue;
+ }
+ switch (*mode++)
+ {
+ case 'm':
+ {
+ ch->len = min(chunk.len, len);
+ if (ch->len)
+ {
+ ch->ptr = chunk.ptr;
+ }
+ else
+ {
+ ch->ptr = NULL;
+ }
+ chunk = chunk_skip(chunk, ch->len);
+ continue;
+ }
+ case 'a':
+ {
+ ch->len = min(chunk.len, len);
+ if (ch->len)
+ {
+ ch->ptr = malloc(ch->len);
+ memcpy(ch->ptr, chunk.ptr, ch->len);
+ }
+ else
+ {
+ ch->ptr = NULL;
+ }
+ chunk = chunk_skip(chunk, ch->len);
+ continue;
+ }
+ case 'c':
+ {
+ ch->len = min(ch->len, chunk.len);
+ ch->len = min(ch->len, len);
+ if (ch->len)
+ {
+ memcpy(ch->ptr, chunk.ptr, ch->len);
+ }
+ else
+ {
+ ch->ptr = NULL;
+ }
+ chunk = chunk_skip(chunk, ch->len);
+ continue;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ va_end(chunks);
+}
+
+/**
+ * Described in header.
+ */
+bool chunk_write(chunk_t chunk, const char *path, const char *label, mode_t mask, bool force)
+{
+ mode_t oldmask;
+ FILE *fd;
+
+ if (!force)
+ {
+ fd = fopen(path, "r");
+ if (fd)
+ {
+ fclose(fd);
+ DBG1(" %s file '%s' already exists", label, path);
+ return FALSE;
+ }
+ }
+
+ /* set umask */
+ oldmask = umask(mask);
+
+ fd = fopen(path, "w");
+
+ if (fd)
+ {
+ fwrite(chunk.ptr, sizeof(u_char), chunk.len, fd);
+ fclose(fd);
+ DBG1(" written %s file '%s' (%u bytes)", label, path, chunk.len);
+ umask(oldmask);
+ return TRUE;
+ }
+ else
+ {
+ DBG1(" could not open %s file '%s' for writing", label, path);
+ umask(oldmask);
+ return FALSE;
+ }
+}
+
+/**
+ * Described in header.
+ */
+void chunk_free(chunk_t *chunk)
+{
+ free(chunk->ptr);
+ chunk->ptr = NULL;
+ chunk->len = 0;
+}
+
+/**
+ * Described in header.
+ */
+chunk_t chunk_skip(chunk_t chunk, size_t bytes)
+{
+ if (chunk.len > bytes)
+ {
+ chunk.ptr += bytes;
+ chunk.len -= bytes;
+ return chunk;
+ }
+ return chunk_empty;
+}
+
+/**
+ * Described in header.
+ */
+int chunk_compare(chunk_t a, chunk_t b)
+{
+ int compare_len = a.len - b.len;
+ int len = (compare_len < 0)? a.len : b.len;
+
+ if (compare_len != 0 || len == 0)
+ {
+ return compare_len;
+ }
+ return memcmp(a.ptr, b.ptr, len);
+};
+
+/**
+ * Described in header.
+ */
+bool chunk_equals(chunk_t a, chunk_t b)
+{
+ return a.ptr != NULL && b.ptr != NULL &&
+ a.len == b.len && memeq(a.ptr, b.ptr, a.len);
+}
+
+/**
+ * Described in header.
+ */
+bool chunk_equals_or_null(chunk_t a, chunk_t b)
+{
+ if (a.ptr == NULL || b.ptr == NULL)
+ return TRUE;
+ return a.len == b.len && memeq(a.ptr, b.ptr, a.len);
+}
+
+/**
+ * Number of bytes per line to dump raw data
+ */
+#define BYTES_PER_LINE 16
+
+/**
+ * output handler in printf() for byte ranges
+ */
+static int print_bytes(FILE *stream, const struct printf_info *info,
+ const void *const *args)
+{
+ char *bytes = *((void**)(args[0]));
+ int len = *((size_t*)(args[1]));
+
+ char buffer[BYTES_PER_LINE * 3];
+ char ascii_buffer[BYTES_PER_LINE + 1];
+ char *buffer_pos = buffer;
+ char *bytes_pos = bytes;
+ char *bytes_roof = bytes + len;
+ int line_start = 0;
+ int i = 0;
+ int written = 0;
+
+ written += fprintf(stream, "=> %d bytes @ %p", len, bytes);
+
+ while (bytes_pos < bytes_roof)
+ {
+ 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 == BYTES_PER_LINE)
+ {
+ int padding = 3 * (BYTES_PER_LINE - i);
+ int written;
+
+ while (padding--)
+ {
+ *buffer_pos++ = ' ';
+ }
+ *buffer_pos++ = '\0';
+ ascii_buffer[i] = '\0';
+
+ written += fprintf(stream, "\n%4d: %s %s",
+ line_start, buffer, ascii_buffer);
+
+
+ buffer_pos = buffer;
+ line_start += BYTES_PER_LINE;
+ i = 0;
+ }
+ else
+ {
+ *buffer_pos++ = ' ';
+ }
+ }
+ return written;
+}
+
+/**
+ * output handler in printf() for chunks
+ */
+static int print_chunk(FILE *stream, const struct printf_info *info,
+ const void *const *args)
+{
+ chunk_t *chunk = *((chunk_t**)(args[0]));
+ bool first = TRUE;
+ chunk_t copy = *chunk;
+ int written = 0;
+
+ if (!info->alt)
+ {
+ const void *new_args[] = {&chunk->ptr, &chunk->len};
+ return print_bytes(stream, info, new_args);
+ }
+
+ while (copy.len > 0)
+ {
+ if (first)
+ {
+ first = FALSE;
+ }
+ else
+ {
+ written += fprintf(stream, ":");
+ }
+ written += fprintf(stream, "%02x", *copy.ptr++);
+ copy.len--;
+ }
+ return written;
+}
+
+/**
+ * register printf() handlers
+ */
+static void __attribute__ ((constructor))print_register()
+{
+ register_printf_function(PRINTF_CHUNK, print_chunk, arginfo_ptr);
+ register_printf_function(PRINTF_BYTES, print_bytes, arginfo_ptr_int);
+}
diff --git a/src/libstrongswan/chunk.h b/src/libstrongswan/chunk.h
new file mode 100644
index 000000000..a13ccfc22
--- /dev/null
+++ b/src/libstrongswan/chunk.h
@@ -0,0 +1,154 @@
+/**
+ * @file chunk.h
+ *
+ * @brief Pointer/length abstraction and its functions.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 CHUNK_H_
+#define CHUNK_H_
+
+#include <string.h>
+#include <stdarg.h>
+
+#include <library.h>
+
+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;
+};
+
+/**
+ * A { NULL, 0 }-chunk handy for initialization.
+ */
+extern chunk_t chunk_empty;
+
+/**
+ * Create a new chunk pointing to "ptr" with length "len"
+ */
+chunk_t chunk_create(u_char *ptr, size_t len);
+
+/**
+ * Create a clone of a chunk pointing to "ptr"
+ */
+chunk_t chunk_create_clone(u_char *ptr, chunk_t chunk);
+
+/**
+ * Calculate length of multiple chunks
+ */
+size_t chunk_length(const char *mode, ...);
+
+/**
+ * Concatenate chunks into a chunk pointing to "ptr",
+ * "mode" is a string of "c" (copy) and "m" (move), which says
+ * how to handle to chunks in "..."
+ */
+chunk_t chunk_create_cat(u_char *ptr, const char* mode, ...);
+
+/**
+ * Split up a chunk into parts, "mode" is a string of "a" (alloc),
+ * "c" (copy) and "m" (move). Each letter say for the corresponding chunk if
+ * it should get allocated on heap, copied into existing chunk, or the chunk
+ * should point into "chunk". The length of each part is an argument before
+ * each target chunk. E.g.:
+ * chunk_split(chunk, "mcac", 3, &a, 7, &b, 5, &c, d.len, &d);
+ */
+void chunk_split(chunk_t chunk, const char *mode, ...);
+
+/**
+ * Write the binary contents of a chunk_t to a file
+ */
+bool chunk_write(chunk_t chunk, const char *path, const char *label, mode_t mask, bool force);
+
+/**
+ * Free contents of a chunk
+ */
+void chunk_free(chunk_t *chunk);
+
+/**
+ * Initialize a chunk to point to buffer inspectable by sizeof()
+ */
+#define chunk_from_buf(str) { str, sizeof(str) }
+
+/**
+ * Initialize a chunk to point to a thing
+ */
+#define chunk_from_thing(thing) chunk_create((char*)&(thing), sizeof(thing))
+
+/**
+ * Allocate a chunk on the heap
+ */
+#define chunk_alloc(bytes) chunk_create(malloc(bytes), bytes)
+
+/**
+ * Allocate a chunk on the stack
+ */
+#define chunk_alloca(bytes) chunk_create(alloca(bytes), bytes)
+
+/**
+ * Clone a chunk on heap
+ */
+#define chunk_clone(chunk) chunk_create_clone(malloc(chunk.len), chunk)
+
+/**
+ * Clone a chunk on stack
+ */
+#define chunk_clonea(chunk) chunk_create_clone(alloca(chunk.len), chunk)
+
+/**
+ * Concatenate chunks into a chunk on heap
+ */
+#define chunk_cat(mode, ...) chunk_create_cat(malloc(chunk_length(mode, __VA_ARGS__)), mode, __VA_ARGS__)
+
+/**
+ * Concatenate chunks into a chunk on stack
+ */
+#define chunk_cata(mode, ...) chunk_create_cat(alloca(chunk_length(mode, __VA_ARGS__)), mode, __VA_ARGS__)
+
+/**
+ * Skip n bytes in chunk (forward pointer, shorten length)
+ */
+chunk_t chunk_skip(chunk_t chunk, size_t bytes);
+
+/**
+ * Compare two chunks, returns zero if a equals b
+ * or negative/positive if a is small/greater than b
+ */
+int chunk_compare(chunk_t a, chunk_t b);
+
+/**
+ * Compare two chunks for equality,
+ * NULL chunks are never equal.
+ */
+bool chunk_equals(chunk_t a, chunk_t b);
+
+/**
+ * Compare two chunks for equality,
+ * NULL chunks are always equal.
+ */
+bool chunk_equals_or_null(chunk_t a, chunk_t b);
+
+#endif /* CHUNK_H_ */
diff --git a/src/libstrongswan/credential_store.h b/src/libstrongswan/credential_store.h
new file mode 100755
index 000000000..5d51981ec
--- /dev/null
+++ b/src/libstrongswan/credential_store.h
@@ -0,0 +1,294 @@
+/**
+ * @file credential_store.h
+ *
+ * @brief Interface credential_store_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef CREDENTIAL_STORE_H_
+#define CREDENTIAL_STORE_H_
+
+typedef struct credential_store_t credential_store_t;
+
+#include <library.h>
+#include <crypto/x509.h>
+#include <crypto/ca.h>
+#include <crypto/rsa/rsa_private_key.h>
+#include <crypto/rsa/rsa_public_key.h>
+#include <utils/identification.h>
+
+
+/**
+ * @brief The interface for a credential_store backend.
+ *
+ * @b Constructors:
+ * - stroke_create()
+ *
+ * @ingroup config
+ */
+struct credential_store_t {
+
+ /**
+ * @brief Returns the secret shared by two specific IDs.
+ *
+ * The returned chunk must be destroyed by the caller after usage.
+ *
+ * @param this calling object
+ * @param my_id my ID identifiying the secret.
+ * @param other_id peer ID identifying the secret.
+ * @param[out] secret the pre-shared secret will be written there.
+ * @return
+ * - NOT_FOUND if no preshared secrets for specific ID could be found
+ * - SUCCESS
+ *
+ */
+ status_t (*get_shared_key) (credential_store_t *this, identification_t *my_id,
+ identification_t *other_id, chunk_t *shared_key);
+
+ /**
+ * @brief Returns the EAP secret for two specified IDs.
+ *
+ * The returned chunk must be destroyed by the caller after usage.
+ *
+ * @param this calling object
+ * @param my_id my ID identifiying the secret.
+ * @param other_id peer ID identifying the secret.
+ * @param[out] eap_key the EAP secret will be written here
+ * @return
+ * - NOT_FOUND if no preshared secrets for specific ID could be found
+ * - SUCCESS
+ *
+ */
+ status_t (*get_eap_key) (credential_store_t *this, identification_t *my_id,
+ identification_t *other_id, chunk_t *eap_key);
+
+ /**
+ * @brief Returns the RSA public key of a specific ID.
+ *
+ * @param this calling object
+ * @param id identification_t object identifiying the key.
+ * @return public key, or NULL if not found
+ */
+ rsa_public_key_t* (*get_rsa_public_key) (credential_store_t *this, identification_t *id);
+
+ /**
+ * @brief Returns the RSA public key of a specific ID if is trusted
+ *
+ * @param this calling object
+ * @param id identification_t object identifiying the key.
+ * @return public key, or NULL if not found or not trusted
+ */
+ rsa_public_key_t* (*get_trusted_public_key) (credential_store_t *this, identification_t *id);
+
+ /**
+ * @brief Returns the RSA private key belonging to an RSA public key
+ *
+ * The returned rsa_private_key_t must be destroyed by the caller after usage.
+ *
+ * @param this calling object
+ * @param pubkey public key
+ * @return private key, or NULL if not found
+ */
+ rsa_private_key_t* (*get_rsa_private_key) (credential_store_t *this, rsa_public_key_t *pubkey);
+
+ /**
+ * @brief Is there a matching RSA private key belonging to an RSA public key?
+ *
+ * @param this calling object
+ * @param pubkey public key
+ * @return TRUE if matching private key was found
+ */
+ bool (*has_rsa_private_key) (credential_store_t *this, rsa_public_key_t *pubkey);
+
+ /**
+ * @brief Returns the certificate of a specific ID.
+ *
+ * @param this calling object
+ * @param id identification_t object identifiying the cert.
+ * @return certificate, or NULL if not found
+ */
+ x509_t* (*get_certificate) (credential_store_t *this, identification_t *id);
+
+ /**
+ * @brief Returns the auth certificate of a specific subject distinguished name.
+ *
+ * @param this calling object
+ * @param auth_flags set of allowed authority types
+ * @param id identification_t object identifiying the cacert.
+ * @return certificate, or NULL if not found
+ */
+ x509_t* (*get_auth_certificate) (credential_store_t *this, u_int auth_flags, identification_t *id);
+
+ /**
+ * @brief Returns the ca certificate of a specific keyID.
+ *
+ * @param this calling object
+ * @param keyid identification_t object identifiying the cacert.
+ * @return certificate, or NULL if not found
+ */
+ x509_t* (*get_ca_certificate_by_keyid) (credential_store_t *this, chunk_t keyid);
+
+ /**
+ * @brief Returns the issuing ca of a given certificate.
+ *
+ * @param this calling object
+ * @param cert certificate for which issuer ca info is required
+ * @return ca info, or NULL if not found
+ */
+ ca_info_t* (*get_issuer) (credential_store_t *this, const x509_t* cert);
+
+ /**
+ * @brief Verify an X.509 certificate up to trust anchor without any status checks
+ *
+ * @param this calling object
+ * @param cert certificate to be verified
+ * @return TRUE if trusted
+ */
+ bool (*is_trusted) (credential_store_t *this, x509_t *cert);
+
+ /**
+ * @brief Verify an X.509 certificate up to trust anchor including status checks
+ *
+ * @param this calling object
+ * @param cert certificate to be verified
+ * @param found found a certificate copy in the credential store
+ * @return TRUE if valid, trusted, and current status is good
+ */
+ bool (*verify) (credential_store_t *this, x509_t *cert, bool *found);
+
+ /**
+ * @brief If an end certificate does not already exists in the credential store then add it.
+ *
+ * @param this calling object
+ * @param cert certificate to be added
+ * @return pointer to the added or already existing certificate
+ */
+ x509_t* (*add_end_certificate) (credential_store_t *this, x509_t *cert);
+
+ /**
+ * @brief If an authority certificate does not already exists in the credential store then add it.
+ *
+ * @param this calling object
+ * @param cert authority certificate to be added
+ * @param auth_flag authority flags to add to the certificate
+ * @return pointer to the added or already existing certificate
+ */
+ x509_t* (*add_auth_certificate) (credential_store_t *this, x509_t *cert, u_int auth_flag);
+
+ /**
+ * @brief If a ca info record does not already exists in the credential store then add it.
+ *
+ * @param this calling object
+ * @param ca_info ca info record to be added
+ */
+ void (*add_ca_info) (credential_store_t *this, ca_info_t *ca_info);
+
+ /**
+ * @brief Release a ca info record with a given name.
+ *
+ * @param this calling object
+ * @param name name of the ca info record to be released
+ * @return
+ * - SUCCESS, or
+ * - NOT_FOUND
+ */
+ status_t (*release_ca_info) (credential_store_t *this, const char *name);
+
+ /**
+ * @brief Create an iterator over all end certificates.
+ *
+ * @param this calling object
+ * @return iterator
+ */
+ iterator_t* (*create_cert_iterator) (credential_store_t *this);
+
+ /**
+ * @brief Create an iterator over all authority certificates.
+ *
+ * @param this calling object
+ * @return iterator
+ */
+ iterator_t* (*create_auth_cert_iterator) (credential_store_t *this);
+
+ /**
+ * @brief Create an iterator over all CA info records
+ *
+ * @param this calling object
+ * @return iterator
+ */
+ iterator_t* (*create_cainfo_iterator) (credential_store_t *this);
+
+ /**
+ * @brief Loads ca certificates from a default directory.
+ *
+ * Certificates in both DER and PEM format are accepted
+ *
+ * @param this calling object
+ */
+ void (*load_ca_certificates) (credential_store_t *this);
+
+ /**
+ * @brief Loads ocsp certificates from a default directory.
+ *
+ * Certificates in both DER and PEM format are accepted
+ *
+ * @param this calling object
+ */
+ void (*load_ocsp_certificates) (credential_store_t *this);
+
+ /**
+ * @brief Loads CRLs from a default directory.
+ *
+ * Certificates in both DER and PEM format are accepted
+ *
+ * @param this calling object
+ * @param path directory to load crls from
+ */
+ void (*load_crls) (credential_store_t *this);
+
+ /**
+ * @brief Loads secrets in ipsec.secrets
+ *
+ * Currently, all RSA private key files must be in unencrypted form
+ * either in DER or PEM format.
+ *
+ * @param this calling object
+ */
+ void (*load_secrets) (credential_store_t *this);
+
+ /**
+ * @brief Destroys a credential_store_t object.
+ *
+ * @param this calling object
+ */
+ void (*destroy) (credential_store_t *this);
+};
+
+/**
+ * @brief Creates a credential_store_t instance.
+ *
+ * @param strict enforce a strict crl policy
+ * @return credential store instance.
+ *
+ * @ingroup config
+ */
+credential_store_t *credential_store_create(bool strict);
+
+
+#endif /*CREDENTIAL_STORE_H_*/
diff --git a/src/libstrongswan/crypto/ca.c b/src/libstrongswan/crypto/ca.c
new file mode 100644
index 000000000..1f566a098
--- /dev/null
+++ b/src/libstrongswan/crypto/ca.c
@@ -0,0 +1,788 @@
+/**
+ * @file ca.c
+ *
+ * @brief Implementation of ca_info_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <pthread.h>
+
+#include "x509.h"
+#include "crl.h"
+#include "ca.h"
+#include "certinfo.h"
+#include "ocsp.h"
+
+#include <library.h>
+#include <debug.h>
+#include <utils/linked_list.h>
+#include <utils/identification.h>
+#include <utils/fetcher.h>
+
+typedef struct private_ca_info_t private_ca_info_t;
+
+/**
+ * Private data of a ca_info_t object.
+ */
+struct private_ca_info_t {
+ /**
+ * Public interface for this ca info record
+ */
+ ca_info_t public;
+
+ /**
+ * Name of the ca info record
+ */
+ char *name;
+
+ /**
+ * Time when ca info record was installed
+ */
+ time_t installed;
+
+ /**
+ * Distinguished Name of the CA
+ */
+ x509_t *cacert;
+
+ /**
+ * List of crl URIs
+ */
+ linked_list_t *crluris;
+
+ /**
+ * List of ocsp URIs
+ */
+ linked_list_t *ocspuris;
+
+ /**
+ * CRL issued by this ca
+ */
+ crl_t *crl;
+
+ /**
+ * List of certificate info records
+ */
+ linked_list_t *certinfos;
+
+ /**
+ * mutex controls access to the elements:
+ * name, crluris, ocspuris, crl, and certinfos
+ */
+ pthread_mutex_t mutex;
+};
+
+/**
+ * static options set by ca_info_set_options()
+ */
+static bool cache_crls = FALSE;
+static u_int crl_check_interval = 0;
+
+/**
+ * Implements ca_info_t.equals
+ */
+static bool equals(const private_ca_info_t *this, const private_ca_info_t *that)
+{
+ return chunk_equals(this->cacert->get_keyid(this->cacert),
+ that->cacert->get_keyid(that->cacert));
+}
+
+/**
+ * Implements ca_info_t.equals_name_release_info
+ */
+static bool equals_name_release_info(private_ca_info_t *this, const char *name)
+{
+ bool found;
+
+ pthread_mutex_lock(&(this->mutex));
+ found = this->name != NULL && streq(this->name, name);
+
+ if (found)
+ {
+ this->crluris->destroy_offset(this->crluris,
+ offsetof(identification_t, destroy));
+ this->crluris = linked_list_create();
+
+ this->ocspuris->destroy_offset(this->ocspuris,
+ offsetof(identification_t, destroy));
+ this->ocspuris = linked_list_create();
+
+ free(this->name);
+ this->name = NULL;
+ }
+
+ pthread_mutex_unlock(&(this->mutex));
+ return found;
+}
+
+/**
+ * Implements ca_info_t.is_crl_issuer
+ */
+static bool is_cert_issuer(private_ca_info_t *this, const x509_t *cert)
+{
+ return cert->is_issuer(cert, this->cacert);
+}
+
+/**
+ * Implements ca_info_t.is_crl_issuer
+ */
+static bool is_crl_issuer(private_ca_info_t *this, const crl_t *crl)
+{
+ return crl->is_issuer(crl, this->cacert);
+}
+
+/**
+ * Implements ca_info_t.has_crl
+ */
+static bool has_crl(private_ca_info_t *this)
+{
+ bool found;
+
+ pthread_mutex_lock(&(this->mutex));
+ found = this->crl != NULL;
+ pthread_mutex_unlock(&(this->mutex));
+
+ return found;
+}
+
+/**
+ * Implements ca_info_t.has_certinfos
+ */
+static bool has_certinfos(private_ca_info_t *this)
+{
+ bool found;
+
+ pthread_mutex_lock(&(this->mutex));
+ found = this->certinfos->get_count(this->certinfos) > 0;
+ pthread_mutex_unlock(&(this->mutex));
+
+ return found;
+}
+
+/**
+ * Implements ca_info_t.add_crl
+ */
+static void add_crl(private_ca_info_t *this, crl_t *crl)
+{
+ pthread_mutex_lock(&(this->mutex));
+
+ if (this->crl)
+ {
+ if (crl->is_newer(crl, this->crl))
+ {
+ this->crl->destroy(this->crl);
+ this->crl = crl;
+ DBG1(" this crl is newer - existing crl replaced");
+ }
+ else
+ {
+ crl->destroy(crl);
+ DBG1(" this crl is not newer - existing crl retained");
+ }
+ }
+ else
+ {
+ this->crl = crl;
+ DBG2(" crl added");
+ }
+
+ pthread_mutex_unlock(&(this->mutex));
+}
+
+/**
+ * Implements ca_info_t.list_crl
+ */
+static void list_crl(private_ca_info_t *this, FILE *out, bool utc)
+{
+ pthread_mutex_lock(&(this->mutex));
+
+ fprintf(out, "%#U\n", this->crl, utc);
+
+ pthread_mutex_unlock(&(this->mutex));
+}
+
+/**
+ * Implements ca_info_t.list_certinfos
+ */
+static void list_certinfos(private_ca_info_t *this, FILE *out, bool utc)
+{
+ pthread_mutex_lock(&(this->mutex));
+
+ fprintf(out," authname: '%D'\n", this->cacert->get_subject(this->cacert));
+ {
+ chunk_t authkey = this->cacert->get_subjectKeyID(this->cacert);
+
+ fprintf(out," authkey: %#B\n", &authkey);
+ }
+ {
+ iterator_t *iterator = this->certinfos->create_iterator(this->certinfos, TRUE);
+ certinfo_t *certinfo;
+
+ while (iterator->iterate(iterator, (void**)&certinfo))
+ {
+ fprintf(out, "%#Y\n", certinfo, utc);
+ }
+ iterator->destroy(iterator);
+ }
+
+ pthread_mutex_unlock(&(this->mutex));
+}
+
+/**
+ * Find an exact copy of an identification in a linked list
+ */
+static identification_t* find_identification(linked_list_t *list, identification_t *id)
+{
+ identification_t *found_id = NULL, *current_id;
+
+ iterator_t *iterator = list->create_iterator(list, TRUE);
+
+ while (iterator->iterate(iterator, (void**)&current_id))
+ {
+ if (id->equals(id, current_id))
+ {
+ found_id = current_id;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+
+ return found_id;
+}
+
+/**
+ * Add a unique identification to a linked list
+ */
+static identification_t *add_identification(linked_list_t *list, identification_t *id)
+{
+ identification_t *found_id = find_identification(list, id);
+
+ if (found_id)
+ {
+ id->destroy(id);
+ return found_id;
+ }
+ else
+ {
+ list->insert_last(list, (void*)id);
+ return id;
+ }
+}
+
+/**
+ * Implements ca_info_t.add_crluri
+ */
+static void add_crluri(private_ca_info_t *this, chunk_t uri)
+{
+ if (uri.len < 6 ||
+ (strncasecmp(uri.ptr, "http", 4) != 0 &&
+ strncasecmp(uri.ptr, "ldap", 4) != 0 &&
+ strncasecmp(uri.ptr, "file", 4) != 0 &&
+ strncasecmp(uri.ptr, "ftp", 3) != 0))
+ {
+ DBG1(" invalid crl uri '%#B'", uri);
+ return;
+ }
+ else
+ {
+ identification_t *crluri = identification_create_from_encoding(ID_DER_ASN1_GN_URI, uri);
+
+ pthread_mutex_lock(&(this->mutex));
+ add_identification(this->crluris, crluri);
+ pthread_mutex_unlock(&(this->mutex));
+ }
+}
+
+/**
+ * Implements ca_info_t.add_ocspuri
+ */
+static void add_ocspuri(private_ca_info_t *this, chunk_t uri)
+{
+ if (uri.len < 7 || strncasecmp(uri.ptr, "http", 4) != 0)
+ {
+ DBG1(" invalid ocsp uri '%.*s'", uri.len, uri.ptr);
+ return;
+ }
+ else
+ {
+ identification_t *ocspuri = identification_create_from_encoding(ID_DER_ASN1_GN_URI, uri);
+
+ pthread_mutex_lock(&(this->mutex));
+ add_identification(this->ocspuris, ocspuri);
+ pthread_mutex_unlock(&(this->mutex));
+ }
+}
+
+/**
+ * Implements ca_info_t.add_info.
+ */
+void add_info (private_ca_info_t *this, const private_ca_info_t *that)
+{
+ pthread_mutex_lock(&(this->mutex));
+
+ if (this->name == NULL && that->name != NULL)
+ {
+ this->name = strdup(that->name);
+ }
+
+ pthread_mutex_unlock(&(this->mutex));
+
+ {
+ identification_t *uri;
+
+ iterator_t *iterator = that->crluris->create_iterator(that->crluris, TRUE);
+
+ while (iterator->iterate(iterator, (void**)&uri))
+ {
+ add_crluri(this, uri->get_encoding(uri));
+ }
+ iterator->destroy(iterator);
+ }
+
+ {
+ identification_t *uri;
+
+ iterator_t *iterator = that->ocspuris->create_iterator(that->ocspuris, TRUE);
+
+ while (iterator->iterate(iterator, (void**)&uri))
+ {
+ add_ocspuri(this, uri->get_encoding(uri));
+ }
+ iterator->destroy(iterator);
+ }
+}
+
+/**
+ * Implements ca_info_t.get_certificate.
+ */
+static x509_t* get_certificate(private_ca_info_t* this)
+{
+ return this->cacert;
+}
+
+/**
+ * caches a crl by saving it to a given crl directory
+ */
+void cache_crl(private_ca_info_t* this, const char *crl_dir, crl_t *crl)
+{
+ char buffer[BUF_LEN];
+ char *path;
+ char *pos = buffer;
+ int len = BUF_LEN;
+ int n;
+
+ chunk_t authKeyID = this->cacert->get_subjectKeyID(this->cacert);
+ chunk_t uri;
+
+ uri.ptr = buffer;
+ uri.len = 7 + strlen(crl_dir) + 1 + 2*authKeyID.len + 4;
+
+ if (uri.len >= BUF_LEN)
+ {
+ DBG1("file uri exceeds buffer length of %d bytes - crl not saved", BUF_LEN);
+ return;
+ }
+
+ /* print the file uri prefix */
+ n = snprintf(pos, len, "file://");
+ pos += n; len -= n;
+
+ /* remember the start of the path string */
+ path = pos;
+
+ /* print the default crl directory path */
+ n = snprintf(pos, len, "%s/", crl_dir);
+ pos += n; len -= n;
+
+ /* create and print a unique crl filename derived from the authKeyID */
+ while (authKeyID.len-- > 0)
+ {
+ n = snprintf(pos, len, "%02x", *authKeyID.ptr++);
+ pos += n; len -= n;
+ }
+
+ /* add the file suffix */
+ n = snprintf(pos, len, ".crl");
+
+ if (crl->write_to_file(crl, path, 0022, TRUE))
+ {
+ identification_t *crluri = identification_create_from_encoding(ID_DER_ASN1_GN_URI, uri);
+
+ add_identification(this->crluris, crluri);
+ }
+}
+
+/**
+ * Implements ca_info_t.verify_by_crl.
+ */
+static cert_status_t verify_by_crl(private_ca_info_t* this, certinfo_t *certinfo,
+ const char *crl_dir)
+{
+ rsa_public_key_t *issuer_public_key = this->cacert->get_public_key(this->cacert);
+ bool stale;
+
+ pthread_mutex_lock(&(this->mutex));
+ if (this->crl == NULL)
+ {
+ stale = TRUE;
+ DBG1("no crl is locally available");
+ }
+ else
+ {
+ stale = !this->crl->is_valid(this->crl);
+ DBG1("crl is %s", stale? "stale":"valid");
+ }
+
+ if (stale && crl_check_interval > 0)
+ {
+ iterator_t *iterator = this->crluris->create_iterator(this->crluris, TRUE);
+ identification_t *uri;
+
+ while (iterator->iterate(iterator, (void**)&uri))
+ {
+ fetcher_t *fetcher;
+ char uri_string[BUF_LEN];
+ chunk_t uri_chunk = uri->get_encoding(uri);
+ chunk_t response_chunk;
+
+ snprintf(uri_string, BUF_LEN, "%.*s", uri_chunk.len, uri_chunk.ptr);
+ fetcher = fetcher_create(uri_string);
+
+ response_chunk = fetcher->get(fetcher);
+ fetcher->destroy(fetcher);
+ if (response_chunk.ptr != NULL)
+ {
+ crl_t *crl = crl_create_from_chunk(response_chunk);
+
+ if (crl == NULL)
+ {
+ free(response_chunk.ptr);
+ continue;
+ }
+ if (!is_crl_issuer(this, crl))
+ {
+ DBG1(" fetched crl has wrong issuer");
+ crl->destroy(crl);
+ continue;
+ }
+ if (!crl->verify(crl, issuer_public_key))
+ {
+ DBG1("fetched crl signature is invalid");
+ crl->destroy(crl);
+ continue;
+ }
+ DBG2("fetched crl signature is valid");
+
+ if (this->crl == NULL)
+ {
+ this->crl = crl;
+ }
+ else if (crl->is_newer(crl, this->crl))
+ {
+ this->crl->destroy(this->crl);
+ this->crl = crl;
+ DBG1("this crl is newer - existing crl replaced");
+ }
+ else
+ {
+ crl->destroy(crl);
+ DBG1("this crl is not newer - existing crl retained");
+ continue;
+ }
+ if (crl->is_valid(crl))
+ {
+ if (cache_crls && strncasecmp(uri_string, "file", 4) != 0)
+ {
+ cache_crl(this, crl_dir, crl);
+ }
+ /* we found a valid crl and therefore exit the fetch loop */
+ break;
+ }
+ else
+ {
+ DBG1("fetched crl is stale");
+ }
+ }
+ }
+ iterator->destroy(iterator);
+ }
+
+ if (this->crl)
+ {
+ if (!this->crl->verify(this->crl, issuer_public_key))
+ {
+ DBG1("crl signature is invalid");
+ goto ret;
+ }
+ DBG2("crl signature is valid");
+
+ this->crl->get_status(this->crl, certinfo);
+ }
+
+ret:
+ pthread_mutex_unlock(&(this->mutex));
+ return certinfo->get_status(certinfo);
+}
+
+/**
+ * Implements ca_info_t.verify_by_ocsp.
+ */
+static cert_status_t verify_by_ocsp(private_ca_info_t* this,
+ certinfo_t *certinfo,
+ credential_store_t *credentials)
+{
+ bool stale;
+ iterator_t *iterator;
+ certinfo_t *cached_certinfo = NULL;
+ int comparison = 1;
+
+ pthread_mutex_lock(&(this->mutex));
+
+ /* do we support OCSP at all? */
+ if (this->ocspuris->get_count(this->ocspuris) == 0)
+ {
+ goto ret;
+ }
+
+ iterator = this->certinfos->create_iterator(this->certinfos, TRUE);
+
+ /* find the list insertion point in alphabetical order */
+ while(iterator->iterate(iterator, (void**)&cached_certinfo))
+ {
+ comparison = certinfo->compare_serialNumber(certinfo, cached_certinfo);
+
+ if (comparison <= 0)
+ {
+ break;
+ }
+ }
+
+ /* do we have a valid certinfo_t for this serial number in our cache? */
+ if (comparison == 0)
+ {
+ stale = cached_certinfo->get_nextUpdate(cached_certinfo) < time(NULL);
+ DBG1("ocsp status in cache is %s", stale ? "stale":"fresh");
+ }
+ else
+ {
+ stale = TRUE;
+ DBG1("ocsp status is not in cache");
+ }
+
+ if (stale)
+ {
+ ocsp_t *ocsp;
+
+ ocsp = ocsp_create(this->cacert, this->ocspuris);
+ ocsp->fetch(ocsp, certinfo, credentials);
+ if (certinfo->get_status(certinfo) != CERT_UNDEFINED)
+ {
+ if (comparison != 0)
+ {
+ cached_certinfo = certinfo_create(certinfo->get_serialNumber(certinfo));
+
+ if (comparison > 0)
+ {
+ iterator->insert_after(iterator, (void *)cached_certinfo);
+ }
+ else
+ {
+ iterator->insert_before(iterator, (void *)cached_certinfo);
+ }
+ }
+ cached_certinfo->update(cached_certinfo, certinfo);
+ }
+ ocsp->destroy(ocsp);
+ }
+ else
+ {
+ certinfo->update(certinfo, cached_certinfo);
+ }
+
+ iterator->destroy(iterator);
+
+ret:
+ pthread_mutex_unlock(&(this->mutex));
+ return certinfo->get_status(certinfo);
+}
+
+/**
+ * Implements ca_info_t.purge_ocsp
+ */
+static void purge_ocsp(private_ca_info_t *this)
+{
+ pthread_mutex_lock(&(this->mutex));
+
+ this->certinfos->destroy_offset(this->certinfos,
+ offsetof(certinfo_t, destroy));
+ this->certinfos = linked_list_create();
+
+ pthread_mutex_unlock(&(this->mutex));
+}
+
+/**
+ * Implements ca_info_t.destroy
+ */
+static void destroy(private_ca_info_t *this)
+{
+ this->crluris->destroy_offset(this->crluris,
+ offsetof(identification_t, destroy));
+ this->ocspuris->destroy_offset(this->ocspuris,
+ offsetof(identification_t, destroy));
+ this->certinfos->destroy_offset(this->certinfos,
+ offsetof(certinfo_t, destroy));
+ DESTROY_IF(this->crl);
+ free(this->name);
+ free(this);
+}
+
+/**
+ * output handler in printf()
+ */
+static int print(FILE *stream, const struct printf_info *info,
+ const void *const *args)
+{
+ private_ca_info_t *this = *((private_ca_info_t**)(args[0]));
+ bool utc = TRUE;
+ int written = 0;
+ const x509_t *cacert;
+
+ if (info->alt)
+ {
+ utc = *((bool*)args[1]);
+ }
+ if (this == NULL)
+ {
+ return fprintf(stream, "(null)");
+ }
+
+ pthread_mutex_lock(&(this->mutex));
+ written += fprintf(stream, "%#T", &this->installed, utc);
+
+ if (this->name)
+ {
+ written += fprintf(stream, ", \"%s\"\n", this->name);
+ }
+ else
+ {
+ written += fprintf(stream, "\n");
+ }
+
+ cacert = this->cacert;
+ written += fprintf(stream, " authname: '%D'\n", cacert->get_subject(cacert));
+ {
+ chunk_t authkey = cacert->get_subjectKeyID(cacert);
+
+ written += fprintf(stream, " authkey: %#B\n", &authkey);
+ }
+ {
+ chunk_t keyid = cacert->get_keyid(cacert);
+
+ written += fprintf(stream, " keyid: %#B\n", &keyid);
+ }
+ {
+ identification_t *crluri;
+ iterator_t *iterator = this->crluris->create_iterator(this->crluris, TRUE);
+ bool first = TRUE;
+
+ while (iterator->iterate(iterator, (void**)&crluri))
+ {
+ written += fprintf(stream, " %s '%D'\n",
+ first? "crluris:":" ", crluri);
+ first = FALSE;
+ }
+ iterator->destroy(iterator);
+ }
+ {
+ identification_t *ocspuri;
+ iterator_t *iterator = this->ocspuris->create_iterator(this->ocspuris, TRUE);
+ bool first = TRUE;
+
+ while (iterator->iterate(iterator, (void**)&ocspuri))
+ {
+ written += fprintf(stream, " %s '%D'\n",
+ first? "ocspuris:":" ", ocspuri);
+ first = FALSE;
+ }
+ iterator->destroy(iterator);
+ }
+ pthread_mutex_unlock(&(this->mutex));
+ return written;
+}
+
+/**
+ * register printf() handlers
+ */
+static void __attribute__ ((constructor))print_register()
+{
+ register_printf_function(PRINTF_CAINFO, print, arginfo_ptr_alt_ptr_int);
+}
+
+/*
+ * Described in header.
+ */
+void ca_info_set_options(bool cache, u_int interval)
+{
+ cache_crls = cache;
+ crl_check_interval = interval;
+}
+
+/*
+ * Described in header.
+ */
+ca_info_t *ca_info_create(const char *name, x509_t *cacert)
+{
+ private_ca_info_t *this = malloc_thing(private_ca_info_t);
+
+ /* initialize */
+ this->installed = time(NULL);
+ this->name = (name == NULL)? NULL:strdup(name);
+ this->cacert = cacert;
+ this->crluris = linked_list_create();
+ this->ocspuris = linked_list_create();
+ this->certinfos = linked_list_create();
+ this->crl = NULL;
+
+ /* initialize the mutex */
+ pthread_mutex_init(&(this->mutex), NULL);
+
+ /* public functions */
+ this->public.equals = (bool (*) (const ca_info_t*,const ca_info_t*))equals;
+ this->public.equals_name_release_info = (bool (*) (ca_info_t*,const char*))equals_name_release_info;
+ this->public.is_cert_issuer = (bool (*) (ca_info_t*,const x509_t*))is_cert_issuer;
+ this->public.is_crl_issuer = (bool (*) (ca_info_t*,const crl_t*))is_crl_issuer;
+ this->public.add_info = (void (*) (ca_info_t*,const ca_info_t*))add_info;
+ this->public.add_crl = (void (*) (ca_info_t*,crl_t*))add_crl;
+ this->public.has_crl = (bool (*) (ca_info_t*))has_crl;
+ this->public.has_certinfos = (bool (*) (ca_info_t*))has_certinfos;
+ this->public.list_crl = (void (*) (ca_info_t*,FILE*,bool))list_crl;
+ this->public.list_certinfos = (void (*) (ca_info_t*,FILE*,bool))list_certinfos;
+ this->public.add_crluri = (void (*) (ca_info_t*,chunk_t))add_crluri;
+ this->public.add_ocspuri = (void (*) (ca_info_t*,chunk_t))add_ocspuri;
+ this->public.get_certificate = (x509_t* (*) (ca_info_t*))get_certificate;
+ this->public.verify_by_crl = (cert_status_t (*) (ca_info_t*,certinfo_t*, const char*))verify_by_crl;
+ this->public.verify_by_ocsp = (cert_status_t (*) (ca_info_t*,certinfo_t*,credential_store_t*))verify_by_ocsp;
+ this->public.purge_ocsp = (void (*) (ca_info_t*))purge_ocsp;
+ this->public.destroy = (void (*) (ca_info_t*))destroy;
+
+ return &this->public;
+}
diff --git a/src/libstrongswan/crypto/ca.h b/src/libstrongswan/crypto/ca.h
new file mode 100644
index 000000000..c494a4468
--- /dev/null
+++ b/src/libstrongswan/crypto/ca.h
@@ -0,0 +1,215 @@
+/**
+ * @file ca.h
+ *
+ * @brief Interface of ca_info_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef CA_H_
+#define CA_H_
+
+typedef struct ca_info_t ca_info_t;
+
+#include <library.h>
+#include <chunk.h>
+
+#include <credential_store.h>
+
+#include "x509.h"
+#include "crl.h"
+
+/**
+ * @brief X.509 certification authority information record
+ *
+ * @b Constructors:
+ * - ca_info_create()
+ *
+ * @ingroup transforms
+ */
+struct ca_info_t {
+
+ /**
+ * @brief Compare two ca info records
+ *
+ * Comparison is done via the keyid of the ca certificate
+ *
+ * @param this first ca info object
+ * @param that second ca info objct
+ * @return TRUE if a match is found
+ */
+ bool (*equals) (const ca_info_t *this, const ca_info_t* that);
+
+ /**
+ * @brief If the ca info record has the same name then release the name and URIs
+ *
+ * @param this ca info object
+ * @return TRUE if a match is found
+ */
+ bool (*equals_name_release_info) (ca_info_t *this, const char *name);
+
+ /**
+ * @brief Checks if a certificate was issued by this ca
+ *
+ * @param this ca info object
+ * @param cert certificate to be checked
+ * @return TRUE if the issuing ca has been found
+ */
+ bool (*is_cert_issuer) (ca_info_t *this, const x509_t *cert);
+
+ /**
+ * @brief Checks if a crl was issued by this ca
+ *
+ * @param this ca info object
+ * @param crl crl to be checked
+ * @return TRUE if the issuing ca has been found
+ */
+ bool (*is_crl_issuer) (ca_info_t *this, const crl_t *crl);
+
+ /**
+ * @brief Merges info from a secondary ca info object
+ *
+ * @param this primary ca info object
+ * @param that secondary ca info object
+ */
+ void (*add_info) (ca_info_t *this, const ca_info_t *that);
+
+ /**
+ * @brief Adds a new or replaces an obsoleted CRL
+ *
+ * @param this ca info object
+ * @param crl crl to be added
+ */
+ void (*add_crl) (ca_info_t *this, crl_t *crl);
+
+ /**
+ * @brief Does the CA have a CRL?
+ *
+ * @param this ca info object
+ * @return TRUE if crl is available
+ */
+ bool (*has_crl) (ca_info_t *this);
+
+ /**
+ * @brief Does the CA have OCSP certinfos?
+ *
+ * @param this ca info object
+ * @return TRUE if there are any certinfos
+ */
+ bool (*has_certinfos) (ca_info_t *this);
+
+ /**
+ * @brief List the CRL onto the console
+ *
+ * @param this ca info object
+ * @param out output stream
+ * @param utc TRUE - utc
+ FALSE - local time
+ */
+ void (*list_crl) (ca_info_t *this, FILE *out, bool utc);
+
+ /**
+ * @brief List the OCSP certinfos onto the console
+ *
+ * @param this ca info object
+ * @param out output stream
+ * @param utc TRUE - utc
+ FALSE - local time
+ */
+ void (*list_certinfos) (ca_info_t *this, FILE *out, bool utc);
+
+ /**
+ * @brief Adds a CRL URI to a list
+ *
+ * @param this ca info object
+ * @param uri crl uri to be added
+ */
+ void (*add_crluri) (ca_info_t *this, chunk_t uri);
+
+ /**
+ * @brief Adds a OCSP URI to a list
+ *
+ * @param this ca info object
+ * @param uri ocsp uri to be added
+ */
+ void (*add_ocspuri) (ca_info_t *this, chunk_t uri);
+
+ /**
+ * @brief Get the ca certificate
+ *
+ * @param this ca info object
+ * @return ca certificate
+ */
+ x509_t* (*get_certificate) (ca_info_t *this);
+
+ /**
+ * @brief Verify the status of a certificate by CRL
+ *
+ * @param this ca info object
+ * @param certinfo detailed certificate status information
+ * @param crl_dir directory where fetched crls should be stored
+ * @return certificate status
+ */
+ cert_status_t (*verify_by_crl) (ca_info_t *this, certinfo_t *certinfo, const char *crl_dir);
+
+ /**
+ * @brief Verify the status of a certificate by OCSP
+ *
+ * @param this ca info object
+ * @param certinfo detailed certificate status information
+ * @param credentials credential store needed for trust path verification
+ * @return certificate status
+ */
+ cert_status_t (*verify_by_ocsp) (ca_info_t* this, certinfo_t* certinfo, credential_store_t* credentials);
+
+ /**
+ * @brief Purge the OCSP certinfos of a ca info record
+ *
+ * @param this ca info object
+ */
+ void (*purge_ocsp) (ca_info_t *this);
+
+ /**
+ * @brief Destroys a ca info record
+ *
+ * @param this ca info to destroy
+ */
+ void (*destroy) (ca_info_t *this);
+};
+
+/**
+ * @brief Set ca info options
+ *
+ * @param cache TRUE if crls shall be cached by storing them
+ * @param interval crl_check_interval to be set in seconds
+ *
+ * @ingroup crypto
+ */
+void ca_info_set_options(bool cache, u_int interval);
+
+/**
+ * @brief Create a ca info record
+ *
+ * @param name name of the ca info record
+ * @param cacert path to the ca certificate
+ * @return created ca_info_t, or NULL if invalid.
+ *
+ * @ingroup crypto
+ */
+ca_info_t *ca_info_create(const char *name, x509_t *cacert);
+
+#endif /* CA_H_ */
diff --git a/src/libstrongswan/crypto/certinfo.c b/src/libstrongswan/crypto/certinfo.c
new file mode 100644
index 000000000..654e4c2bd
--- /dev/null
+++ b/src/libstrongswan/crypto/certinfo.c
@@ -0,0 +1,305 @@
+/**
+ * @file certinfo.c
+ *
+ * @brief Implementation of certinfo_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <time.h>
+#include <stdio.h>
+
+#include <library.h>
+
+#include "certinfo.h"
+
+typedef struct private_certinfo_t private_certinfo_t;
+
+/**
+ * Private data of a certinfo_t object.
+ */
+struct private_certinfo_t {
+ /**
+ * Public interface for this certificate status information object.
+ */
+ certinfo_t public;
+
+ /**
+ * Serial number of the certificate
+ */
+ chunk_t serialNumber;
+
+ /**
+ * Certificate status
+ */
+ cert_status_t status;
+
+ /**
+ * Certificate status is for one-time use only
+ */
+ bool once;
+
+ /**
+ * Time when the certificate status info was generated
+ */
+ time_t thisUpdate;
+
+ /**
+ * Time when an updated certifcate status info will be available
+ */
+ time_t nextUpdate;
+
+ /**
+ * Time of certificate revocation
+ */
+ time_t revocationTime;
+
+ /**
+ * Reason of certificate revocation
+ */
+ crl_reason_t revocationReason;
+};
+
+ENUM(cert_status_names, CERT_GOOD, CERT_UNTRUSTED,
+ "good",
+ "revoked",
+ "unknown",
+ "unknown",
+ "untrusted",
+);
+
+ENUM(crl_reason_names, REASON_UNSPECIFIED, REASON_REMOVE_FROM_CRL,
+ "unspecified",
+ "key compromise",
+ "ca compromise",
+ "affiliation changed",
+ "superseded",
+ "cessation of operation",
+ "certificate hold",
+ "reason #7",
+ "remove from crl",
+);
+
+/**
+ * Implements certinfo_t.compare_serialNumber
+ */
+static int compare_serialNumber(const private_certinfo_t *this, const private_certinfo_t *that)
+{
+ return chunk_compare(this->serialNumber, that->serialNumber);
+}
+
+/**
+ * Implements certinfo_t.equals_serialNumber
+ */
+static bool equals_serialNumber(const private_certinfo_t *this, const private_certinfo_t *that)
+{
+ return chunk_equals(this->serialNumber, that->serialNumber);
+}
+
+/**
+ * Implements certinfo_t.get_serialNumber
+ */
+static chunk_t get_serialNumber(const private_certinfo_t *this)
+{
+ return this->serialNumber;
+}
+
+/**
+ * Implements certinfo_t.set_status
+ */
+static void set_status(private_certinfo_t *this, cert_status_t status)
+{
+ this->status = status;
+}
+
+/**
+ * Implements certinfo_t.get_status
+ */
+static cert_status_t get_status(const private_certinfo_t *this)
+{
+ return this->status;
+}
+
+/**
+ * Implements certinfo_t.set_thisUpdate
+ */
+static void set_thisUpdate(private_certinfo_t *this, time_t thisUpdate)
+{
+ this->thisUpdate = thisUpdate;
+}
+
+/**
+ * Implements certinfo_t.get_thisUpdate
+ */
+static time_t get_thisUpdate(const private_certinfo_t *this)
+{
+ return this->thisUpdate;
+}
+
+/**
+ * Implements certinfo_t.set_nextUpdate
+ */
+static void set_nextUpdate(private_certinfo_t *this, time_t nextUpdate)
+{
+ this->nextUpdate = nextUpdate;
+}
+
+/**
+ * Implements certinfo_t.get_nextUpdate
+ */
+static time_t get_nextUpdate(const private_certinfo_t *this)
+{
+ return this->nextUpdate;
+}
+
+/**
+ * Implements certinfo_t.set_revocationTime
+ */
+static void set_revocationTime(private_certinfo_t *this, time_t revocationTime)
+{
+ this->revocationTime = revocationTime;
+}
+
+/**
+ * Implements certinfo_t.get_revocationTime
+ */
+static time_t get_revocationTime(const private_certinfo_t *this)
+{
+ return this->revocationTime;
+}
+
+/**
+ * Implements certinfo_t.set_revocationReason
+ */
+static void set_revocationReason(private_certinfo_t *this, crl_reason_t reason)
+{
+ this->revocationReason = reason;
+}
+
+/**
+ * Implements certinfo_t.get_revocationReason
+ */
+static crl_reason_t get_revocationReason(const private_certinfo_t *this)
+{
+ return this->revocationReason;
+}
+
+/**
+ * Implements certinfo_t.update
+ */
+static void update(private_certinfo_t *this, const private_certinfo_t *that)
+{
+ if (equals_serialNumber(this, that))
+ {
+ chunk_t this_serialNumber = this->serialNumber;
+
+ *this = *that;
+ this->serialNumber = this_serialNumber;
+ }
+}
+
+/**
+ * Implements certinfo_t.destroy
+ */
+static void destroy(private_certinfo_t *this)
+{
+ free(this->serialNumber.ptr);
+ free(this);
+}
+
+/**
+ * output handler in printf()
+ */
+static int print(FILE *stream, const struct printf_info *info,
+ const void *const *args)
+{
+ private_certinfo_t *this = *((private_certinfo_t**)(args[0]));
+ bool utc = TRUE;
+ int written = 0;
+ time_t now;
+
+ if (info->alt)
+ {
+ utc = *((bool*)args[1]);
+ }
+
+ if (this == NULL)
+ {
+ return fprintf(stream, "(null)");
+ }
+
+ now = time(NULL);
+
+ written += fprintf(stream, "%#T, until %#T, ",
+ &this->thisUpdate, utc,
+ &this->nextUpdate, utc);
+ if (now > this->nextUpdate)
+ {
+ written += fprintf(stream, "expired (%V ago)\n", &now, &this->nextUpdate);
+ }
+ else
+ {
+ written += fprintf(stream, "ok (expires in %V)\n", &now, &this->nextUpdate);
+ }
+ written += fprintf(stream, " serial: %#B, %N",
+ &this->serialNumber,
+ cert_status_names, this->status);
+ return written;
+}
+
+/**
+ * register printf() handlers
+ */
+static void __attribute__ ((constructor))print_register()
+{
+ register_printf_function(PRINTF_CERTINFO, print, arginfo_ptr_alt_ptr_int);
+}
+
+/*
+ * Described in header.
+ */
+certinfo_t *certinfo_create(chunk_t serial)
+{
+ private_certinfo_t *this = malloc_thing(private_certinfo_t);
+
+ /* initialize */
+ this->serialNumber = chunk_clone(serial);
+ this->status = CERT_UNDEFINED;
+ this->thisUpdate = UNDEFINED_TIME;
+ this->nextUpdate = UNDEFINED_TIME;
+ this->revocationTime = UNDEFINED_TIME;
+ this->revocationReason = REASON_UNSPECIFIED;
+
+ /* public functions */
+ this->public.compare_serialNumber = (int (*) (const certinfo_t*,const certinfo_t*))compare_serialNumber;
+ this->public.equals_serialNumber = (bool (*) (const certinfo_t*,const certinfo_t*))equals_serialNumber;
+ this->public.get_serialNumber = (chunk_t (*) (const certinfo_t*))get_serialNumber;
+ this->public.set_status = (void (*) (certinfo_t*,cert_status_t))set_status;
+ this->public.get_status = (cert_status_t (*) (const certinfo_t*))get_status;
+ this->public.set_thisUpdate = (void (*) (certinfo_t*,time_t))set_thisUpdate;
+ this->public.get_thisUpdate = (time_t (*) (const certinfo_t*))get_thisUpdate;
+ this->public.set_nextUpdate = (void (*) (certinfo_t*,time_t))set_nextUpdate;
+ this->public.get_nextUpdate = (time_t (*) (const certinfo_t*))get_nextUpdate;
+ this->public.set_revocationTime = (void (*) (certinfo_t*,time_t))set_revocationTime;
+ this->public.get_revocationTime = (time_t (*) (const certinfo_t*))get_revocationTime;
+ this->public.set_revocationReason = (void (*) (certinfo_t*, crl_reason_t))set_revocationReason;
+ this->public.get_revocationReason = (crl_reason_t(*) (const certinfo_t*))get_revocationReason;
+ this->public.update = (void (*) (certinfo_t*, const certinfo_t*))update;
+ this->public.destroy = (void (*) (certinfo_t*))destroy;
+
+ return &this->public;
+}
diff --git a/src/libstrongswan/crypto/certinfo.h b/src/libstrongswan/crypto/certinfo.h
new file mode 100644
index 000000000..476befda8
--- /dev/null
+++ b/src/libstrongswan/crypto/certinfo.h
@@ -0,0 +1,203 @@
+/**
+ * @file certinfo.h
+ *
+ * @brief Interface of certinfo_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef CERTINFO_H_
+#define CERTINFO_H_
+
+typedef enum cert_status_t cert_status_t;
+typedef enum crl_reason_t crl_reason_t;
+typedef struct certinfo_t certinfo_t;
+
+#include <library.h>
+
+/**
+ * RFC 2560 OCSP - certificate status
+ */
+enum cert_status_t {
+ CERT_GOOD = 0,
+ CERT_REVOKED = 1,
+ CERT_UNKNOWN = 2,
+ CERT_UNDEFINED = 3,
+ CERT_UNTRUSTED = 4 /* private use */
+};
+
+extern enum_name_t *cert_status_names;
+
+/**
+ * RFC 2459 CRL reason codes
+ */
+enum crl_reason_t {
+ REASON_UNSPECIFIED = 0,
+ REASON_KEY_COMPROMISE = 1,
+ REASON_CA_COMPROMISE = 2,
+ REASON_AFFILIATION_CHANGED = 3,
+ REASON_SUPERSEDED = 4,
+ REASON_CESSATION_OF_OPERATON = 5,
+ REASON_CERTIFICATE_HOLD = 6,
+ REASON_REMOVE_FROM_CRL = 8
+};
+
+extern enum_name_t *crl_reason_names;
+
+/**
+ * @brief X.509 certificate status information
+ *
+ * @ingroup transforms
+ */
+struct certinfo_t {
+
+ /**
+ * @brief Check if both certinfo objects have the same serialNumber.
+ *
+ * @param this calling object
+ * @param that second certinfo_t object
+ * @return TRUE if the same serialNumber
+ */
+ bool (*equals_serialNumber) (const certinfo_t *this, const certinfo_t *that);
+
+ /**
+ * @brief Compares two serial numbers.
+ *
+ * @param this calling object
+ * @param that second certinfo_t object
+ * @return negative if this is smaller than that
+ * zero if this equals that
+ * positive if this is greater than that
+ */
+ int (*compare_serialNumber) (const certinfo_t *this, const certinfo_t *that);
+
+ /**
+ * @brief Get serial number.
+ *
+ * @param this calling object
+ * @return serialNumber
+ */
+ chunk_t (*get_serialNumber) (const certinfo_t *this);
+
+ /**
+ * @brief Set certificate status.
+ *
+ * @param this calling object
+ * @param status status
+ */
+ void (*set_status) (certinfo_t *this, cert_status_t status);
+
+ /**
+ * @brief Get certificate status.
+ *
+ * @param this calling object
+ * @return status
+ */
+ cert_status_t (*get_status) (const certinfo_t *this);
+
+ /**
+ * @brief Set thisUpdate.
+ *
+ * @param this calling object
+ * @param thisUpdate thisUpdate
+ */
+ void (*set_thisUpdate) (certinfo_t *this, time_t thisUpdate);
+
+ /**
+ * @brief Get thisUpdate.
+ *
+ * @param this calling object
+ * @return thisUpdate
+ */
+ time_t (*get_thisUpdate) (const certinfo_t *this);
+
+ /**
+ * @brief Set nextUpdate.
+ *
+ * @param this calling object
+ * @param nextUpdate
+ */
+ void (*set_nextUpdate) (certinfo_t *this, time_t nextUpdate);
+
+ /**
+ * @brief Get nextUpdate.
+ *
+ * @param this calling object
+ * @return nextUpdate
+ */
+ time_t (*get_nextUpdate) (const certinfo_t *this);
+
+ /**
+ * @brief Set revocationTime.
+ *
+ * @param this calling object
+ * @param revocationTime revocationTime
+ */
+ void (*set_revocationTime) (certinfo_t *this, time_t revocationTime);
+
+ /**
+ * @brief Get revocationTime.
+ *
+ * @param this calling object
+ * @return revocationTime
+ */
+ time_t (*get_revocationTime) (const certinfo_t *this);
+
+ /**
+ * @brief Set revocationReason.
+ *
+ * @param this calling object
+ * @param reason revocationReason
+ */
+ void (*set_revocationReason) (certinfo_t *this, crl_reason_t reason);
+
+ /**
+ * @brief Get revocationReason.
+ *
+ * @param this calling object
+ * @return revocationReason
+ */
+ crl_reason_t (*get_revocationReason) (const certinfo_t *this);
+
+ /**
+ * @brief Set revocationReason.
+ *
+ * @param this calling object to be updated
+ * @param that object containing updated information
+ */
+ void (*update) (certinfo_t *this, const certinfo_t *that);
+
+ /**
+ * @brief Destroys the certinfo_t object.
+ *
+ * @param this certinfo_t to destroy
+ */
+ void (*destroy) (certinfo_t *this);
+
+};
+
+/**
+ * @brief Create a certinfo_t object.
+ *
+ * @param serial chunk serial number of the certificate
+ * @return created certinfo_t object
+ *
+ * @ingroup transforms
+ */
+certinfo_t *certinfo_create(chunk_t serial);
+
+#endif /* CERTINFO_H_ */
diff --git a/src/libstrongswan/crypto/crl.c b/src/libstrongswan/crypto/crl.c
new file mode 100755
index 000000000..00d6a3ac3
--- /dev/null
+++ b/src/libstrongswan/crypto/crl.c
@@ -0,0 +1,533 @@
+/**
+ * @file crl.c
+ *
+ * @brief Implementation of crl_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <unistd.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <library.h>
+#include <debug.h>
+#include <asn1/oid.h>
+#include <asn1/asn1.h>
+#include <asn1/pem.h>
+#include <utils/linked_list.h>
+#include <utils/identification.h>
+
+#include "certinfo.h"
+#include "x509.h"
+#include "crl.h"
+
+#define CRL_WARNING_INTERVAL 7 /* days */
+
+extern char* check_expiry(time_t expiration_date, int warning_interval, bool strict);
+extern time_t parse_time(chunk_t blob, int level0);
+extern void parse_authorityKeyIdentifier(chunk_t blob, int level0 , chunk_t *authKeyID, chunk_t *authKeySerialNumber);
+
+/* access structure for a revoked certificate */
+
+typedef struct revokedCert_t revokedCert_t;
+
+struct revokedCert_t {
+ chunk_t userCertificate;
+ time_t revocationDate;
+ crl_reason_t revocationReason;
+};
+
+typedef struct private_crl_t private_crl_t;
+
+/**
+ * Private data of a crl_t object.
+ */
+struct private_crl_t {
+ /**
+ * Public interface for this crl.
+ */
+ crl_t public;
+
+ /**
+ * Time when crl was installed
+ */
+ time_t installed;
+
+ /**
+ * List of crlDistributionPoints
+ */
+ linked_list_t *crlDistributionPoints;
+
+ /**
+ * X.509 crl in DER format
+ */
+ chunk_t certificateList;
+
+ /**
+ * X.509 crl body over which signature is computed
+ */
+ chunk_t tbsCertList;
+
+ /**
+ * Version of the X.509 crl
+ */
+ u_int version;
+
+ /**
+ * Signature algorithm
+ */
+ int sigAlg;
+
+ /**
+ * ID representing the crl issuer
+ */
+ identification_t *issuer;
+
+ /**
+ * Time when the crl was generated
+ */
+ time_t thisUpdate;
+
+ /**
+ * Time when an update crl will be available
+ */
+ time_t nextUpdate;
+
+ /**
+ * List of identification_t's representing subjectAltNames
+ */
+ linked_list_t *revokedCertificates;
+
+ /**
+ * Authority Key Identifier
+ */
+ chunk_t authKeyID;
+
+ /**
+ * Authority Key Serial Number
+ */
+ chunk_t authKeySerialNumber;
+
+ /**
+ * Signature algorithm (must be identical to sigAlg)
+ */
+ int algorithm;
+
+ /**
+ * Signature
+ */
+ chunk_t signature;
+};
+
+/**
+ * ASN.1 definition of an X.509 certificate revocation list
+ */
+static const asn1Object_t crlObjects[] = {
+ { 0, "certificateList", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
+ { 1, "tbsCertList", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
+ { 2, "version", ASN1_INTEGER, ASN1_OPT |
+ ASN1_BODY }, /* 2 */
+ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 3 */
+ { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 4 */
+ { 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */
+ { 2, "thisUpdate", ASN1_EOC, ASN1_RAW }, /* 6 */
+ { 2, "nextUpdate", ASN1_EOC, ASN1_RAW }, /* 7 */
+ { 2, "revokedCertificates", ASN1_SEQUENCE, ASN1_OPT |
+ ASN1_LOOP }, /* 8 */
+ { 3, "certList", ASN1_SEQUENCE, ASN1_NONE }, /* 9 */
+ { 4, "userCertificate", ASN1_INTEGER, ASN1_BODY }, /* 10 */
+ { 4, "revocationDate", ASN1_EOC, ASN1_RAW }, /* 11 */
+ { 4, "crlEntryExtensions", ASN1_SEQUENCE, ASN1_OPT |
+ ASN1_LOOP }, /* 12 */
+ { 5, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */
+ { 6, "extnID", ASN1_OID, ASN1_BODY }, /* 14 */
+ { 6, "critical", ASN1_BOOLEAN, ASN1_DEF |
+ ASN1_BODY }, /* 15 */
+ { 6, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 16 */
+ { 4, "end opt or loop", ASN1_EOC, ASN1_END }, /* 17 */
+ { 2, "end opt or loop", ASN1_EOC, ASN1_END }, /* 18 */
+ { 2, "optional extensions", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 19 */
+ { 3, "crlExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 20 */
+ { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 21 */
+ { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 22 */
+ { 5, "critical", ASN1_BOOLEAN, ASN1_DEF |
+ ASN1_BODY }, /* 23 */
+ { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 24 */
+ { 3, "end loop", ASN1_EOC, ASN1_END }, /* 25 */
+ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 26 */
+ { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 27 */
+ { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY } /* 28 */
+ };
+
+#define CRL_OBJ_CERTIFICATE_LIST 0
+#define CRL_OBJ_TBS_CERT_LIST 1
+#define CRL_OBJ_VERSION 2
+#define CRL_OBJ_SIG_ALG 4
+#define CRL_OBJ_ISSUER 5
+#define CRL_OBJ_THIS_UPDATE 6
+#define CRL_OBJ_NEXT_UPDATE 7
+#define CRL_OBJ_USER_CERTIFICATE 10
+#define CRL_OBJ_REVOCATION_DATE 11
+#define CRL_OBJ_CRL_ENTRY_EXTN_ID 14
+#define CRL_OBJ_CRL_ENTRY_CRITICAL 15
+#define CRL_OBJ_CRL_ENTRY_EXTN_VALUE 16
+#define CRL_OBJ_EXTN_ID 22
+#define CRL_OBJ_CRITICAL 23
+#define CRL_OBJ_EXTN_VALUE 24
+#define CRL_OBJ_ALGORITHM 27
+#define CRL_OBJ_SIGNATURE 28
+#define CRL_OBJ_ROOF 29
+
+/**
+ * Parses a CRL revocation reason code
+ */
+static crl_reason_t parse_crl_reasonCode(chunk_t object)
+{
+ crl_reason_t reason = REASON_UNSPECIFIED;
+
+ if (*object.ptr == ASN1_ENUMERATED && asn1_length(&object) == 1)
+ {
+ reason = *object.ptr;
+ }
+ DBG2(" '%N'", crl_reason_names, reason);
+
+ return reason;
+}
+
+/**
+ * Parses an X.509 Certificate Revocation List (CRL)
+ */
+bool parse_x509crl(chunk_t blob, u_int level0, private_crl_t *crl)
+{
+ asn1_ctx_t ctx;
+ bool critical;
+ chunk_t extnID;
+ chunk_t userCertificate = chunk_empty;
+ revokedCert_t *revokedCert = NULL;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+
+ asn1_init(&ctx, blob, level0, FALSE, FALSE);
+
+ while (objectID < CRL_OBJ_ROOF)
+ {
+ if (!extract_object(crlObjects, &objectID, &object, &level, &ctx))
+ return FALSE;
+
+ /* those objects which will parsed further need the next higher level */
+ level++;
+
+ switch (objectID)
+ {
+ case CRL_OBJ_CERTIFICATE_LIST:
+ crl->certificateList = object;
+ break;
+ case CRL_OBJ_TBS_CERT_LIST:
+ crl->tbsCertList = object;
+ break;
+ case CRL_OBJ_VERSION:
+ crl->version = (object.len) ? (1+(u_int)*object.ptr) : 1;
+ DBG2(" v%d", crl->version);
+ break;
+ case CRL_OBJ_SIG_ALG:
+ crl->sigAlg = parse_algorithmIdentifier(object, level, NULL);
+ break;
+ case CRL_OBJ_ISSUER:
+ crl->issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object);
+ DBG2(" '%D'", crl->issuer);
+ break;
+ case CRL_OBJ_THIS_UPDATE:
+ crl->thisUpdate = parse_time(object, level);
+ break;
+ case CRL_OBJ_NEXT_UPDATE:
+ crl->nextUpdate = parse_time(object, level);
+ break;
+ case CRL_OBJ_USER_CERTIFICATE:
+ userCertificate = object;
+ break;
+ case CRL_OBJ_REVOCATION_DATE:
+ revokedCert = malloc_thing(revokedCert_t);
+ revokedCert->userCertificate = userCertificate;
+ revokedCert->revocationDate = parse_time(object, level);
+ revokedCert->revocationReason = REASON_UNSPECIFIED;
+ crl->revokedCertificates->insert_last(crl->revokedCertificates, (void *)revokedCert);
+ break;
+ case CRL_OBJ_CRL_ENTRY_EXTN_ID:
+ case CRL_OBJ_EXTN_ID:
+ extnID = object;
+ break;
+ case CRL_OBJ_CRL_ENTRY_CRITICAL:
+ case CRL_OBJ_CRITICAL:
+ critical = object.len && *object.ptr;
+ DBG2(" %s",(critical)?"TRUE":"FALSE");
+ break;
+ case CRL_OBJ_CRL_ENTRY_EXTN_VALUE:
+ case CRL_OBJ_EXTN_VALUE:
+ {
+ int extn_oid = known_oid(extnID);
+
+ if (revokedCert && extn_oid == OID_CRL_REASON_CODE)
+ {
+ revokedCert->revocationReason = parse_crl_reasonCode(object);
+ }
+ else if (extn_oid == OID_AUTHORITY_KEY_ID)
+ {
+ parse_authorityKeyIdentifier(object, level, &crl->authKeyID, &crl->authKeySerialNumber);
+ }
+ }
+ break;
+ case CRL_OBJ_ALGORITHM:
+ crl->algorithm = parse_algorithmIdentifier(object, level, NULL);
+ break;
+ case CRL_OBJ_SIGNATURE:
+ crl->signature = object;
+ break;
+ default:
+ break;
+ }
+ objectID++;
+ }
+ time(&crl->installed);
+ return TRUE;
+}
+
+/**
+ * Implements crl_t.is_valid
+ */
+static bool is_valid(const private_crl_t *this)
+{
+ time_t current_time = time(NULL);
+
+ DBG2(" this update : %T", &this->thisUpdate);
+ DBG2(" current time: %T", &current_time);
+ DBG2(" next update: %T", &this->nextUpdate);
+
+ return current_time < this->nextUpdate;
+}
+
+/**
+ * Implements crl_t.get_issuer
+ */
+static identification_t *get_issuer(const private_crl_t *this)
+{
+ return this->issuer;
+}
+
+/**
+ * Implements crl_t.equals_issuer
+ */
+static bool equals_issuer(const private_crl_t *this, const private_crl_t *other)
+{
+ return (this->authKeyID.ptr)
+ ? chunk_equals(this->authKeyID, other->authKeyID)
+ : (this->issuer->equals(this->issuer, other->issuer)
+ && chunk_equals_or_null(this->authKeySerialNumber, other->authKeySerialNumber));
+}
+
+/**
+ * Implements crl_t.is_issuer
+ */
+static bool is_issuer(const private_crl_t *this, const x509_t *issuer)
+{
+ return (this->authKeyID.ptr)
+ ? chunk_equals(this->authKeyID, issuer->get_subjectKeyID(issuer))
+ : (this->issuer->equals(this->issuer, issuer->get_subject(issuer))
+ && chunk_equals_or_null(this->authKeySerialNumber, issuer->get_serialNumber(issuer)));
+}
+
+/**
+ * Implements crl_t.is_newer
+ */
+static bool is_newer(const private_crl_t *this, const private_crl_t *other)
+{
+ return (this->nextUpdate > other->nextUpdate);
+}
+
+/**
+ * Implements crl_t.verify
+ */
+static bool verify(const private_crl_t *this, const rsa_public_key_t *signer)
+{
+ return signer->verify_emsa_pkcs1_signature(signer, this->tbsCertList, this->signature) == SUCCESS;
+}
+
+/**
+ * Implements crl_t.get_status
+ */
+static void get_status(const private_crl_t *this, certinfo_t *certinfo)
+{
+ chunk_t serialNumber = certinfo->get_serialNumber(certinfo);
+ iterator_t *iterator;
+ revokedCert_t *revokedCert;
+
+ certinfo->set_nextUpdate(certinfo, this->nextUpdate);
+ certinfo->set_status(certinfo, CERT_GOOD);
+
+ iterator = this->revokedCertificates->create_iterator(this->revokedCertificates, TRUE);
+ while (iterator->iterate(iterator, (void**)&revokedCert))
+ {
+ if (chunk_equals(serialNumber, revokedCert->userCertificate))
+ {
+ certinfo->set_status(certinfo, CERT_REVOKED);
+ certinfo->set_revocationTime(certinfo, revokedCert->revocationDate);
+ certinfo->set_revocationReason(certinfo, revokedCert->revocationReason);
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+}
+
+/**
+ * Implements crl_t.write_to_file.
+ */
+static bool write_to_file(private_crl_t *this, const char *path, mode_t mask, bool force)
+{
+ return chunk_write(this->certificateList, path, "crl", mask, force);
+}
+
+/**
+ * Implements crl_t.destroy
+ */
+static void destroy(private_crl_t *this)
+{
+ this->revokedCertificates->destroy_function(this->revokedCertificates, free);
+ this->crlDistributionPoints->destroy_offset(this->crlDistributionPoints,
+ offsetof(identification_t, destroy));
+ DESTROY_IF(this->issuer);
+ free(this->certificateList.ptr);
+ free(this);
+}
+
+/**
+ * output handler in printf()
+ */
+static int print(FILE *stream, const struct printf_info *info,
+ const void *const *args)
+{
+ private_crl_t *this = *((private_crl_t**)(args[0]));
+ bool utc = TRUE;
+ int written = 0;
+ time_t now;
+
+ if (info->alt)
+ {
+ utc = *((bool*)args[1]);
+ }
+
+ if (this == NULL)
+ {
+ return fprintf(stream, "(null)");
+ }
+
+ now = time(NULL);
+
+ written += fprintf(stream, "%#T, revoked certs: %d\n", &this->installed, utc,
+ this->revokedCertificates->get_count(this->revokedCertificates));
+ written += fprintf(stream, " issuer: '%D'\n", this->issuer);
+ written += fprintf(stream, " updates: this %#T\n", &this->thisUpdate, utc);
+ written += fprintf(stream, " next %#T ", &this->nextUpdate, utc);
+ if (this->nextUpdate == UNDEFINED_TIME)
+ {
+ written += fprintf(stream, "ok (expires never)");
+ }
+ else if (now > this->nextUpdate)
+ {
+ written += fprintf(stream, "expired (%V ago)", &now, &this->nextUpdate);
+ }
+ else if (now > this->nextUpdate - CRL_WARNING_INTERVAL * 60 * 60 * 24)
+ {
+ written += fprintf(stream, "ok (expires in %V)", &now, &this->nextUpdate);
+ }
+ else
+ {
+ written += fprintf(stream, "ok");
+ }
+ if (this->authKeyID.ptr)
+ {
+ written += fprintf(stream, "\n authkey: %#B", &this->authKeyID);
+ }
+ if (this->authKeySerialNumber.ptr)
+ {
+ written += fprintf(stream, "\n aserial: %#B", &this->authKeySerialNumber);
+ }
+ return written;
+}
+
+/**
+ * register printf() handlers
+ */
+static void __attribute__ ((constructor))print_register()
+{
+ register_printf_function(PRINTF_CRL, print, arginfo_ptr_alt_ptr_int);
+}
+
+/*
+ * Described in header.
+ */
+crl_t *crl_create_from_chunk(chunk_t chunk)
+{
+ private_crl_t *this = malloc_thing(private_crl_t);
+
+ /* initialize */
+ this->crlDistributionPoints = linked_list_create();
+ this->tbsCertList = chunk_empty;
+ this->issuer = NULL;
+ this->revokedCertificates = linked_list_create();
+ this->authKeyID = chunk_empty;
+ this->authKeySerialNumber = chunk_empty;
+
+ /* public functions */
+ this->public.get_issuer = (identification_t* (*) (const crl_t*))get_issuer;
+ this->public.equals_issuer = (bool (*) (const crl_t*,const crl_t*))equals_issuer;
+ this->public.is_issuer = (bool (*) (const crl_t*,const x509_t*))is_issuer;
+ this->public.is_valid = (bool (*) (const crl_t*))is_valid;
+ this->public.is_newer = (bool (*) (const crl_t*,const crl_t*))is_newer;
+ this->public.verify = (bool (*) (const crl_t*,const rsa_public_key_t*))verify;
+ this->public.get_status = (void (*) (const crl_t*,certinfo_t*))get_status;
+ this->public.write_to_file = (bool (*) (const crl_t*,const char*,mode_t,bool))write_to_file;
+ this->public.destroy = (void (*) (crl_t*))destroy;
+
+ if (!parse_x509crl(chunk, 0, this))
+ {
+ destroy(this);
+ return NULL;
+ }
+
+ return &this->public;
+}
+
+/*
+ * Described in header.
+ */
+crl_t *crl_create_from_file(const char *filename)
+{
+ bool pgp = FALSE;
+ chunk_t chunk = chunk_empty;
+ crl_t *crl = NULL;
+
+ if (!pem_asn1_load_file(filename, NULL, "crl", &chunk, &pgp))
+ return NULL;
+
+ crl = crl_create_from_chunk(chunk);
+
+ if (crl == NULL)
+ free(chunk.ptr);
+ return crl;
+}
diff --git a/src/libstrongswan/crypto/crl.h b/src/libstrongswan/crypto/crl.h
new file mode 100755
index 000000000..8a11fc390
--- /dev/null
+++ b/src/libstrongswan/crypto/crl.h
@@ -0,0 +1,147 @@
+/**
+ * @file crl.h
+ *
+ * @brief Interface of crl_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 CRL_H_
+#define CRL_H_
+
+typedef struct crl_t crl_t;
+
+#include <library.h>
+#include <crypto/rsa/rsa_public_key.h>
+#include <crypto/certinfo.h>
+#include <utils/identification.h>
+#include <utils/iterator.h>
+
+/**
+ * @brief X.509 certificate revocation list
+ *
+ * @b Constructors:
+ * - crl_create_from_chunk()
+ * - crl_create_from_file()
+ *
+ * @ingroup transforms
+ */
+struct crl_t {
+
+ /**
+ * @brief Get the crl's issuer ID.
+ *
+ * The resulting ID is always a identification_t
+ * of type ID_DER_ASN1_DN.
+ *
+ * @param this calling object
+ * @return issuers ID
+ */
+ identification_t *(*get_issuer) (const crl_t *this);
+
+ /**
+ * @brief Check if both crls have the same issuer.
+ *
+ * @param this calling object
+ * @param other other crl
+ * @return TRUE if the same issuer
+ */
+ bool (*equals_issuer) (const crl_t *this, const crl_t *other);
+
+ /**
+ * @brief Check if ia candidate cert is the issuer of the crl
+ *
+ * @param this calling object
+ * @param issuer candidate issuer of the crl
+ * @return TRUE if issuer
+ */
+ bool (*is_issuer) (const crl_t *this, const x509_t *issuer);
+
+ /**
+ * @brief Checks the validity interval of the crl
+ *
+ * @param this calling object
+ * @return TRUE if the crl is valid
+ */
+ bool (*is_valid) (const crl_t *this);
+
+ /**
+ * @brief Checks if this crl is newer (thisUpdate) than the other crl
+ *
+ * @param this calling object
+ * @param other other crl object
+ * @return TRUE if this was issued more recently than other
+ */
+ bool (*is_newer) (const crl_t *this, const crl_t *other);
+
+ /**
+ * @brief Check if a crl is trustworthy.
+ *
+ * @param this calling object
+ * @param signer signer's RSA public key
+ * @return TRUE if crl is trustworthy
+ */
+ bool (*verify) (const crl_t *this, const rsa_public_key_t *signer);
+
+ /**
+ * @brief Get the certificate status
+ *
+ * @param this calling object
+ * @param certinfo certinfo is updated
+ */
+ void (*get_status) (const crl_t *this, certinfo_t *certinfo);
+
+ /**
+ * @brief Write a der-encoded crl to a file
+ *
+ * @param this calling object
+ * @param path path where the file is to be stored
+ * @param mask file access control rights
+ * @param force overwrite the file if it already exists
+ * @return TRUE if successfully written
+ */
+ bool (*write_to_file) (const crl_t *this, const char *path, mode_t mask, bool force);
+
+ /**
+ * @brief Destroys the crl.
+ *
+ * @param this crl to destroy
+ */
+ void (*destroy) (crl_t *this);
+};
+
+/**
+ * @brief Read a x509 crl from a DER encoded blob.
+ *
+ * @param chunk chunk containing DER encoded data
+ * @return created crl_t, or NULL if invalid.
+ *
+ * @ingroup transforms
+ */
+crl_t *crl_create_from_chunk(chunk_t chunk);
+
+/**
+ * @brief Read a x509 crl from a DER encoded file.
+ *
+ * @param filename file containing DER encoded data
+ * @return created crl_t, or NULL if invalid.
+ *
+ * @ingroup transforms
+ */
+crl_t *crl_create_from_file(const char *filename);
+
+#endif /* CRL_H_ */
diff --git a/src/libstrongswan/crypto/crypters/aes_cbc_crypter.c b/src/libstrongswan/crypto/crypters/aes_cbc_crypter.c
new file mode 100644
index 000000000..947188af3
--- /dev/null
+++ b/src/libstrongswan/crypto/crypters/aes_cbc_crypter.c
@@ -0,0 +1,1620 @@
+/**
+ * @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-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "aes_cbc_crypter.h"
+
+
+
+/*
+ * The number of key schedule words for different block and key lengths
+ * allowing for method of computation which requires the length to be a
+ * multiple of the key length. This version of AES implementation supports
+ * all three keylengths 16, 24 and 32 bytes!
+ *
+ * Nk = 4 6 8
+ * -------------
+ * Nb = 4 | 60 60 64
+ * 6 | 96 90 96
+ * 8 | 120 120 120
+ */
+#define AES_KS_LENGTH 120
+#define AES_RC_LENGTH 29
+
+#define AES_BLOCK_SIZE 16
+
+typedef struct private_aes_cbc_crypter_t private_aes_cbc_crypter_t;
+
+/**
+ * @brief Class implementing the AES symmetric encryption algorithm.
+ *
+ * @ingroup crypters
+ */
+struct private_aes_cbc_crypter_t {
+
+ /**
+ * Public part of this class.
+ */
+ aes_cbc_crypter_t public;
+
+ /**
+ * Number of words in the key input block.
+ */
+ u_int32_t aes_Nkey;
+
+ /**
+ * The number of cipher rounds.
+ */
+ u_int32_t aes_Nrnd;
+
+ /**
+ * The encryption key schedule.
+ */
+ u_int32_t aes_e_key[AES_KS_LENGTH];
+
+ /**
+ * The decryption key schedule.
+ */
+ u_int32_t aes_d_key[AES_KS_LENGTH];
+
+ /**
+ * Key size of this AES cypher object.
+ */
+ u_int32_t key_size;
+
+ /**
+ * Decrypts a block.
+ *
+ * No memory gets allocated.
+ *
+ * @param this calling object
+ * @param[in] in_blk block to decrypt
+ * @param[out] out_blk decrypted data are written to this location
+ */
+ void (*decrypt_block) (const private_aes_cbc_crypter_t *this, const unsigned char in_blk[], unsigned char out_blk[]);
+
+ /**
+ * Encrypts a block.
+ *
+ * No memory gets allocated.
+ *
+ * @param this calling object
+ * @param[in] in_blk block to encrypt
+ * @param[out] out_blk encrypted data are written to this location
+ */
+ void (*encrypt_block) (const private_aes_cbc_crypter_t *this, const unsigned char in_blk[], unsigned char out_blk[]);
+};
+
+
+/* ugly macro stuff */
+
+/* 1. Define UNROLL for full loop unrolling in encryption and decryption.
+ * 2. Define PARTIAL_UNROLL to unroll two loops in encryption and decryption.
+ * 3. Define FIXED_TABLES for compiled rather than dynamic tables.
+ * 4. Define FF_TABLES to use tables for field multiplies and inverses.
+ * Do not enable this without understanding stack space requirements.
+ * 5. Define ARRAYS to use arrays to hold the local state block. If this
+ * is not defined, individually declared 32-bit words are used.
+ * 6. Define FAST_VARIABLE if a high speed variable block implementation
+ * is needed (essentially three separate fixed block size code sequences)
+ * 7. Define either ONE_TABLE or FOUR_TABLES for a fast table driven
+ * version using 1 table (2 kbytes of table space) or 4 tables (8
+ * kbytes of table space) for higher speed.
+ * 8. Define either ONE_LR_TABLE or FOUR_LR_TABLES for a further speed
+ * increase by using tables for the last rounds but with more table
+ * space (2 or 8 kbytes extra).
+ * 9. If neither ONE_TABLE nor FOUR_TABLES is defined, a compact but
+ * slower version is provided.
+ * 10. If fast decryption key scheduling is needed define ONE_IM_TABLE
+ * or FOUR_IM_TABLES for higher speed (2 or 8 kbytes extra).
+ */
+
+#define UNROLL
+//#define PARTIAL_UNROLL
+
+#define FIXED_TABLES
+//#define FF_TABLES
+//#define ARRAYS
+#define FAST_VARIABLE
+
+//#define ONE_TABLE
+#define FOUR_TABLES
+
+//#define ONE_LR_TABLE
+#define FOUR_LR_TABLES
+
+//#define ONE_IM_TABLE
+#define FOUR_IM_TABLES
+
+#if defined(UNROLL) && defined (PARTIAL_UNROLL)
+#error both UNROLL and PARTIAL_UNROLL are defined
+#endif
+
+#if defined(ONE_TABLE) && defined (FOUR_TABLES)
+#error both ONE_TABLE and FOUR_TABLES are defined
+#endif
+
+#if defined(ONE_LR_TABLE) && defined (FOUR_LR_TABLES)
+#error both ONE_LR_TABLE and FOUR_LR_TABLES are defined
+#endif
+
+#if defined(ONE_IM_TABLE) && defined (FOUR_IM_TABLES)
+#error both ONE_IM_TABLE and FOUR_IM_TABLES are defined
+#endif
+
+#if defined(AES_BLOCK_SIZE) && AES_BLOCK_SIZE != 16 && AES_BLOCK_SIZE != 24 && AES_BLOCK_SIZE != 32
+#error an illegal block size has been specified
+#endif
+
+/**
+ * Rotates bytes within words by n positions, moving bytes
+ * to higher index positions with wrap around into low positions.
+ */
+#define upr(x,n) (((x) << 8 * (n)) | ((x) >> (32 - 8 * (n))))
+/**
+ * Moves bytes by n positions to higher index positions in
+ * words but without wrap around.
+ */
+#define ups(x,n) ((x) << 8 * (n))
+
+/**
+ * Extracts a byte from a word.
+ */
+#define bval(x,n) ((unsigned char)((x) >> 8 * (n)))
+#define bytes2word(b0, b1, b2, b3) \
+ ((u_int32_t)(b3) << 24 | (u_int32_t)(b2) << 16 | (u_int32_t)(b1) << 8 | (b0))
+
+
+/* little endian processor without data alignment restrictions: AES_LE_OK */
+/* original code: i386 */
+#if defined(i386) || defined(_I386) || defined(__i386__) || defined(__i386)
+#define AES_LE_OK 1
+/* added (tested): alpha --jjo */
+#elif defined(__alpha__)|| defined (__alpha)
+#define AES_LE_OK 1
+/* added (tested): ia64 --jjo */
+#elif defined(__ia64__)|| defined (__ia64)
+#define AES_LE_OK 1
+#endif
+
+#ifdef AES_LE_OK
+/* little endian processor without data alignment restrictions */
+#define word_in(x) *(u_int32_t*)(x)
+#define const_word_in(x) *(const u_int32_t*)(x)
+#define word_out(x,v) *(u_int32_t*)(x) = (v)
+#define const_word_out(x,v) *(const u_int32_t*)(x) = (v)
+#else
+/* slower but generic big endian or with data alignment restrictions */
+/* some additional "const" touches to stop "gcc -Wcast-qual" complains --jjo */
+#define word_in(x) ((u_int32_t)(((unsigned char *)(x))[0])|((u_int32_t)(((unsigned char *)(x))[1])<<8)|((u_int32_t)(((unsigned char *)(x))[2])<<16)|((u_int32_t)(((unsigned char *)(x))[3])<<24))
+#define const_word_in(x) ((const u_int32_t)(((const unsigned char *)(x))[0])|((const u_int32_t)(((const unsigned char *)(x))[1])<<8)|((const u_int32_t)(((const unsigned char *)(x))[2])<<16)|((const u_int32_t)(((const unsigned char *)(x))[3])<<24))
+#define word_out(x,v) ((unsigned char *)(x))[0]=(v),((unsigned char *)(x))[1]=((v)>>8),((unsigned char *)(x))[2]=((v)>>16),((unsigned char *)(x))[3]=((v)>>24)
+#define const_word_out(x,v) ((const unsigned char *)(x))[0]=(v),((const unsigned char *)(x))[1]=((v)>>8),((const unsigned char *)(x))[2]=((v)>>16),((const unsigned char *)(x))[3]=((v)>>24)
+#endif
+
+// Disable at least some poor combinations of options
+
+#if !defined(ONE_TABLE) && !defined(FOUR_TABLES)
+#define FIXED_TABLES
+#undef UNROLL
+#undef ONE_LR_TABLE
+#undef FOUR_LR_TABLES
+#undef ONE_IM_TABLE
+#undef FOUR_IM_TABLES
+#elif !defined(FOUR_TABLES)
+#ifdef FOUR_LR_TABLES
+#undef FOUR_LR_TABLES
+#define ONE_LR_TABLE
+#endif
+#ifdef FOUR_IM_TABLES
+#undef FOUR_IM_TABLES
+#define ONE_IM_TABLE
+#endif
+#elif !defined(AES_BLOCK_SIZE)
+#if defined(UNROLL)
+#define PARTIAL_UNROLL
+#undef UNROLL
+#endif
+#endif
+
+// the finite field modular polynomial and elements
+
+#define ff_poly 0x011b
+#define ff_hi 0x80
+
+// multiply four bytes in GF(2^8) by 'x' {02} in parallel
+
+#define m1 0x80808080
+#define m2 0x7f7f7f7f
+#define m3 0x0000001b
+#define FFmulX(x) ((((x) & m2) << 1) ^ ((((x) & m1) >> 7) * m3))
+
+// The following defines provide alternative definitions of FFmulX that might
+// give improved performance if a fast 32-bit multiply is not available. Note
+// that a temporary variable u needs to be defined where FFmulX is used.
+
+// #define FFmulX(x) (u = (x) & m1, u |= (u >> 1), ((x) & m2) << 1) ^ ((u >> 3) | (u >> 6))
+// #define m4 0x1b1b1b1b
+// #define FFmulX(x) (u = (x) & m1, ((x) & m2) << 1) ^ ((u - (u >> 7)) & m4)
+
+// perform column mix operation on four bytes in parallel
+
+#define fwd_mcol(x) (f2 = FFmulX(x), f2 ^ upr(x ^ f2,3) ^ upr(x,2) ^ upr(x,1))
+
+#if defined(FIXED_TABLES)
+
+// the S-Box table
+
+static const unsigned char s_box[256] =
+{
+ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
+ 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
+ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
+ 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
+ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
+ 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
+ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
+ 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
+ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
+ 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
+ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
+ 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
+ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
+ 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
+ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
+ 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
+ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
+ 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
+ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
+ 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
+ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
+ 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
+ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
+ 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
+ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
+ 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
+ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
+ 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
+ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
+ 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
+ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
+ 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
+};
+
+// the inverse S-Box table
+
+static const unsigned char inv_s_box[256] =
+{
+ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38,
+ 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
+ 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
+ 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
+ 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d,
+ 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
+ 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2,
+ 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
+ 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
+ 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
+ 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda,
+ 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
+ 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a,
+ 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
+ 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
+ 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
+ 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea,
+ 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
+ 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85,
+ 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
+ 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
+ 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
+ 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20,
+ 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
+ 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31,
+ 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
+ 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
+ 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
+ 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0,
+ 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
+ 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26,
+ 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
+};
+
+#define w0(p) 0x000000##p
+
+// Number of elements required in this table for different
+// block and key lengths is:
+//
+// Nk = 4 6 8
+// ----------
+// Nb = 4 | 10 8 7
+// 6 | 19 12 11
+// 8 | 29 19 14
+//
+// this table can be a table of bytes if the key schedule
+// code is adjusted accordingly
+
+static const u_int32_t rcon_tab[29] =
+{
+ w0(01), w0(02), w0(04), w0(08),
+ w0(10), w0(20), w0(40), w0(80),
+ w0(1b), w0(36), w0(6c), w0(d8),
+ w0(ab), w0(4d), w0(9a), w0(2f),
+ w0(5e), w0(bc), w0(63), w0(c6),
+ w0(97), w0(35), w0(6a), w0(d4),
+ w0(b3), w0(7d), w0(fa), w0(ef),
+ w0(c5)
+};
+
+#undef w0
+
+#define r0(p,q,r,s) 0x##p##q##r##s
+#define r1(p,q,r,s) 0x##q##r##s##p
+#define r2(p,q,r,s) 0x##r##s##p##q
+#define r3(p,q,r,s) 0x##s##p##q##r
+#define w0(p) 0x000000##p
+#define w1(p) 0x0000##p##00
+#define w2(p) 0x00##p##0000
+#define w3(p) 0x##p##000000
+
+#if defined(FIXED_TABLES) && (defined(ONE_TABLE) || defined(FOUR_TABLES))
+
+// data for forward tables (other than last round)
+
+#define f_table \
+ r(a5,63,63,c6), r(84,7c,7c,f8), r(99,77,77,ee), r(8d,7b,7b,f6),\
+ r(0d,f2,f2,ff), r(bd,6b,6b,d6), r(b1,6f,6f,de), r(54,c5,c5,91),\
+ r(50,30,30,60), r(03,01,01,02), r(a9,67,67,ce), r(7d,2b,2b,56),\
+ r(19,fe,fe,e7), r(62,d7,d7,b5), r(e6,ab,ab,4d), r(9a,76,76,ec),\
+ r(45,ca,ca,8f), r(9d,82,82,1f), r(40,c9,c9,89), r(87,7d,7d,fa),\
+ r(15,fa,fa,ef), r(eb,59,59,b2), r(c9,47,47,8e), r(0b,f0,f0,fb),\
+ r(ec,ad,ad,41), r(67,d4,d4,b3), r(fd,a2,a2,5f), r(ea,af,af,45),\
+ r(bf,9c,9c,23), r(f7,a4,a4,53), r(96,72,72,e4), r(5b,c0,c0,9b),\
+ r(c2,b7,b7,75), r(1c,fd,fd,e1), r(ae,93,93,3d), r(6a,26,26,4c),\
+ r(5a,36,36,6c), r(41,3f,3f,7e), r(02,f7,f7,f5), r(4f,cc,cc,83),\
+ r(5c,34,34,68), r(f4,a5,a5,51), r(34,e5,e5,d1), r(08,f1,f1,f9),\
+ r(93,71,71,e2), r(73,d8,d8,ab), r(53,31,31,62), r(3f,15,15,2a),\
+ r(0c,04,04,08), r(52,c7,c7,95), r(65,23,23,46), r(5e,c3,c3,9d),\
+ r(28,18,18,30), r(a1,96,96,37), r(0f,05,05,0a), r(b5,9a,9a,2f),\
+ r(09,07,07,0e), r(36,12,12,24), r(9b,80,80,1b), r(3d,e2,e2,df),\
+ r(26,eb,eb,cd), r(69,27,27,4e), r(cd,b2,b2,7f), r(9f,75,75,ea),\
+ r(1b,09,09,12), r(9e,83,83,1d), r(74,2c,2c,58), r(2e,1a,1a,34),\
+ r(2d,1b,1b,36), r(b2,6e,6e,dc), r(ee,5a,5a,b4), r(fb,a0,a0,5b),\
+ r(f6,52,52,a4), r(4d,3b,3b,76), r(61,d6,d6,b7), r(ce,b3,b3,7d),\
+ r(7b,29,29,52), r(3e,e3,e3,dd), r(71,2f,2f,5e), r(97,84,84,13),\
+ r(f5,53,53,a6), r(68,d1,d1,b9), r(00,00,00,00), r(2c,ed,ed,c1),\
+ r(60,20,20,40), r(1f,fc,fc,e3), r(c8,b1,b1,79), r(ed,5b,5b,b6),\
+ r(be,6a,6a,d4), r(46,cb,cb,8d), r(d9,be,be,67), r(4b,39,39,72),\
+ r(de,4a,4a,94), r(d4,4c,4c,98), r(e8,58,58,b0), r(4a,cf,cf,85),\
+ r(6b,d0,d0,bb), r(2a,ef,ef,c5), r(e5,aa,aa,4f), r(16,fb,fb,ed),\
+ r(c5,43,43,86), r(d7,4d,4d,9a), r(55,33,33,66), r(94,85,85,11),\
+ r(cf,45,45,8a), r(10,f9,f9,e9), r(06,02,02,04), r(81,7f,7f,fe),\
+ r(f0,50,50,a0), r(44,3c,3c,78), r(ba,9f,9f,25), r(e3,a8,a8,4b),\
+ r(f3,51,51,a2), r(fe,a3,a3,5d), r(c0,40,40,80), r(8a,8f,8f,05),\
+ r(ad,92,92,3f), r(bc,9d,9d,21), r(48,38,38,70), r(04,f5,f5,f1),\
+ r(df,bc,bc,63), r(c1,b6,b6,77), r(75,da,da,af), r(63,21,21,42),\
+ r(30,10,10,20), r(1a,ff,ff,e5), r(0e,f3,f3,fd), r(6d,d2,d2,bf),\
+ r(4c,cd,cd,81), r(14,0c,0c,18), r(35,13,13,26), r(2f,ec,ec,c3),\
+ r(e1,5f,5f,be), r(a2,97,97,35), r(cc,44,44,88), r(39,17,17,2e),\
+ r(57,c4,c4,93), r(f2,a7,a7,55), r(82,7e,7e,fc), r(47,3d,3d,7a),\
+ r(ac,64,64,c8), r(e7,5d,5d,ba), r(2b,19,19,32), r(95,73,73,e6),\
+ r(a0,60,60,c0), r(98,81,81,19), r(d1,4f,4f,9e), r(7f,dc,dc,a3),\
+ r(66,22,22,44), r(7e,2a,2a,54), r(ab,90,90,3b), r(83,88,88,0b),\
+ r(ca,46,46,8c), r(29,ee,ee,c7), r(d3,b8,b8,6b), r(3c,14,14,28),\
+ r(79,de,de,a7), r(e2,5e,5e,bc), r(1d,0b,0b,16), r(76,db,db,ad),\
+ r(3b,e0,e0,db), r(56,32,32,64), r(4e,3a,3a,74), r(1e,0a,0a,14),\
+ r(db,49,49,92), r(0a,06,06,0c), r(6c,24,24,48), r(e4,5c,5c,b8),\
+ r(5d,c2,c2,9f), r(6e,d3,d3,bd), r(ef,ac,ac,43), r(a6,62,62,c4),\
+ r(a8,91,91,39), r(a4,95,95,31), r(37,e4,e4,d3), r(8b,79,79,f2),\
+ r(32,e7,e7,d5), r(43,c8,c8,8b), r(59,37,37,6e), r(b7,6d,6d,da),\
+ r(8c,8d,8d,01), r(64,d5,d5,b1), r(d2,4e,4e,9c), r(e0,a9,a9,49),\
+ r(b4,6c,6c,d8), r(fa,56,56,ac), r(07,f4,f4,f3), r(25,ea,ea,cf),\
+ r(af,65,65,ca), r(8e,7a,7a,f4), r(e9,ae,ae,47), r(18,08,08,10),\
+ r(d5,ba,ba,6f), r(88,78,78,f0), r(6f,25,25,4a), r(72,2e,2e,5c),\
+ r(24,1c,1c,38), r(f1,a6,a6,57), r(c7,b4,b4,73), r(51,c6,c6,97),\
+ r(23,e8,e8,cb), r(7c,dd,dd,a1), r(9c,74,74,e8), r(21,1f,1f,3e),\
+ r(dd,4b,4b,96), r(dc,bd,bd,61), r(86,8b,8b,0d), r(85,8a,8a,0f),\
+ r(90,70,70,e0), r(42,3e,3e,7c), r(c4,b5,b5,71), r(aa,66,66,cc),\
+ r(d8,48,48,90), r(05,03,03,06), r(01,f6,f6,f7), r(12,0e,0e,1c),\
+ r(a3,61,61,c2), r(5f,35,35,6a), r(f9,57,57,ae), r(d0,b9,b9,69),\
+ r(91,86,86,17), r(58,c1,c1,99), r(27,1d,1d,3a), r(b9,9e,9e,27),\
+ r(38,e1,e1,d9), r(13,f8,f8,eb), r(b3,98,98,2b), r(33,11,11,22),\
+ r(bb,69,69,d2), r(70,d9,d9,a9), r(89,8e,8e,07), r(a7,94,94,33),\
+ r(b6,9b,9b,2d), r(22,1e,1e,3c), r(92,87,87,15), r(20,e9,e9,c9),\
+ r(49,ce,ce,87), r(ff,55,55,aa), r(78,28,28,50), r(7a,df,df,a5),\
+ r(8f,8c,8c,03), r(f8,a1,a1,59), r(80,89,89,09), r(17,0d,0d,1a),\
+ r(da,bf,bf,65), r(31,e6,e6,d7), r(c6,42,42,84), r(b8,68,68,d0),\
+ r(c3,41,41,82), r(b0,99,99,29), r(77,2d,2d,5a), r(11,0f,0f,1e),\
+ r(cb,b0,b0,7b), r(fc,54,54,a8), r(d6,bb,bb,6d), r(3a,16,16,2c)
+
+// data for inverse tables (other than last round)
+
+#define i_table \
+ r(50,a7,f4,51), r(53,65,41,7e), r(c3,a4,17,1a), r(96,5e,27,3a),\
+ r(cb,6b,ab,3b), r(f1,45,9d,1f), r(ab,58,fa,ac), r(93,03,e3,4b),\
+ r(55,fa,30,20), r(f6,6d,76,ad), r(91,76,cc,88), r(25,4c,02,f5),\
+ r(fc,d7,e5,4f), r(d7,cb,2a,c5), r(80,44,35,26), r(8f,a3,62,b5),\
+ r(49,5a,b1,de), r(67,1b,ba,25), r(98,0e,ea,45), r(e1,c0,fe,5d),\
+ r(02,75,2f,c3), r(12,f0,4c,81), r(a3,97,46,8d), r(c6,f9,d3,6b),\
+ r(e7,5f,8f,03), r(95,9c,92,15), r(eb,7a,6d,bf), r(da,59,52,95),\
+ r(2d,83,be,d4), r(d3,21,74,58), r(29,69,e0,49), r(44,c8,c9,8e),\
+ r(6a,89,c2,75), r(78,79,8e,f4), r(6b,3e,58,99), r(dd,71,b9,27),\
+ r(b6,4f,e1,be), r(17,ad,88,f0), r(66,ac,20,c9), r(b4,3a,ce,7d),\
+ r(18,4a,df,63), r(82,31,1a,e5), r(60,33,51,97), r(45,7f,53,62),\
+ r(e0,77,64,b1), r(84,ae,6b,bb), r(1c,a0,81,fe), r(94,2b,08,f9),\
+ r(58,68,48,70), r(19,fd,45,8f), r(87,6c,de,94), r(b7,f8,7b,52),\
+ r(23,d3,73,ab), r(e2,02,4b,72), r(57,8f,1f,e3), r(2a,ab,55,66),\
+ r(07,28,eb,b2), r(03,c2,b5,2f), r(9a,7b,c5,86), r(a5,08,37,d3),\
+ r(f2,87,28,30), r(b2,a5,bf,23), r(ba,6a,03,02), r(5c,82,16,ed),\
+ r(2b,1c,cf,8a), r(92,b4,79,a7), r(f0,f2,07,f3), r(a1,e2,69,4e),\
+ r(cd,f4,da,65), r(d5,be,05,06), r(1f,62,34,d1), r(8a,fe,a6,c4),\
+ r(9d,53,2e,34), r(a0,55,f3,a2), r(32,e1,8a,05), r(75,eb,f6,a4),\
+ r(39,ec,83,0b), r(aa,ef,60,40), r(06,9f,71,5e), r(51,10,6e,bd),\
+ r(f9,8a,21,3e), r(3d,06,dd,96), r(ae,05,3e,dd), r(46,bd,e6,4d),\
+ r(b5,8d,54,91), r(05,5d,c4,71), r(6f,d4,06,04), r(ff,15,50,60),\
+ r(24,fb,98,19), r(97,e9,bd,d6), r(cc,43,40,89), r(77,9e,d9,67),\
+ r(bd,42,e8,b0), r(88,8b,89,07), r(38,5b,19,e7), r(db,ee,c8,79),\
+ r(47,0a,7c,a1), r(e9,0f,42,7c), r(c9,1e,84,f8), r(00,00,00,00),\
+ r(83,86,80,09), r(48,ed,2b,32), r(ac,70,11,1e), r(4e,72,5a,6c),\
+ r(fb,ff,0e,fd), r(56,38,85,0f), r(1e,d5,ae,3d), r(27,39,2d,36),\
+ r(64,d9,0f,0a), r(21,a6,5c,68), r(d1,54,5b,9b), r(3a,2e,36,24),\
+ r(b1,67,0a,0c), r(0f,e7,57,93), r(d2,96,ee,b4), r(9e,91,9b,1b),\
+ r(4f,c5,c0,80), r(a2,20,dc,61), r(69,4b,77,5a), r(16,1a,12,1c),\
+ r(0a,ba,93,e2), r(e5,2a,a0,c0), r(43,e0,22,3c), r(1d,17,1b,12),\
+ r(0b,0d,09,0e), r(ad,c7,8b,f2), r(b9,a8,b6,2d), r(c8,a9,1e,14),\
+ r(85,19,f1,57), r(4c,07,75,af), r(bb,dd,99,ee), r(fd,60,7f,a3),\
+ r(9f,26,01,f7), r(bc,f5,72,5c), r(c5,3b,66,44), r(34,7e,fb,5b),\
+ r(76,29,43,8b), r(dc,c6,23,cb), r(68,fc,ed,b6), r(63,f1,e4,b8),\
+ r(ca,dc,31,d7), r(10,85,63,42), r(40,22,97,13), r(20,11,c6,84),\
+ r(7d,24,4a,85), r(f8,3d,bb,d2), r(11,32,f9,ae), r(6d,a1,29,c7),\
+ r(4b,2f,9e,1d), r(f3,30,b2,dc), r(ec,52,86,0d), r(d0,e3,c1,77),\
+ r(6c,16,b3,2b), r(99,b9,70,a9), r(fa,48,94,11), r(22,64,e9,47),\
+ r(c4,8c,fc,a8), r(1a,3f,f0,a0), r(d8,2c,7d,56), r(ef,90,33,22),\
+ r(c7,4e,49,87), r(c1,d1,38,d9), r(fe,a2,ca,8c), r(36,0b,d4,98),\
+ r(cf,81,f5,a6), r(28,de,7a,a5), r(26,8e,b7,da), r(a4,bf,ad,3f),\
+ r(e4,9d,3a,2c), r(0d,92,78,50), r(9b,cc,5f,6a), r(62,46,7e,54),\
+ r(c2,13,8d,f6), r(e8,b8,d8,90), r(5e,f7,39,2e), r(f5,af,c3,82),\
+ r(be,80,5d,9f), r(7c,93,d0,69), r(a9,2d,d5,6f), r(b3,12,25,cf),\
+ r(3b,99,ac,c8), r(a7,7d,18,10), r(6e,63,9c,e8), r(7b,bb,3b,db),\
+ r(09,78,26,cd), r(f4,18,59,6e), r(01,b7,9a,ec), r(a8,9a,4f,83),\
+ r(65,6e,95,e6), r(7e,e6,ff,aa), r(08,cf,bc,21), r(e6,e8,15,ef),\
+ r(d9,9b,e7,ba), r(ce,36,6f,4a), r(d4,09,9f,ea), r(d6,7c,b0,29),\
+ r(af,b2,a4,31), r(31,23,3f,2a), r(30,94,a5,c6), r(c0,66,a2,35),\
+ r(37,bc,4e,74), r(a6,ca,82,fc), r(b0,d0,90,e0), r(15,d8,a7,33),\
+ r(4a,98,04,f1), r(f7,da,ec,41), r(0e,50,cd,7f), r(2f,f6,91,17),\
+ r(8d,d6,4d,76), r(4d,b0,ef,43), r(54,4d,aa,cc), r(df,04,96,e4),\
+ r(e3,b5,d1,9e), r(1b,88,6a,4c), r(b8,1f,2c,c1), r(7f,51,65,46),\
+ r(04,ea,5e,9d), r(5d,35,8c,01), r(73,74,87,fa), r(2e,41,0b,fb),\
+ r(5a,1d,67,b3), r(52,d2,db,92), r(33,56,10,e9), r(13,47,d6,6d),\
+ r(8c,61,d7,9a), r(7a,0c,a1,37), r(8e,14,f8,59), r(89,3c,13,eb),\
+ r(ee,27,a9,ce), r(35,c9,61,b7), r(ed,e5,1c,e1), r(3c,b1,47,7a),\
+ r(59,df,d2,9c), r(3f,73,f2,55), r(79,ce,14,18), r(bf,37,c7,73),\
+ r(ea,cd,f7,53), r(5b,aa,fd,5f), r(14,6f,3d,df), r(86,db,44,78),\
+ r(81,f3,af,ca), r(3e,c4,68,b9), r(2c,34,24,38), r(5f,40,a3,c2),\
+ r(72,c3,1d,16), r(0c,25,e2,bc), r(8b,49,3c,28), r(41,95,0d,ff),\
+ r(71,01,a8,39), r(de,b3,0c,08), r(9c,e4,b4,d8), r(90,c1,56,64),\
+ r(61,84,cb,7b), r(70,b6,32,d5), r(74,5c,6c,48), r(42,57,b8,d0)
+
+// generate the required tables in the desired endian format
+
+#undef r
+#define r r0
+
+#if defined(ONE_TABLE)
+static const u_int32_t ft_tab[256] =
+ { f_table };
+#elif defined(FOUR_TABLES)
+static const u_int32_t ft_tab[4][256] =
+{ { f_table },
+#undef r
+#define r r1
+ { f_table },
+#undef r
+#define r r2
+ { f_table },
+#undef r
+#define r r3
+ { f_table }
+};
+#endif
+
+#undef r
+#define r r0
+#if defined(ONE_TABLE)
+static const u_int32_t it_tab[256] =
+ { i_table };
+#elif defined(FOUR_TABLES)
+static const u_int32_t it_tab[4][256] =
+{ { i_table },
+#undef r
+#define r r1
+ { i_table },
+#undef r
+#define r r2
+ { i_table },
+#undef r
+#define r r3
+ { i_table }
+};
+#endif
+
+#endif
+
+#if defined(FIXED_TABLES) && (defined(ONE_LR_TABLE) || defined(FOUR_LR_TABLES))
+
+// data for inverse tables (last round)
+
+#define li_table \
+ w(52), w(09), w(6a), w(d5), w(30), w(36), w(a5), w(38),\
+ w(bf), w(40), w(a3), w(9e), w(81), w(f3), w(d7), w(fb),\
+ w(7c), w(e3), w(39), w(82), w(9b), w(2f), w(ff), w(87),\
+ w(34), w(8e), w(43), w(44), w(c4), w(de), w(e9), w(cb),\
+ w(54), w(7b), w(94), w(32), w(a6), w(c2), w(23), w(3d),\
+ w(ee), w(4c), w(95), w(0b), w(42), w(fa), w(c3), w(4e),\
+ w(08), w(2e), w(a1), w(66), w(28), w(d9), w(24), w(b2),\
+ w(76), w(5b), w(a2), w(49), w(6d), w(8b), w(d1), w(25),\
+ w(72), w(f8), w(f6), w(64), w(86), w(68), w(98), w(16),\
+ w(d4), w(a4), w(5c), w(cc), w(5d), w(65), w(b6), w(92),\
+ w(6c), w(70), w(48), w(50), w(fd), w(ed), w(b9), w(da),\
+ w(5e), w(15), w(46), w(57), w(a7), w(8d), w(9d), w(84),\
+ w(90), w(d8), w(ab), w(00), w(8c), w(bc), w(d3), w(0a),\
+ w(f7), w(e4), w(58), w(05), w(b8), w(b3), w(45), w(06),\
+ w(d0), w(2c), w(1e), w(8f), w(ca), w(3f), w(0f), w(02),\
+ w(c1), w(af), w(bd), w(03), w(01), w(13), w(8a), w(6b),\
+ w(3a), w(91), w(11), w(41), w(4f), w(67), w(dc), w(ea),\
+ w(97), w(f2), w(cf), w(ce), w(f0), w(b4), w(e6), w(73),\
+ w(96), w(ac), w(74), w(22), w(e7), w(ad), w(35), w(85),\
+ w(e2), w(f9), w(37), w(e8), w(1c), w(75), w(df), w(6e),\
+ w(47), w(f1), w(1a), w(71), w(1d), w(29), w(c5), w(89),\
+ w(6f), w(b7), w(62), w(0e), w(aa), w(18), w(be), w(1b),\
+ w(fc), w(56), w(3e), w(4b), w(c6), w(d2), w(79), w(20),\
+ w(9a), w(db), w(c0), w(fe), w(78), w(cd), w(5a), w(f4),\
+ w(1f), w(dd), w(a8), w(33), w(88), w(07), w(c7), w(31),\
+ w(b1), w(12), w(10), w(59), w(27), w(80), w(ec), w(5f),\
+ w(60), w(51), w(7f), w(a9), w(19), w(b5), w(4a), w(0d),\
+ w(2d), w(e5), w(7a), w(9f), w(93), w(c9), w(9c), w(ef),\
+ w(a0), w(e0), w(3b), w(4d), w(ae), w(2a), w(f5), w(b0),\
+ w(c8), w(eb), w(bb), w(3c), w(83), w(53), w(99), w(61),\
+ w(17), w(2b), w(04), w(7e), w(ba), w(77), w(d6), w(26),\
+ w(e1), w(69), w(14), w(63), w(55), w(21), w(0c), w(7d),
+
+// generate the required tables in the desired endian format
+
+#undef r
+#define r(p,q,r,s) w0(q)
+#if defined(ONE_LR_TABLE)
+static const u_int32_t fl_tab[256] =
+ { f_table };
+#elif defined(FOUR_LR_TABLES)
+static const u_int32_t fl_tab[4][256] =
+{ { f_table },
+#undef r
+#define r(p,q,r,s) w1(q)
+ { f_table },
+#undef r
+#define r(p,q,r,s) w2(q)
+ { f_table },
+#undef r
+#define r(p,q,r,s) w3(q)
+ { f_table }
+};
+#endif
+
+#undef w
+#define w w0
+#if defined(ONE_LR_TABLE)
+static const u_int32_t il_tab[256] =
+ { li_table };
+#elif defined(FOUR_LR_TABLES)
+static const u_int32_t il_tab[4][256] =
+{ { li_table },
+#undef w
+#define w w1
+ { li_table },
+#undef w
+#define w w2
+ { li_table },
+#undef w
+#define w w3
+ { li_table }
+};
+#endif
+
+#endif
+
+#if defined(FIXED_TABLES) && (defined(ONE_IM_TABLE) || defined(FOUR_IM_TABLES))
+
+#define m_table \
+ r(00,00,00,00), r(0b,0d,09,0e), r(16,1a,12,1c), r(1d,17,1b,12),\
+ r(2c,34,24,38), r(27,39,2d,36), r(3a,2e,36,24), r(31,23,3f,2a),\
+ r(58,68,48,70), r(53,65,41,7e), r(4e,72,5a,6c), r(45,7f,53,62),\
+ r(74,5c,6c,48), r(7f,51,65,46), r(62,46,7e,54), r(69,4b,77,5a),\
+ r(b0,d0,90,e0), r(bb,dd,99,ee), r(a6,ca,82,fc), r(ad,c7,8b,f2),\
+ r(9c,e4,b4,d8), r(97,e9,bd,d6), r(8a,fe,a6,c4), r(81,f3,af,ca),\
+ r(e8,b8,d8,90), r(e3,b5,d1,9e), r(fe,a2,ca,8c), r(f5,af,c3,82),\
+ r(c4,8c,fc,a8), r(cf,81,f5,a6), r(d2,96,ee,b4), r(d9,9b,e7,ba),\
+ r(7b,bb,3b,db), r(70,b6,32,d5), r(6d,a1,29,c7), r(66,ac,20,c9),\
+ r(57,8f,1f,e3), r(5c,82,16,ed), r(41,95,0d,ff), r(4a,98,04,f1),\
+ r(23,d3,73,ab), r(28,de,7a,a5), r(35,c9,61,b7), r(3e,c4,68,b9),\
+ r(0f,e7,57,93), r(04,ea,5e,9d), r(19,fd,45,8f), r(12,f0,4c,81),\
+ r(cb,6b,ab,3b), r(c0,66,a2,35), r(dd,71,b9,27), r(d6,7c,b0,29),\
+ r(e7,5f,8f,03), r(ec,52,86,0d), r(f1,45,9d,1f), r(fa,48,94,11),\
+ r(93,03,e3,4b), r(98,0e,ea,45), r(85,19,f1,57), r(8e,14,f8,59),\
+ r(bf,37,c7,73), r(b4,3a,ce,7d), r(a9,2d,d5,6f), r(a2,20,dc,61),\
+ r(f6,6d,76,ad), r(fd,60,7f,a3), r(e0,77,64,b1), r(eb,7a,6d,bf),\
+ r(da,59,52,95), r(d1,54,5b,9b), r(cc,43,40,89), r(c7,4e,49,87),\
+ r(ae,05,3e,dd), r(a5,08,37,d3), r(b8,1f,2c,c1), r(b3,12,25,cf),\
+ r(82,31,1a,e5), r(89,3c,13,eb), r(94,2b,08,f9), r(9f,26,01,f7),\
+ r(46,bd,e6,4d), r(4d,b0,ef,43), r(50,a7,f4,51), r(5b,aa,fd,5f),\
+ r(6a,89,c2,75), r(61,84,cb,7b), r(7c,93,d0,69), r(77,9e,d9,67),\
+ r(1e,d5,ae,3d), r(15,d8,a7,33), r(08,cf,bc,21), r(03,c2,b5,2f),\
+ r(32,e1,8a,05), r(39,ec,83,0b), r(24,fb,98,19), r(2f,f6,91,17),\
+ r(8d,d6,4d,76), r(86,db,44,78), r(9b,cc,5f,6a), r(90,c1,56,64),\
+ r(a1,e2,69,4e), r(aa,ef,60,40), r(b7,f8,7b,52), r(bc,f5,72,5c),\
+ r(d5,be,05,06), r(de,b3,0c,08), r(c3,a4,17,1a), r(c8,a9,1e,14),\
+ r(f9,8a,21,3e), r(f2,87,28,30), r(ef,90,33,22), r(e4,9d,3a,2c),\
+ r(3d,06,dd,96), r(36,0b,d4,98), r(2b,1c,cf,8a), r(20,11,c6,84),\
+ r(11,32,f9,ae), r(1a,3f,f0,a0), r(07,28,eb,b2), r(0c,25,e2,bc),\
+ r(65,6e,95,e6), r(6e,63,9c,e8), r(73,74,87,fa), r(78,79,8e,f4),\
+ r(49,5a,b1,de), r(42,57,b8,d0), r(5f,40,a3,c2), r(54,4d,aa,cc),\
+ r(f7,da,ec,41), r(fc,d7,e5,4f), r(e1,c0,fe,5d), r(ea,cd,f7,53),\
+ r(db,ee,c8,79), r(d0,e3,c1,77), r(cd,f4,da,65), r(c6,f9,d3,6b),\
+ r(af,b2,a4,31), r(a4,bf,ad,3f), r(b9,a8,b6,2d), r(b2,a5,bf,23),\
+ r(83,86,80,09), r(88,8b,89,07), r(95,9c,92,15), r(9e,91,9b,1b),\
+ r(47,0a,7c,a1), r(4c,07,75,af), r(51,10,6e,bd), r(5a,1d,67,b3),\
+ r(6b,3e,58,99), r(60,33,51,97), r(7d,24,4a,85), r(76,29,43,8b),\
+ r(1f,62,34,d1), r(14,6f,3d,df), r(09,78,26,cd), r(02,75,2f,c3),\
+ r(33,56,10,e9), r(38,5b,19,e7), r(25,4c,02,f5), r(2e,41,0b,fb),\
+ r(8c,61,d7,9a), r(87,6c,de,94), r(9a,7b,c5,86), r(91,76,cc,88),\
+ r(a0,55,f3,a2), r(ab,58,fa,ac), r(b6,4f,e1,be), r(bd,42,e8,b0),\
+ r(d4,09,9f,ea), r(df,04,96,e4), r(c2,13,8d,f6), r(c9,1e,84,f8),\
+ r(f8,3d,bb,d2), r(f3,30,b2,dc), r(ee,27,a9,ce), r(e5,2a,a0,c0),\
+ r(3c,b1,47,7a), r(37,bc,4e,74), r(2a,ab,55,66), r(21,a6,5c,68),\
+ r(10,85,63,42), r(1b,88,6a,4c), r(06,9f,71,5e), r(0d,92,78,50),\
+ r(64,d9,0f,0a), r(6f,d4,06,04), r(72,c3,1d,16), r(79,ce,14,18),\
+ r(48,ed,2b,32), r(43,e0,22,3c), r(5e,f7,39,2e), r(55,fa,30,20),\
+ r(01,b7,9a,ec), r(0a,ba,93,e2), r(17,ad,88,f0), r(1c,a0,81,fe),\
+ r(2d,83,be,d4), r(26,8e,b7,da), r(3b,99,ac,c8), r(30,94,a5,c6),\
+ r(59,df,d2,9c), r(52,d2,db,92), r(4f,c5,c0,80), r(44,c8,c9,8e),\
+ r(75,eb,f6,a4), r(7e,e6,ff,aa), r(63,f1,e4,b8), r(68,fc,ed,b6),\
+ r(b1,67,0a,0c), r(ba,6a,03,02), r(a7,7d,18,10), r(ac,70,11,1e),\
+ r(9d,53,2e,34), r(96,5e,27,3a), r(8b,49,3c,28), r(80,44,35,26),\
+ r(e9,0f,42,7c), r(e2,02,4b,72), r(ff,15,50,60), r(f4,18,59,6e),\
+ r(c5,3b,66,44), r(ce,36,6f,4a), r(d3,21,74,58), r(d8,2c,7d,56),\
+ r(7a,0c,a1,37), r(71,01,a8,39), r(6c,16,b3,2b), r(67,1b,ba,25),\
+ r(56,38,85,0f), r(5d,35,8c,01), r(40,22,97,13), r(4b,2f,9e,1d),\
+ r(22,64,e9,47), r(29,69,e0,49), r(34,7e,fb,5b), r(3f,73,f2,55),\
+ r(0e,50,cd,7f), r(05,5d,c4,71), r(18,4a,df,63), r(13,47,d6,6d),\
+ r(ca,dc,31,d7), r(c1,d1,38,d9), r(dc,c6,23,cb), r(d7,cb,2a,c5),\
+ r(e6,e8,15,ef), r(ed,e5,1c,e1), r(f0,f2,07,f3), r(fb,ff,0e,fd),\
+ r(92,b4,79,a7), r(99,b9,70,a9), r(84,ae,6b,bb), r(8f,a3,62,b5),\
+ r(be,80,5d,9f), r(b5,8d,54,91), r(a8,9a,4f,83), r(a3,97,46,8d)
+
+#undef r
+#define r r0
+
+#if defined(ONE_IM_TABLE)
+static const u_int32_t im_tab[256] =
+ { m_table };
+#elif defined(FOUR_IM_TABLES)
+static const u_int32_t im_tab[4][256] =
+{ { m_table },
+#undef r
+#define r r1
+ { m_table },
+#undef r
+#define r r2
+ { m_table },
+#undef r
+#define r r3
+ { m_table }
+};
+#endif
+
+#endif
+
+#else
+
+static int tab_gen = 0;
+
+static unsigned char s_box[256]; // the S box
+static unsigned char inv_s_box[256]; // the inverse S box
+static u_int32_t rcon_tab[AES_RC_LENGTH]; // table of round constants
+
+#if defined(ONE_TABLE)
+static u_int32_t ft_tab[256];
+static u_int32_t it_tab[256];
+#elif defined(FOUR_TABLES)
+static u_int32_t ft_tab[4][256];
+static u_int32_t it_tab[4][256];
+#endif
+
+#if defined(ONE_LR_TABLE)
+static u_int32_t fl_tab[256];
+static u_int32_t il_tab[256];
+#elif defined(FOUR_LR_TABLES)
+static u_int32_t fl_tab[4][256];
+static u_int32_t il_tab[4][256];
+#endif
+
+#if defined(ONE_IM_TABLE)
+static u_int32_t im_tab[256];
+#elif defined(FOUR_IM_TABLES)
+static u_int32_t im_tab[4][256];
+#endif
+
+// Generate the tables for the dynamic table option
+
+#if !defined(FF_TABLES)
+
+// It will generally be sensible to use tables to compute finite
+// field multiplies and inverses but where memory is scarse this
+// code might sometimes be better.
+
+// return 2 ^ (n - 1) where n is the bit number of the highest bit
+// set in x with x in the range 1 < x < 0x00000200. This form is
+// used so that locals within FFinv can be bytes rather than words
+
+static unsigned char hibit(const u_int32_t x)
+{ unsigned char r = (unsigned char)((x >> 1) | (x >> 2));
+
+ r |= (r >> 2);
+ r |= (r >> 4);
+ return (r + 1) >> 1;
+}
+
+// return the inverse of the finite field element x
+
+static unsigned char FFinv(const unsigned char x)
+{ unsigned char p1 = x, p2 = 0x1b, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0;
+
+ if(x < 2) return x;
+
+ for(;;)
+ {
+ if(!n1) return v1;
+
+ while(n2 >= n1)
+ {
+ n2 /= n1; p2 ^= p1 * n2; v2 ^= v1 * n2; n2 = hibit(p2);
+ }
+
+ if(!n2) return v2;
+
+ while(n1 >= n2)
+ {
+ n1 /= n2; p1 ^= p2 * n1; v1 ^= v2 * n1; n1 = hibit(p1);
+ }
+ }
+}
+
+// define the finite field multiplies required for Rijndael
+
+#define FFmul02(x) ((((x) & 0x7f) << 1) ^ ((x) & 0x80 ? 0x1b : 0))
+#define FFmul03(x) ((x) ^ FFmul02(x))
+#define FFmul09(x) ((x) ^ FFmul02(FFmul02(FFmul02(x))))
+#define FFmul0b(x) ((x) ^ FFmul02((x) ^ FFmul02(FFmul02(x))))
+#define FFmul0d(x) ((x) ^ FFmul02(FFmul02((x) ^ FFmul02(x))))
+#define FFmul0e(x) FFmul02((x) ^ FFmul02((x) ^ FFmul02(x)))
+
+#else
+
+#define FFinv(x) ((x) ? pow[255 - log[x]]: 0)
+
+#define FFmul02(x) (x ? pow[log[x] + 0x19] : 0)
+#define FFmul03(x) (x ? pow[log[x] + 0x01] : 0)
+#define FFmul09(x) (x ? pow[log[x] + 0xc7] : 0)
+#define FFmul0b(x) (x ? pow[log[x] + 0x68] : 0)
+#define FFmul0d(x) (x ? pow[log[x] + 0xee] : 0)
+#define FFmul0e(x) (x ? pow[log[x] + 0xdf] : 0)
+
+#endif
+
+// The forward and inverse affine transformations used in the S-box
+
+#define fwd_affine(x) \
+ (w = (u_int32_t)x, w ^= (w<<1)^(w<<2)^(w<<3)^(w<<4), 0x63^(unsigned char)(w^(w>>8)))
+
+#define inv_affine(x) \
+ (w = (u_int32_t)x, w = (w<<1)^(w<<3)^(w<<6), 0x05^(unsigned char)(w^(w>>8)))
+
+static void gen_tabs(void)
+{ u_int32_t i, w;
+
+#if defined(FF_TABLES)
+
+ unsigned char pow[512], log[256];
+
+ // log and power tables for GF(2^8) finite field with
+ // 0x011b as modular polynomial - the simplest primitive
+ // root is 0x03, used here to generate the tables
+
+ i = 0; w = 1;
+ do
+ {
+ pow[i] = (unsigned char)w;
+ pow[i + 255] = (unsigned char)w;
+ log[w] = (unsigned char)i++;
+ w ^= (w << 1) ^ (w & ff_hi ? ff_poly : 0);
+ }
+ while (w != 1);
+
+#endif
+
+ for(i = 0, w = 1; i < AES_RC_LENGTH; ++i)
+ {
+ rcon_tab[i] = bytes2word(w, 0, 0, 0);
+ w = (w << 1) ^ (w & ff_hi ? ff_poly : 0);
+ }
+
+ for(i = 0; i < 256; ++i)
+ { unsigned char b;
+
+ s_box[i] = b = fwd_affine(FFinv((unsigned char)i));
+
+ w = bytes2word(b, 0, 0, 0);
+#if defined(ONE_LR_TABLE)
+ fl_tab[i] = w;
+#elif defined(FOUR_LR_TABLES)
+ fl_tab[0][i] = w;
+ fl_tab[1][i] = upr(w,1);
+ fl_tab[2][i] = upr(w,2);
+ fl_tab[3][i] = upr(w,3);
+#endif
+ w = bytes2word(FFmul02(b), b, b, FFmul03(b));
+#if defined(ONE_TABLE)
+ ft_tab[i] = w;
+#elif defined(FOUR_TABLES)
+ ft_tab[0][i] = w;
+ ft_tab[1][i] = upr(w,1);
+ ft_tab[2][i] = upr(w,2);
+ ft_tab[3][i] = upr(w,3);
+#endif
+ inv_s_box[i] = b = FFinv(inv_affine((unsigned char)i));
+
+ w = bytes2word(b, 0, 0, 0);
+#if defined(ONE_LR_TABLE)
+ il_tab[i] = w;
+#elif defined(FOUR_LR_TABLES)
+ il_tab[0][i] = w;
+ il_tab[1][i] = upr(w,1);
+ il_tab[2][i] = upr(w,2);
+ il_tab[3][i] = upr(w,3);
+#endif
+ w = bytes2word(FFmul0e(b), FFmul09(b), FFmul0d(b), FFmul0b(b));
+#if defined(ONE_TABLE)
+ it_tab[i] = w;
+#elif defined(FOUR_TABLES)
+ it_tab[0][i] = w;
+ it_tab[1][i] = upr(w,1);
+ it_tab[2][i] = upr(w,2);
+ it_tab[3][i] = upr(w,3);
+#endif
+#if defined(ONE_IM_TABLE)
+ im_tab[b] = w;
+#elif defined(FOUR_IM_TABLES)
+ im_tab[0][b] = w;
+ im_tab[1][b] = upr(w,1);
+ im_tab[2][b] = upr(w,2);
+ im_tab[3][b] = upr(w,3);
+#endif
+
+ }
+}
+
+#endif
+
+#define no_table(x,box,vf,rf,c) bytes2word( \
+ box[bval(vf(x,0,c),rf(0,c))], \
+ box[bval(vf(x,1,c),rf(1,c))], \
+ box[bval(vf(x,2,c),rf(2,c))], \
+ box[bval(vf(x,3,c),rf(3,c))])
+
+#define one_table(x,op,tab,vf,rf,c) \
+ ( tab[bval(vf(x,0,c),rf(0,c))] \
+ ^ op(tab[bval(vf(x,1,c),rf(1,c))],1) \
+ ^ op(tab[bval(vf(x,2,c),rf(2,c))],2) \
+ ^ op(tab[bval(vf(x,3,c),rf(3,c))],3))
+
+#define four_tables(x,tab,vf,rf,c) \
+ ( tab[0][bval(vf(x,0,c),rf(0,c))] \
+ ^ tab[1][bval(vf(x,1,c),rf(1,c))] \
+ ^ tab[2][bval(vf(x,2,c),rf(2,c))] \
+ ^ tab[3][bval(vf(x,3,c),rf(3,c))])
+
+#define vf1(x,r,c) (x)
+#define rf1(r,c) (r)
+#define rf2(r,c) ((r-c)&3)
+
+#if defined(FOUR_LR_TABLES)
+#define ls_box(x,c) four_tables(x,fl_tab,vf1,rf2,c)
+#elif defined(ONE_LR_TABLE)
+#define ls_box(x,c) one_table(x,upr,fl_tab,vf1,rf2,c)
+#else
+#define ls_box(x,c) no_table(x,s_box,vf1,rf2,c)
+#endif
+
+#if defined(FOUR_IM_TABLES)
+#define inv_mcol(x) four_tables(x,im_tab,vf1,rf1,0)
+#elif defined(ONE_IM_TABLE)
+#define inv_mcol(x) one_table(x,upr,im_tab,vf1,rf1,0)
+#else
+#define inv_mcol(x) \
+ (f9 = (x),f2 = FFmulX(f9), f4 = FFmulX(f2), f8 = FFmulX(f4), f9 ^= f8, \
+ f2 ^= f4 ^ f8 ^ upr(f2 ^ f9,3) ^ upr(f4 ^ f9,2) ^ upr(f9,1))
+#endif
+
+#define nc (AES_BLOCK_SIZE/4)
+
+// Initialise the key schedule from the user supplied key. The key
+// length is now specified in bytes - 16, 24 or 32 as appropriate.
+// This corresponds to bit lengths of 128, 192 and 256 bits, and
+// to Nk values of 4, 6 and 8 respectively.
+
+#define mx(t,f) (*t++ = inv_mcol(*f),f++)
+#define cp(t,f) *t++ = *f++
+
+#if AES_BLOCK_SIZE == 16
+#define cpy(d,s) cp(d,s); cp(d,s); cp(d,s); cp(d,s)
+#define mix(d,s) mx(d,s); mx(d,s); mx(d,s); mx(d,s)
+#elif AES_BLOCK_SIZE == 24
+#define cpy(d,s) cp(d,s); cp(d,s); cp(d,s); cp(d,s); \
+ cp(d,s); cp(d,s)
+#define mix(d,s) mx(d,s); mx(d,s); mx(d,s); mx(d,s); \
+ mx(d,s); mx(d,s)
+#elif AES_BLOCK_SIZE == 32
+#define cpy(d,s) cp(d,s); cp(d,s); cp(d,s); cp(d,s); \
+ cp(d,s); cp(d,s); cp(d,s); cp(d,s)
+#define mix(d,s) mx(d,s); mx(d,s); mx(d,s); mx(d,s); \
+ mx(d,s); mx(d,s); mx(d,s); mx(d,s)
+#else
+
+#define cpy(d,s) \
+switch(nc) \
+{ case 8: cp(d,s); cp(d,s); \
+ case 6: cp(d,s); cp(d,s); \
+ case 4: cp(d,s); cp(d,s); \
+ cp(d,s); cp(d,s); \
+}
+
+#define mix(d,s) \
+switch(nc) \
+{ case 8: mx(d,s); mx(d,s); \
+ case 6: mx(d,s); mx(d,s); \
+ case 4: mx(d,s); mx(d,s); \
+ mx(d,s); mx(d,s); \
+}
+
+#endif
+
+// y = output word, x = input word, r = row, c = column
+// for r = 0, 1, 2 and 3 = column accessed for row r
+
+#if defined(ARRAYS)
+#define s(x,c) x[c]
+#else
+#define s(x,c) x##c
+#endif
+
+// I am grateful to Frank Yellin for the following constructions
+// which, given the column (c) of the output state variable that
+// is being computed, return the input state variables which are
+// needed for each row (r) of the state
+
+// For the fixed block size options, compilers reduce these two
+// expressions to fixed variable references. For variable block
+// size code conditional clauses will sometimes be returned
+
+#define unused 77 // Sunset Strip
+
+#define fwd_var(x,r,c) \
+ ( r==0 ? \
+ ( c==0 ? s(x,0) \
+ : c==1 ? s(x,1) \
+ : c==2 ? s(x,2) \
+ : c==3 ? s(x,3) \
+ : c==4 ? s(x,4) \
+ : c==5 ? s(x,5) \
+ : c==6 ? s(x,6) \
+ : s(x,7)) \
+ : r==1 ? \
+ ( c==0 ? s(x,1) \
+ : c==1 ? s(x,2) \
+ : c==2 ? s(x,3) \
+ : c==3 ? nc==4 ? s(x,0) : s(x,4) \
+ : c==4 ? s(x,5) \
+ : c==5 ? nc==8 ? s(x,6) : s(x,0) \
+ : c==6 ? s(x,7) \
+ : s(x,0)) \
+ : r==2 ? \
+ ( c==0 ? nc==8 ? s(x,3) : s(x,2) \
+ : c==1 ? nc==8 ? s(x,4) : s(x,3) \
+ : c==2 ? nc==4 ? s(x,0) : nc==8 ? s(x,5) : s(x,4) \
+ : c==3 ? nc==4 ? s(x,1) : nc==8 ? s(x,6) : s(x,5) \
+ : c==4 ? nc==8 ? s(x,7) : s(x,0) \
+ : c==5 ? nc==8 ? s(x,0) : s(x,1) \
+ : c==6 ? s(x,1) \
+ : s(x,2)) \
+ : \
+ ( c==0 ? nc==8 ? s(x,4) : s(x,3) \
+ : c==1 ? nc==4 ? s(x,0) : nc==8 ? s(x,5) : s(x,4) \
+ : c==2 ? nc==4 ? s(x,1) : nc==8 ? s(x,6) : s(x,5) \
+ : c==3 ? nc==4 ? s(x,2) : nc==8 ? s(x,7) : s(x,0) \
+ : c==4 ? nc==8 ? s(x,0) : s(x,1) \
+ : c==5 ? nc==8 ? s(x,1) : s(x,2) \
+ : c==6 ? s(x,2) \
+ : s(x,3)))
+
+#define inv_var(x,r,c) \
+ ( r==0 ? \
+ ( c==0 ? s(x,0) \
+ : c==1 ? s(x,1) \
+ : c==2 ? s(x,2) \
+ : c==3 ? s(x,3) \
+ : c==4 ? s(x,4) \
+ : c==5 ? s(x,5) \
+ : c==6 ? s(x,6) \
+ : s(x,7)) \
+ : r==1 ? \
+ ( c==0 ? nc==4 ? s(x,3) : nc==8 ? s(x,7) : s(x,5) \
+ : c==1 ? s(x,0) \
+ : c==2 ? s(x,1) \
+ : c==3 ? s(x,2) \
+ : c==4 ? s(x,3) \
+ : c==5 ? s(x,4) \
+ : c==6 ? s(x,5) \
+ : s(x,6)) \
+ : r==2 ? \
+ ( c==0 ? nc==4 ? s(x,2) : nc==8 ? s(x,5) : s(x,4) \
+ : c==1 ? nc==4 ? s(x,3) : nc==8 ? s(x,6) : s(x,5) \
+ : c==2 ? nc==8 ? s(x,7) : s(x,0) \
+ : c==3 ? nc==8 ? s(x,0) : s(x,1) \
+ : c==4 ? nc==8 ? s(x,1) : s(x,2) \
+ : c==5 ? nc==8 ? s(x,2) : s(x,3) \
+ : c==6 ? s(x,3) \
+ : s(x,4)) \
+ : \
+ ( c==0 ? nc==4 ? s(x,1) : nc==8 ? s(x,4) : s(x,3) \
+ : c==1 ? nc==4 ? s(x,2) : nc==8 ? s(x,5) : s(x,4) \
+ : c==2 ? nc==4 ? s(x,3) : nc==8 ? s(x,6) : s(x,5) \
+ : c==3 ? nc==8 ? s(x,7) : s(x,0) \
+ : c==4 ? nc==8 ? s(x,0) : s(x,1) \
+ : c==5 ? nc==8 ? s(x,1) : s(x,2) \
+ : c==6 ? s(x,2) \
+ : s(x,3)))
+
+#define si(y,x,k,c) s(y,c) = const_word_in(x + 4 * c) ^ k[c]
+#define so(y,x,c) word_out(y + 4 * c, s(x,c))
+
+#if defined(FOUR_TABLES)
+#define fwd_rnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,ft_tab,fwd_var,rf1,c)
+#define inv_rnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,it_tab,inv_var,rf1,c)
+#elif defined(ONE_TABLE)
+#define fwd_rnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,upr,ft_tab,fwd_var,rf1,c)
+#define inv_rnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,upr,it_tab,inv_var,rf1,c)
+#else
+#define fwd_rnd(y,x,k,c) s(y,c) = fwd_mcol(no_table(x,s_box,fwd_var,rf1,c)) ^ (k)[c]
+#define inv_rnd(y,x,k,c) s(y,c) = inv_mcol(no_table(x,inv_s_box,inv_var,rf1,c) ^ (k)[c])
+#endif
+
+#if defined(FOUR_LR_TABLES)
+#define fwd_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,fl_tab,fwd_var,rf1,c)
+#define inv_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,il_tab,inv_var,rf1,c)
+#elif defined(ONE_LR_TABLE)
+#define fwd_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,ups,fl_tab,fwd_var,rf1,c)
+#define inv_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,ups,il_tab,inv_var,rf1,c)
+#else
+#define fwd_lrnd(y,x,k,c) s(y,c) = no_table(x,s_box,fwd_var,rf1,c) ^ (k)[c]
+#define inv_lrnd(y,x,k,c) s(y,c) = no_table(x,inv_s_box,inv_var,rf1,c) ^ (k)[c]
+#endif
+
+#if AES_BLOCK_SIZE == 16
+
+#if defined(ARRAYS)
+#define locals(y,x) x[4],y[4]
+#else
+#define locals(y,x) x##0,x##1,x##2,x##3,y##0,y##1,y##2,y##3
+// the following defines prevent the compiler requiring the declaration
+// of generated but unused variables in the fwd_var and inv_var macros
+#define b04 unused
+#define b05 unused
+#define b06 unused
+#define b07 unused
+#define b14 unused
+#define b15 unused
+#define b16 unused
+#define b17 unused
+#endif
+#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \
+ s(y,2) = s(x,2); s(y,3) = s(x,3);
+#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3)
+#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3)
+#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3)
+
+#elif AES_BLOCK_SIZE == 24
+
+#if defined(ARRAYS)
+#define locals(y,x) x[6],y[6]
+#else
+#define locals(y,x) x##0,x##1,x##2,x##3,x##4,x##5, \
+ y##0,y##1,y##2,y##3,y##4,y##5
+#define b06 unused
+#define b07 unused
+#define b16 unused
+#define b17 unused
+#endif
+#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \
+ s(y,2) = s(x,2); s(y,3) = s(x,3); \
+ s(y,4) = s(x,4); s(y,5) = s(x,5);
+#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); \
+ si(y,x,k,3); si(y,x,k,4); si(y,x,k,5)
+#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); \
+ so(y,x,3); so(y,x,4); so(y,x,5)
+#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); \
+ rm(y,x,k,3); rm(y,x,k,4); rm(y,x,k,5)
+#else
+
+#if defined(ARRAYS)
+#define locals(y,x) x[8],y[8]
+#else
+#define locals(y,x) x##0,x##1,x##2,x##3,x##4,x##5,x##6,x##7, \
+ y##0,y##1,y##2,y##3,y##4,y##5,y##6,y##7
+#endif
+#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \
+ s(y,2) = s(x,2); s(y,3) = s(x,3); \
+ s(y,4) = s(x,4); s(y,5) = s(x,5); \
+ s(y,6) = s(x,6); s(y,7) = s(x,7);
+
+#if AES_BLOCK_SIZE == 32
+
+#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3); \
+ si(y,x,k,4); si(y,x,k,5); si(y,x,k,6); si(y,x,k,7)
+#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3); \
+ so(y,x,4); so(y,x,5); so(y,x,6); so(y,x,7)
+#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3); \
+ rm(y,x,k,4); rm(y,x,k,5); rm(y,x,k,6); rm(y,x,k,7)
+#else
+
+#define state_in(y,x,k) \
+switch(nc) \
+{ case 8: si(y,x,k,7); si(y,x,k,6); \
+ case 6: si(y,x,k,5); si(y,x,k,4); \
+ case 4: si(y,x,k,3); si(y,x,k,2); \
+ si(y,x,k,1); si(y,x,k,0); \
+}
+
+#define state_out(y,x) \
+switch(nc) \
+{ case 8: so(y,x,7); so(y,x,6); \
+ case 6: so(y,x,5); so(y,x,4); \
+ case 4: so(y,x,3); so(y,x,2); \
+ so(y,x,1); so(y,x,0); \
+}
+
+#if defined(FAST_VARIABLE)
+
+#define round(rm,y,x,k) \
+switch(nc) \
+{ case 8: rm(y,x,k,7); rm(y,x,k,6); \
+ rm(y,x,k,5); rm(y,x,k,4); \
+ rm(y,x,k,3); rm(y,x,k,2); \
+ rm(y,x,k,1); rm(y,x,k,0); \
+ break; \
+ case 6: rm(y,x,k,5); rm(y,x,k,4); \
+ rm(y,x,k,3); rm(y,x,k,2); \
+ rm(y,x,k,1); rm(y,x,k,0); \
+ break; \
+ case 4: rm(y,x,k,3); rm(y,x,k,2); \
+ rm(y,x,k,1); rm(y,x,k,0); \
+ break; \
+}
+#else
+
+#define round(rm,y,x,k) \
+switch(nc) \
+{ case 8: rm(y,x,k,7); rm(y,x,k,6); \
+ case 6: rm(y,x,k,5); rm(y,x,k,4); \
+ case 4: rm(y,x,k,3); rm(y,x,k,2); \
+ rm(y,x,k,1); rm(y,x,k,0); \
+}
+
+#endif
+
+#endif
+#endif
+
+/**
+ * Implementation of private_aes_cbc_crypter_t.encrypt_block.
+ */
+static void encrypt_block(const private_aes_cbc_crypter_t *this, const unsigned char in_blk[], unsigned char out_blk[])
+{ u_int32_t locals(b0, b1);
+ const u_int32_t *kp = this->aes_e_key;
+
+#if !defined(ONE_TABLE) && !defined(FOUR_TABLES)
+ u_int32_t f2;
+#endif
+
+ state_in(b0, in_blk, kp); kp += nc;
+
+#if defined(UNROLL)
+
+ switch(this->aes_Nrnd)
+ {
+ case 14: round(fwd_rnd, b1, b0, kp );
+ round(fwd_rnd, b0, b1, kp + nc ); kp += 2 * nc;
+ case 12: round(fwd_rnd, b1, b0, kp );
+ round(fwd_rnd, b0, b1, kp + nc ); kp += 2 * nc;
+ case 10: round(fwd_rnd, b1, b0, kp );
+ round(fwd_rnd, b0, b1, kp + nc);
+ round(fwd_rnd, b1, b0, kp + 2 * nc);
+ round(fwd_rnd, b0, b1, kp + 3 * nc);
+ round(fwd_rnd, b1, b0, kp + 4 * nc);
+ round(fwd_rnd, b0, b1, kp + 5 * nc);
+ round(fwd_rnd, b1, b0, kp + 6 * nc);
+ round(fwd_rnd, b0, b1, kp + 7 * nc);
+ round(fwd_rnd, b1, b0, kp + 8 * nc);
+ round(fwd_lrnd, b0, b1, kp + 9 * nc);
+ }
+
+#elif defined(PARTIAL_UNROLL)
+ { u_int32_t rnd;
+
+ for(rnd = 0; rnd < (this->aes_Nrnd >> 1) - 1; ++rnd)
+ {
+ round(fwd_rnd, b1, b0, kp);
+ round(fwd_rnd, b0, b1, kp + nc); kp += 2 * nc;
+ }
+
+ round(fwd_rnd, b1, b0, kp);
+ round(fwd_lrnd, b0, b1, kp + nc);
+ }
+#else
+ { u_int32_t rnd;
+
+ for(rnd = 0; rnd < this->aes_Nrnd - 1; ++rnd)
+ {
+ round(fwd_rnd, b1, b0, kp);
+ l_copy(b0, b1); kp += nc;
+ }
+
+ round(fwd_lrnd, b0, b1, kp);
+ }
+#endif
+
+ state_out(out_blk, b0);
+}
+
+/**
+ * Implementation of private_aes_cbc_crypter_t.decrypt_block.
+ */
+static void decrypt_block(const private_aes_cbc_crypter_t *this, const unsigned char in_blk[], unsigned char out_blk[])
+{ u_int32_t locals(b0, b1);
+ const u_int32_t *kp = this->aes_d_key;
+
+#if !defined(ONE_TABLE) && !defined(FOUR_TABLES)
+ u_int32_t f2, f4, f8, f9;
+#endif
+
+ state_in(b0, in_blk, kp); kp += nc;
+
+#if defined(UNROLL)
+
+ switch(this->aes_Nrnd)
+ {
+ case 14: round(inv_rnd, b1, b0, kp );
+ round(inv_rnd, b0, b1, kp + nc ); kp += 2 * nc;
+ case 12: round(inv_rnd, b1, b0, kp );
+ round(inv_rnd, b0, b1, kp + nc ); kp += 2 * nc;
+ case 10: round(inv_rnd, b1, b0, kp );
+ round(inv_rnd, b0, b1, kp + nc);
+ round(inv_rnd, b1, b0, kp + 2 * nc);
+ round(inv_rnd, b0, b1, kp + 3 * nc);
+ round(inv_rnd, b1, b0, kp + 4 * nc);
+ round(inv_rnd, b0, b1, kp + 5 * nc);
+ round(inv_rnd, b1, b0, kp + 6 * nc);
+ round(inv_rnd, b0, b1, kp + 7 * nc);
+ round(inv_rnd, b1, b0, kp + 8 * nc);
+ round(inv_lrnd, b0, b1, kp + 9 * nc);
+ }
+
+#elif defined(PARTIAL_UNROLL)
+ { u_int32_t rnd;
+
+ for(rnd = 0; rnd < (this->aes_Nrnd >> 1) - 1; ++rnd)
+ {
+ round(inv_rnd, b1, b0, kp);
+ round(inv_rnd, b0, b1, kp + nc); kp += 2 * nc;
+ }
+
+ round(inv_rnd, b1, b0, kp);
+ round(inv_lrnd, b0, b1, kp + nc);
+ }
+#else
+ { u_int32_t rnd;
+
+ for(rnd = 0; rnd < this->aes_Nrnd - 1; ++rnd)
+ {
+ round(inv_rnd, b1, b0, kp);
+ l_copy(b0, b1); kp += nc;
+ }
+
+ round(inv_lrnd, b0, b1, kp);
+ }
+#endif
+
+ state_out(out_blk, b0);
+}
+
+/**
+ * Implementation of crypter_t.decrypt.
+ */
+static status_t decrypt (private_aes_cbc_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *decrypted)
+{
+ int ret, pos;
+ const u_int32_t *iv_i;
+ u_int8_t *in, *out;
+
+ ret = data.len;
+ if (((data.len) % 16) != 0)
+ {
+ /* data length must be padded to a multiple of blocksize */
+ return INVALID_ARG;
+ }
+
+ decrypted->ptr = malloc(data.len);
+ if (decrypted->ptr == NULL)
+ {
+ return OUT_OF_RES;
+ }
+ decrypted->len = data.len;
+
+ in = data.ptr;
+ out = decrypted->ptr;
+
+ pos=data.len-16;
+ in+=pos;
+ out+=pos;
+ while(pos>=0) {
+ this->decrypt_block(this,in,out);
+ if (pos==0)
+ iv_i=(const u_int32_t*) (iv.ptr);
+ else
+ iv_i=(const u_int32_t*) (in-16);
+ *((u_int32_t *)(&out[ 0])) ^= iv_i[0];
+ *((u_int32_t *)(&out[ 4])) ^= iv_i[1];
+ *((u_int32_t *)(&out[ 8])) ^= iv_i[2];
+ *((u_int32_t *)(&out[12])) ^= iv_i[3];
+ in-=16;
+ out-=16;
+ pos-=16;
+ }
+
+ return SUCCESS;
+}
+
+
+/**
+ * Implementation of crypter_t.decrypt.
+ */
+static status_t encrypt (private_aes_cbc_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *encrypted)
+{
+ int ret, pos;
+ const u_int32_t *iv_i;
+ u_int8_t *in, *out;
+
+ ret = data.len;
+ if (((data.len) % 16) != 0)
+ {
+ /* data length must be padded to a multiple of blocksize */
+ return INVALID_ARG;
+ }
+
+ encrypted->ptr = malloc(data.len);
+ if (encrypted->ptr == NULL)
+ {
+ return OUT_OF_RES;
+ }
+ encrypted->len = data.len;
+
+ in = data.ptr;
+ out = encrypted->ptr;
+
+ pos=0;
+ while(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 > (nc) ? this->aes_Nkey : (nc)) + 6;
+
+ this->aes_e_key[0] = const_word_in(in_key );
+ this->aes_e_key[1] = const_word_in(in_key + 4);
+ this->aes_e_key[2] = const_word_in(in_key + 8);
+ this->aes_e_key[3] = const_word_in(in_key + 12);
+
+ kf = this->aes_e_key;
+ kt = kf + nc * (this->aes_Nrnd + 1) - this->aes_Nkey;
+ rci = 0;
+
+ switch(this->aes_Nkey)
+ {
+ case 4: do
+ { kf[4] = kf[0] ^ ls_box(kf[3],3) ^ rcon_tab[rci++];
+ kf[5] = kf[1] ^ kf[4];
+ kf[6] = kf[2] ^ kf[5];
+ kf[7] = kf[3] ^ kf[6];
+ kf += 4;
+ }
+ while(kf < kt);
+ break;
+
+ case 6: this->aes_e_key[4] = const_word_in(in_key + 16);
+ this->aes_e_key[5] = const_word_in(in_key + 20);
+ do
+ { kf[ 6] = kf[0] ^ ls_box(kf[5],3) ^ rcon_tab[rci++];
+ kf[ 7] = kf[1] ^ kf[ 6];
+ kf[ 8] = kf[2] ^ kf[ 7];
+ kf[ 9] = kf[3] ^ kf[ 8];
+ kf[10] = kf[4] ^ kf[ 9];
+ kf[11] = kf[5] ^ kf[10];
+ kf += 6;
+ }
+ while(kf < kt);
+ break;
+
+ case 8: this->aes_e_key[4] = const_word_in(in_key + 16);
+ this->aes_e_key[5] = const_word_in(in_key + 20);
+ this->aes_e_key[6] = const_word_in(in_key + 24);
+ this->aes_e_key[7] = const_word_in(in_key + 28);
+ do
+ { kf[ 8] = kf[0] ^ ls_box(kf[7],3) ^ rcon_tab[rci++];
+ kf[ 9] = kf[1] ^ kf[ 8];
+ kf[10] = kf[2] ^ kf[ 9];
+ kf[11] = kf[3] ^ kf[10];
+ kf[12] = kf[4] ^ ls_box(kf[11],0);
+ kf[13] = kf[5] ^ kf[12];
+ kf[14] = kf[6] ^ kf[13];
+ kf[15] = kf[7] ^ kf[14];
+ kf += 8;
+ }
+ while (kf < kt);
+ break;
+ }
+
+ if(!f)
+ {
+ u_int32_t i;
+
+ kt = this->aes_d_key + nc * this->aes_Nrnd;
+ kf = this->aes_e_key;
+
+ cpy(kt, kf); kt -= 2 * nc;
+
+ for(i = 1; i < this->aes_Nrnd; ++i)
+ {
+#if defined(ONE_TABLE) || defined(FOUR_TABLES)
+#if !defined(ONE_IM_TABLE) && !defined(FOUR_IM_TABLES)
+ u_int32_t f2, f4, f8, f9;
+#endif
+ mix(kt, kf);
+#else
+ cpy(kt, kf);
+#endif
+ kt -= 2 * nc;
+ }
+ cpy(kt, kf);
+ }
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of crypter_t.destroy and aes_cbc_crypter_t.destroy.
+ */
+static void destroy (private_aes_cbc_crypter_t *this)
+{
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+aes_cbc_crypter_t *aes_cbc_crypter_create(size_t key_size)
+{
+ private_aes_cbc_crypter_t *this = malloc_thing(private_aes_cbc_crypter_t);
+
+ #if !defined(FIXED_TABLES)
+ if(!tab_gen) { gen_tabs(); tab_gen = 1; }
+ #endif
+
+ this->key_size = key_size;
+ switch(key_size) {
+ case 32: /* bytes */
+ this->aes_Nkey = 8;
+ break;
+ case 24: /* bytes */
+ this->aes_Nkey = 6;
+ break;
+ case 16: /* bytes */
+ this->aes_Nkey = 4;
+ break;
+ default:
+ free(this);
+ return NULL;
+ }
+
+ /* functions of crypter_t interface */
+ this->public.crypter_interface.encrypt = (status_t (*) (crypter_t *, chunk_t,chunk_t, chunk_t *)) encrypt;
+ this->public.crypter_interface.decrypt = (status_t (*) (crypter_t *, chunk_t , chunk_t, chunk_t *)) decrypt;
+ this->public.crypter_interface.get_block_size = (size_t (*) (crypter_t *)) get_block_size;
+ this->public.crypter_interface.get_key_size = (size_t (*) (crypter_t *)) get_key_size;
+ this->public.crypter_interface.set_key = (status_t (*) (crypter_t *,chunk_t)) set_key;
+ this->public.crypter_interface.destroy = (void (*) (crypter_t *)) destroy;
+
+ /* private functions */
+ this->decrypt_block = decrypt_block;
+ this->encrypt_block = encrypt_block;
+
+ return &(this->public);
+}
diff --git a/src/libstrongswan/crypto/crypters/aes_cbc_crypter.h b/src/libstrongswan/crypto/crypters/aes_cbc_crypter.h
new file mode 100644
index 000000000..5da248b8c
--- /dev/null
+++ b/src/libstrongswan/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-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef AES_CBC_CRYPTER_H_
+#define AES_CBC_CRYPTER_H_
+
+typedef struct aes_cbc_crypter_t aes_cbc_crypter_t;
+
+#include <crypto/crypters/crypter.h>
+
+/**
+ * @brief Class implementing the AES symmetric encryption algorithm.
+ *
+ * @b Constructors:
+ * - aes_cbc_crypter_create()
+ *
+ * @ingroup crypters
+ */
+struct aes_cbc_crypter_t {
+
+ /**
+ * The crypter_t interface.
+ */
+ crypter_t crypter_interface;
+};
+
+/**
+ * @brief Constructor to create aes_cbc_crypter_t objects.
+ *
+ * Supported key sizes are: 16, 24 or 32.
+ *
+ * @param key_size key size in bytes
+ * @return
+ * - aes_cbc_crypter_t object
+ * - NULL if key size not supported
+ */
+aes_cbc_crypter_t *aes_cbc_crypter_create(size_t key_size);
+
+
+#endif /* AES_CBC_CRYPTER_H_ */
diff --git a/src/libstrongswan/crypto/crypters/crypter.c b/src/libstrongswan/crypto/crypters/crypter.c
new file mode 100644
index 000000000..7f62741a7
--- /dev/null
+++ b/src/libstrongswan/crypto/crypters/crypter.c
@@ -0,0 +1,68 @@
+/**
+ * @file crypter.c
+ *
+ * @brief Generic constructor for crypter_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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>
+#include <crypto/crypters/des_crypter.h>
+
+
+ENUM_BEGIN(encryption_algorithm_names, ENCR_UNDEFINED, ENCR_UNDEFINED,
+ "UNDEFINED");
+ENUM_NEXT(encryption_algorithm_names, ENCR_DES_IV64, ENCR_DES_IV32, ENCR_UNDEFINED,
+ "DES_IV64",
+ "DES",
+ "3DES",
+ "RC5",
+ "IDEA",
+ "CAST",
+ "BLOWFISH",
+ "3IDEA",
+ "DES_IV32");
+ENUM_NEXT(encryption_algorithm_names, ENCR_NULL, ENCR_AES_CTR, ENCR_DES_IV32,
+ "NULL",
+ "AES_CBC",
+ "AES_CTR");
+ENUM_END(encryption_algorithm_names, ENCR_AES_CTR);
+
+/*
+ * Described in header.
+ */
+crypter_t *crypter_create(encryption_algorithm_t encryption_algorithm, size_t key_size)
+{
+ switch (encryption_algorithm)
+ {
+ case ENCR_AES_CBC:
+ {
+ return (crypter_t*)aes_cbc_crypter_create(key_size);
+ }
+ case ENCR_DES:
+ case ENCR_3DES:
+ {
+ return (crypter_t*)des_crypter_create(encryption_algorithm);
+ }
+ default:
+ return NULL;
+ }
+}
diff --git a/src/libstrongswan/crypto/crypters/crypter.h b/src/libstrongswan/crypto/crypters/crypter.h
new file mode 100644
index 000000000..46d94ce93
--- /dev/null
+++ b/src/libstrongswan/crypto/crypters/crypter.h
@@ -0,0 +1,155 @@
+/**
+ * @file crypter.h
+ *
+ * @brief Interface crypter_t
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef enum encryption_algorithm_t encryption_algorithm_t;
+typedef struct crypter_t crypter_t;
+
+#include <library.h>
+
+/**
+ * @brief Encryption algorithm, as in IKEv2 RFC 3.3.2.
+ *
+ * Currently only the following algorithms are implemented:
+ * - ENCR_AES_CBC
+ * - ENCR_DES
+ * - ENCR_3DES
+ *
+ * @ingroup crypters
+ */
+enum encryption_algorithm_t {
+ ENCR_UNDEFINED = 1024,
+ ENCR_DES_IV64 = 1,
+ /** Implemented in class des_crypter_t */
+ ENCR_DES = 2,
+ /** Implemented in class des_crypter_t */
+ ENCR_3DES = 3,
+ ENCR_RC5 = 4,
+ ENCR_IDEA = 5,
+ 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
+};
+
+/**
+ * enum name for encryption_algorithm_t.
+ */
+extern enum_name_t *encryption_algorithm_names;
+
+/**
+ * @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:
+ * - ENCR_AES_CBC
+ * - ENCR_DES
+ * - ENCR_3DES
+ *
+ * The key_size is ignored for algorithms with fixed key size.
+ *
+ * @param encryption_algorithm Algorithm to use for crypter
+ * @param key_size size of the key in bytes
+ * @return
+ * - crypter_t object
+ * - NULL if encryption algorithm/key_size is not supported
+ */
+crypter_t *crypter_create(encryption_algorithm_t encryption_algorithm, size_t key_size);
+
+#endif /*CRYPTER_H_*/
diff --git a/src/libstrongswan/crypto/crypters/des_crypter.c b/src/libstrongswan/crypto/crypters/des_crypter.c
new file mode 100644
index 000000000..dc5a8ff55
--- /dev/null
+++ b/src/libstrongswan/crypto/crypters/des_crypter.c
@@ -0,0 +1,1535 @@
+/**
+ * @file des_crypter.c
+ *
+ * @brief Implementation of des_crypter_t
+ *
+ */
+
+/* Copyright (C) 2006 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * Derived from Plutos DES library by Eric Young.
+ *
+ * Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include "des_crypter.h"
+
+typedef u_char des_cblock[8];
+
+typedef struct des_ks_struct {
+ des_cblock _;
+} des_key_schedule[16];
+
+
+typedef struct private_des_crypter_t private_des_crypter_t;
+
+/**
+ * Private data for des_crypter_t
+ */
+struct private_des_crypter_t {
+
+ /**
+ * Public part of this class.
+ */
+ des_crypter_t public;
+
+ /**
+ * Key size, depends on algoritm...
+ */
+ size_t key_size;
+
+ union {
+ /** key schedule for single des */
+ des_key_schedule ks;
+ /** key schedule for 3des */
+ des_key_schedule ks3[3];
+ };
+};
+
+
+#define DES_ENCRYPT 1
+#define DES_DECRYPT 0
+
+#define DES_LONG u_int32_t
+
+#if defined(WIN32) || defined(WIN16)
+#ifndef MSDOS
+#define MSDOS
+#endif
+#endif
+
+#ifndef DES_DEFAULT_OPTIONS
+/* the following is tweaked from a config script, that is why it is a
+ * protected undef/define */
+#ifndef DES_PTR
+#define DES_PTR
+#endif
+
+/* This helps C compiler generate the correct code for multiple functional
+ * units. It reduces register dependancies at the expense of 2 more
+ * registers */
+#ifndef DES_RISC1
+#define DES_RISC1
+#endif
+
+#ifndef DES_RISC2
+#undef DES_RISC2
+#endif
+
+#if defined(DES_RISC1) && defined(DES_RISC2)
+YOU SHOULD NOT HAVE BOTH DES_RISC1 AND DES_RISC2 DEFINED!!!!!
+#endif
+
+/* Unroll the inner loop, this sometimes helps, sometimes hinders.
+ * Very mucy CPU dependant */
+#ifndef DES_UNROLL
+#define DES_UNROLL
+#endif
+
+/* These default values were supplied by
+ * Peter Gutman <pgut001@cs.auckland.ac.nz>
+ * They are only used if nothing else has been defined */
+#if !defined(DES_PTR) && !defined(DES_RISC1) && !defined(DES_RISC2) && !defined(DES_UNROLL)
+/* Special defines which change the way the code is built depending on the
+ CPU and OS. For SGI machines you can use _MIPS_SZLONG (32 or 64) to find
+ even newer MIPS CPU's, but at the moment one size fits all for
+ optimization options. Older Sparc's work better with only UNROLL, but
+ there's no way to tell at compile time what it is you're running on */
+
+#if defined( sun ) /* Newer Sparc's */
+#define DES_PTR
+#define DES_RISC1
+#define DES_UNROLL
+#elif defined( __ultrix ) /* Older MIPS */
+#define DES_PTR
+#define DES_RISC2
+#define DES_UNROLL
+#elif defined( __osf1__ ) /* Alpha */
+#define DES_PTR
+#define DES_RISC2
+#elif defined ( _AIX ) /* RS6000 */
+ /* Unknown */
+#elif defined( __hpux ) /* HP-PA */
+ /* Unknown */
+#elif defined( __aux ) /* 68K */
+ /* Unknown */
+#elif defined( __dgux ) /* 88K (but P6 in latest boxes) */
+#define DES_UNROLL
+#elif defined( __sgi ) /* Newer MIPS */
+#define DES_PTR
+#define DES_RISC2
+#define DES_UNROLL
+#elif defined( i386 ) /* x86 boxes, should be gcc */
+#define DES_PTR
+#define DES_RISC1
+#define DES_UNROLL
+#endif /* Systems-specific speed defines */
+#endif
+
+#endif /* DES_DEFAULT_OPTIONS */
+
+#ifdef MSDOS /* Visual C++ 2.1 (Windows NT/95) */
+#include <stdlib.h>
+#include <errno.h>
+#include <time.h>
+#include <io.h>
+#ifndef RAND
+#define RAND
+#endif
+#undef NOPROTO
+#endif
+
+#if defined(__STDC__) || defined(VMS) || defined(M_XENIX) || defined(MSDOS)
+#ifndef __KERNEL__
+#include <string.h>
+#else
+#include <linux/string.h>
+#endif
+#endif
+
+#ifndef RAND
+#define RAND
+#endif
+
+#ifdef linux
+#undef RAND
+#endif
+
+#ifdef MSDOS
+#define getpid() 2
+#define RAND
+#undef NOPROTO
+#endif
+
+#if defined(NOCONST)
+#define const
+#endif
+
+#ifdef __STDC__
+#undef NOPROTO
+#endif
+
+#ifdef RAND
+#define srandom(s) srand(s)
+#define random rand
+#endif
+
+#define ITERATIONS 16
+#define HALF_ITERATIONS 8
+
+/* used in des_read and des_write */
+#define MAXWRITE (1024*16)
+#define BSIZE (MAXWRITE+4)
+
+#define c2l(c,l) (l =((DES_LONG)(*((c)++))) , \
+ l|=((DES_LONG)(*((c)++)))<< 8L, \
+ l|=((DES_LONG)(*((c)++)))<<16L, \
+ l|=((DES_LONG)(*((c)++)))<<24L)
+
+/* NOTE - c is not incremented as per c2l */
+#define c2ln(c,l1,l2,n) { \
+ c+=n; \
+ l1=l2=0; \
+ switch (n) { \
+ case 8: l2 =((DES_LONG)(*(--(c))))<<24L; \
+ case 7: l2|=((DES_LONG)(*(--(c))))<<16L; \
+ case 6: l2|=((DES_LONG)(*(--(c))))<< 8L; \
+ case 5: l2|=((DES_LONG)(*(--(c)))); \
+ case 4: l1 =((DES_LONG)(*(--(c))))<<24L; \
+ case 3: l1|=((DES_LONG)(*(--(c))))<<16L; \
+ case 2: l1|=((DES_LONG)(*(--(c))))<< 8L; \
+ case 1: l1|=((DES_LONG)(*(--(c)))); \
+} \
+}
+
+#define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \
+ *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>16L)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>24L)&0xff))
+
+/* replacements for htonl and ntohl since I have no idea what to do
+ * when faced with machines with 8 byte longs. */
+#define HDRSIZE 4
+
+#define n2l(c,l) (l =((DES_LONG)(*((c)++)))<<24L, \
+ l|=((DES_LONG)(*((c)++)))<<16L, \
+ l|=((DES_LONG)(*((c)++)))<< 8L, \
+ l|=((DES_LONG)(*((c)++))))
+
+#define l2n(l,c) (*((c)++)=(unsigned char)(((l)>>24L)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>16L)&0xff), \
+ *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
+ *((c)++)=(unsigned char)(((l) )&0xff))
+
+/* NOTE - c is not incremented as per l2c */
+#define l2cn(l1,l2,c,n) { \
+ c+=n; \
+ switch (n) { \
+ case 8: *(--(c))=(unsigned char)(((l2)>>24L)&0xff); \
+ case 7: *(--(c))=(unsigned char)(((l2)>>16L)&0xff); \
+ case 6: *(--(c))=(unsigned char)(((l2)>> 8L)&0xff); \
+ case 5: *(--(c))=(unsigned char)(((l2) )&0xff); \
+ case 4: *(--(c))=(unsigned char)(((l1)>>24L)&0xff); \
+ case 3: *(--(c))=(unsigned char)(((l1)>>16L)&0xff); \
+ case 2: *(--(c))=(unsigned char)(((l1)>> 8L)&0xff); \
+ case 1: *(--(c))=(unsigned char)(((l1) )&0xff); \
+} \
+}
+
+#if defined(WIN32)
+#define ROTATE(a,n) (_lrotr(a,n))
+#else
+#define ROTATE(a,n) (((a)>>(n))+((a)<<(32-(n))))
+#endif
+
+/* Don't worry about the LOAD_DATA() stuff, that is used by
+ * fcrypt() to add it's little bit to the front */
+
+#ifdef DES_FCRYPT
+
+#define LOAD_DATA_tmp(R,S,u,t,E0,E1) \
+{ DES_LONG tmp; LOAD_DATA(R,S,u,t,E0,E1,tmp); }
+
+#define LOAD_DATA(R,S,u,t,E0,E1,tmp) \
+ t=R^(R>>16L); \
+ u=t&E0; t&=E1; \
+ tmp=(u<<16); u^=R^s[S ]; u^=tmp; \
+ tmp=(t<<16); t^=R^s[S+1]; t^=tmp
+#else
+#define LOAD_DATA_tmp(a,b,c,d,e,f) LOAD_DATA(a,b,c,d,e,f,g)
+#define LOAD_DATA(R,S,u,t,E0,E1,tmp) \
+ u=R^s[S ]; \
+ t=R^s[S+1]
+#endif
+
+/* The changes to this macro may help or hinder, depending on the
+ * compiler and the achitecture. gcc2 always seems to do well :-).
+ * Inspired by Dana How <how@isl.stanford.edu>
+ * DO NOT use the alternative version on machines with 8 byte longs.
+ * It does not seem to work on the Alpha, even when DES_LONG is 4
+ * bytes, probably an issue of accessing non-word aligned objects :-( */
+#ifdef DES_PTR
+
+/* It recently occured to me that 0^0^0^0^0^0^0 == 0, so there
+ * is no reason to not xor all the sub items together. This potentially
+ * saves a register since things can be xored directly into L */
+
+#if defined(DES_RISC1) || defined(DES_RISC2)
+#ifdef DES_RISC1
+#define D_ENCRYPT(LL,R,S) { \
+ unsigned int u1,u2,u3; \
+ LOAD_DATA(R,S,u,t,E0,E1,u1); \
+ u2=(int)u>>8L; \
+ u1=(int)u&0xfc; \
+ u2&=0xfc; \
+ t=ROTATE(t,4); \
+ u>>=16L; \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP +u1); \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x200+u2); \
+ u3=(int)(u>>8L); \
+ u1=(int)u&0xfc; \
+ u3&=0xfc; \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x400+u1); \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x600+u3); \
+ u2=(int)t>>8L; \
+ u1=(int)t&0xfc; \
+ u2&=0xfc; \
+ t>>=16L; \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x100+u1); \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x300+u2); \
+ u3=(int)t>>8L; \
+ u1=(int)t&0xfc; \
+ u3&=0xfc; \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x500+u1); \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x700+u3); }
+#endif
+#ifdef DES_RISC2
+#define D_ENCRYPT(LL,R,S) { \
+ unsigned int u1,u2,s1,s2; \
+ LOAD_DATA(R,S,u,t,E0,E1,u1); \
+ u2=(int)u>>8L; \
+ u1=(int)u&0xfc; \
+ u2&=0xfc; \
+ t=ROTATE(t,4); \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP +u1); \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x200+u2); \
+ s1=(int)(u>>16L); \
+ s2=(int)(u>>24L); \
+ s1&=0xfc; \
+ s2&=0xfc; \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x400+s1); \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x600+s2); \
+ u2=(int)t>>8L; \
+ u1=(int)t&0xfc; \
+ u2&=0xfc; \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x100+u1); \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x300+u2); \
+ s1=(int)(t>>16L); \
+ s2=(int)(t>>24L); \
+ s1&=0xfc; \
+ s2&=0xfc; \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x500+s1); \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x700+s2); }
+#endif
+#else
+#define D_ENCRYPT(LL,R,S) { \
+ LOAD_DATA_tmp(R,S,u,t,E0,E1); \
+ t=ROTATE(t,4); \
+ LL^= \
+ *(DES_LONG *)((unsigned char *)des_SP +((u )&0xfc))^ \
+ *(DES_LONG *)((unsigned char *)des_SP+0x200+((u>> 8L)&0xfc))^ \
+ *(DES_LONG *)((unsigned char *)des_SP+0x400+((u>>16L)&0xfc))^ \
+ *(DES_LONG *)((unsigned char *)des_SP+0x600+((u>>24L)&0xfc))^ \
+ *(DES_LONG *)((unsigned char *)des_SP+0x100+((t )&0xfc))^ \
+ *(DES_LONG *)((unsigned char *)des_SP+0x300+((t>> 8L)&0xfc))^ \
+ *(DES_LONG *)((unsigned char *)des_SP+0x500+((t>>16L)&0xfc))^ \
+ *(DES_LONG *)((unsigned char *)des_SP+0x700+((t>>24L)&0xfc)); }
+#endif
+
+#else /* original version */
+
+#if defined(DES_RISC1) || defined(DES_RISC2)
+#ifdef DES_RISC1
+#define D_ENCRYPT(LL,R,S) {\
+ unsigned int u1,u2,u3; \
+ LOAD_DATA(R,S,u,t,E0,E1,u1); \
+ u>>=2L; \
+ t=ROTATE(t,6); \
+ u2=(int)u>>8L; \
+ u1=(int)u&0x3f; \
+ u2&=0x3f; \
+ u>>=16L; \
+ LL^=des_SPtrans[0][u1]; \
+ LL^=des_SPtrans[2][u2]; \
+ u3=(int)u>>8L; \
+ u1=(int)u&0x3f; \
+ u3&=0x3f; \
+ LL^=des_SPtrans[4][u1]; \
+ LL^=des_SPtrans[6][u3]; \
+ u2=(int)t>>8L; \
+ u1=(int)t&0x3f; \
+ u2&=0x3f; \
+ t>>=16L; \
+ LL^=des_SPtrans[1][u1]; \
+ LL^=des_SPtrans[3][u2]; \
+ u3=(int)t>>8L; \
+ u1=(int)t&0x3f; \
+ u3&=0x3f; \
+ LL^=des_SPtrans[5][u1]; \
+ LL^=des_SPtrans[7][u3]; }
+#endif
+#ifdef DES_RISC2
+#define D_ENCRYPT(LL,R,S) {\
+ unsigned int u1,u2,s1,s2; \
+ LOAD_DATA(R,S,u,t,E0,E1,u1); \
+ u>>=2L; \
+ t=ROTATE(t,6); \
+ u2=(int)u>>8L; \
+ u1=(int)u&0x3f; \
+ u2&=0x3f; \
+ LL^=des_SPtrans[0][u1]; \
+ LL^=des_SPtrans[2][u2]; \
+ s1=(int)u>>16L; \
+ s2=(int)u>>24L; \
+ s1&=0x3f; \
+ s2&=0x3f; \
+ LL^=des_SPtrans[4][s1]; \
+ LL^=des_SPtrans[6][s2]; \
+ u2=(int)t>>8L; \
+ u1=(int)t&0x3f; \
+ u2&=0x3f; \
+ LL^=des_SPtrans[1][u1]; \
+ LL^=des_SPtrans[3][u2]; \
+ s1=(int)t>>16; \
+ s2=(int)t>>24L; \
+ s1&=0x3f; \
+ s2&=0x3f; \
+ LL^=des_SPtrans[5][s1]; \
+ LL^=des_SPtrans[7][s2]; }
+#endif
+
+#else
+
+#define D_ENCRYPT(LL,R,S) {\
+ LOAD_DATA_tmp(R,S,u,t,E0,E1); \
+ t=ROTATE(t,4); \
+ LL^=\
+ des_SPtrans[0][(u>> 2L)&0x3f]^ \
+ des_SPtrans[2][(u>>10L)&0x3f]^ \
+ des_SPtrans[4][(u>>18L)&0x3f]^ \
+ des_SPtrans[6][(u>>26L)&0x3f]^ \
+ des_SPtrans[1][(t>> 2L)&0x3f]^ \
+ des_SPtrans[3][(t>>10L)&0x3f]^ \
+ des_SPtrans[5][(t>>18L)&0x3f]^ \
+ des_SPtrans[7][(t>>26L)&0x3f]; }
+#endif
+#endif
+
+ /* IP and FP
+ * The problem is more of a geometric problem that random bit fiddling.
+ 0 1 2 3 4 5 6 7 62 54 46 38 30 22 14 6
+ 8 9 10 11 12 13 14 15 60 52 44 36 28 20 12 4
+ 16 17 18 19 20 21 22 23 58 50 42 34 26 18 10 2
+ 24 25 26 27 28 29 30 31 to 56 48 40 32 24 16 8 0
+
+ 32 33 34 35 36 37 38 39 63 55 47 39 31 23 15 7
+ 40 41 42 43 44 45 46 47 61 53 45 37 29 21 13 5
+ 48 49 50 51 52 53 54 55 59 51 43 35 27 19 11 3
+ 56 57 58 59 60 61 62 63 57 49 41 33 25 17 9 1
+
+ The output has been subject to swaps of the form
+ 0 1 -> 3 1 but the odd and even bits have been put into
+ 2 3 2 0
+ different words. The main trick is to remember that
+ t=((l>>size)^r)&(mask);
+ r^=t;
+ l^=(t<<size);
+ can be used to swap and move bits between words.
+
+ So l = 0 1 2 3 r = 16 17 18 19
+ 4 5 6 7 20 21 22 23
+ 8 9 10 11 24 25 26 27
+ 12 13 14 15 28 29 30 31
+ becomes (for size == 2 and mask == 0x3333)
+ t = 2^16 3^17 -- -- l = 0 1 16 17 r = 2 3 18 19
+ 6^20 7^21 -- -- 4 5 20 21 6 7 22 23
+ 10^24 11^25 -- -- 8 9 24 25 10 11 24 25
+ 14^28 15^29 -- -- 12 13 28 29 14 15 28 29
+
+ Thanks for hints from Richard Outerbridge - he told me IP&FP
+ could be done in 15 xor, 10 shifts and 5 ands.
+ When I finally started to think of the problem in 2D
+ I first got ~42 operations without xors. When I remembered
+ how to use xors :-) I got it to its final state.
+ */
+#define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\
+ (b)^=(t),\
+ (a)^=((t)<<(n)))
+
+#define IP(l,r) \
+{ \
+ register DES_LONG tt; \
+ PERM_OP(r,l,tt, 4,0x0f0f0f0fL); \
+ PERM_OP(l,r,tt,16,0x0000ffffL); \
+ PERM_OP(r,l,tt, 2,0x33333333L); \
+ PERM_OP(l,r,tt, 8,0x00ff00ffL); \
+ PERM_OP(r,l,tt, 1,0x55555555L); \
+}
+
+#define FP(l,r) \
+{ \
+ register DES_LONG tt; \
+ PERM_OP(l,r,tt, 1,0x55555555L); \
+ PERM_OP(r,l,tt, 8,0x00ff00ffL); \
+ PERM_OP(l,r,tt, 2,0x33333333L); \
+ PERM_OP(r,l,tt,16,0x0000ffffL); \
+ PERM_OP(l,r,tt, 4,0x0f0f0f0fL); \
+}
+
+#ifndef NOPROTO
+void fcrypt_body(DES_LONG *out,des_key_schedule ks,
+ DES_LONG Eswap0, DES_LONG Eswap1);
+#else
+void fcrypt_body();
+#endif
+
+static const DES_LONG des_skb[8][64]={
+ { /* for C bits (numbered as per FIPS 46) 1 2 3 4 5 6 */
+ 0x00000000L,0x00000010L,0x20000000L,0x20000010L,
+ 0x00010000L,0x00010010L,0x20010000L,0x20010010L,
+ 0x00000800L,0x00000810L,0x20000800L,0x20000810L,
+ 0x00010800L,0x00010810L,0x20010800L,0x20010810L,
+ 0x00000020L,0x00000030L,0x20000020L,0x20000030L,
+ 0x00010020L,0x00010030L,0x20010020L,0x20010030L,
+ 0x00000820L,0x00000830L,0x20000820L,0x20000830L,
+ 0x00010820L,0x00010830L,0x20010820L,0x20010830L,
+ 0x00080000L,0x00080010L,0x20080000L,0x20080010L,
+ 0x00090000L,0x00090010L,0x20090000L,0x20090010L,
+ 0x00080800L,0x00080810L,0x20080800L,0x20080810L,
+ 0x00090800L,0x00090810L,0x20090800L,0x20090810L,
+ 0x00080020L,0x00080030L,0x20080020L,0x20080030L,
+ 0x00090020L,0x00090030L,0x20090020L,0x20090030L,
+ 0x00080820L,0x00080830L,0x20080820L,0x20080830L,
+ 0x00090820L,0x00090830L,0x20090820L,0x20090830L,
+ },
+ { /* for C bits (numbered as per FIPS 46) 7 8 10 11 12 13 */
+ 0x00000000L,0x02000000L,0x00002000L,0x02002000L,
+ 0x00200000L,0x02200000L,0x00202000L,0x02202000L,
+ 0x00000004L,0x02000004L,0x00002004L,0x02002004L,
+ 0x00200004L,0x02200004L,0x00202004L,0x02202004L,
+ 0x00000400L,0x02000400L,0x00002400L,0x02002400L,
+ 0x00200400L,0x02200400L,0x00202400L,0x02202400L,
+ 0x00000404L,0x02000404L,0x00002404L,0x02002404L,
+ 0x00200404L,0x02200404L,0x00202404L,0x02202404L,
+ 0x10000000L,0x12000000L,0x10002000L,0x12002000L,
+ 0x10200000L,0x12200000L,0x10202000L,0x12202000L,
+ 0x10000004L,0x12000004L,0x10002004L,0x12002004L,
+ 0x10200004L,0x12200004L,0x10202004L,0x12202004L,
+ 0x10000400L,0x12000400L,0x10002400L,0x12002400L,
+ 0x10200400L,0x12200400L,0x10202400L,0x12202400L,
+ 0x10000404L,0x12000404L,0x10002404L,0x12002404L,
+ 0x10200404L,0x12200404L,0x10202404L,0x12202404L,
+ },
+ { /* for C bits (numbered as per FIPS 46) 14 15 16 17 19 20 */
+ 0x00000000L,0x00000001L,0x00040000L,0x00040001L,
+ 0x01000000L,0x01000001L,0x01040000L,0x01040001L,
+ 0x00000002L,0x00000003L,0x00040002L,0x00040003L,
+ 0x01000002L,0x01000003L,0x01040002L,0x01040003L,
+ 0x00000200L,0x00000201L,0x00040200L,0x00040201L,
+ 0x01000200L,0x01000201L,0x01040200L,0x01040201L,
+ 0x00000202L,0x00000203L,0x00040202L,0x00040203L,
+ 0x01000202L,0x01000203L,0x01040202L,0x01040203L,
+ 0x08000000L,0x08000001L,0x08040000L,0x08040001L,
+ 0x09000000L,0x09000001L,0x09040000L,0x09040001L,
+ 0x08000002L,0x08000003L,0x08040002L,0x08040003L,
+ 0x09000002L,0x09000003L,0x09040002L,0x09040003L,
+ 0x08000200L,0x08000201L,0x08040200L,0x08040201L,
+ 0x09000200L,0x09000201L,0x09040200L,0x09040201L,
+ 0x08000202L,0x08000203L,0x08040202L,0x08040203L,
+ 0x09000202L,0x09000203L,0x09040202L,0x09040203L,
+ },
+ { /* for C bits (numbered as per FIPS 46) 21 23 24 26 27 28 */
+ 0x00000000L,0x00100000L,0x00000100L,0x00100100L,
+ 0x00000008L,0x00100008L,0x00000108L,0x00100108L,
+ 0x00001000L,0x00101000L,0x00001100L,0x00101100L,
+ 0x00001008L,0x00101008L,0x00001108L,0x00101108L,
+ 0x04000000L,0x04100000L,0x04000100L,0x04100100L,
+ 0x04000008L,0x04100008L,0x04000108L,0x04100108L,
+ 0x04001000L,0x04101000L,0x04001100L,0x04101100L,
+ 0x04001008L,0x04101008L,0x04001108L,0x04101108L,
+ 0x00020000L,0x00120000L,0x00020100L,0x00120100L,
+ 0x00020008L,0x00120008L,0x00020108L,0x00120108L,
+ 0x00021000L,0x00121000L,0x00021100L,0x00121100L,
+ 0x00021008L,0x00121008L,0x00021108L,0x00121108L,
+ 0x04020000L,0x04120000L,0x04020100L,0x04120100L,
+ 0x04020008L,0x04120008L,0x04020108L,0x04120108L,
+ 0x04021000L,0x04121000L,0x04021100L,0x04121100L,
+ 0x04021008L,0x04121008L,0x04021108L,0x04121108L,
+ },
+ { /* for D bits (numbered as per FIPS 46) 1 2 3 4 5 6 */
+ 0x00000000L,0x10000000L,0x00010000L,0x10010000L,
+ 0x00000004L,0x10000004L,0x00010004L,0x10010004L,
+ 0x20000000L,0x30000000L,0x20010000L,0x30010000L,
+ 0x20000004L,0x30000004L,0x20010004L,0x30010004L,
+ 0x00100000L,0x10100000L,0x00110000L,0x10110000L,
+ 0x00100004L,0x10100004L,0x00110004L,0x10110004L,
+ 0x20100000L,0x30100000L,0x20110000L,0x30110000L,
+ 0x20100004L,0x30100004L,0x20110004L,0x30110004L,
+ 0x00001000L,0x10001000L,0x00011000L,0x10011000L,
+ 0x00001004L,0x10001004L,0x00011004L,0x10011004L,
+ 0x20001000L,0x30001000L,0x20011000L,0x30011000L,
+ 0x20001004L,0x30001004L,0x20011004L,0x30011004L,
+ 0x00101000L,0x10101000L,0x00111000L,0x10111000L,
+ 0x00101004L,0x10101004L,0x00111004L,0x10111004L,
+ 0x20101000L,0x30101000L,0x20111000L,0x30111000L,
+ 0x20101004L,0x30101004L,0x20111004L,0x30111004L,
+ },
+ { /* for D bits (numbered as per FIPS 46) 8 9 11 12 13 14 */
+ 0x00000000L,0x08000000L,0x00000008L,0x08000008L,
+ 0x00000400L,0x08000400L,0x00000408L,0x08000408L,
+ 0x00020000L,0x08020000L,0x00020008L,0x08020008L,
+ 0x00020400L,0x08020400L,0x00020408L,0x08020408L,
+ 0x00000001L,0x08000001L,0x00000009L,0x08000009L,
+ 0x00000401L,0x08000401L,0x00000409L,0x08000409L,
+ 0x00020001L,0x08020001L,0x00020009L,0x08020009L,
+ 0x00020401L,0x08020401L,0x00020409L,0x08020409L,
+ 0x02000000L,0x0A000000L,0x02000008L,0x0A000008L,
+ 0x02000400L,0x0A000400L,0x02000408L,0x0A000408L,
+ 0x02020000L,0x0A020000L,0x02020008L,0x0A020008L,
+ 0x02020400L,0x0A020400L,0x02020408L,0x0A020408L,
+ 0x02000001L,0x0A000001L,0x02000009L,0x0A000009L,
+ 0x02000401L,0x0A000401L,0x02000409L,0x0A000409L,
+ 0x02020001L,0x0A020001L,0x02020009L,0x0A020009L,
+ 0x02020401L,0x0A020401L,0x02020409L,0x0A020409L,
+ },
+ { /* for D bits (numbered as per FIPS 46) 16 17 18 19 20 21 */
+ 0x00000000L,0x00000100L,0x00080000L,0x00080100L,
+ 0x01000000L,0x01000100L,0x01080000L,0x01080100L,
+ 0x00000010L,0x00000110L,0x00080010L,0x00080110L,
+ 0x01000010L,0x01000110L,0x01080010L,0x01080110L,
+ 0x00200000L,0x00200100L,0x00280000L,0x00280100L,
+ 0x01200000L,0x01200100L,0x01280000L,0x01280100L,
+ 0x00200010L,0x00200110L,0x00280010L,0x00280110L,
+ 0x01200010L,0x01200110L,0x01280010L,0x01280110L,
+ 0x00000200L,0x00000300L,0x00080200L,0x00080300L,
+ 0x01000200L,0x01000300L,0x01080200L,0x01080300L,
+ 0x00000210L,0x00000310L,0x00080210L,0x00080310L,
+ 0x01000210L,0x01000310L,0x01080210L,0x01080310L,
+ 0x00200200L,0x00200300L,0x00280200L,0x00280300L,
+ 0x01200200L,0x01200300L,0x01280200L,0x01280300L,
+ 0x00200210L,0x00200310L,0x00280210L,0x00280310L,
+ 0x01200210L,0x01200310L,0x01280210L,0x01280310L,
+ },
+ { /* for D bits (numbered as per FIPS 46) 22 23 24 25 27 28 */
+ 0x00000000L,0x04000000L,0x00040000L,0x04040000L,
+ 0x00000002L,0x04000002L,0x00040002L,0x04040002L,
+ 0x00002000L,0x04002000L,0x00042000L,0x04042000L,
+ 0x00002002L,0x04002002L,0x00042002L,0x04042002L,
+ 0x00000020L,0x04000020L,0x00040020L,0x04040020L,
+ 0x00000022L,0x04000022L,0x00040022L,0x04040022L,
+ 0x00002020L,0x04002020L,0x00042020L,0x04042020L,
+ 0x00002022L,0x04002022L,0x00042022L,0x04042022L,
+ 0x00000800L,0x04000800L,0x00040800L,0x04040800L,
+ 0x00000802L,0x04000802L,0x00040802L,0x04040802L,
+ 0x00002800L,0x04002800L,0x00042800L,0x04042800L,
+ 0x00002802L,0x04002802L,0x00042802L,0x04042802L,
+ 0x00000820L,0x04000820L,0x00040820L,0x04040820L,
+ 0x00000822L,0x04000822L,0x00040822L,0x04040822L,
+ 0x00002820L,0x04002820L,0x00042820L,0x04042820L,
+ 0x00002822L,0x04002822L,0x00042822L,0x04042822L,
+ }
+};
+
+const DES_LONG des_SPtrans[8][64]={
+ {
+ /* nibble 0 */
+ 0x02080800L, 0x00080000L, 0x02000002L, 0x02080802L,
+ 0x02000000L, 0x00080802L, 0x00080002L, 0x02000002L,
+ 0x00080802L, 0x02080800L, 0x02080000L, 0x00000802L,
+ 0x02000802L, 0x02000000L, 0x00000000L, 0x00080002L,
+ 0x00080000L, 0x00000002L, 0x02000800L, 0x00080800L,
+ 0x02080802L, 0x02080000L, 0x00000802L, 0x02000800L,
+ 0x00000002L, 0x00000800L, 0x00080800L, 0x02080002L,
+ 0x00000800L, 0x02000802L, 0x02080002L, 0x00000000L,
+ 0x00000000L, 0x02080802L, 0x02000800L, 0x00080002L,
+ 0x02080800L, 0x00080000L, 0x00000802L, 0x02000800L,
+ 0x02080002L, 0x00000800L, 0x00080800L, 0x02000002L,
+ 0x00080802L, 0x00000002L, 0x02000002L, 0x02080000L,
+ 0x02080802L, 0x00080800L, 0x02080000L, 0x02000802L,
+ 0x02000000L, 0x00000802L, 0x00080002L, 0x00000000L,
+ 0x00080000L, 0x02000000L, 0x02000802L, 0x02080800L,
+ 0x00000002L, 0x02080002L, 0x00000800L, 0x00080802L,
+ },
+ { /* nibble 1 */
+ 0x40108010L, 0x00000000L, 0x00108000L, 0x40100000L,
+ 0x40000010L, 0x00008010L, 0x40008000L, 0x00108000L,
+ 0x00008000L, 0x40100010L, 0x00000010L, 0x40008000L,
+ 0x00100010L, 0x40108000L, 0x40100000L, 0x00000010L,
+ 0x00100000L, 0x40008010L, 0x40100010L, 0x00008000L,
+ 0x00108010L, 0x40000000L, 0x00000000L, 0x00100010L,
+ 0x40008010L, 0x00108010L, 0x40108000L, 0x40000010L,
+ 0x40000000L, 0x00100000L, 0x00008010L, 0x40108010L,
+ 0x00100010L, 0x40108000L, 0x40008000L, 0x00108010L,
+ 0x40108010L, 0x00100010L, 0x40000010L, 0x00000000L,
+ 0x40000000L, 0x00008010L, 0x00100000L, 0x40100010L,
+ 0x00008000L, 0x40000000L, 0x00108010L, 0x40008010L,
+ 0x40108000L, 0x00008000L, 0x00000000L, 0x40000010L,
+ 0x00000010L, 0x40108010L, 0x00108000L, 0x40100000L,
+ 0x40100010L, 0x00100000L, 0x00008010L, 0x40008000L,
+ 0x40008010L, 0x00000010L, 0x40100000L, 0x00108000L,
+ },
+ { /* nibble 2 */
+ 0x04000001L, 0x04040100L, 0x00000100L, 0x04000101L,
+ 0x00040001L, 0x04000000L, 0x04000101L, 0x00040100L,
+ 0x04000100L, 0x00040000L, 0x04040000L, 0x00000001L,
+ 0x04040101L, 0x00000101L, 0x00000001L, 0x04040001L,
+ 0x00000000L, 0x00040001L, 0x04040100L, 0x00000100L,
+ 0x00000101L, 0x04040101L, 0x00040000L, 0x04000001L,
+ 0x04040001L, 0x04000100L, 0x00040101L, 0x04040000L,
+ 0x00040100L, 0x00000000L, 0x04000000L, 0x00040101L,
+ 0x04040100L, 0x00000100L, 0x00000001L, 0x00040000L,
+ 0x00000101L, 0x00040001L, 0x04040000L, 0x04000101L,
+ 0x00000000L, 0x04040100L, 0x00040100L, 0x04040001L,
+ 0x00040001L, 0x04000000L, 0x04040101L, 0x00000001L,
+ 0x00040101L, 0x04000001L, 0x04000000L, 0x04040101L,
+ 0x00040000L, 0x04000100L, 0x04000101L, 0x00040100L,
+ 0x04000100L, 0x00000000L, 0x04040001L, 0x00000101L,
+ 0x04000001L, 0x00040101L, 0x00000100L, 0x04040000L,
+ },
+ { /* nibble 3 */
+ 0x00401008L, 0x10001000L, 0x00000008L, 0x10401008L,
+ 0x00000000L, 0x10400000L, 0x10001008L, 0x00400008L,
+ 0x10401000L, 0x10000008L, 0x10000000L, 0x00001008L,
+ 0x10000008L, 0x00401008L, 0x00400000L, 0x10000000L,
+ 0x10400008L, 0x00401000L, 0x00001000L, 0x00000008L,
+ 0x00401000L, 0x10001008L, 0x10400000L, 0x00001000L,
+ 0x00001008L, 0x00000000L, 0x00400008L, 0x10401000L,
+ 0x10001000L, 0x10400008L, 0x10401008L, 0x00400000L,
+ 0x10400008L, 0x00001008L, 0x00400000L, 0x10000008L,
+ 0x00401000L, 0x10001000L, 0x00000008L, 0x10400000L,
+ 0x10001008L, 0x00000000L, 0x00001000L, 0x00400008L,
+ 0x00000000L, 0x10400008L, 0x10401000L, 0x00001000L,
+ 0x10000000L, 0x10401008L, 0x00401008L, 0x00400000L,
+ 0x10401008L, 0x00000008L, 0x10001000L, 0x00401008L,
+ 0x00400008L, 0x00401000L, 0x10400000L, 0x10001008L,
+ 0x00001008L, 0x10000000L, 0x10000008L, 0x10401000L,
+ },
+ { /* nibble 4 */
+ 0x08000000L, 0x00010000L, 0x00000400L, 0x08010420L,
+ 0x08010020L, 0x08000400L, 0x00010420L, 0x08010000L,
+ 0x00010000L, 0x00000020L, 0x08000020L, 0x00010400L,
+ 0x08000420L, 0x08010020L, 0x08010400L, 0x00000000L,
+ 0x00010400L, 0x08000000L, 0x00010020L, 0x00000420L,
+ 0x08000400L, 0x00010420L, 0x00000000L, 0x08000020L,
+ 0x00000020L, 0x08000420L, 0x08010420L, 0x00010020L,
+ 0x08010000L, 0x00000400L, 0x00000420L, 0x08010400L,
+ 0x08010400L, 0x08000420L, 0x00010020L, 0x08010000L,
+ 0x00010000L, 0x00000020L, 0x08000020L, 0x08000400L,
+ 0x08000000L, 0x00010400L, 0x08010420L, 0x00000000L,
+ 0x00010420L, 0x08000000L, 0x00000400L, 0x00010020L,
+ 0x08000420L, 0x00000400L, 0x00000000L, 0x08010420L,
+ 0x08010020L, 0x08010400L, 0x00000420L, 0x00010000L,
+ 0x00010400L, 0x08010020L, 0x08000400L, 0x00000420L,
+ 0x00000020L, 0x00010420L, 0x08010000L, 0x08000020L,
+ },
+ { /* nibble 5 */
+ 0x80000040L, 0x00200040L, 0x00000000L, 0x80202000L,
+ 0x00200040L, 0x00002000L, 0x80002040L, 0x00200000L,
+ 0x00002040L, 0x80202040L, 0x00202000L, 0x80000000L,
+ 0x80002000L, 0x80000040L, 0x80200000L, 0x00202040L,
+ 0x00200000L, 0x80002040L, 0x80200040L, 0x00000000L,
+ 0x00002000L, 0x00000040L, 0x80202000L, 0x80200040L,
+ 0x80202040L, 0x80200000L, 0x80000000L, 0x00002040L,
+ 0x00000040L, 0x00202000L, 0x00202040L, 0x80002000L,
+ 0x00002040L, 0x80000000L, 0x80002000L, 0x00202040L,
+ 0x80202000L, 0x00200040L, 0x00000000L, 0x80002000L,
+ 0x80000000L, 0x00002000L, 0x80200040L, 0x00200000L,
+ 0x00200040L, 0x80202040L, 0x00202000L, 0x00000040L,
+ 0x80202040L, 0x00202000L, 0x00200000L, 0x80002040L,
+ 0x80000040L, 0x80200000L, 0x00202040L, 0x00000000L,
+ 0x00002000L, 0x80000040L, 0x80002040L, 0x80202000L,
+ 0x80200000L, 0x00002040L, 0x00000040L, 0x80200040L,
+ },
+ { /* nibble 6 */
+ 0x00004000L, 0x00000200L, 0x01000200L, 0x01000004L,
+ 0x01004204L, 0x00004004L, 0x00004200L, 0x00000000L,
+ 0x01000000L, 0x01000204L, 0x00000204L, 0x01004000L,
+ 0x00000004L, 0x01004200L, 0x01004000L, 0x00000204L,
+ 0x01000204L, 0x00004000L, 0x00004004L, 0x01004204L,
+ 0x00000000L, 0x01000200L, 0x01000004L, 0x00004200L,
+ 0x01004004L, 0x00004204L, 0x01004200L, 0x00000004L,
+ 0x00004204L, 0x01004004L, 0x00000200L, 0x01000000L,
+ 0x00004204L, 0x01004000L, 0x01004004L, 0x00000204L,
+ 0x00004000L, 0x00000200L, 0x01000000L, 0x01004004L,
+ 0x01000204L, 0x00004204L, 0x00004200L, 0x00000000L,
+ 0x00000200L, 0x01000004L, 0x00000004L, 0x01000200L,
+ 0x00000000L, 0x01000204L, 0x01000200L, 0x00004200L,
+ 0x00000204L, 0x00004000L, 0x01004204L, 0x01000000L,
+ 0x01004200L, 0x00000004L, 0x00004004L, 0x01004204L,
+ 0x01000004L, 0x01004200L, 0x01004000L, 0x00004004L,
+ },
+ { /* nibble 7 */
+ 0x20800080L, 0x20820000L, 0x00020080L, 0x00000000L,
+ 0x20020000L, 0x00800080L, 0x20800000L, 0x20820080L,
+ 0x00000080L, 0x20000000L, 0x00820000L, 0x00020080L,
+ 0x00820080L, 0x20020080L, 0x20000080L, 0x20800000L,
+ 0x00020000L, 0x00820080L, 0x00800080L, 0x20020000L,
+ 0x20820080L, 0x20000080L, 0x00000000L, 0x00820000L,
+ 0x20000000L, 0x00800000L, 0x20020080L, 0x20800080L,
+ 0x00800000L, 0x00020000L, 0x20820000L, 0x00000080L,
+ 0x00800000L, 0x00020000L, 0x20000080L, 0x20820080L,
+ 0x00020080L, 0x20000000L, 0x00000000L, 0x00820000L,
+ 0x20800080L, 0x20020080L, 0x20020000L, 0x00800080L,
+ 0x20820000L, 0x00000080L, 0x00800080L, 0x20020000L,
+ 0x20820080L, 0x00800000L, 0x20800000L, 0x20000080L,
+ 0x00820000L, 0x00020080L, 0x20020080L, 0x20800000L,
+ 0x00000080L, 0x20820000L, 0x00820080L, 0x00000000L,
+ 0x20000000L, 0x20800080L, 0x00020000L, 0x00820080L,
+ }
+};
+
+#define HPERM_OP(a,t,n,m) ((t)=((((a)<<(16-(n)))^(a))&(m)),\
+ (a)=(a)^(t)^(t>>(16-(n))))
+
+static const unsigned char odd_parity[256]={
+ 1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14,
+ 16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31,
+ 32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47,
+ 49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62,
+ 64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79,
+ 81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94,
+ 97, 97, 98, 98,100,100,103,103,104,104,107,107,109,109,110,110,
+ 112,112,115,115,117,117,118,118,121,121,122,122,124,124,127,127,
+ 128,128,131,131,133,133,134,134,137,137,138,138,140,140,143,143,
+ 145,145,146,146,148,148,151,151,152,152,155,155,157,157,158,158,
+ 161,161,162,162,164,164,167,167,168,168,171,171,173,173,174,174,
+ 176,176,179,179,181,181,182,182,185,185,186,186,188,188,191,191,
+ 193,193,194,194,196,196,199,199,200,200,203,203,205,205,206,206,
+ 208,208,211,211,213,213,214,214,217,217,218,218,220,220,223,223,
+ 224,224,227,227,229,229,230,230,233,233,234,234,236,236,239,239,
+ 241,241,242,242,244,244,247,247,248,248,251,251,253,253,254,254
+};
+
+/**
+ * Create key schedule for a single DES 64Bit key
+ */
+static int des_set_key(des_cblock *key, des_key_schedule *schedule)
+{
+ static int shifts2[16] = {0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0};
+ register DES_LONG c,d,t,s,t2;
+ register unsigned char *in;
+ register DES_LONG *k;
+ register int i;
+
+ for (i = 0; i < sizeof(des_cblock); i++)
+ {
+ (*key)[i] = odd_parity[(*key)[i]];
+ }
+
+ k=(DES_LONG *)schedule;
+ in=(unsigned char *)key;
+
+ c2l(in,c);
+ c2l(in,d);
+
+ /* do PC1 in 60 simple operations */
+/* PERM_OP(d,c,t,4,0x0f0f0f0fL);
+ HPERM_OP(c,t,-2, 0xcccc0000L);
+ HPERM_OP(c,t,-1, 0xaaaa0000L);
+ HPERM_OP(c,t, 8, 0x00ff0000L);
+ HPERM_OP(c,t,-1, 0xaaaa0000L);
+ HPERM_OP(d,t,-8, 0xff000000L);
+ HPERM_OP(d,t, 8, 0x00ff0000L);
+ HPERM_OP(d,t, 2, 0x33330000L);
+ d=((d&0x00aa00aaL)<<7L)|((d&0x55005500L)>>7L)|(d&0xaa55aa55L);
+ d=(d>>8)|((c&0xf0000000L)>>4);
+ c&=0x0fffffffL; */
+
+ /* I now do it in 47 simple operations :-)
+ * Thanks to John Fletcher (john_fletcher@lccmail.ocf.llnl.gov)
+ * for the inspiration. :-) */
+ PERM_OP (d,c,t,4,0x0f0f0f0fL);
+ HPERM_OP(c,t,-2,0xcccc0000L);
+ HPERM_OP(d,t,-2,0xcccc0000L);
+ PERM_OP (d,c,t,1,0x55555555L);
+ PERM_OP (c,d,t,8,0x00ff00ffL);
+ PERM_OP (d,c,t,1,0x55555555L);
+ d= (((d&0x000000ffL)<<16L)| (d&0x0000ff00L) |
+ ((d&0x00ff0000L)>>16L)|((c&0xf0000000L)>>4L));
+ c&=0x0fffffffL;
+
+ for (i=0; i<ITERATIONS; i++)
+ {
+ if (shifts2[i])
+ { c=((c>>2L)|(c<<26L)); d=((d>>2L)|(d<<26L)); }
+ else
+ { c=((c>>1L)|(c<<27L)); d=((d>>1L)|(d<<27L)); }
+ c&=0x0fffffffL;
+ d&=0x0fffffffL;
+ /* could be a few less shifts but I am to lazy at this
+ * point in time to investigate */
+ s= des_skb[0][ (c )&0x3f ]|
+ des_skb[1][((c>> 6)&0x03)|((c>> 7L)&0x3c)]|
+ des_skb[2][((c>>13)&0x0f)|((c>>14L)&0x30)]|
+ des_skb[3][((c>>20)&0x01)|((c>>21L)&0x06) |
+ ((c>>22L)&0x38)];
+ t= des_skb[4][ (d )&0x3f ]|
+ des_skb[5][((d>> 7L)&0x03)|((d>> 8L)&0x3c)]|
+ des_skb[6][ (d>>15L)&0x3f ]|
+ des_skb[7][((d>>21L)&0x0f)|((d>>22L)&0x30)];
+
+ /* table contained 0213 4657 */
+ t2=((t<<16L)|(s&0x0000ffffL))&0xffffffffL;
+ *(k++)=ROTATE(t2,30)&0xffffffffL;
+
+ t2=((s>>16L)|(t&0xffff0000L));
+ *(k++)=ROTATE(t2,26)&0xffffffffL;
+ }
+ return(0);
+}
+
+
+static void des_encrypt(DES_LONG *data, des_key_schedule ks, int enc)
+{
+ register DES_LONG l,r,t,u;
+#ifdef DES_PTR
+ register unsigned char *des_SP=(unsigned char *)des_SPtrans;
+#endif
+#ifndef DES_UNROLL
+ register int i;
+#endif
+ register DES_LONG *s;
+
+ r=data[0];
+ l=data[1];
+
+ IP(r,l);
+ /* Things have been modified so that the initial rotate is
+ * done outside the loop. This required the
+ * des_SPtrans values in sp.h to be rotated 1 bit to the right.
+ * One perl script later and things have a 5% speed up on a sparc2.
+ * Thanks to Richard Outerbridge <71755.204@CompuServe.COM>
+ * for pointing this out. */
+ /* clear the top bits on machines with 8byte longs */
+ /* shift left by 2 */
+ r=ROTATE(r,29)&0xffffffffL;
+ l=ROTATE(l,29)&0xffffffffL;
+
+ s=(DES_LONG *)ks;
+ /* I don't know if it is worth the effort of loop unrolling the
+ * inner loop */
+ if (enc)
+ {
+#ifdef DES_UNROLL
+ D_ENCRYPT(l,r, 0); /* 1 */
+ D_ENCRYPT(r,l, 2); /* 2 */
+ D_ENCRYPT(l,r, 4); /* 3 */
+ D_ENCRYPT(r,l, 6); /* 4 */
+ D_ENCRYPT(l,r, 8); /* 5 */
+ D_ENCRYPT(r,l,10); /* 6 */
+ D_ENCRYPT(l,r,12); /* 7 */
+ D_ENCRYPT(r,l,14); /* 8 */
+ D_ENCRYPT(l,r,16); /* 9 */
+ D_ENCRYPT(r,l,18); /* 10 */
+ D_ENCRYPT(l,r,20); /* 11 */
+ D_ENCRYPT(r,l,22); /* 12 */
+ D_ENCRYPT(l,r,24); /* 13 */
+ D_ENCRYPT(r,l,26); /* 14 */
+ D_ENCRYPT(l,r,28); /* 15 */
+ D_ENCRYPT(r,l,30); /* 16 */
+#else
+ for (i=0; i<32; i+=8)
+{
+ D_ENCRYPT(l,r,i+0); /* 1 */
+ D_ENCRYPT(r,l,i+2); /* 2 */
+ D_ENCRYPT(l,r,i+4); /* 3 */
+ D_ENCRYPT(r,l,i+6); /* 4 */
+}
+#endif
+ }
+ else
+{
+#ifdef DES_UNROLL
+ D_ENCRYPT(l,r,30); /* 16 */
+ D_ENCRYPT(r,l,28); /* 15 */
+ D_ENCRYPT(l,r,26); /* 14 */
+ D_ENCRYPT(r,l,24); /* 13 */
+ D_ENCRYPT(l,r,22); /* 12 */
+ D_ENCRYPT(r,l,20); /* 11 */
+ D_ENCRYPT(l,r,18); /* 10 */
+ D_ENCRYPT(r,l,16); /* 9 */
+ D_ENCRYPT(l,r,14); /* 8 */
+ D_ENCRYPT(r,l,12); /* 7 */
+ D_ENCRYPT(l,r,10); /* 6 */
+ D_ENCRYPT(r,l, 8); /* 5 */
+ D_ENCRYPT(l,r, 6); /* 4 */
+ D_ENCRYPT(r,l, 4); /* 3 */
+ D_ENCRYPT(l,r, 2); /* 2 */
+ D_ENCRYPT(r,l, 0); /* 1 */
+#else
+ for (i=30; i>0; i-=8)
+{
+ D_ENCRYPT(l,r,i-0); /* 16 */
+ D_ENCRYPT(r,l,i-2); /* 15 */
+ D_ENCRYPT(l,r,i-4); /* 14 */
+ D_ENCRYPT(r,l,i-6); /* 13 */
+}
+#endif
+}
+
+ /* rotate and clear the top bits on machines with 8byte longs */
+ l=ROTATE(l,3)&0xffffffffL;
+ r=ROTATE(r,3)&0xffffffffL;
+
+ FP(r,l);
+ data[0]=l;
+ data[1]=r;
+ l=r=t=u=0;
+}
+
+/**
+ * DES CBC encrypt decrypt routine
+ */
+static void des_cbc_encrypt(des_cblock *input, des_cblock *output, long length,
+ des_key_schedule schedule, des_cblock *ivec, int enc)
+{
+ register DES_LONG tin0,tin1;
+ register DES_LONG tout0,tout1,xor0,xor1;
+ register unsigned char *in,*out;
+ register long l=length;
+ DES_LONG tin[2];
+ unsigned char *iv;
+
+ in=(unsigned char *)input;
+ out=(unsigned char *)output;
+ iv=(unsigned char *)ivec;
+
+ if (enc)
+ {
+ c2l(iv,tout0);
+ c2l(iv,tout1);
+ for (l-=8; l>=0; l-=8)
+ {
+ c2l(in,tin0);
+ c2l(in,tin1);
+ tin0^=tout0; tin[0]=tin0;
+ tin1^=tout1; tin[1]=tin1;
+ des_encrypt((DES_LONG *)tin,schedule,DES_ENCRYPT);
+ tout0=tin[0]; l2c(tout0,out);
+ tout1=tin[1]; l2c(tout1,out);
+ }
+ if (l != -8)
+ {
+ c2ln(in,tin0,tin1,l+8);
+ tin0^=tout0; tin[0]=tin0;
+ tin1^=tout1; tin[1]=tin1;
+ des_encrypt((DES_LONG *)tin,schedule,DES_ENCRYPT);
+ tout0=tin[0]; l2c(tout0,out);
+ tout1=tin[1]; l2c(tout1,out);
+ }
+ }
+ else
+ {
+ c2l(iv,xor0);
+ c2l(iv,xor1);
+ for (l-=8; l>=0; l-=8)
+ {
+ c2l(in,tin0); tin[0]=tin0;
+ c2l(in,tin1); tin[1]=tin1;
+ des_encrypt((DES_LONG *)tin,schedule,DES_DECRYPT);
+ tout0=tin[0]^xor0;
+ tout1=tin[1]^xor1;
+ l2c(tout0,out);
+ l2c(tout1,out);
+ xor0=tin0;
+ xor1=tin1;
+ }
+ if (l != -8)
+ {
+ c2l(in,tin0); tin[0]=tin0;
+ c2l(in,tin1); tin[1]=tin1;
+ des_encrypt((DES_LONG *)tin,schedule,DES_DECRYPT);
+ tout0=tin[0]^xor0;
+ tout1=tin[1]^xor1;
+ l2cn(tout0,tout1,out,l+8);
+ /* xor0=tin0;
+ xor1=tin1; */
+ }
+ }
+ tin0=tin1=tout0=tout1=xor0=xor1=0;
+ tin[0]=tin[1]=0;
+}
+
+static void des_encrypt2(DES_LONG *data, des_key_schedule ks, int enc)
+{
+ register DES_LONG l,r,t,u;
+#ifdef DES_PTR
+ register unsigned char *des_SP=(unsigned char *)des_SPtrans;
+#endif
+#ifndef DES_UNROLL
+ register int i;
+#endif
+ register DES_LONG *s;
+
+ r=data[0];
+ l=data[1];
+
+ /* Things have been modified so that the initial rotate is
+ * done outside the loop. This required the
+ * des_SPtrans values in sp.h to be rotated 1 bit to the right.
+ * One perl script later and things have a 5% speed up on a sparc2.
+ * Thanks to Richard Outerbridge <71755.204@CompuServe.COM>
+ * for pointing this out.
+ * clear the top bits on machines with 8byte longs */
+ r=ROTATE(r,29)&0xffffffffL;
+ l=ROTATE(l,29)&0xffffffffL;
+
+ s=(DES_LONG *)ks;
+ /* I don't know if it is worth the effort of loop unrolling the
+ * inner loop */
+ if (enc)
+ {
+#ifdef DES_UNROLL
+ D_ENCRYPT(l,r, 0); /* 1 */
+ D_ENCRYPT(r,l, 2); /* 2 */
+ D_ENCRYPT(l,r, 4); /* 3 */
+ D_ENCRYPT(r,l, 6); /* 4 */
+ D_ENCRYPT(l,r, 8); /* 5 */
+ D_ENCRYPT(r,l,10); /* 6 */
+ D_ENCRYPT(l,r,12); /* 7 */
+ D_ENCRYPT(r,l,14); /* 8 */
+ D_ENCRYPT(l,r,16); /* 9 */
+ D_ENCRYPT(r,l,18); /* 10 */
+ D_ENCRYPT(l,r,20); /* 11 */
+ D_ENCRYPT(r,l,22); /* 12 */
+ D_ENCRYPT(l,r,24); /* 13 */
+ D_ENCRYPT(r,l,26); /* 14 */
+ D_ENCRYPT(l,r,28); /* 15 */
+ D_ENCRYPT(r,l,30); /* 16 */
+#else
+ for (i=0; i<32; i+=8)
+{
+ D_ENCRYPT(l,r,i+0); /* 1 */
+ D_ENCRYPT(r,l,i+2); /* 2 */
+ D_ENCRYPT(l,r,i+4); /* 3 */
+ D_ENCRYPT(r,l,i+6); /* 4 */
+}
+#endif
+ }
+ else
+{
+#ifdef DES_UNROLL
+ D_ENCRYPT(l,r,30); /* 16 */
+ D_ENCRYPT(r,l,28); /* 15 */
+ D_ENCRYPT(l,r,26); /* 14 */
+ D_ENCRYPT(r,l,24); /* 13 */
+ D_ENCRYPT(l,r,22); /* 12 */
+ D_ENCRYPT(r,l,20); /* 11 */
+ D_ENCRYPT(l,r,18); /* 10 */
+ D_ENCRYPT(r,l,16); /* 9 */
+ D_ENCRYPT(l,r,14); /* 8 */
+ D_ENCRYPT(r,l,12); /* 7 */
+ D_ENCRYPT(l,r,10); /* 6 */
+ D_ENCRYPT(r,l, 8); /* 5 */
+ D_ENCRYPT(l,r, 6); /* 4 */
+ D_ENCRYPT(r,l, 4); /* 3 */
+ D_ENCRYPT(l,r, 2); /* 2 */
+ D_ENCRYPT(r,l, 0); /* 1 */
+#else
+ for (i=30; i>0; i-=8)
+{
+ D_ENCRYPT(l,r,i-0); /* 16 */
+ D_ENCRYPT(r,l,i-2); /* 15 */
+ D_ENCRYPT(l,r,i-4); /* 14 */
+ D_ENCRYPT(r,l,i-6); /* 13 */
+}
+#endif
+}
+ /* rotate and clear the top bits on machines with 8byte longs */
+ data[0]=ROTATE(l,3)&0xffffffffL;
+ data[1]=ROTATE(r,3)&0xffffffffL;
+ l=r=t=u=0;
+}
+
+/**
+ * Single block 3DES EDE encrypt routine
+ */
+static void des_encrypt3(DES_LONG *data, des_key_schedule ks1,
+ des_key_schedule ks2, des_key_schedule ks3)
+{
+ register DES_LONG l,r;
+
+ l=data[0];
+ r=data[1];
+ IP(l,r);
+ data[0]=l;
+ data[1]=r;
+ des_encrypt2((DES_LONG *)data,ks1,DES_ENCRYPT);
+ des_encrypt2((DES_LONG *)data,ks2,DES_DECRYPT);
+ des_encrypt2((DES_LONG *)data,ks3,DES_ENCRYPT);
+ l=data[0];
+ r=data[1];
+ FP(r,l);
+ data[0]=l;
+ data[1]=r;
+}
+
+/**
+ * Single block 3DES EDE decrypt routine
+ */
+static void des_decrypt3(DES_LONG *data, des_key_schedule ks1,
+ des_key_schedule ks2, des_key_schedule ks3)
+{
+ register DES_LONG l,r;
+
+ l=data[0];
+ r=data[1];
+ IP(l,r);
+ data[0]=l;
+ data[1]=r;
+ des_encrypt2((DES_LONG *)data,ks3,DES_DECRYPT);
+ des_encrypt2((DES_LONG *)data,ks2,DES_ENCRYPT);
+ des_encrypt2((DES_LONG *)data,ks1,DES_DECRYPT);
+ l=data[0];
+ r=data[1];
+ FP(r,l);
+ data[0]=l;
+ data[1]=r;
+}
+
+/**
+ * 3DES EDE CBC encrypt/decrypt routine
+ */
+static void des_ede3_cbc_encrypt(des_cblock *input, des_cblock *output, long length,
+ des_key_schedule ks1, des_key_schedule ks2,
+ des_key_schedule ks3, des_cblock *ivec, int enc)
+{
+ register DES_LONG tin0,tin1;
+ register DES_LONG tout0,tout1,xor0,xor1;
+ register unsigned char *in,*out;
+ register long l=length;
+ DES_LONG tin[2];
+ unsigned char *iv;
+
+ in=(unsigned char *)input;
+ out=(unsigned char *)output;
+ iv=(unsigned char *)ivec;
+
+ if (enc)
+ {
+ c2l(iv,tout0);
+ c2l(iv,tout1);
+ for (l-=8; l>=0; l-=8)
+ {
+ c2l(in,tin0);
+ c2l(in,tin1);
+ tin0^=tout0;
+ tin1^=tout1;
+
+ tin[0]=tin0;
+ tin[1]=tin1;
+ des_encrypt3((DES_LONG *)tin,ks1,ks2,ks3);
+ tout0=tin[0];
+ tout1=tin[1];
+
+ l2c(tout0,out);
+ l2c(tout1,out);
+ }
+ if (l != -8)
+ {
+ c2ln(in,tin0,tin1,l+8);
+ tin0^=tout0;
+ tin1^=tout1;
+
+ tin[0]=tin0;
+ tin[1]=tin1;
+ des_encrypt3((DES_LONG *)tin,ks1,ks2,ks3);
+ tout0=tin[0];
+ tout1=tin[1];
+
+ l2c(tout0,out);
+ l2c(tout1,out);
+ }
+ iv=(unsigned char *)ivec;
+ l2c(tout0,iv);
+ l2c(tout1,iv);
+ }
+ else
+ {
+ register DES_LONG t0,t1;
+
+ c2l(iv,xor0);
+ c2l(iv,xor1);
+ for (l-=8; l>=0; l-=8)
+ {
+ c2l(in,tin0);
+ c2l(in,tin1);
+
+ t0=tin0;
+ t1=tin1;
+
+ tin[0]=tin0;
+ tin[1]=tin1;
+ des_decrypt3((DES_LONG *)tin,ks1,ks2,ks3);
+ tout0=tin[0];
+ tout1=tin[1];
+
+ tout0^=xor0;
+ tout1^=xor1;
+ l2c(tout0,out);
+ l2c(tout1,out);
+ xor0=t0;
+ xor1=t1;
+ }
+ if (l != -8)
+ {
+ c2l(in,tin0);
+ c2l(in,tin1);
+
+ t0=tin0;
+ t1=tin1;
+
+ tin[0]=tin0;
+ tin[1]=tin1;
+ des_decrypt3((DES_LONG *)tin,ks1,ks2,ks3);
+ tout0=tin[0];
+ tout1=tin[1];
+
+ tout0^=xor0;
+ tout1^=xor1;
+ l2cn(tout0,tout1,out,l+8);
+ xor0=t0;
+ xor1=t1;
+ }
+
+ iv=(unsigned char *)ivec;
+ l2c(xor0,iv);
+ l2c(xor1,iv);
+ }
+ tin0=tin1=tout0=tout1=xor0=xor1=0;
+ tin[0]=tin[1]=0;
+}
+
+/**
+ * Implementation of crypter_t.decrypt for DES.
+ */
+static status_t decrypt(private_des_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *decrypted)
+{
+ des_cblock ivb;
+
+ if (data.len % sizeof(des_cblock) != 0 ||
+ iv.len != sizeof(des_cblock))
+ {
+ return INVALID_ARG;
+ }
+
+ *decrypted = chunk_alloc(data.len);
+ memcpy(&ivb, iv.ptr, sizeof(des_cblock));
+ des_cbc_encrypt((des_cblock*)(data.ptr), (des_cblock*)(decrypted->ptr),
+ data.len, this->ks, &ivb, DES_DECRYPT);
+ return SUCCESS;
+}
+
+
+/**
+ * Implementation of crypter_t.decrypt for DES.
+ */
+static status_t encrypt(private_des_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *encrypted)
+{
+ des_cblock ivb;
+
+ if (data.len % sizeof(des_cblock) != 0 ||
+ iv.len != sizeof(des_cblock))
+ {
+ return INVALID_ARG;
+ }
+
+ *encrypted = chunk_alloc(data.len);
+ memcpy(&ivb, iv.ptr, sizeof(des_cblock));
+ des_cbc_encrypt((des_cblock*)(data.ptr), (des_cblock*)(encrypted->ptr),
+ data.len, this->ks, &ivb, DES_ENCRYPT);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of crypter_t.decrypt for 3DES.
+ */
+static status_t decrypt3(private_des_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *decrypted)
+{
+ des_cblock ivb;
+
+ if (data.len % sizeof(des_cblock) != 0 ||
+ iv.len != sizeof(des_cblock))
+ {
+ return INVALID_ARG;
+ }
+
+ *decrypted = chunk_alloc(data.len);
+ memcpy(&ivb, iv.ptr, sizeof(des_cblock));
+ des_ede3_cbc_encrypt((des_cblock*)(data.ptr), (des_cblock*)(decrypted->ptr),
+ data.len, this->ks3[0], this->ks3[1], this->ks3[2],
+ &ivb, DES_DECRYPT);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of crypter_t.decrypt for 3DES.
+ */
+static status_t encrypt3(private_des_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *encrypted)
+{
+ des_cblock ivb;
+
+ if (data.len % sizeof(des_cblock) != 0 ||
+ iv.len != sizeof(des_cblock))
+ {
+ return INVALID_ARG;
+ }
+
+ *encrypted = chunk_alloc(data.len);
+ memcpy(&ivb, iv.ptr, sizeof(des_cblock));
+ des_ede3_cbc_encrypt((des_cblock*)(data.ptr), (des_cblock*)(encrypted->ptr),
+ data.len, this->ks3[0], this->ks3[1], this->ks3[2],
+ &ivb, DES_ENCRYPT);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of crypter_t.get_block_size.
+ */
+static size_t get_block_size (private_des_crypter_t *this)
+{
+ return sizeof(des_cblock);
+}
+
+/**
+ * Implementation of crypter_t.get_key_size.
+ */
+static size_t get_key_size (private_des_crypter_t *this)
+{
+ return this->key_size;
+}
+
+/**
+ * Implementation of crypter_t.set_key for DES.
+ */
+static status_t set_key(private_des_crypter_t *this, chunk_t key)
+{
+ if (key.len != sizeof(des_cblock))
+ {
+ return INVALID_ARG;
+ }
+
+ des_set_key((des_cblock*)(key.ptr), &this->ks);
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of crypter_t.set_key for 3DES.
+ */
+static status_t set_key3(private_des_crypter_t *this, chunk_t key)
+{
+ if (key.len != 3 * sizeof(des_cblock))
+ {
+ return INVALID_ARG;
+ }
+
+ des_set_key((des_cblock*)(key.ptr) + 0, &this->ks3[0]);
+ des_set_key((des_cblock*)(key.ptr) + 1, &this->ks3[1]);
+ des_set_key((des_cblock*)(key.ptr) + 2, &this->ks3[2]);
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of crypter_t.destroy and des_crypter_t.destroy.
+ */
+static void destroy(private_des_crypter_t *this)
+{
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+des_crypter_t *des_crypter_create(encryption_algorithm_t algo)
+{
+ private_des_crypter_t *this = malloc_thing(private_des_crypter_t);
+
+ /* functions of crypter_t interface */
+ this->public.crypter_interface.get_block_size = (size_t (*) (crypter_t *)) get_block_size;
+ this->public.crypter_interface.get_key_size = (size_t (*) (crypter_t *)) get_key_size;
+ this->public.crypter_interface.destroy = (void (*) (crypter_t *)) destroy;
+
+ /* use functions depending on algorithm */
+ switch (algo)
+ {
+ case ENCR_DES:
+ this->key_size = sizeof(des_cblock);
+ this->public.crypter_interface.set_key = (status_t (*) (crypter_t *,chunk_t)) set_key;
+ this->public.crypter_interface.encrypt = (status_t (*) (crypter_t *, chunk_t,chunk_t, chunk_t *)) encrypt;
+ this->public.crypter_interface.decrypt = (status_t (*) (crypter_t *, chunk_t , chunk_t, chunk_t *)) decrypt;
+ break;
+ case ENCR_3DES:
+ this->key_size = 3 * sizeof(des_cblock);
+ this->public.crypter_interface.set_key = (status_t (*) (crypter_t *,chunk_t)) set_key3;
+ this->public.crypter_interface.encrypt = (status_t (*) (crypter_t *, chunk_t,chunk_t, chunk_t *)) encrypt3;
+ this->public.crypter_interface.decrypt = (status_t (*) (crypter_t *, chunk_t , chunk_t, chunk_t *)) decrypt3;
+ break;
+ default:
+ free(this);
+ return NULL;
+ }
+ return &(this->public);
+}
diff --git a/src/libstrongswan/crypto/crypters/des_crypter.h b/src/libstrongswan/crypto/crypters/des_crypter.h
new file mode 100644
index 000000000..0c87b0a9c
--- /dev/null
+++ b/src/libstrongswan/crypto/crypters/des_crypter.h
@@ -0,0 +1,58 @@
+/**
+ * @file des_crypter.h
+ *
+ * @brief Interface of des_crypter_t
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef DES_CRYPTER_H_
+#define DES_CRYPTER_H_
+
+typedef struct des_crypter_t des_crypter_t;
+
+#include <crypto/crypters/crypter.h>
+
+
+/**
+ * @brief Class implementing the DES and 3DES encryption algorithms.
+ *
+ * @b Constructors:
+ * - des_crypter_create()
+ *
+ * @ingroup crypters
+ */
+struct des_crypter_t {
+
+ /**
+ * The crypter_t interface.
+ */
+ crypter_t crypter_interface;
+};
+
+/**
+ * @brief Constructor to create des_crypter_t objects.
+ *
+ * @param algo ENCR_DES for single DES, ENCR_3DES for triple DES
+ * @return
+ * - des_crypter_t object
+ * - NULL if algo not supported
+ */
+des_crypter_t *des_crypter_create(encryption_algorithm_t algo);
+
+
+#endif /* DES_CRYPTER_H_ */
diff --git a/src/libstrongswan/crypto/diffie_hellman.c b/src/libstrongswan/crypto/diffie_hellman.c
new file mode 100644
index 000000000..e4062066c
--- /dev/null
+++ b/src/libstrongswan/crypto/diffie_hellman.c
@@ -0,0 +1,612 @@
+/**
+ * @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-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <utils/randomizer.h>
+
+ENUM_BEGIN(diffie_hellman_group_names, MODP_NONE, MODP_1024_BIT,
+ "MODP_NONE",
+ "MODP_768_BIT",
+ "MODP_1024_BIT");
+ENUM_NEXT(diffie_hellman_group_names, MODP_1536_BIT, MODP_1536_BIT, MODP_1024_BIT,
+ "MODP_1536_BIT");
+ENUM_NEXT(diffie_hellman_group_names, MODP_2048_BIT, MODP_8192_BIT, MODP_1536_BIT,
+ "MODP_2048_BIT",
+ "MODP_3072_BIT",
+ "MODP_4096_BIT",
+ "MODP_6144_BIT",
+ "MODP_8192_BIT");
+ENUM_END(diffie_hellman_group_names, MODP_8192_BIT);
+
+
+/**
+ * Modulus of Group 1 (MODP_768_BIT).
+ */
+static u_int8_t group1_modulus[] = {
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34,
+ 0xC4,0xC6,0x62,0x8B,0x80 ,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,
+ 0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
+ 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37,
+ 0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,
+ 0xF4,0x4C,0x42,0xE9,0xA6,0x3A,0x36,0x20,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
+};
+
+/**
+ * Modulus of Group 2 (MODP_1024_BIT).
+ */
+static u_int8_t group2_modulus[] = {
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34,
+ 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,
+ 0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
+ 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37,
+ 0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,
+ 0xF4,0x4C,0x42,0xE9,0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
+ 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,0x7C,0x4B,0x1F,0xE6,
+ 0x49,0x28,0x66,0x51,0xEC,0xE6,0x53,0x81,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
+};
+
+/**
+ * Modulus of Group 5 (MODP_1536_BIT).
+ */
+static u_int8_t group5_modulus[] = {
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34,
+ 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,
+ 0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
+ 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37,
+ 0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,
+ 0xF4,0x4C,0x42,0xE9,0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
+ 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,0x7C,0x4B,0x1F,0xE6,
+ 0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,
+ 0x98,0xDA,0x48,0x36,0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,
+ 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,0x20,0x85,0x52,0xBB,
+ 0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,
+ 0xF1,0x74,0x6C,0x08,0xCA,0x23,0x73,0x27,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
+};
+/**
+ * Modulus of Group 14 (MODP_2048_BIT).
+ */
+static u_int8_t group14_modulus[] = {
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34,
+ 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,
+ 0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
+ 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37,
+ 0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,
+ 0xF4,0x4C,0x42,0xE9,0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
+ 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,0x7C,0x4B,0x1F,0xE6,
+ 0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,
+ 0x98,0xDA,0x48,0x36,0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,
+ 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,0x20,0x85,0x52,0xBB,
+ 0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,
+ 0xF1,0x74,0x6C,0x08,0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B,
+ 0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,0xEC,0x07,0xA2,0x8F,
+ 0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18,
+ 0x39,0x95,0x49,0x7C,0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10,
+ 0x15,0x72,0x8E,0x5A,0x8A,0xAC,0xAA,0x68,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
+};
+
+/**
+ * Modulus of Group 15 (MODP_3072_BIT).
+ */
+static u_int8_t group15_modulus[] = {
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34,
+ 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,
+ 0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
+ 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37,
+ 0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,
+ 0xF4,0x4C,0x42,0xE9,0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
+ 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,0x7C,0x4B,0x1F,0xE6,
+ 0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,
+ 0x98,0xDA,0x48,0x36,0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,
+ 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,0x20,0x85,0x52,0xBB,
+ 0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,
+ 0xF1,0x74,0x6C,0x08,0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B,
+ 0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,0xEC,0x07,0xA2,0x8F,
+ 0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18,
+ 0x39,0x95,0x49,0x7C,0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10,
+ 0x15,0x72,0x8E,0x5A,0x8A,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,0x04,0x50,0x7A,0x33,
+ 0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A,
+ 0x8A,0xEA,0x71,0x57,0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7,
+ 0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,0x4A,0x25,0x61,0x9D,
+ 0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64,
+ 0xD8,0x76,0x02,0x73,0x3E,0xC8,0x6A,0x64,0x52,0x1F,0x2B,0x18,0x17,0x7B,0x20,0x0C,
+ 0xBB,0xE1,0x17,0x57,0x7A,0x61,0x5D,0x6C,0x77,0x09,0x88,0xC0,0xBA,0xD9,0x46,0xE2,
+ 0x08,0xE2,0x4F,0xA0,0x74,0xE5,0xAB,0x31,0x43,0xDB,0x5B,0xFC,0xE0,0xFD,0x10,0x8E,
+ 0x4B,0x82,0xD1,0x20,0xA9,0x3A,0xD2,0xCA,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
+};
+
+/**
+ * Modulus of Group 16 (MODP_4096_BIT).
+ */
+static u_int8_t group16_modulus[] = {
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34,
+ 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,
+ 0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
+ 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37,
+ 0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,
+ 0xF4,0x4C,0x42,0xE9,0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
+ 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,0x7C,0x4B,0x1F,0xE6,
+ 0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,
+ 0x98,0xDA,0x48,0x36,0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,
+ 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,0x20,0x85,0x52,0xBB,
+ 0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,
+ 0xF1,0x74,0x6C,0x08,0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B,
+ 0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,0xEC,0x07,0xA2,0x8F,
+ 0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18,
+ 0x39,0x95,0x49,0x7C,0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10,
+ 0x15,0x72,0x8E,0x5A,0x8A,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,0x04,0x50,0x7A,0x33,
+ 0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A,
+ 0x8A,0xEA,0x71,0x57,0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7,
+ 0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,0x4A,0x25,0x61,0x9D,
+ 0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64,
+ 0xD8,0x76,0x02,0x73,0x3E,0xC8,0x6A,0x64,0x52,0x1F,0x2B,0x18,0x17,0x7B,0x20,0x0C,
+ 0xBB,0xE1,0x17,0x57,0x7A,0x61,0x5D,0x6C,0x77,0x09,0x88,0xC0,0xBA,0xD9,0x46,0xE2,
+ 0x08,0xE2,0x4F,0xA0,0x74,0xE5,0xAB,0x31,0x43,0xDB,0x5B,0xFC,0xE0,0xFD,0x10,0x8E,
+ 0x4B,0x82,0xD1,0x20,0xA9,0x21,0x08,0x01,0x1A,0x72,0x3C,0x12,0xA7,0x87,0xE6,0xD7,
+ 0x88,0x71,0x9A,0x10,0xBD,0xBA,0x5B,0x26,0x99,0xC3,0x27,0x18,0x6A,0xF4,0xE2,0x3C,
+ 0x1A,0x94,0x68,0x34,0xB6,0x15,0x0B,0xDA,0x25,0x83,0xE9,0xCA,0x2A,0xD4,0x4C,0xE8,
+ 0xDB,0xBB,0xC2,0xDB,0x04,0xDE,0x8E,0xF9,0x2E,0x8E,0xFC,0x14,0x1F,0xBE,0xCA,0xA6,
+ 0x28,0x7C,0x59,0x47,0x4E,0x6B,0xC0,0x5D,0x99,0xB2,0x96,0x4F,0xA0,0x90,0xC3,0xA2,
+ 0x23,0x3B,0xA1,0x86,0x51,0x5B,0xE7,0xED,0x1F,0x61,0x29,0x70,0xCE,0xE2,0xD7,0xAF,
+ 0xB8,0x1B,0xDD,0x76,0x21,0x70,0x48,0x1C,0xD0,0x06,0x91,0x27,0xD5,0xB0,0x5A,0xA9,
+ 0x93,0xB4,0xEA,0x98,0x8D,0x8F,0xDD,0xC1,0x86,0xFF,0xB7,0xDC,0x90,0xA6,0xC0,0x8F,
+ 0x4D,0xF4,0x35,0xC9,0x34,0x06,0x31,0x99,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
+};
+
+/**
+ * Modulus of Group 17 (MODP_6144_BIT).
+ */
+static u_int8_t group17_modulus[] = {
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34,
+ 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,
+ 0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
+ 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37,
+ 0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,
+ 0xF4,0x4C,0x42,0xE9,0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
+ 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,0x7C,0x4B,0x1F,0xE6,
+ 0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,
+ 0x98,0xDA,0x48,0x36,0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,
+ 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,0x20,0x85,0x52,0xBB,
+ 0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,
+ 0xF1,0x74,0x6C,0x08,0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B,
+ 0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,0xEC,0x07,0xA2,0x8F,
+ 0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18,
+ 0x39,0x95,0x49,0x7C,0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10,
+ 0x15,0x72,0x8E,0x5A,0x8A,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,0x04,0x50,0x7A,0x33,
+ 0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A,
+ 0x8A,0xEA,0x71,0x57,0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7,
+ 0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,0x4A,0x25,0x61,0x9D,
+ 0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64,
+ 0xD8,0x76,0x02,0x73,0x3E,0xC8,0x6A,0x64,0x52,0x1F,0x2B,0x18,0x17,0x7B,0x20,0x0C,
+ 0xBB,0xE1,0x17,0x57,0x7A,0x61,0x5D,0x6C,0x77,0x09,0x88,0xC0,0xBA,0xD9,0x46,0xE2,
+ 0x08,0xE2,0x4F,0xA0,0x74,0xE5,0xAB,0x31,0x43,0xDB,0x5B,0xFC,0xE0,0xFD,0x10,0x8E,
+ 0x4B,0x82,0xD1,0x20,0xA9,0x21,0x08,0x01,0x1A,0x72,0x3C,0x12,0xA7,0x87,0xE6,0xD7,
+ 0x88,0x71,0x9A,0x10,0xBD,0xBA,0x5B,0x26,0x99,0xC3,0x27,0x18,0x6A,0xF4,0xE2,0x3C,
+ 0x1A,0x94,0x68,0x34,0xB6,0x15,0x0B,0xDA,0x25,0x83,0xE9,0xCA,0x2A,0xD4,0x4C,0xE8,
+ 0xDB,0xBB,0xC2,0xDB,0x04,0xDE,0x8E,0xF9,0x2E,0x8E,0xFC,0x14,0x1F,0xBE,0xCA,0xA6,
+ 0x28,0x7C,0x59,0x47,0x4E,0x6B,0xC0,0x5D,0x99,0xB2,0x96,0x4F,0xA0,0x90,0xC3,0xA2,
+ 0x23,0x3B,0xA1,0x86,0x51,0x5B,0xE7,0xED,0x1F,0x61,0x29,0x70,0xCE,0xE2,0xD7,0xAF,
+ 0xB8,0x1B,0xDD,0x76,0x21,0x70,0x48,0x1C,0xD0,0x06,0x91,0x27,0xD5,0xB0,0x5A,0xA9,
+ 0x93,0xB4,0xEA,0x98,0x8D,0x8F,0xDD,0xC1,0x86,0xFF,0xB7,0xDC,0x90,0xA6,0xC0,0x8F,
+ 0x4D,0xF4,0x35,0xC9,0x34,0x02,0x84,0x92,0x36,0xC3,0xFA,0xB4,0xD2,0x7C,0x70,0x26,
+ 0xC1,0xD4,0xDC,0xB2,0x60,0x26,0x46,0xDE,0xC9,0x75,0x1E,0x76,0x3D,0xBA,0x37,0xBD,
+ 0xF8,0xFF,0x94,0x06,0xAD,0x9E,0x53,0x0E,0xE5,0xDB,0x38,0x2F,0x41,0x30,0x01,0xAE,
+ 0xB0,0x6A,0x53,0xED,0x90,0x27,0xD8,0x31,0x17,0x97,0x27,0xB0,0x86,0x5A,0x89,0x18,
+ 0xDA,0x3E,0xDB,0xEB,0xCF,0x9B,0x14,0xED,0x44,0xCE,0x6C,0xBA,0xCE,0xD4,0xBB,0x1B,
+ 0xDB,0x7F,0x14,0x47,0xE6,0xCC,0x25,0x4B,0x33,0x20,0x51,0x51,0x2B,0xD7,0xAF,0x42,
+ 0x6F,0xB8,0xF4,0x01,0x37,0x8C,0xD2,0xBF,0x59,0x83,0xCA,0x01,0xC6,0x4B,0x92,0xEC,
+ 0xF0,0x32,0xEA,0x15,0xD1,0x72,0x1D,0x03,0xF4,0x82,0xD7,0xCE,0x6E,0x74,0xFE,0xF6,
+ 0xD5,0x5E,0x70,0x2F,0x46,0x98,0x0C,0x82,0xB5,0xA8,0x40,0x31,0x90,0x0B,0x1C,0x9E,
+ 0x59,0xE7,0xC9,0x7F,0xBE,0xC7,0xE8,0xF3,0x23,0xA9,0x7A,0x7E,0x36,0xCC,0x88,0xBE,
+ 0x0F,0x1D,0x45,0xB7,0xFF,0x58,0x5A,0xC5,0x4B,0xD4,0x07,0xB2,0x2B,0x41,0x54,0xAA,
+ 0xCC,0x8F,0x6D,0x7E,0xBF,0x48,0xE1,0xD8,0x14,0xCC,0x5E,0xD2,0x0F,0x80,0x37,0xE0,
+ 0xA7,0x97,0x15,0xEE,0xF2,0x9B,0xE3,0x28,0x06,0xA1,0xD5,0x8B,0xB7,0xC5,0xDA,0x76,
+ 0xF5,0x50,0xAA,0x3D,0x8A,0x1F,0xBF,0xF0,0xEB,0x19,0xCC,0xB1,0xA3,0x13,0xD5,0x5C,
+ 0xDA,0x56,0xC9,0xEC,0x2E,0xF2,0x96,0x32,0x38,0x7F,0xE8,0xD7,0x6E,0x3C,0x04,0x68,
+ 0x04,0x3E,0x8F,0x66,0x3F,0x48,0x60,0xEE,0x12,0xBF,0x2D,0x5B,0x0B,0x74,0x74,0xD6,
+ 0xE6,0x94,0xF9,0x1E,0x6D,0xCC,0x40,0x24,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
+};
+
+/**
+ * Modulus of Group 18 (MODP_8192_BIT).
+ */
+static u_int8_t group18_modulus[] = {
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34,
+ 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,
+ 0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
+ 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37,
+ 0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,
+ 0xF4,0x4C,0x42,0xE9,0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
+ 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,0x7C,0x4B,0x1F,0xE6,
+ 0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,
+ 0x98,0xDA,0x48,0x36,0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,
+ 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,0x20,0x85,0x52,0xBB,
+ 0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,
+ 0xF1,0x74,0x6C,0x08,0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B,
+ 0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,0xEC,0x07,0xA2,0x8F,
+ 0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18,
+ 0x39,0x95,0x49,0x7C,0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10,
+ 0x15,0x72,0x8E,0x5A,0x8A,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,0x04,0x50,0x7A,0x33,
+ 0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A,
+ 0x8A,0xEA,0x71,0x57,0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7,
+ 0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,0x4A,0x25,0x61,0x9D,
+ 0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64,
+ 0xD8,0x76,0x02,0x73,0x3E,0xC8,0x6A,0x64,0x52,0x1F,0x2B,0x18,0x17,0x7B,0x20,0x0C,
+ 0xBB,0xE1,0x17,0x57,0x7A,0x61,0x5D,0x6C,0x77,0x09,0x88,0xC0,0xBA,0xD9,0x46,0xE2,
+ 0x08,0xE2,0x4F,0xA0,0x74,0xE5,0xAB,0x31,0x43,0xDB,0x5B,0xFC,0xE0,0xFD,0x10,0x8E,
+ 0x4B,0x82,0xD1,0x20,0xA9,0x21,0x08,0x01,0x1A,0x72,0x3C,0x12,0xA7,0x87,0xE6,0xD7,
+ 0x88,0x71,0x9A,0x10,0xBD,0xBA,0x5B,0x26,0x99,0xC3,0x27,0x18,0x6A,0xF4,0xE2,0x3C,
+ 0x1A,0x94,0x68,0x34,0xB6,0x15,0x0B,0xDA,0x25,0x83,0xE9,0xCA,0x2A,0xD4,0x4C,0xE8,
+ 0xDB,0xBB,0xC2,0xDB,0x04,0xDE,0x8E,0xF9,0x2E,0x8E,0xFC,0x14,0x1F,0xBE,0xCA,0xA6,
+ 0x28,0x7C,0x59,0x47,0x4E,0x6B,0xC0,0x5D,0x99,0xB2,0x96,0x4F,0xA0,0x90,0xC3,0xA2,
+ 0x23,0x3B,0xA1,0x86,0x51,0x5B,0xE7,0xED,0x1F,0x61,0x29,0x70,0xCE,0xE2,0xD7,0xAF,
+ 0xB8,0x1B,0xDD,0x76,0x21,0x70,0x48,0x1C,0xD0,0x06,0x91,0x27,0xD5,0xB0,0x5A,0xA9,
+ 0x93,0xB4,0xEA,0x98,0x8D,0x8F,0xDD,0xC1,0x86,0xFF,0xB7,0xDC,0x90,0xA6,0xC0,0x8F,
+ 0x4D,0xF4,0x35,0xC9,0x34,0x02,0x84,0x92,0x36,0xC3,0xFA,0xB4,0xD2,0x7C,0x70,0x26,
+ 0xC1,0xD4,0xDC,0xB2,0x60,0x26,0x46,0xDE,0xC9,0x75,0x1E,0x76,0x3D,0xBA,0x37,0xBD,
+ 0xF8,0xFF,0x94,0x06,0xAD,0x9E,0x53,0x0E,0xE5,0xDB,0x38,0x2F,0x41,0x30,0x01,0xAE,
+ 0xB0,0x6A,0x53,0xED,0x90,0x27,0xD8,0x31,0x17,0x97,0x27,0xB0,0x86,0x5A,0x89,0x18,
+ 0xDA,0x3E,0xDB,0xEB,0xCF,0x9B,0x14,0xED,0x44,0xCE,0x6C,0xBA,0xCE,0xD4,0xBB,0x1B,
+ 0xDB,0x7F,0x14,0x47,0xE6,0xCC,0x25,0x4B,0x33,0x20,0x51,0x51,0x2B,0xD7,0xAF,0x42,
+ 0x6F,0xB8,0xF4,0x01,0x37,0x8C,0xD2,0xBF,0x59,0x83,0xCA,0x01,0xC6,0x4B,0x92,0xEC,
+ 0xF0,0x32,0xEA,0x15,0xD1,0x72,0x1D,0x03,0xF4,0x82,0xD7,0xCE,0x6E,0x74,0xFE,0xF6,
+ 0xD5,0x5E,0x70,0x2F,0x46,0x98,0x0C,0x82,0xB5,0xA8,0x40,0x31,0x90,0x0B,0x1C,0x9E,
+ 0x59,0xE7,0xC9,0x7F,0xBE,0xC7,0xE8,0xF3,0x23,0xA9,0x7A,0x7E,0x36,0xCC,0x88,0xBE,
+ 0x0F,0x1D,0x45,0xB7,0xFF,0x58,0x5A,0xC5,0x4B,0xD4,0x07,0xB2,0x2B,0x41,0x54,0xAA,
+ 0xCC,0x8F,0x6D,0x7E,0xBF,0x48,0xE1,0xD8,0x14,0xCC,0x5E,0xD2,0x0F,0x80,0x37,0xE0,
+ 0xA7,0x97,0x15,0xEE,0xF2,0x9B,0xE3,0x28,0x06,0xA1,0xD5,0x8B,0xB7,0xC5,0xDA,0x76,
+ 0xF5,0x50,0xAA,0x3D,0x8A,0x1F,0xBF,0xF0,0xEB,0x19,0xCC,0xB1,0xA3,0x13,0xD5,0x5C,
+ 0xDA,0x56,0xC9,0xEC,0x2E,0xF2,0x96,0x32,0x38,0x7F,0xE8,0xD7,0x6E,0x3C,0x04,0x68,
+ 0x04,0x3E,0x8F,0x66,0x3F,0x48,0x60,0xEE,0x12,0xBF,0x2D,0x5B,0x0B,0x74,0x74,0xD6,
+ 0xE6,0x94,0xF9,0x1E,0x6D,0xBE,0x11,0x59,0x74,0xA3,0x92,0x6F,0x12,0xFE,0xE5,0xE4,
+ 0x38,0x77,0x7C,0xB6,0xA9,0x32,0xDF,0x8C,0xD8,0xBE,0xC4,0xD0,0x73,0xB9,0x31,0xBA,
+ 0x3B,0xC8,0x32,0xB6,0x8D,0x9D,0xD3,0x00,0x74,0x1F,0xA7,0xBF,0x8A,0xFC,0x47,0xED,
+ 0x25,0x76,0xF6,0x93,0x6B,0xA4,0x24,0x66,0x3A,0xAB,0x63,0x9C,0x5A,0xE4,0xF5,0x68,
+ 0x34,0x23,0xB4,0x74,0x2B,0xF1,0xC9,0x78,0x23,0x8F,0x16,0xCB,0xE3,0x9D,0x65,0x2D,
+ 0xE3,0xFD,0xB8,0xBE,0xFC,0x84,0x8A,0xD9,0x22,0x22,0x2E,0x04,0xA4,0x03,0x7C,0x07,
+ 0x13,0xEB,0x57,0xA8,0x1A,0x23,0xF0,0xC7,0x34,0x73,0xFC,0x64,0x6C,0xEA,0x30,0x6B,
+ 0x4B,0xCB,0xC8,0x86,0x2F,0x83,0x85,0xDD,0xFA,0x9D,0x4B,0x7F,0xA2,0xC0,0x87,0xE8,
+ 0x79,0x68,0x33,0x03,0xED,0x5B,0xDD,0x3A,0x06,0x2B,0x3C,0xF5,0xB3,0xA2,0x78,0xA6,
+ 0x6D,0x2A,0x13,0xF8,0x3F,0x44,0xF8,0x2D,0xDF,0x31,0x0E,0xE0,0x74,0xAB,0x6A,0x36,
+ 0x45,0x97,0xE8,0x99,0xA0,0x25,0x5D,0xC1,0x64,0xF3,0x1C,0xC5,0x08,0x46,0x85,0x1D,
+ 0xF9,0xAB,0x48,0x19,0x5D,0xED,0x7E,0xA1,0xB1,0xD5,0x10,0xBD,0x7E,0xE7,0x4D,0x73,
+ 0xFA,0xF3,0x6B,0xC3,0x1E,0xCF,0xA2,0x68,0x35,0x90,0x46,0xF4,0xEB,0x87,0x9F,0x92,
+ 0x40,0x09,0x43,0x8B,0x48,0x1C,0x6C,0xD7,0x88,0x9A,0x00,0x2E,0xD5,0xEE,0x38,0x2B,
+ 0xC9,0x19,0x0D,0xA6,0xFC,0x02,0x6E,0x47,0x95,0x58,0xE4,0x47,0x56,0x77,0xE9,0xAA,
+ 0x9E,0x30,0x50,0xE2,0x76,0x56,0x94,0xDF,0xC8,0x1F,0x56,0xE8,0x80,0xB9,0x6E,0x71,
+ 0x60,0xC9,0x80,0xDD,0x98,0xED,0xD3,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+};
+
+typedef struct modulus_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/src/libstrongswan/crypto/diffie_hellman.h b/src/libstrongswan/crypto/diffie_hellman.h
new file mode 100644
index 000000000..29a2ab45b
--- /dev/null
+++ b/src/libstrongswan/crypto/diffie_hellman.h
@@ -0,0 +1,147 @@
+/**
+ * @file diffie_hellman.h
+ *
+ * @brief Interface of diffie_hellman_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef enum diffie_hellman_group_t diffie_hellman_group_t;
+typedef struct diffie_hellman_t diffie_hellman_t;
+
+#include <library.h>
+
+/**
+ * @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_NONE = 0,
+ 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
+};
+
+/**
+ * enum name for diffie_hellman_group_t.
+ */
+extern enum_name_t *diffie_hellman_group_names;
+
+/**
+ * @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/src/libstrongswan/crypto/hashers/hasher.c b/src/libstrongswan/crypto/hashers/hasher.c
new file mode 100644
index 000000000..7fa6346d6
--- /dev/null
+++ b/src/libstrongswan/crypto/hashers/hasher.c
@@ -0,0 +1,65 @@
+/**
+ * @file hasher.c
+ *
+ * @brief Generic constructor for hasher_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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/sha2_hasher.h>
+#include <crypto/hashers/md5_hasher.h>
+
+
+ENUM(hash_algorithm_names, HASH_MD2, HASH_SHA512,
+ "HASH_MD2",
+ "HASH_MD5",
+ "HASH_SHA1",
+ "HASH_SHA256",
+ "HASH_SHA384",
+ "HASH_SHA512"
+);
+
+/*
+ * Described in header.
+ */
+hasher_t *hasher_create(hash_algorithm_t hash_algorithm)
+{
+ switch (hash_algorithm)
+ {
+ case HASH_SHA1:
+ {
+ return (hasher_t*)sha1_hasher_create();
+ }
+ case HASH_SHA256:
+ case HASH_SHA384:
+ case HASH_SHA512:
+ {
+ return (hasher_t*)sha2_hasher_create(hash_algorithm);
+ }
+ case HASH_MD5:
+ {
+ return (hasher_t*)md5_hasher_create();
+ }
+ default:
+ return NULL;
+ }
+}
diff --git a/src/libstrongswan/crypto/hashers/hasher.h b/src/libstrongswan/crypto/hashers/hasher.h
new file mode 100644
index 000000000..6c17f892d
--- /dev/null
+++ b/src/libstrongswan/crypto/hashers/hasher.h
@@ -0,0 +1,159 @@
+/**
+ * @file hasher.h
+ *
+ * @brief Interface hasher_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef enum hash_algorithm_t hash_algorithm_t;
+typedef struct hasher_t hasher_t;
+
+#include <library.h>
+
+/**
+ * @brief Algorithms to use for hashing.
+ *
+ * Currently only the following algorithms are implemented:
+ * - HASH_MD5
+ * - HASH_SHA1
+ * - HASH_SHA256
+ * - HASH_SHA384
+ * - HASH_SHA512
+ *
+ * @ingroup hashers
+ */
+enum hash_algorithm_t {
+ HASH_MD2 = 0,
+ /** Implemented in class md5_hasher_t */
+ HASH_MD5 = 1,
+ /** Implemented in class sha1_hasher_t */
+ HASH_SHA1 = 2,
+ /** Implemented in class sha2_hasher_t */
+ HASH_SHA256 = 3,
+ /** Implemented in class sha2_hasher_t */
+ HASH_SHA384 = 4,
+ /** Implemented in class sha2_hasher_t */
+ HASH_SHA512 = 5,
+};
+
+#define HASH_SIZE_MD2 16
+#define HASH_SIZE_MD5 16
+#define HASH_SIZE_SHA1 20
+#define HASH_SIZE_SHA256 32
+#define HASH_SIZE_SHA384 48
+#define HASH_SIZE_SHA512 64
+#define HASH_SIZE_MAX 64
+
+/**
+ * enum names for hash_algorithm_t.
+ */
+extern enum_name_t *hash_algorithm_names;
+
+
+/**
+ * @brief Generic interface for all hash functions.
+ *
+ * @b Constructors:
+ * - hasher_create()
+ *
+ * @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 reset.
+ *
+ * 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 reset.
+ *
+ * @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.
+ *
+ * @param this calling object
+ */
+ void (*reset) (hasher_t *this);
+
+ /**
+ * @brief Get the state of the hasher.
+ *
+ * A hasher stores internal state information. This state may be
+ * manipulated to include a "seed" into the hashing operation. It used by
+ * some exotic protocols (such as AKA).
+ * The data pointed by chunk may be manipulated, but not replaced nor freed.
+ * This is more a hack than a feature. The hasher's state may be byte
+ * order dependant; use with care.
+ *
+ * @param this calling object
+ */
+ chunk_t (*get_state) (hasher_t *this);
+
+ /**
+ * @brief Destroys a hasher object.
+ *
+ * @param this calling object
+ */
+ 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/src/libstrongswan/crypto/hashers/md5_hasher.c b/src/libstrongswan/crypto/hashers/md5_hasher.c
new file mode 100644
index 000000000..d4dde3693
--- /dev/null
+++ b/src/libstrongswan/crypto/hashers/md5_hasher.c
@@ -0,0 +1,405 @@
+/**
+ * @file md5_hasher.c
+ *
+ * @brief Implementation of md5_hasher_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ * Copyright (C) 1991-1992, RSA Data Security, Inc. Created 1991.
+ * All rights reserved.
+ *
+ * Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm.
+ * Ported to fulfill hasher_t interface.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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"
+
+
+/* Constants for MD5Transform routine. */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+static u_int8_t PADDING[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*
+ * ugly macro stuff
+ */
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (u_int32_t)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (u_int32_t)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (u_int32_t)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (u_int32_t)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+
+
+typedef struct private_md5_hasher_t private_md5_hasher_t;
+
+/**
+ * Private data structure with hasing context.
+ */
+struct private_md5_hasher_t {
+ /**
+ * Public interface for this hasher.
+ */
+ md5_hasher_t public;
+
+ /*
+ * State of the hasher.
+ */
+ u_int32_t state[5];
+ u_int32_t count[2];
+ u_int8_t buffer[64];
+};
+
+
+#if BYTE_ORDER != LITTLE_ENDIAN
+
+/* Encodes input (u_int32_t) into output (u_int8_t). Assumes len is
+ * a multiple of 4.
+ */
+static void Encode (u_int8_t *output, u_int32_t *input, size_t len)
+{
+ size_t i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ {
+ output[j] = (u_int8_t)(input[i] & 0xff);
+ output[j+1] = (u_int8_t)((input[i] >> 8) & 0xff);
+ output[j+2] = (u_int8_t)((input[i] >> 16) & 0xff);
+ output[j+3] = (u_int8_t)((input[i] >> 24) & 0xff);
+ }
+}
+
+/* Decodes input (u_int8_t) into output (u_int32_t). Assumes len is
+ * a multiple of 4.
+ */
+static void Decode(u_int32_t *output, u_int8_t *input, size_t len)
+{
+ size_t i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ {
+ output[i] = ((u_int32_t)input[j]) | (((u_int32_t)input[j+1]) << 8) |
+ (((u_int32_t)input[j+2]) << 16) | (((u_int32_t)input[j+3]) << 24);
+ }
+}
+
+#elif BYTE_ORDER == LITTLE_ENDIAN
+ #define Encode memcpy
+ #define Decode memcpy
+#endif
+
+/* MD5 basic transformation. Transforms state based on block.
+ */
+static void MD5Transform(u_int32_t state[4], u_int8_t block[64])
+{
+ u_int32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode(x, block, 64);
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
+ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+ * operation, processing another message block, and updating the
+ * context.
+ */
+static void MD5Update(private_md5_hasher_t *this, u_int8_t *input, size_t inputLen)
+{
+ u_int32_t i;
+ size_t index, partLen;
+
+ /* Compute number of bytes mod 64 */
+ index = (u_int8_t)((this->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((this->count[0] += (inputLen << 3)) < (inputLen << 3))
+ {
+ this->count[1]++;
+ }
+ this->count[1] += (inputLen >> 29);
+
+ partLen = 64 - index;
+
+ /* Transform as many times as possible. */
+ if (inputLen >= partLen)
+ {
+ memcpy(&this->buffer[index], input, partLen);
+ MD5Transform (this->state, this->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ {
+ MD5Transform (this->state, &input[i]);
+ }
+ index = 0;
+ }
+ else
+ {
+ i = 0;
+ }
+
+ /* Buffer remaining input */
+ memcpy(&this->buffer[index], &input[i], inputLen-i);
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+ * the message digest and zeroizing the context.
+ */
+static void MD5Final (private_md5_hasher_t *this, u_int8_t digest[16])
+{
+ u_int8_t bits[8];
+ size_t index, padLen;
+
+ /* Save number of bits */
+ Encode (bits, this->count, 8);
+
+ /* Pad out to 56 mod 64. */
+ index = (size_t)((this->count[0] >> 3) & 0x3f);
+ padLen = (index < 56) ? (56 - index) : (120 - index);
+ MD5Update (this, PADDING, padLen);
+
+ /* Append length (before padding) */
+ MD5Update (this, bits, 8);
+
+ if (digest != NULL) /* Bill Simpson's padding */
+ {
+ /* store state in digest */
+ Encode (digest, this->state, 16);
+ }
+}
+
+
+
+/**
+ * Implementation of hasher_t.get_hash.
+ */
+static void get_hash(private_md5_hasher_t *this, chunk_t chunk, u_int8_t *buffer)
+{
+ MD5Update(this, chunk.ptr, chunk.len);
+ if (buffer != NULL)
+ {
+ MD5Final(this, buffer);
+ this->public.hasher_interface.reset(&(this->public.hasher_interface));
+ }
+}
+
+
+/**
+ * Implementation of hasher_t.allocate_hash.
+ */
+static void allocate_hash(private_md5_hasher_t *this, chunk_t chunk, chunk_t *hash)
+{
+ chunk_t allocated_hash;
+
+ MD5Update(this, chunk.ptr, chunk.len);
+ if (hash != NULL)
+ {
+ allocated_hash.ptr = malloc(HASH_SIZE_MD5);
+ allocated_hash.len = HASH_SIZE_MD5;
+
+ MD5Final(this, allocated_hash.ptr);
+ this->public.hasher_interface.reset(&(this->public.hasher_interface));
+
+ *hash = allocated_hash;
+ }
+}
+
+/**
+ * Implementation of hasher_t.get_hash_size.
+ */
+static size_t get_hash_size(private_md5_hasher_t *this)
+{
+ return HASH_SIZE_MD5;
+}
+
+/**
+ * Implementation of hasher_t.reset.
+ */
+static void reset(private_md5_hasher_t *this)
+{
+ this->state[0] = 0x67452301;
+ this->state[1] = 0xefcdab89;
+ this->state[2] = 0x98badcfe;
+ this->state[3] = 0x10325476;
+ this->count[0] = 0;
+ this->count[1] = 0;
+}
+
+/**
+ * Implementation of hasher_t.get_state
+ */
+static chunk_t get_state(private_md5_hasher_t *this)
+{
+ chunk_t chunk;
+
+ chunk.ptr = (u_char*)&this->state[0];
+ chunk.len = sizeof(this->state);
+
+ return chunk;
+}
+
+/**
+ * Implementation of hasher_t.destroy.
+ */
+static void destroy(private_md5_hasher_t *this)
+{
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+md5_hasher_t *md5_hasher_create(void)
+{
+ private_md5_hasher_t *this = malloc_thing(private_md5_hasher_t);
+
+ this->public.hasher_interface.get_hash = (void (*) (hasher_t*, chunk_t, u_int8_t*))get_hash;
+ this->public.hasher_interface.allocate_hash = (void (*) (hasher_t*, chunk_t, chunk_t*))allocate_hash;
+ this->public.hasher_interface.get_hash_size = (size_t (*) (hasher_t*))get_hash_size;
+ this->public.hasher_interface.reset = (void (*) (hasher_t*))reset;
+ this->public.hasher_interface.get_state = (chunk_t (*) (hasher_t*))get_state;
+ this->public.hasher_interface.destroy = (void (*) (hasher_t*))destroy;
+
+ /* initialize */
+ reset(this);
+
+ return &(this->public);
+}
diff --git a/src/libstrongswan/crypto/hashers/md5_hasher.h b/src/libstrongswan/crypto/hashers/md5_hasher.h
new file mode 100644
index 000000000..715f11663
--- /dev/null
+++ b/src/libstrongswan/crypto/hashers/md5_hasher.h
@@ -0,0 +1,60 @@
+/**
+ * @file md5_hasher.h
+ *
+ * @brief Interface for md5_hasher_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef MD5_HASHER_H_
+#define MD5_HASHER_H_
+
+typedef struct md5_hasher_t md5_hasher_t;
+
+#include <crypto/hashers/hasher.h>
+
+/**
+ * @brief Implementation of hasher_t interface using the
+ * MD5 algorithm.
+ *
+ * @b Constructors:
+ * - hasher_create() using HASH_MD5 as algorithm
+ * - md5_hasher_create()
+ *
+ * @see hasher_t
+ *
+ * @ingroup hashers
+ */
+struct md5_hasher_t {
+
+ /**
+ * Generic hasher_t interface for this hasher.
+ */
+ hasher_t hasher_interface;
+};
+
+/**
+ * @brief Creates a new md5_hasher_t.
+ *
+ * @return md5_hasher_t object
+ *
+ * @ingroup hashers
+ */
+md5_hasher_t *md5_hasher_create(void);
+
+#endif /*MD5_HASHER_H_*/
diff --git a/src/libstrongswan/crypto/hashers/sha1_hasher.c b/src/libstrongswan/crypto/hashers/sha1_hasher.c
new file mode 100644
index 000000000..6a86937ae
--- /dev/null
+++ b/src/libstrongswan/crypto/hashers/sha1_hasher.c
@@ -0,0 +1,280 @@
+/**
+ * @file sha1_hasher.c
+ *
+ * @brief Implementation of hasher_sha_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * Ported from Steve Reid's <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"
+
+/*
+ * ugly macro stuff
+ */
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+ #define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) |(rol(block->l[i],8)&0x00FF00FF))
+#elif BYTE_ORDER == BIG_ENDIAN
+ #define blk0(i) block->l[i]
+#else
+ #error "Endianness not defined!"
+#endif
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+
+typedef struct private_sha1_hasher_t private_sha1_hasher_t;
+
+/**
+ * Private data structure with hasing context.
+ */
+struct private_sha1_hasher_t {
+ /**
+ * Public interface for this hasher.
+ */
+ sha1_hasher_t public;
+
+ /*
+ * State of the hasher.
+ */
+ u_int32_t state[5];
+ u_int32_t count[2];
+ u_int8_t buffer[64];
+};
+
+/*
+ * Hash a single 512-bit block. This is the core of the algorithm. *
+ */
+static void SHA1Transform(u_int32_t state[5], const unsigned char buffer[64])
+{
+ u_int32_t a, b, c, d, e;
+ typedef union {
+ u_int8_t c[64];
+ u_int32_t l[16];
+ } CHAR64LONG16;
+ CHAR64LONG16 block[1]; /* use array to appear as a pointer */
+ memcpy(block, buffer, 64);
+
+ /* Copy context->state[] to working vars */
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+ R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+ R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+ R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+ /* Add the working vars back into context.state[] */
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+ /* Wipe variables */
+ a = b = c = d = e = 0;
+ memset(block, '\0', sizeof(block));
+}
+
+/*
+ * Run your data through this.
+ */
+static void SHA1Update(private_sha1_hasher_t* this, u_int8_t *data, u_int32_t len)
+{
+ u_int32_t i;
+ u_int32_t j;
+
+ j = this->count[0];
+ if ((this->count[0] += len << 3) < j)
+ {
+ this->count[1]++;
+ }
+ this->count[1] += (len>>29);
+ j = (j >> 3) & 63;
+ if ((j + len) > 63)
+ {
+ memcpy(&this->buffer[j], data, (i = 64-j));
+ SHA1Transform(this->state, this->buffer);
+ for ( ; i + 63 < len; i += 64)
+ {
+ SHA1Transform(this->state, &data[i]);
+ }
+ j = 0;
+ }
+ else
+ {
+ i = 0;
+ }
+ memcpy(&this->buffer[j], &data[i], len - i);
+}
+
+
+/*
+ * Add padding and return the message digest.
+ */
+static void SHA1Final(private_sha1_hasher_t *this, u_int8_t *digest)
+{
+ u_int32_t i;
+ u_int8_t finalcount[8];
+ u_int8_t c;
+
+ for (i = 0; i < 8; i++)
+ {
+ finalcount[i] = (u_int8_t)((this->count[(i >= 4 ? 0 : 1)]
+ >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
+ }
+ c = 0200;
+ SHA1Update(this, &c, 1);
+ while ((this->count[0] & 504) != 448)
+ {
+ c = 0000;
+ SHA1Update(this, &c, 1);
+ }
+ SHA1Update(this, finalcount, 8); /* Should cause a SHA1Transform() */
+ for (i = 0; i < 20; i++)
+ {
+ digest[i] = (u_int8_t)((this->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+ }
+}
+
+
+/**
+ * Implementation of hasher_t.get_hash.
+ */
+static void get_hash(private_sha1_hasher_t *this, chunk_t chunk, u_int8_t *buffer)
+{
+ SHA1Update(this, chunk.ptr, chunk.len);
+ if (buffer != NULL)
+ {
+ SHA1Final(this, buffer);
+ this->public.hasher_interface.reset(&(this->public.hasher_interface));
+ }
+}
+
+
+/**
+ * Implementation of hasher_t.allocate_hash.
+ */
+static void allocate_hash(private_sha1_hasher_t *this, chunk_t chunk, chunk_t *hash)
+{
+ chunk_t allocated_hash;
+
+ SHA1Update(this, chunk.ptr, chunk.len);
+ if (hash != NULL)
+ {
+ allocated_hash.ptr = malloc(HASH_SIZE_SHA1);
+ allocated_hash.len = HASH_SIZE_SHA1;
+
+ SHA1Final(this, allocated_hash.ptr);
+ this->public.hasher_interface.reset(&(this->public.hasher_interface));
+
+ *hash = allocated_hash;
+ }
+}
+
+/**
+ * Implementation of hasher_t.get_hash_size.
+ */
+static size_t get_hash_size(private_sha1_hasher_t *this)
+{
+ return HASH_SIZE_SHA1;
+}
+
+/**
+ * Implementation of hasher_t.reset.
+ */
+static void reset(private_sha1_hasher_t *this)
+{
+ this->state[0] = 0x67452301;
+ this->state[1] = 0xEFCDAB89;
+ this->state[2] = 0x98BADCFE;
+ this->state[3] = 0x10325476;
+ this->state[4] = 0xC3D2E1F0;
+ this->count[0] = 0;
+ this->count[1] = 0;
+}
+
+/**
+ * Implementation of hasher_t.get_state
+ */
+static chunk_t get_state(private_sha1_hasher_t *this)
+{
+ chunk_t chunk;
+
+ chunk.ptr = (u_char*)&this->state[0];
+ chunk.len = sizeof(this->state);
+
+ return chunk;
+}
+
+/**
+ * Implementation of hasher_t.destroy.
+ */
+static void destroy(private_sha1_hasher_t *this)
+{
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+sha1_hasher_t *sha1_hasher_create(void)
+{
+ private_sha1_hasher_t *this = malloc_thing(private_sha1_hasher_t);
+
+ this->public.hasher_interface.get_hash = (void (*) (hasher_t*, chunk_t, u_int8_t*))get_hash;
+ this->public.hasher_interface.allocate_hash = (void (*) (hasher_t*, chunk_t, chunk_t*))allocate_hash;
+ this->public.hasher_interface.get_hash_size = (size_t (*) (hasher_t*))get_hash_size;
+ this->public.hasher_interface.reset = (void (*) (hasher_t*))reset;
+ this->public.hasher_interface.get_state = (chunk_t (*) (hasher_t*))get_state;
+ this->public.hasher_interface.destroy = (void (*) (hasher_t*))destroy;
+
+ /* initialize */
+ reset(this);
+
+ return &(this->public);
+}
diff --git a/src/libstrongswan/crypto/hashers/sha1_hasher.h b/src/libstrongswan/crypto/hashers/sha1_hasher.h
new file mode 100644
index 000000000..380fa9845
--- /dev/null
+++ b/src/libstrongswan/crypto/hashers/sha1_hasher.h
@@ -0,0 +1,60 @@
+/**
+ * @file sha1_hasher.h
+ *
+ * @brief Interface of sha1_hasher_t
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef SHA1_HASHER_H_
+#define SHA1_HASHER_H_
+
+typedef struct sha1_hasher_t sha1_hasher_t;
+
+#include <crypto/hashers/hasher.h>
+
+/**
+ * @brief Implementation of hasher_t interface using the
+ * SHA1 algorithm.
+ *
+ * @b Constructors:
+ * - hasher_create() using HASH_SHA1 as algorithm
+ * - sha1_hasher_create()
+ *
+ * @see hasher_t
+ *
+ * @ingroup hashers
+ */
+struct sha1_hasher_t {
+
+ /**
+ * Generic hasher_t interface for this hasher.
+ */
+ hasher_t hasher_interface;
+};
+
+/**
+ * @brief Creates a new sha1_hasher_t.
+ *
+ * @return sha1_hasher_t object
+ *
+ * @ingroup hashers
+ */
+sha1_hasher_t *sha1_hasher_create(void);
+
+#endif /*SHA1_HASHER_H_*/
diff --git a/src/libstrongswan/crypto/hashers/sha2_hasher.c b/src/libstrongswan/crypto/hashers/sha2_hasher.c
new file mode 100644
index 000000000..b68972cec
--- /dev/null
+++ b/src/libstrongswan/crypto/hashers/sha2_hasher.c
@@ -0,0 +1,672 @@
+/**
+ * @file sha2_hasher.c
+ *
+ * @brief Implementation of hasher_sha_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2001 Jari Ruusu.
+ *
+ * Ported from strongSwans implementation written by Jari Ruusu.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 "sha2_hasher.h"
+
+
+typedef struct private_sha512_hasher_t private_sha512_hasher_t;
+
+/**
+ * Private data structure with hasing context for SHA384 and SHA512
+ */
+struct private_sha512_hasher_t {
+ /**
+ * Public interface for this hasher.
+ */
+ sha2_hasher_t public;
+
+ unsigned char sha_out[128]; /* results are here, bytes 0..47/0..63 */
+ u_int64_t sha_H[8];
+ u_int64_t sha_blocks;
+ u_int64_t sha_blocksMSB;
+ int sha_bufCnt;
+};
+
+
+typedef struct private_sha256_hasher_t private_sha256_hasher_t;
+
+/**
+ * Private data structure with hasing context for SHA256
+ */
+struct private_sha256_hasher_t {
+ /**
+ * Public interface for this hasher.
+ */
+ sha2_hasher_t public;
+
+ unsigned char sha_out[64]; /* results are here, bytes 0...31 */
+ u_int32_t sha_H[8];
+ u_int64_t sha_blocks;
+ int sha_bufCnt;
+};
+
+
+static const u_int32_t sha256_hashInit[8] = {
+ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c,
+ 0x1f83d9ab, 0x5be0cd19
+};
+
+static const u_int32_t sha256_K[64] = {
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
+ 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
+ 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
+ 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
+ 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
+ 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+};
+
+static const u_int64_t sha512_hashInit[8] = {
+ 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL,
+ 0xa54ff53a5f1d36f1ULL, 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
+ 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL
+};
+
+static const u_int64_t sha384_hashInit[8] = {
+ 0xcbbb9d5dc1059ed8ULL, 0x629a292a367cd507ULL, 0x9159015a3070dd17ULL,
+ 0x152fecd8f70e5939ULL, 0x67332667ffc00b31ULL, 0x8eb44a8768581511ULL,
+ 0xdb0c2e0d64f98fa7ULL, 0x47b5481dbefa4fa4ULL
+};
+
+static const u_int64_t sha512_K[80] = {
+ 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL,
+ 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
+ 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL,
+ 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
+ 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL,
+ 0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
+ 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL,
+ 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
+ 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL,
+ 0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
+ 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL,
+ 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
+ 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL,
+ 0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
+ 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL,
+ 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
+ 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL,
+ 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
+ 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL,
+ 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
+ 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL,
+ 0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
+ 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL,
+ 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
+ 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL,
+ 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
+ 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
+};
+
+
+/* set macros for SHA256 */
+#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z)))
+#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
+#define R(x,y) ((y) >> (x))
+
+#define S(x,y) (((y) >> (x)) | ((y) << (32 - (x))))
+#define uSig0(x) ((S(2,(x))) ^ (S(13,(x))) ^ (S(22,(x))))
+#define uSig1(x) ((S(6,(x))) ^ (S(11,(x))) ^ (S(25,(x))))
+#define lSig0(x) ((S(7,(x))) ^ (S(18,(x))) ^ (R(3,(x))))
+#define lSig1(x) ((S(17,(x))) ^ (S(19,(x))) ^ (R(10,(x))))
+
+/**
+ * Single block SHA256 transformation
+ */
+static void sha256_transform(private_sha256_hasher_t *ctx,
+ const unsigned char *datap)
+{
+ register int j;
+ u_int32_t a, b, c, d, e, f, g, h;
+ u_int32_t T1, T2, W[64], Wm2, Wm15;
+
+ /* read the data, big endian byte order */
+ j = 0;
+ do {
+ W[j] = (((u_int32_t)(datap[0]))<<24) | (((u_int32_t)(datap[1]))<<16) |
+ (((u_int32_t)(datap[2]))<<8 ) | ((u_int32_t)(datap[3]));
+ datap += 4;
+ } while(++j < 16);
+
+ /* initialize variables a...h */
+ a = ctx->sha_H[0];
+ b = ctx->sha_H[1];
+ c = ctx->sha_H[2];
+ d = ctx->sha_H[3];
+ e = ctx->sha_H[4];
+ f = ctx->sha_H[5];
+ g = ctx->sha_H[6];
+ h = ctx->sha_H[7];
+
+ /* apply compression function */
+ j = 0;
+ do
+ {
+ if(j >= 16)
+ {
+ Wm2 = W[j - 2];
+ Wm15 = W[j - 15];
+ W[j] = lSig1(Wm2) + W[j - 7] + lSig0(Wm15) + W[j - 16];
+ }
+ T1 = h + uSig1(e) + Ch(e,f,g) + sha256_K[j] + W[j];
+ T2 = uSig0(a) + Maj(a,b,c);
+ h = g; g = f; f = e;
+ e = d + T1;
+ d = c; c = b; b = a;
+ a = T1 + T2;
+ } while(++j < 64);
+
+ /* compute intermediate hash value */
+ ctx->sha_H[0] += a;
+ ctx->sha_H[1] += b;
+ ctx->sha_H[2] += c;
+ ctx->sha_H[3] += d;
+ ctx->sha_H[4] += e;
+ ctx->sha_H[5] += f;
+ ctx->sha_H[6] += g;
+ ctx->sha_H[7] += h;
+
+ ctx->sha_blocks++;
+}
+
+/**
+ * Update SHA256 hash
+ */
+static void sha256_write(private_sha256_hasher_t *ctx,
+ const unsigned char *datap, int length)
+{
+ while(length > 0)
+ {
+ if(!ctx->sha_bufCnt)
+ {
+ while(length >= sizeof(ctx->sha_out))
+ {
+ sha256_transform(ctx, datap);
+ datap += sizeof(ctx->sha_out);
+ length -= sizeof(ctx->sha_out);
+ }
+ if(!length) return;
+ }
+ ctx->sha_out[ctx->sha_bufCnt] = *datap++;
+ length--;
+ if(++ctx->sha_bufCnt == sizeof(ctx->sha_out))
+ {
+ sha256_transform(ctx, &ctx->sha_out[0]);
+ ctx->sha_bufCnt = 0;
+ }
+ }
+}
+
+/**
+ * finalize SHA256 hash
+ */
+static void sha256_final(private_sha256_hasher_t *ctx)
+{
+ register int j;
+ u_int64_t bitLength;
+ u_int32_t i;
+ unsigned char padByte, *datap;
+
+ bitLength = (ctx->sha_blocks << 9) | (ctx->sha_bufCnt << 3);
+ padByte = 0x80;
+ sha256_write(ctx, &padByte, 1);
+
+ /* pad extra space with zeroes */
+ padByte = 0;
+ while(ctx->sha_bufCnt != 56)
+ {
+ sha256_write(ctx, &padByte, 1);
+ }
+
+ /* write bit length, big endian byte order */
+ ctx->sha_out[56] = bitLength >> 56;
+ ctx->sha_out[57] = bitLength >> 48;
+ ctx->sha_out[58] = bitLength >> 40;
+ ctx->sha_out[59] = bitLength >> 32;
+ ctx->sha_out[60] = bitLength >> 24;
+ ctx->sha_out[61] = bitLength >> 16;
+ ctx->sha_out[62] = bitLength >> 8;
+ ctx->sha_out[63] = bitLength;
+ sha256_transform(ctx, &ctx->sha_out[0]);
+
+ /* return results in ctx->sha_out[0...31] */
+ datap = &ctx->sha_out[0];
+ j = 0;
+ do {
+ i = ctx->sha_H[j];
+ datap[0] = i >> 24;
+ datap[1] = i >> 16;
+ datap[2] = i >> 8;
+ datap[3] = i;
+ datap += 4;
+ } while(++j < 8);
+}
+
+/* update macros for SHA512 */
+#undef S
+#undef uSig0
+#undef uSig1
+#undef lSig0
+#undef lSig1
+#define S(x,y) (((y) >> (x)) | ((y) << (64 - (x))))
+#define uSig0(x) ((S(28,(x))) ^ (S(34,(x))) ^ (S(39,(x))))
+#define uSig1(x) ((S(14,(x))) ^ (S(18,(x))) ^ (S(41,(x))))
+#define lSig0(x) ((S(1,(x))) ^ (S(8,(x))) ^ (R(7,(x))))
+#define lSig1(x) ((S(19,(x))) ^ (S(61,(x))) ^ (R(6,(x))))
+
+/**
+ * Single block SHA384/SHA512 transformation
+ */
+static void sha512_transform(private_sha512_hasher_t *ctx,
+ const unsigned char *datap)
+{
+ register int j;
+ u_int64_t a, b, c, d, e, f, g, h;
+ u_int64_t T1, T2, W[80], Wm2, Wm15;
+
+ /* read the data, big endian byte order */
+ j = 0;
+ do {
+ W[j] = (((u_int64_t)(datap[0]))<<56) | (((u_int64_t)(datap[1]))<<48) |
+ (((u_int64_t)(datap[2]))<<40) | (((u_int64_t)(datap[3]))<<32) |
+ (((u_int64_t)(datap[4]))<<24) | (((u_int64_t)(datap[5]))<<16) |
+ (((u_int64_t)(datap[6]))<<8 ) | ((u_int64_t)(datap[7]));
+ datap += 8;
+ } while(++j < 16);
+
+ /* initialize variables a...h */
+ a = ctx->sha_H[0];
+ b = ctx->sha_H[1];
+ c = ctx->sha_H[2];
+ d = ctx->sha_H[3];
+ e = ctx->sha_H[4];
+ f = ctx->sha_H[5];
+ g = ctx->sha_H[6];
+ h = ctx->sha_H[7];
+
+ /* apply compression function */
+ j = 0;
+ do {
+ if(j >= 16) {
+ Wm2 = W[j - 2];
+ Wm15 = W[j - 15];
+ W[j] = lSig1(Wm2) + W[j - 7] + lSig0(Wm15) + W[j - 16];
+ }
+ T1 = h + uSig1(e) + Ch(e,f,g) + sha512_K[j] + W[j];
+ T2 = uSig0(a) + Maj(a,b,c);
+ h = g; g = f; f = e;
+ e = d + T1;
+ d = c; c = b; b = a;
+ a = T1 + T2;
+ } while(++j < 80);
+
+ /* compute intermediate hash value */
+ ctx->sha_H[0] += a;
+ ctx->sha_H[1] += b;
+ ctx->sha_H[2] += c;
+ ctx->sha_H[3] += d;
+ ctx->sha_H[4] += e;
+ ctx->sha_H[5] += f;
+ ctx->sha_H[6] += g;
+ ctx->sha_H[7] += h;
+
+ ctx->sha_blocks++;
+ if(!ctx->sha_blocks) ctx->sha_blocksMSB++;
+}
+
+/**
+ * Update a SHA384/SHA512 hash
+ */
+static void sha512_write(private_sha512_hasher_t *ctx,
+ const unsigned char *datap, int length)
+{
+ while(length > 0)
+ {
+ if(!ctx->sha_bufCnt)
+ {
+ while(length >= sizeof(ctx->sha_out))
+ {
+ sha512_transform(ctx, datap);
+ datap += sizeof(ctx->sha_out);
+ length -= sizeof(ctx->sha_out);
+ }
+ if(!length) return;
+ }
+ ctx->sha_out[ctx->sha_bufCnt] = *datap++;
+ length--;
+ if(++ctx->sha_bufCnt == sizeof(ctx->sha_out))
+ {
+ sha512_transform(ctx, &ctx->sha_out[0]);
+ ctx->sha_bufCnt = 0;
+ }
+ }
+}
+
+/**
+ * Finalize a SHA384/SHA512 hash
+ */
+static void sha512_final(private_sha512_hasher_t *ctx)
+{
+ register int j;
+ u_int64_t bitLength, bitLengthMSB;
+ u_int64_t i;
+ unsigned char padByte, *datap;
+
+ bitLength = (ctx->sha_blocks << 10) | (ctx->sha_bufCnt << 3);
+ bitLengthMSB = (ctx->sha_blocksMSB << 10) | (ctx->sha_blocks >> 54);
+ padByte = 0x80;
+ sha512_write(ctx, &padByte, 1);
+
+ /* pad extra space with zeroes */
+ padByte = 0;
+ while(ctx->sha_bufCnt != 112)
+ {
+ sha512_write(ctx, &padByte, 1);
+ }
+
+ /* write bit length, big endian byte order */
+ ctx->sha_out[112] = bitLengthMSB >> 56;
+ ctx->sha_out[113] = bitLengthMSB >> 48;
+ ctx->sha_out[114] = bitLengthMSB >> 40;
+ ctx->sha_out[115] = bitLengthMSB >> 32;
+ ctx->sha_out[116] = bitLengthMSB >> 24;
+ ctx->sha_out[117] = bitLengthMSB >> 16;
+ ctx->sha_out[118] = bitLengthMSB >> 8;
+ ctx->sha_out[119] = bitLengthMSB;
+ ctx->sha_out[120] = bitLength >> 56;
+ ctx->sha_out[121] = bitLength >> 48;
+ ctx->sha_out[122] = bitLength >> 40;
+ ctx->sha_out[123] = bitLength >> 32;
+ ctx->sha_out[124] = bitLength >> 24;
+ ctx->sha_out[125] = bitLength >> 16;
+ ctx->sha_out[126] = bitLength >> 8;
+ ctx->sha_out[127] = bitLength;
+ sha512_transform(ctx, &ctx->sha_out[0]);
+
+ /* return results in ctx->sha_out[0...63] */
+ datap = &ctx->sha_out[0];
+ j = 0;
+ do {
+ i = ctx->sha_H[j];
+ datap[0] = i >> 56;
+ datap[1] = i >> 48;
+ datap[2] = i >> 40;
+ datap[3] = i >> 32;
+ datap[4] = i >> 24;
+ datap[5] = i >> 16;
+ datap[6] = i >> 8;
+ datap[7] = i;
+ datap += 8;
+ } while(++j < 8);
+}
+
+/**
+ * Implementation of hasher_t.get_hash for SHA256.
+ */
+static void get_hash256(private_sha256_hasher_t *this,
+ chunk_t chunk, u_int8_t *buffer)
+{
+ sha256_write(this, chunk.ptr, chunk.len);
+ if (buffer != NULL)
+ {
+ sha256_final(this);
+ memcpy(buffer, this->sha_out, HASH_SIZE_SHA256);
+ this->public.hasher_interface.reset(&(this->public.hasher_interface));
+ }
+}
+
+/**
+ * Implementation of hasher_t.get_hash for SHA384.
+ */
+static void get_hash384(private_sha512_hasher_t *this,
+ chunk_t chunk, u_int8_t *buffer)
+{
+ sha512_write(this, chunk.ptr, chunk.len);
+ if (buffer != NULL)
+ {
+ sha512_final(this);
+ memcpy(buffer, this->sha_out, HASH_SIZE_SHA384);
+ this->public.hasher_interface.reset(&(this->public.hasher_interface));
+ }
+}
+
+/**
+ * Implementation of hasher_t.get_hash for SHA512.
+ */
+static void get_hash512(private_sha512_hasher_t *this,
+ chunk_t chunk, u_int8_t *buffer)
+{
+ sha512_write(this, chunk.ptr, chunk.len);
+ if (buffer != NULL)
+ {
+ sha512_final(this);
+ memcpy(buffer, this->sha_out, HASH_SIZE_SHA512);
+ this->public.hasher_interface.reset(&(this->public.hasher_interface));
+ }
+}
+
+/**
+ * Implementation of hasher_t.allocate_hash for SHA256.
+ */
+static void allocate_hash256(private_sha256_hasher_t *this,
+ chunk_t chunk, chunk_t *hash)
+{
+ chunk_t allocated_hash;
+
+ sha256_write(this, chunk.ptr, chunk.len);
+ if (hash != NULL)
+ {
+ sha256_final(this);
+ allocated_hash = chunk_alloc(HASH_SIZE_SHA256);
+ memcpy(allocated_hash.ptr, this->sha_out, HASH_SIZE_SHA256);
+ this->public.hasher_interface.reset(&(this->public.hasher_interface));
+ *hash = allocated_hash;
+ }
+}
+
+/**
+ * Implementation of hasher_t.allocate_hash for SHA384.
+ */
+static void allocate_hash384(private_sha512_hasher_t *this,
+ chunk_t chunk, chunk_t *hash)
+{
+ chunk_t allocated_hash;
+
+ sha512_write(this, chunk.ptr, chunk.len);
+ if (hash != NULL)
+ {
+ sha512_final(this);
+ allocated_hash = chunk_alloc(HASH_SIZE_SHA384);
+ memcpy(allocated_hash.ptr, this->sha_out, HASH_SIZE_SHA384);
+ this->public.hasher_interface.reset(&(this->public.hasher_interface));
+ *hash = allocated_hash;
+ }
+}
+
+/**
+ * Implementation of hasher_t.allocate_hash for SHA512.
+ */
+static void allocate_hash512(private_sha512_hasher_t *this,
+ chunk_t chunk, chunk_t *hash)
+{
+ chunk_t allocated_hash;
+
+ sha512_write(this, chunk.ptr, chunk.len);
+ if (hash != NULL)
+ {
+ sha512_final(this);
+ allocated_hash = chunk_alloc(HASH_SIZE_SHA512);
+ memcpy(allocated_hash.ptr, this->sha_out, HASH_SIZE_SHA512);
+ this->public.hasher_interface.reset(&(this->public.hasher_interface));
+ *hash = allocated_hash;
+ }
+}
+
+/**
+ * Implementation of hasher_t.get_hash_size for SHA256.
+ */
+static size_t get_hash_size256(private_sha256_hasher_t *this)
+{
+ return HASH_SIZE_SHA256;
+}
+
+/**
+ * Implementation of hasher_t.get_hash_size for SHA384.
+ */
+static size_t get_hash_size384(private_sha512_hasher_t *this)
+{
+ return HASH_SIZE_SHA384;
+}
+
+/**
+ * Implementation of hasher_t.get_hash_size for SHA512.
+ */
+static size_t get_hash_size512(private_sha512_hasher_t *this)
+{
+ return HASH_SIZE_SHA512;
+}
+
+/**
+ * Implementation of hasher_t.reset for SHA256
+ */
+static void reset256(private_sha256_hasher_t *ctx)
+{
+ memcpy(&ctx->sha_H[0], &sha256_hashInit[0], sizeof(ctx->sha_H));
+ ctx->sha_blocks = 0;
+ ctx->sha_bufCnt = 0;
+}
+
+/**
+ * Implementation of hasher_t.reset for SHA384
+ */
+static void reset384(private_sha512_hasher_t *ctx)
+{
+ memcpy(&ctx->sha_H[0], &sha384_hashInit[0], sizeof(ctx->sha_H));
+ ctx->sha_blocks = 0;
+ ctx->sha_blocksMSB = 0;
+ ctx->sha_bufCnt = 0;
+}
+
+/**
+ * Implementation of hasher_t.reset for SHA512
+ */
+static void reset512(private_sha512_hasher_t *ctx)
+{
+ memcpy(&ctx->sha_H[0], &sha512_hashInit[0], sizeof(ctx->sha_H));
+ ctx->sha_blocks = 0;
+ ctx->sha_blocksMSB = 0;
+ ctx->sha_bufCnt = 0;
+}
+
+/**
+ * Implementation of hasher_t.get_state for SHA256
+ */
+static chunk_t get_state256(private_sha256_hasher_t *ctx)
+{
+ chunk_t chunk;
+ chunk.ptr = (u_char*)&ctx->sha_H[0];
+ chunk.len = HASH_SIZE_SHA256;
+ return chunk;
+}
+
+/**
+ * Implementation of hasher_t.get_state for SHA384
+ */
+static chunk_t get_state384(private_sha512_hasher_t *ctx)
+{
+ chunk_t chunk;
+ chunk.ptr = (u_char*)&ctx->sha_H[0];
+ chunk.len = HASH_SIZE_SHA384;
+ return chunk;
+}
+/**
+ * Implementation of hasher_t.get_state for SHA512
+ */
+static chunk_t get_state512(private_sha512_hasher_t *ctx)
+{
+ chunk_t chunk;
+ chunk.ptr = (u_char*)&ctx->sha_H[0];
+ chunk.len = HASH_SIZE_SHA512;
+ return chunk;
+}
+
+/**
+ * Implementation of hasher_t.destroy.
+ */
+static void destroy(sha2_hasher_t *this)
+{
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+sha2_hasher_t *sha2_hasher_create(hash_algorithm_t algorithm)
+{
+ sha2_hasher_t *this;
+
+ switch (algorithm)
+ {
+ case HASH_SHA256:
+ this = (sha2_hasher_t*)malloc_thing(private_sha256_hasher_t);
+ this->hasher_interface.reset = (void(*)(hasher_t*))reset256;
+ this->hasher_interface.get_state = (chunk_t(*)(hasher_t*))get_state256;
+ this->hasher_interface.get_hash_size = (size_t(*)(hasher_t*))get_hash_size256;
+ this->hasher_interface.get_hash = (void(*)(hasher_t*,chunk_t,u_int8_t*))get_hash256;
+ this->hasher_interface.allocate_hash = (void(*)(hasher_t*,chunk_t,chunk_t*))allocate_hash256;
+ break;
+ case HASH_SHA384:
+ /* uses SHA512 data structure */
+ this = (sha2_hasher_t*)malloc_thing(private_sha512_hasher_t);
+ this->hasher_interface.reset = (void(*)(hasher_t*))reset384;
+ this->hasher_interface.get_state = (chunk_t(*)(hasher_t*))get_state384;
+ this->hasher_interface.get_hash_size = (size_t(*)(hasher_t*))get_hash_size384;
+ this->hasher_interface.get_hash = (void(*)(hasher_t*,chunk_t,u_int8_t*))get_hash384;
+ this->hasher_interface.allocate_hash = (void(*)(hasher_t*,chunk_t,chunk_t*))allocate_hash384;
+ break;
+ case HASH_SHA512:
+ this = (sha2_hasher_t*)malloc_thing(private_sha512_hasher_t);
+ this->hasher_interface.reset = (void(*)(hasher_t*))reset512;
+ this->hasher_interface.get_state = (chunk_t(*)(hasher_t*))get_state512;
+ this->hasher_interface.get_hash_size = (size_t(*)(hasher_t*))get_hash_size512;
+ this->hasher_interface.get_hash = (void(*)(hasher_t*,chunk_t,u_int8_t*))get_hash512;
+ this->hasher_interface.allocate_hash = (void(*)(hasher_t*,chunk_t,chunk_t*))allocate_hash512;
+ break;
+ default:
+ return NULL;
+ }
+ this->hasher_interface.destroy = (void(*)(hasher_t*))destroy;
+
+ /* initialize */
+ this->hasher_interface.reset(&this->hasher_interface);
+
+ return this;
+}
diff --git a/src/libstrongswan/crypto/hashers/sha2_hasher.h b/src/libstrongswan/crypto/hashers/sha2_hasher.h
new file mode 100644
index 000000000..91e82fedb
--- /dev/null
+++ b/src/libstrongswan/crypto/hashers/sha2_hasher.h
@@ -0,0 +1,62 @@
+/**
+ * @file sha2_hasher.h
+ *
+ * @brief Interface of sha2_hasher_t
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef SHA2_HASHER_H_
+#define SHA2_HASHER_H_
+
+typedef struct sha2_hasher_t sha2_hasher_t;
+
+#include <crypto/hashers/hasher.h>
+
+/**
+ * @brief Implementation of hasher_t interface using the SHA2 algorithms.
+ *
+ * SHA2 is an other name for the SHA-256, SHA-384 and SHA-512 variants of
+ * the SHA hash algorithm.
+ *
+ * @b Constructors:
+ * - hasher_create() using HASH_SHA256, HASH_SHA384 or HASH_SHA512 as algorithm
+ * - sha2_hasher_create()
+ *
+ * @see hasher_t
+ *
+ * @ingroup hashers
+ */
+struct sha2_hasher_t {
+
+ /**
+ * Generic hasher_t interface for this hasher.
+ */
+ hasher_t hasher_interface;
+};
+
+/**
+ * @brief Creates a new sha2_hasher_t.
+ *
+ * @param algorithm HASH_SHA256, HASH_SHA384 or HASH_SHA512
+ * @return sha2_hasher_t object
+ *
+ * @ingroup hashers
+ */
+sha2_hasher_t *sha2_hasher_create(hash_algorithm_t algorithm);
+
+#endif /* SHA2_HASHER_H_ */
diff --git a/src/libstrongswan/crypto/hmac.c b/src/libstrongswan/crypto/hmac.c
new file mode 100644
index 000000000..df4f90bc8
--- /dev/null
+++ b/src/libstrongswan/crypto/hmac.c
@@ -0,0 +1,215 @@
+/**
+ * @file hmac.c
+ *
+ * @brief Implementation of hmac_t.
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General hmac License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it 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:
+ case HASH_SHA256:
+ this->b = 64;
+ break;
+ case HASH_SHA384:
+ case HASH_SHA512:
+ this->b = 128;
+ break;
+ default:
+ free(this);
+ return NULL;
+ }
+
+ /* build the hasher */
+ this->h = hasher_create(hash_algorithm);
+
+ /* build ipad and opad */
+ this->opaded_key.ptr = malloc(this->b);
+ this->opaded_key.len = this->b;
+
+ this->ipaded_key.ptr = malloc(this->b);
+ this->ipaded_key.len = this->b;
+
+ return &(this->hmac);
+}
diff --git a/src/libstrongswan/crypto/hmac.h b/src/libstrongswan/crypto/hmac.h
new file mode 100644
index 000000000..d320bc5aa
--- /dev/null
+++ b/src/libstrongswan/crypto/hmac.h
@@ -0,0 +1,117 @@
+/**
+ * @file hmac.h
+ *
+ * @brief Interface of hmac_t.
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef HMAC_H_
+#define HMAC_H_
+
+typedef struct hmac_t hmac_t;
+
+#include <crypto/hashers/hasher.h>
+
+/**
+ * @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/src/libstrongswan/crypto/ocsp.c b/src/libstrongswan/crypto/ocsp.c
new file mode 100644
index 000000000..471996c8e
--- /dev/null
+++ b/src/libstrongswan/crypto/ocsp.c
@@ -0,0 +1,924 @@
+/**
+ * @file ocsp.c
+ *
+ * @brief Implementation of ocsp_t.
+ *
+ */
+
+/* Support of the Online Certificate Status Protocol (OCSP)
+ * Copyright (C) 2003 Christoph Gysin, Simon Zwahlen
+ * 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.
+ *
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <asn1/oid.h>
+#include <asn1/asn1.h>
+#include <utils/identification.h>
+#include <utils/randomizer.h>
+#include <utils/fetcher.h>
+#include <debug.h>
+
+#include "hashers/hasher.h"
+#include "rsa/rsa_public_key.h"
+#include "certinfo.h"
+#include "x509.h"
+#include "ocsp.h"
+
+#define NONCE_LENGTH 16
+
+typedef struct private_ocsp_t private_ocsp_t;
+
+/**
+ * Private data of a ocsp_t object.
+ */
+struct private_ocsp_t {
+ /**
+ * Public interface for this ocsp object.
+ */
+ ocsp_t public;
+
+ /**
+ * CA certificate.
+ */
+ x509_t *cacert;
+
+ /**
+ * Requestor certificate
+ */
+ x509_t *requestor_cert;
+
+ /**
+ * Linked list of ocsp uris
+ */
+ linked_list_t *uris;
+
+ /**
+ * Linked list of certinfos to be requested
+ */
+ linked_list_t *certinfos;
+
+ /**
+ * Nonce required for ocsp request and response
+ */
+ chunk_t nonce;
+
+ /**
+ * SHA-1 hash over issuer distinguished name
+ */
+ chunk_t authNameID;
+
+ /**
+ * SHA-1 hash over issuer public key
+ */
+ chunk_t authKeyID;
+};
+
+ENUM(response_status_names, STATUS_SUCCESSFUL, STATUS_UNAUTHORIZED,
+ "successful",
+ "malformed request",
+ "internal error",
+ "try later",
+ "signature required",
+ "unauthorized"
+);
+
+/* response container */
+typedef struct response_t response_t;
+
+struct response_t {
+ chunk_t chunk;
+ chunk_t tbs;
+ identification_t *responder_id_name;
+ chunk_t responder_id_key;
+ time_t produced_at;
+ chunk_t responses;
+ chunk_t nonce;
+ int algorithm;
+ chunk_t signature;
+ x509_t *responder_cert;
+
+ /**
+ * @brief Destroys the response_t object
+ *
+ * @param this response_t to destroy
+ */
+ void (*destroy) (response_t *this);
+};
+
+/**
+ * Implements response_t.destroy.
+ */
+static void response_destroy(response_t *this)
+{
+ DESTROY_IF(this->responder_id_name);
+ DESTROY_IF(this->responder_cert);
+ free(this->chunk.ptr);
+ free(this);
+}
+
+/**
+ * Creates a response_t object
+ */
+static response_t* response_create_from_chunk(chunk_t chunk)
+{
+ response_t *this = malloc_thing(response_t);
+
+ this->chunk = chunk;
+ this->tbs = chunk_empty;
+ this->responder_id_name = NULL;
+ this->responder_id_key = chunk_empty;
+ this->produced_at = UNDEFINED_TIME;
+ this->responses = chunk_empty;
+ this->nonce = chunk_empty;
+ this->algorithm = OID_UNKNOWN;
+ this->signature = chunk_empty;
+ this->responder_cert = NULL;
+
+ this->destroy = (void (*) (response_t*))response_destroy;
+
+ return this;
+}
+
+/* some OCSP specific prefabricated ASN.1 constants */
+
+static u_char ASN1_nonce_oid_str[] = {
+ 0x06, 0x09,
+ 0x2B, 0x06,
+ 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x02
+};
+
+static u_char ASN1_response_oid_str[] = {
+ 0x06, 0x09,
+ 0x2B, 0x06,
+ 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x04
+};
+
+static u_char ASN1_response_content_str[] = {
+ 0x04, 0x0D,
+ 0x30, 0x0B,
+ 0x06, 0x09,
+ 0x2B, 0x06,
+ 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01
+};
+
+static const chunk_t ASN1_nonce_oid = chunk_from_buf(ASN1_nonce_oid_str);
+static const chunk_t ASN1_response_oid = chunk_from_buf(ASN1_response_oid_str);
+static const chunk_t ASN1_response_content = chunk_from_buf(ASN1_response_content_str);
+
+/* asn.1 definitions for parsing */
+
+static const asn1Object_t ocspResponseObjects[] = {
+ { 0, "OCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "responseStatus", ASN1_ENUMERATED, ASN1_BODY }, /* 1 */
+ { 1, "responseBytesContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 2 */
+ { 2, "responseBytes", ASN1_SEQUENCE, ASN1_NONE }, /* 3 */
+ { 3, "responseType", ASN1_OID, ASN1_BODY }, /* 4 */
+ { 3, "response", ASN1_OCTET_STRING, ASN1_BODY }, /* 5 */
+ { 1, "end opt", ASN1_EOC, ASN1_END } /* 6 */
+};
+
+#define OCSP_RESPONSE_STATUS 1
+#define OCSP_RESPONSE_TYPE 4
+#define OCSP_RESPONSE 5
+#define OCSP_RESPONSE_ROOF 7
+
+static const asn1Object_t basicResponseObjects[] = {
+ { 0, "BasicOCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "tbsResponseData", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
+ { 2, "versionContext", ASN1_CONTEXT_C_0, ASN1_NONE |
+ ASN1_DEF }, /* 2 */
+ { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */
+ { 2, "responderIdContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 4 */
+ { 3, "responderIdByName", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */
+ { 2, "end choice", ASN1_EOC, ASN1_END }, /* 6 */
+ { 2, "responderIdContext", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 7 */
+ { 3, "responderIdByKey", ASN1_OCTET_STRING, ASN1_BODY }, /* 8 */
+ { 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */
+ { 2, "producedAt", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 10 */
+ { 2, "responses", ASN1_SEQUENCE, ASN1_OBJ }, /* 11 */
+ { 2, "responseExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 12 */
+ { 3, "responseExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 13 */
+ { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 14 */
+ { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 15 */
+ { 5, "critical", ASN1_BOOLEAN, ASN1_BODY |
+ ASN1_DEF }, /* 16 */
+ { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 17 */
+ { 4, "end loop", ASN1_EOC, ASN1_END }, /* 18 */
+ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 19 */
+ { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 20 */
+ { 1, "signature", ASN1_BIT_STRING, ASN1_BODY }, /* 21 */
+ { 1, "certsContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 22 */
+ { 2, "certs", ASN1_SEQUENCE, ASN1_LOOP }, /* 23 */
+ { 3, "certificate", ASN1_SEQUENCE, ASN1_RAW }, /* 24 */
+ { 2, "end loop", ASN1_EOC, ASN1_END }, /* 25 */
+ { 1, "end opt", ASN1_EOC, ASN1_END } /* 26 */
+};
+
+#define BASIC_RESPONSE_TBS_DATA 1
+#define BASIC_RESPONSE_VERSION 3
+#define BASIC_RESPONSE_ID_BY_NAME 5
+#define BASIC_RESPONSE_ID_BY_KEY 8
+#define BASIC_RESPONSE_PRODUCED_AT 10
+#define BASIC_RESPONSE_RESPONSES 11
+#define BASIC_RESPONSE_EXT_ID 15
+#define BASIC_RESPONSE_CRITICAL 16
+#define BASIC_RESPONSE_EXT_VALUE 17
+#define BASIC_RESPONSE_ALGORITHM 20
+#define BASIC_RESPONSE_SIGNATURE 21
+#define BASIC_RESPONSE_CERTIFICATE 24
+#define BASIC_RESPONSE_ROOF 27
+
+static const asn1Object_t responsesObjects[] = {
+ { 0, "responses", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */
+ { 1, "singleResponse", ASN1_EOC, ASN1_RAW }, /* 1 */
+ { 0, "end loop", ASN1_EOC, ASN1_END } /* 2 */
+};
+
+#define RESPONSES_SINGLE_RESPONSE 1
+#define RESPONSES_ROOF 3
+
+static const asn1Object_t singleResponseObjects[] = {
+ { 0, "singleResponse", ASN1_SEQUENCE, ASN1_BODY }, /* 0 */
+ { 1, "certID", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */
+ { 2, "algorithm", ASN1_EOC, ASN1_RAW }, /* 2 */
+ { 2, "issuerNameHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 3 */
+ { 2, "issuerKeyHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 4 */
+ { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 5 */
+ { 1, "certStatusGood", ASN1_CONTEXT_S_0, ASN1_OPT }, /* 6 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 7 */
+ { 1, "certStatusRevoked", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 8 */
+ { 2, "revocationTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 9 */
+ { 2, "revocationReason", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 10 */
+ { 3, "crlReason", ASN1_ENUMERATED, ASN1_BODY }, /* 11 */
+ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 12 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 13 */
+ { 1, "certStatusUnknown", ASN1_CONTEXT_S_2, ASN1_OPT }, /* 14 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 15 */
+ { 1, "thisUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 16 */
+ { 1, "nextUpdateContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 17 */
+ { 2, "nextUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 18 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 19 */
+ { 1, "singleExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 20 */
+ { 2, "singleExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 21 */
+ { 3, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 22 */
+ { 4, "extnID", ASN1_OID, ASN1_BODY }, /* 23 */
+ { 4, "critical", ASN1_BOOLEAN, ASN1_BODY |
+ ASN1_DEF }, /* 24 */
+ { 4, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 25 */
+ { 2, "end loop", ASN1_EOC, ASN1_END }, /* 26 */
+ { 1, "end opt", ASN1_EOC, ASN1_END } /* 27 */
+};
+
+#define SINGLE_RESPONSE_ALGORITHM 2
+#define SINGLE_RESPONSE_ISSUER_NAME_HASH 3
+#define SINGLE_RESPONSE_ISSUER_KEY_HASH 4
+#define SINGLE_RESPONSE_SERIAL_NUMBER 5
+#define SINGLE_RESPONSE_CERT_STATUS_GOOD 6
+#define SINGLE_RESPONSE_CERT_STATUS_REVOKED 8
+#define SINGLE_RESPONSE_CERT_STATUS_REVOCATION_TIME 9
+#define SINGLE_RESPONSE_CERT_STATUS_CRL_REASON 11
+#define SINGLE_RESPONSE_CERT_STATUS_UNKNOWN 14
+#define SINGLE_RESPONSE_THIS_UPDATE 16
+#define SINGLE_RESPONSE_NEXT_UPDATE 18
+#define SINGLE_RESPONSE_EXT_ID 23
+#define SINGLE_RESPONSE_CRITICAL 24
+#define SINGLE_RESPONSE_EXT_VALUE 25
+#define SINGLE_RESPONSE_ROOF 28
+
+/**
+ * build requestorName (into TBSRequest)
+ */
+static chunk_t build_requestor_name(private_ocsp_t *this)
+{
+ identification_t *requestor_name = this->requestor_cert->get_subject(this->requestor_cert);
+
+ return asn1_wrap(ASN1_CONTEXT_C_1, "m",
+ asn1_simple_object(ASN1_CONTEXT_C_4,
+ requestor_name->get_encoding(requestor_name)));
+}
+
+/**
+ * build request (into requestList)
+ * no singleRequestExtensions used
+ */
+static chunk_t build_request(private_ocsp_t *this, certinfo_t *certinfo)
+{
+ chunk_t serialNumber = certinfo->get_serialNumber(certinfo);
+
+ chunk_t reqCert = asn1_wrap(ASN1_SEQUENCE, "cmmm",
+ ASN1_sha1_id,
+ asn1_simple_object(ASN1_OCTET_STRING, this->authNameID),
+ asn1_simple_object(ASN1_OCTET_STRING, this->authKeyID),
+ asn1_simple_object(ASN1_INTEGER, serialNumber));
+
+ return asn1_wrap(ASN1_SEQUENCE, "m", reqCert);
+}
+
+/**
+ * build requestList (into TBSRequest)
+ */
+static chunk_t build_request_list(private_ocsp_t *this)
+{
+ chunk_t requestList;
+ size_t datalen = 0;
+ linked_list_t *request_list = linked_list_create();
+
+ {
+ iterator_t *iterator = this->certinfos->create_iterator(this->certinfos, TRUE);
+ certinfo_t *certinfo;
+
+ while (iterator->iterate(iterator, (void**)&certinfo))
+ {
+ chunk_t *request = malloc_thing(chunk_t);
+
+ *request = build_request(this, certinfo);
+ request_list->insert_last(request_list, (void*)request);
+ datalen += request->len;
+ }
+ iterator->destroy(iterator);
+ }
+ {
+ iterator_t *iterator = request_list->create_iterator(request_list, TRUE);
+ chunk_t *request;
+
+ u_char *pos = build_asn1_object(&requestList, ASN1_SEQUENCE, datalen);
+
+ while (iterator->iterate(iterator, (void**)&request))
+ {
+ memcpy(pos, request->ptr, request->len);
+ pos += request->len;
+ free(request->ptr);
+ free(request);
+ }
+ iterator->destroy(iterator);
+ request_list->destroy(request_list);
+ }
+ return requestList;
+}
+
+/**
+ * build nonce extension (into requestExtensions)
+ */
+static chunk_t build_nonce_extension(private_ocsp_t *this)
+{
+ randomizer_t *randomizer = randomizer_create();
+
+ /* generate a random nonce */
+ randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_LENGTH, &this->nonce);
+ randomizer->destroy(randomizer);
+
+ return asn1_wrap(ASN1_SEQUENCE, "cm",
+ ASN1_nonce_oid,
+ asn1_simple_object(ASN1_OCTET_STRING, this->nonce));
+}
+
+/**
+ * build requestExtensions (into TBSRequest)
+ */
+static chunk_t build_request_ext(private_ocsp_t *this)
+{
+ return asn1_wrap(ASN1_CONTEXT_C_2, "m",
+ asn1_wrap(ASN1_SEQUENCE, "mm",
+ build_nonce_extension(this),
+ asn1_wrap(ASN1_SEQUENCE, "cc",
+ ASN1_response_oid,
+ ASN1_response_content
+ )
+ )
+ );
+}
+
+/**
+ * build TBSRequest (into OCSPRequest)
+ */
+static chunk_t build_tbs_request(private_ocsp_t *this, bool has_requestor_cert)
+{
+ /* version is skipped since the default is ok */
+ return asn1_wrap(ASN1_SEQUENCE, "mmm",
+ (has_requestor_cert)? build_requestor_name(this): chunk_empty,
+ build_request_list(this),
+ build_request_ext(this));
+}
+
+/**
+ * build signature into ocsp request
+ * gets built only if a request cert with a corresponding private key is found
+ */
+static chunk_t build_signature(private_ocsp_t *this, chunk_t tbsRequest)
+{
+ /* TODO */
+ return chunk_empty;
+}
+
+/**
+ * assembles an ocsp request and sets the nonce field in private_ocsp_t to the sent nonce
+ */
+static chunk_t ocsp_build_request(private_ocsp_t *this)
+{
+ bool has_requestor_cert;
+ chunk_t keyid = this->cacert->get_keyid(this->cacert);
+ chunk_t tbsRequest, signature;
+
+ DBG2("assembling ocsp request");
+ DBG2("issuer: '%D'", this->cacert->get_subject(this->cacert));
+ DBG2("keyid: %#B", &keyid);
+
+ /* looks for requestor cert and matching private key */
+ has_requestor_cert = FALSE;
+
+ /* TODO has_requestor_cert = get_ocsp_requestor_cert(location); */
+
+ /* build content */
+ tbsRequest = build_tbs_request(this, has_requestor_cert);
+
+ /* sign tbsReuqest */
+ signature = (has_requestor_cert)? build_signature(this, tbsRequest): chunk_empty;
+
+ return asn1_wrap(ASN1_SEQUENCE, "mm",
+ tbsRequest,
+ signature);
+
+ return signature;
+}
+
+/**
+ * parse a basic OCSP response
+ */
+static bool ocsp_parse_basic_response(chunk_t blob, int level0, response_t *res)
+{
+ u_int level, version;
+ u_int extn_oid = OID_UNKNOWN;
+ asn1_ctx_t ctx;
+ bool critical;
+ chunk_t object;
+ int objectID = 0;
+
+ asn1_init(&ctx, blob, level0, FALSE, FALSE);
+
+ while (objectID < BASIC_RESPONSE_ROOF)
+ {
+ if (!extract_object(basicResponseObjects, &objectID, &object, &level, &ctx))
+ {
+ return FALSE;
+ }
+
+ switch (objectID)
+ {
+ case BASIC_RESPONSE_TBS_DATA:
+ res->tbs = object;
+ break;
+ case BASIC_RESPONSE_VERSION:
+ version = (object.len)? (1 + (u_int)*object.ptr) : 1;
+ if (version != OCSP_BASIC_RESPONSE_VERSION)
+ {
+ DBG1("wrong ocsp basic response version (version= %i)", version);
+ return FALSE;
+ }
+ break;
+ case BASIC_RESPONSE_ID_BY_NAME:
+ res->responder_id_name = identification_create_from_encoding(ID_DER_ASN1_DN, object);
+ DBG2(" '%D'", res->responder_id_name);
+ break;
+ case BASIC_RESPONSE_ID_BY_KEY:
+ res->responder_id_key = object;
+ break;
+ case BASIC_RESPONSE_PRODUCED_AT:
+ res->produced_at = asn1totime(&object, ASN1_GENERALIZEDTIME);
+ break;
+ case BASIC_RESPONSE_RESPONSES:
+ res->responses = object;
+ break;
+ case BASIC_RESPONSE_EXT_ID:
+ extn_oid = known_oid(object);
+ break;
+ case BASIC_RESPONSE_CRITICAL:
+ critical = object.len && *object.ptr;
+ DBG2(" %s", critical? "TRUE" : "FALSE");
+ break;
+ case BASIC_RESPONSE_EXT_VALUE:
+ if (extn_oid == OID_NONCE)
+ res->nonce = object;
+ break;
+ case BASIC_RESPONSE_ALGORITHM:
+ res->algorithm = parse_algorithmIdentifier(object, level+1, NULL);
+ break;
+ case BASIC_RESPONSE_SIGNATURE:
+ res->signature = object;
+ break;
+ case BASIC_RESPONSE_CERTIFICATE:
+ {
+ chunk_t blob = chunk_clone(object);
+
+ res->responder_cert = x509_create_from_chunk(blob, level+1);
+ }
+ break;
+ }
+ objectID++;
+ }
+ return TRUE;
+}
+
+/**
+ * parse an ocsp response and return the result as a response_t struct
+ */
+static response_status ocsp_parse_response(response_t *res)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+
+ response_status rStatus = STATUS_INTERNALERROR;
+ u_int ocspResponseType = OID_UNKNOWN;
+
+ asn1_init(&ctx, res->chunk, 0, FALSE, FALSE);
+
+ while (objectID < OCSP_RESPONSE_ROOF)
+ {
+ if (!extract_object(ocspResponseObjects, &objectID, &object, &level, &ctx))
+ {
+ return STATUS_INTERNALERROR;
+ }
+
+ switch (objectID)
+ {
+ case OCSP_RESPONSE_STATUS:
+ rStatus = (response_status) *object.ptr;
+ DBG2(" '%N'", response_status_names, rStatus);
+
+ switch (rStatus)
+ {
+ case STATUS_SUCCESSFUL:
+ break;
+ case STATUS_MALFORMEDREQUEST:
+ case STATUS_INTERNALERROR:
+ case STATUS_TRYLATER:
+ case STATUS_SIGREQUIRED:
+ case STATUS_UNAUTHORIZED:
+ DBG1("unsuccessful ocsp response: server said '%N'",
+ response_status_names, rStatus);
+ return rStatus;
+ default:
+ return STATUS_INTERNALERROR;
+ }
+ break;
+ case OCSP_RESPONSE_TYPE:
+ ocspResponseType = known_oid(object);
+ break;
+ case OCSP_RESPONSE:
+ {
+ switch (ocspResponseType)
+ {
+ case OID_BASIC:
+ if (!ocsp_parse_basic_response(object, level+1, res))
+ {
+ return STATUS_INTERNALERROR;
+ }
+ break;
+ default:
+ DBG1("ocsp response is not of type BASIC");
+ DBG1("ocsp response OID: %#B", &object);
+ return STATUS_INTERNALERROR;
+ }
+ }
+ break;
+ }
+ objectID++;
+ }
+ return rStatus;
+}
+
+/**
+ * Check if the OCSP response has a valid signature
+ */
+static bool ocsp_valid_response(response_t *res, x509_t *ocsp_cert)
+{
+ rsa_public_key_t *public_key;
+ time_t until = UNDEFINED_TIME;
+ err_t ugh;
+
+ DBG2("verifying ocsp response signature:");
+ DBG2("signer: '%D'", ocsp_cert->get_subject(ocsp_cert));
+ DBG2("issuer: '%D'", ocsp_cert->get_issuer(ocsp_cert));
+
+ ugh = ocsp_cert->is_valid(ocsp_cert, &until);
+ if (ugh != NULL)
+ {
+ DBG1("ocsp signer certificate %s", ugh);
+ return FALSE;
+ }
+ public_key = ocsp_cert->get_public_key(ocsp_cert);
+
+ return public_key->verify_emsa_pkcs1_signature(public_key, res->tbs, res->signature) == SUCCESS;
+}
+
+/**
+ * parse a single OCSP response
+ */
+static bool ocsp_parse_single_response(private_ocsp_t *this, chunk_t blob, int level0)
+{
+ u_int level, extn_oid;
+ asn1_ctx_t ctx;
+ bool critical;
+ chunk_t object;
+ int objectID = 0;
+
+ certinfo_t *certinfo = NULL;
+
+ asn1_init(&ctx, blob, level0, FALSE, FALSE);
+
+ while (objectID < SINGLE_RESPONSE_ROOF)
+ {
+ if (!extract_object(singleResponseObjects, &objectID, &object, &level, &ctx))
+ {
+ return FALSE;
+ }
+
+ switch (objectID)
+ {
+ case SINGLE_RESPONSE_ALGORITHM:
+ if (parse_algorithmIdentifier(object, level+1, NULL) != OID_SHA1)
+ {
+ DBG1("only sha-1 hash supported in ocsp single response");
+ return FALSE;
+ }
+ break;
+ case SINGLE_RESPONSE_ISSUER_NAME_HASH:
+ if (!chunk_equals(object, this->authNameID))
+ {
+ DBG1("ocsp single response has wrong issuer name hash");
+ return FALSE;
+ }
+ break;
+ case SINGLE_RESPONSE_ISSUER_KEY_HASH:
+ if (!chunk_equals(object, this->authKeyID))
+ {
+ DBG1("ocsp single response has wrong issuer key hash");
+ return FALSE;
+ }
+ break;
+ case SINGLE_RESPONSE_SERIAL_NUMBER:
+ {
+ iterator_t *iterator = this->certinfos->create_iterator(this->certinfos, TRUE);
+ certinfo_t *current_certinfo;
+
+ while (iterator->iterate(iterator, (void**)&current_certinfo))
+ {
+ if (chunk_equals(object, current_certinfo->get_serialNumber(current_certinfo)))
+ {
+ certinfo = current_certinfo;
+ }
+ }
+ iterator->destroy(iterator);
+ if (certinfo == NULL)
+ {
+ DBG1("unrequested serial number in ocsp single response");
+ return FALSE;
+ }
+ }
+ break;
+ case SINGLE_RESPONSE_CERT_STATUS_GOOD:
+ certinfo->set_status(certinfo, CERT_GOOD);
+ break;
+ case SINGLE_RESPONSE_CERT_STATUS_REVOKED:
+ certinfo->set_status(certinfo, CERT_REVOKED);
+ break;
+ case SINGLE_RESPONSE_CERT_STATUS_REVOCATION_TIME:
+ certinfo->set_revocationTime(certinfo,
+ asn1totime(&object, ASN1_GENERALIZEDTIME));
+ break;
+ case SINGLE_RESPONSE_CERT_STATUS_CRL_REASON:
+ certinfo->set_revocationReason(certinfo,
+ (object.len == 1) ? *object.ptr : REASON_UNSPECIFIED);
+ break;
+ case SINGLE_RESPONSE_CERT_STATUS_UNKNOWN:
+ certinfo->set_status(certinfo, CERT_UNKNOWN);
+ break;
+ case SINGLE_RESPONSE_THIS_UPDATE:
+ certinfo->set_thisUpdate(certinfo,
+ asn1totime(&object, ASN1_GENERALIZEDTIME));
+ break;
+ case SINGLE_RESPONSE_NEXT_UPDATE:
+ certinfo->set_nextUpdate(certinfo,
+ asn1totime(&object, ASN1_GENERALIZEDTIME));
+ break;
+ case SINGLE_RESPONSE_EXT_ID:
+ extn_oid = known_oid(object);
+ break;
+ case SINGLE_RESPONSE_CRITICAL:
+ critical = object.len && *object.ptr;
+ DBG2(" %s", critical ? "TRUE" : "FALSE");
+ case SINGLE_RESPONSE_EXT_VALUE:
+ break;
+ }
+ objectID++;
+ }
+ return TRUE;
+}
+
+/**
+ * verify and process ocsp response and update the ocsp cache
+ */
+static void ocsp_process_response(private_ocsp_t *this, response_t *res, credential_store_t *credentials)
+{
+ x509_t *ocsp_cert = NULL;
+
+ /* parse the ocsp response without looking at the single responses yet */
+ response_status status = ocsp_parse_response(res);
+
+ if (status != STATUS_SUCCESSFUL)
+ {
+ DBG1("error in ocsp response");
+ return;
+ }
+
+ /* check if there was a nonce in the request */
+ if (this->nonce.ptr != NULL && res->nonce.ptr == NULL)
+ {
+ DBG1("ocsp response contains no nonce, replay attack possible");
+ }
+
+ /* check if the nonces are identical */
+ if (res->nonce.ptr != NULL && !chunk_equals(res->nonce, this->nonce))
+ {
+ DBG1("invalid nonce in ocsp response");
+ return;
+ }
+
+ /* check if we received a trusted responder certificate */
+ if (res->responder_cert)
+ {
+ if (res->responder_cert->is_ocsp_signer(res->responder_cert))
+ {
+ DBG2("received certificate is ocsp signer");
+ if (credentials->is_trusted(credentials, res->responder_cert))
+ {
+ DBG1("received ocsp signer certificate is trusted");
+ ocsp_cert = credentials->add_auth_certificate(credentials,
+ res->responder_cert, AUTH_OCSP);
+ res->responder_cert = NULL;
+ }
+ else
+ {
+ DBG1("received ocsp signer certificate is not trusted - rejected");
+ }
+ }
+ else
+ {
+ DBG1("received certificate is no ocsp signer - rejected");
+ }
+ }
+
+ /* if we didn't receive a trusted responder cert, search the credential store */
+ if (ocsp_cert == NULL)
+ {
+ ocsp_cert = credentials->get_auth_certificate(credentials,
+ AUTH_OCSP|AUTH_CA, res->responder_id_name);
+ if (ocsp_cert == NULL)
+ {
+ DBG1("no ocsp signer certificate found");
+ return;
+ }
+ }
+
+ /* check the response signature */
+ if (!ocsp_valid_response(res, ocsp_cert))
+ {
+ DBG1("ocsp response signature is invalid");
+ return;
+ }
+ DBG2("ocsp response signature is valid");
+
+ /* now parse the single responses one at a time */
+ {
+ u_int level;
+ asn1_ctx_t ctx;
+ chunk_t object;
+ int objectID = 0;
+
+ asn1_init(&ctx, res->responses, 0, FALSE, FALSE);
+
+ while (objectID < RESPONSES_ROOF)
+ {
+ if (!extract_object(responsesObjects, &objectID, &object, &level, &ctx))
+ {
+ return;
+ }
+ if (objectID == RESPONSES_SINGLE_RESPONSE)
+ {
+ ocsp_parse_single_response(this, object, level+1);
+ }
+ objectID++;
+ }
+ }
+}
+
+/**
+ * Implements ocsp_t.fetch.
+ */
+static void fetch(private_ocsp_t *this, certinfo_t *certinfo, credential_store_t *credentials)
+{
+ chunk_t request;
+ response_t *response = NULL;
+
+ if (this->uris->get_count(this->uris) == 0)
+ {
+ return;
+ }
+ this->certinfos->insert_last(this->certinfos, (void*)certinfo);
+
+ request = ocsp_build_request(this);
+ DBG3("ocsp request: %B", &request);
+ {
+ iterator_t *iterator = this->uris->create_iterator(this->uris, TRUE);
+ identification_t *uri;
+
+ while (iterator->iterate(iterator, (void**)&uri))
+ {
+ fetcher_t *fetcher;
+ char uri_string[BUF_LEN];
+ chunk_t uri_chunk = uri->get_encoding(uri);
+ chunk_t response_chunk;
+
+ snprintf(uri_string, BUF_LEN, "%.*s", uri_chunk.len, uri_chunk.ptr);
+ fetcher = fetcher_create(uri_string);
+
+ response_chunk = fetcher->post(fetcher, "application/ocsp-request", request);
+ fetcher->destroy(fetcher);
+ if (response_chunk.ptr != NULL)
+ {
+ response = response_create_from_chunk(response_chunk);
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ }
+ free(request.ptr);
+
+ if (response == NULL)
+ {
+ return;
+ }
+ DBG3("ocsp response: %B", &response->chunk);
+ ocsp_process_response(this, response, credentials);
+ response->destroy(response);
+}
+
+/**
+ * Implements ocsp_t.destroy.
+ */
+static void destroy(private_ocsp_t *this)
+{
+ this->certinfos->destroy(this->certinfos);
+ free(this->authNameID.ptr);
+ free(this->nonce.ptr);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+ocsp_t *ocsp_create(x509_t *cacert, linked_list_t *uris)
+{
+ private_ocsp_t *this = malloc_thing(private_ocsp_t);
+
+ /* initialize */
+ this->cacert = cacert;
+ this->uris = uris;
+ this->certinfos = linked_list_create();
+ this->nonce = chunk_empty;
+ this->authKeyID = cacert->get_subjectKeyID(cacert);
+ {
+ hasher_t *hasher = hasher_create(HASH_SHA1);
+ identification_t *issuer = cacert->get_subject(cacert);
+
+ hasher->allocate_hash(hasher, issuer->get_encoding(issuer),
+ &this->authNameID);
+ hasher->destroy(hasher);
+ }
+
+ /* public functions */
+ this->public.fetch = (void (*) (ocsp_t*,certinfo_t*,credential_store_t*))fetch;
+ this->public.destroy = (void (*) (ocsp_t*))destroy;
+
+ return &this->public;
+}
diff --git a/src/libstrongswan/crypto/ocsp.h b/src/libstrongswan/crypto/ocsp.h
new file mode 100644
index 000000000..42059e1c6
--- /dev/null
+++ b/src/libstrongswan/crypto/ocsp.h
@@ -0,0 +1,86 @@
+/**
+ * @file ocsp.h
+ *
+ * @brief Interface of ocsp_t
+ *
+ */
+
+/* Support of the Online Certificate Status Protocol (OCSP) Support
+ * Copyright (C) 2003 Christoph Gysin, Simon Zwahlen
+ * Copyright (C) 2007 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil, Switzerland
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 OCSP_H_
+#define OCSP_H_
+
+typedef struct ocsp_t ocsp_t;
+
+#include <credential_store.h>
+#include <utils/linked_list.h>
+
+#include "certinfo.h"
+
+/* constants */
+#define OCSP_BASIC_RESPONSE_VERSION 1
+#define OCSP_DEFAULT_VALID_TIME 120 /* validity of one-time response in seconds */
+#define OCSP_WARNING_INTERVAL 2 /* days */
+
+/* OCSP response status */
+typedef enum {
+ STATUS_SUCCESSFUL = 0,
+ STATUS_MALFORMEDREQUEST = 1,
+ STATUS_INTERNALERROR = 2,
+ STATUS_TRYLATER = 3,
+ STATUS_SIGREQUIRED = 5,
+ STATUS_UNAUTHORIZED= 6
+} response_status;
+
+/**
+ * @brief Online Certficate Status Protocol (OCSP)
+ *
+ * @ingroup transforms
+ */
+struct ocsp_t {
+
+ /**
+ * @brief Fetches the actual certificate status via OCSP
+ *
+ * @param uris linked list of ocsp uris
+ * @param certinfo certificate status info to be updated
+ * @param credentials credential store needed for trust path verification
+ */
+ void (*fetch) (ocsp_t *this, certinfo_t *certinfo, credential_store_t *credentials);
+
+ /**
+ * @brief Destroys the ocsp_t object.
+ *
+ * @param this ocsp object to destroy
+ */
+ void (*destroy) (ocsp_t *this);
+
+};
+
+/**
+ * @brief Create an ocsp_t object.
+ *
+ * @param cacert ca certificate
+ * @param uris linked list of ocsp uris
+ * @return created ocsp_t object
+ *
+ * @ingroup transforms
+ */
+ocsp_t *ocsp_create(x509_t *cacert, linked_list_t *uris);
+
+#endif /* OCSP_H_ */
diff --git a/src/libstrongswan/crypto/prf_plus.c b/src/libstrongswan/crypto/prf_plus.c
new file mode 100644
index 000000000..6bd444b1f
--- /dev/null
+++ b/src/libstrongswan/crypto/prf_plus.c
@@ -0,0 +1,156 @@
+/**
+ * @file prf_plus.c
+ *
+ * @brief Implementation of prf_plus_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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"
+
+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/src/libstrongswan/crypto/prf_plus.h b/src/libstrongswan/crypto/prf_plus.h
new file mode 100644
index 000000000..90f9ce2eb
--- /dev/null
+++ b/src/libstrongswan/crypto/prf_plus.h
@@ -0,0 +1,92 @@
+/**
+ * @file prf_plus.h
+ *
+ * @brief Interface for prf_plus.h.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct prf_plus_t prf_plus_t;
+
+#include <crypto/prfs/prf.h>
+
+/**
+ * @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/src/libstrongswan/crypto/prfs/fips_prf.c b/src/libstrongswan/crypto/prfs/fips_prf.c
new file mode 100644
index 000000000..0ab80b089
--- /dev/null
+++ b/src/libstrongswan/crypto/prfs/fips_prf.c
@@ -0,0 +1,258 @@
+/**
+ * @file fips_prf.c
+ *
+ * @brief Implementation for fips_prf_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "fips_prf.h"
+
+#include <arpa/inet.h>
+
+#include <debug.h>
+
+typedef struct private_fips_prf_t private_fips_prf_t;
+
+/**
+ * Private data of a fips_prf_t object.
+ */
+struct private_fips_prf_t {
+ /**
+ * Public fips_prf_t interface.
+ */
+ fips_prf_t public;
+
+ /**
+ * key of prf function, "b" long
+ */
+ u_int8_t *key;
+
+ /**
+ * size of "b" in bytes
+ */
+ size_t b;
+
+ /**
+ * G function, either SHA1 or DES
+ */
+ void (*g)(u_int8_t t[], chunk_t c, u_int8_t res[]);
+};
+
+/**
+ * t used in G(), equals to initial SHA1 value
+ */
+static u_int8_t t[] = {
+ 0x67,0x45,0x23,0x01,0xEF,0xCD,0xAB,0x89,0x98,0xBA,
+ 0xDC,0xFE,0x10,0x32,0x54,0x76,0xC3,0xD2,0xE1,0xF0,
+};
+
+/**
+ * sum = (a + b) mod 2 ^ (length * 8)
+ */
+static void add_mod(size_t length, u_int8_t a[], u_int8_t b[], u_int8_t sum[])
+{
+ int i, c = 0;
+
+ for(i = length - 1; i >= 0; i--)
+ {
+ u_int32_t tmp;
+
+ tmp = a[i] + b[i] + c;
+ sum[i] = 0xff & tmp;
+ c = tmp >> 8;
+ }
+}
+
+/**
+ * calculate "chunk mod 2^(length*8)" and save it into buffer
+ */
+static void chunk_mod(size_t length, chunk_t chunk, u_int8_t buffer[])
+{
+ if (chunk.len < length)
+ {
+ /* apply seed as least significant bits, others are zero */
+ memset(buffer, 0, length - chunk.len);
+ memcpy(buffer + length - chunk.len, chunk.ptr, chunk.len);
+ }
+ else
+ {
+ /* use least significant bytes from seed, as we use mod 2^b */
+ memcpy(buffer, chunk.ptr + chunk.len - length, length);
+ }
+}
+
+/**
+ * Implementation of prf_t.get_bytes.
+ *
+ * Test vector:
+ *
+ * key:
+ * 0xbd, 0x02, 0x9b, 0xbe, 0x7f, 0x51, 0x96, 0x0b,
+ * 0xcf, 0x9e, 0xdb, 0x2b, 0x61, 0xf0, 0x6f, 0x0f,
+ * 0xeb, 0x5a, 0x38, 0xb6
+ *
+ * seed:
+ * 0x00
+ *
+ * result:
+ * 0x20, 0x70, 0xb3, 0x22, 0x3d, 0xba, 0x37, 0x2f,
+ * 0xde, 0x1c, 0x0f, 0xfc, 0x7b, 0x2e, 0x3b, 0x49,
+ * 0x8b, 0x26, 0x06, 0x14, 0x3c, 0x6c, 0x18, 0xba,
+ * 0xcb, 0x0f, 0x6c, 0x55, 0xba, 0xbb, 0x13, 0x78,
+ * 0x8e, 0x20, 0xd7, 0x37, 0xa3, 0x27, 0x51, 0x16
+ */
+static void get_bytes(private_fips_prf_t *this, chunk_t seed, u_int8_t w[])
+{
+ int i;
+ u_int8_t xval[this->b];
+ u_int8_t xseed[this->b];
+ u_int8_t sum[this->b];
+ u_int8_t *xkey = this->key;
+ u_int8_t one[this->b];
+ chunk_t xval_chunk = chunk_from_buf(xval);
+
+ memset(one, 0, this->b);
+ one[this->b - 1] = 0x01;
+
+ /* 3.1 */
+ chunk_mod(this->b, seed, xseed);
+
+ /* 3.2 */
+ for (i = 0; i < 2; i++) /* twice */
+ {
+ /* a. XVAL = (XKEY + XSEED j) mod 2^b */
+ add_mod(this->b, xkey, xseed, xval);
+ DBG3("XVAL %b", xval, this->b);
+ /* b. wi = G(t, XVAL ) */
+ this->g(t, xval_chunk, &w[i * this->b]);
+ DBG3("w[%d] %b", i, &w[i * this->b], this->b);
+ /* c. XKEY = (1 + XKEY + wi) mod 2b */
+ add_mod(this->b, xkey, &w[i * this->b], sum);
+ add_mod(this->b, sum, one, xkey);
+ DBG3("XKEY %b", xkey, this->b);
+ }
+
+ /* 3.3 done already, mod q not used */
+}
+
+/**
+ * Implementation of prf_t.get_block_size.
+ */
+static size_t get_block_size(private_fips_prf_t *this)
+{
+ return 2 * this->b;
+}
+/**
+ * Implementation of prf_t.allocate_bytes.
+ */
+static void allocate_bytes(private_fips_prf_t *this, chunk_t seed, chunk_t *chunk)
+{
+ *chunk = chunk_alloc(get_block_size(this));
+ get_bytes(this, seed, chunk->ptr);
+}
+
+/**
+ * Implementation of prf_t.get_key_size.
+ */
+static size_t get_key_size(private_fips_prf_t *this)
+{
+ return this->b;
+}
+
+/**
+ * Implementation of prf_t.set_key.
+ */
+static void set_key(private_fips_prf_t *this, chunk_t key)
+{
+ /* save key as "key mod 2^b" */
+ chunk_mod(this->b, key, this->key);
+}
+
+/**
+ * Implementation of the G() function based on SHA1
+ */
+void g_sha1(u_int8_t t[], chunk_t c, u_int8_t res[])
+{
+ hasher_t *hasher;
+ u_int8_t buf[64];
+ chunk_t state_chunk;
+ u_int32_t *state, *iv, *hash;
+
+ if (c.len < sizeof(buf))
+ {
+ /* pad c with zeros */
+ memset(buf, 0, sizeof(buf));
+ memcpy(buf, c.ptr, c.len);
+ c.ptr = buf;
+ c.len = sizeof(buf);
+ }
+ else
+ {
+ /* not more than 512 bits can be G()-ed */
+ c.len = sizeof(buf);
+ }
+
+ /* our SHA1 hasher's state is 32-Bit integers in host order. We must
+ * convert them */
+ hasher = hasher_create(HASH_SHA1);
+ state_chunk = hasher->get_state(hasher);
+ state = (u_int32_t*)state_chunk.ptr;
+ iv = (u_int32_t*)t;
+ hash = (u_int32_t*)res;
+ state[0] = htonl(iv[0]);
+ state[1] = htonl(iv[1]);
+ state[2] = htonl(iv[2]);
+ state[3] = htonl(iv[3]);
+ hasher->get_hash(hasher, c, NULL);
+ hash[0] = htonl(state[0]);
+ hash[1] = htonl(state[1]);
+ hash[2] = htonl(state[2]);
+ hash[3] = htonl(state[3]);
+ hash[4] = htonl(state[4]);
+ hasher->destroy(hasher);
+}
+
+/**
+ * Implementation of prf_t.destroy.
+ */
+static void destroy(private_fips_prf_t *this)
+{
+ free(this->key);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+fips_prf_t *fips_prf_create(size_t b, void(*g)(u_int8_t[],chunk_t,u_int8_t[]))
+{
+ private_fips_prf_t *this = malloc_thing(private_fips_prf_t);
+
+ this->public.prf_interface.get_bytes = (void (*) (prf_t *,chunk_t,u_int8_t*))get_bytes;
+ this->public.prf_interface.allocate_bytes = (void (*) (prf_t*,chunk_t,chunk_t*))allocate_bytes;
+ this->public.prf_interface.get_block_size = (size_t (*) (prf_t*))get_block_size;
+ this->public.prf_interface.get_key_size = (size_t (*) (prf_t*))get_key_size;
+ this->public.prf_interface.set_key = (void (*) (prf_t *,chunk_t))set_key;
+ this->public.prf_interface.destroy = (void (*) (prf_t *))destroy;
+
+ this->g = g;
+ this->b = b;
+ this->key = malloc(b);
+
+ return &(this->public);
+}
diff --git a/src/libstrongswan/crypto/prfs/fips_prf.h b/src/libstrongswan/crypto/prfs/fips_prf.h
new file mode 100644
index 000000000..283ee1f61
--- /dev/null
+++ b/src/libstrongswan/crypto/prfs/fips_prf.h
@@ -0,0 +1,80 @@
+/**
+ * @file fips_prf.h
+ *
+ * @brief Interface of fips_prf_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef FIPS_PRF_H_
+#define FIPS_PRF_H_
+
+typedef struct fips_prf_t fips_prf_t;
+
+#include <library.h>
+#include <crypto/prfs/prf.h>
+#include <crypto/hashers/hasher.h>
+
+/**
+ * @brief Implementation of prf_t using the FIPS 186-2-change1 standard.
+ *
+ * FIPS defines a "General Purpose Random Number Generator" (Revised
+ * Algorithm for Computing m values of x (Appendix 3.1 of FIPS 186-2)). This
+ * implementation is not intended for private key generation and therefore does
+ * not include the "mod q" operation (see FIPS 186-2-change1 p74).
+ * The FIPS PRF is stateful; the key changes every time when bytes are acquired.
+ *
+ * @b Constructors:
+ * - fips_prf_create()
+ * - prf_create() using one of the FIPS algorithms
+ *
+ * @ingroup prfs
+ */
+struct fips_prf_t {
+
+ /**
+ * Generic prf_t interface for this fips_prf_t class.
+ */
+ prf_t prf_interface;
+};
+
+/**
+ * @brief Creates a new fips_prf_t object.
+ *
+ * FIPS 186-2 defines G() functions used in the PRF function. It can
+ * be implemented either based on SHA1 or DES.
+ *
+ * @param b size of b (in bytes, not bits)
+ * @param g G() function to use (e.g. g_sha1)
+ * @return
+ * - fips_prf_t object
+ * - NULL if b invalid not supported
+ *
+ * @ingroup prfs
+ */
+fips_prf_t *fips_prf_create(size_t b, void(*g)(u_int8_t[],chunk_t,u_int8_t[]));
+
+/**
+ * @brief Implementation of the G() function based on SHA1.
+ *
+ * @param t initialization vector for SHA1 hasher, 20 bytes long
+ * @param c value to hash, not longer than 512 bit
+ * @param res result of G(), requries 20 bytes
+ */
+void g_sha1(u_int8_t t[], chunk_t c, u_int8_t res[]);
+
+#endif /* FIPS_PRF_H_ */
diff --git a/src/libstrongswan/crypto/prfs/hmac_prf.c b/src/libstrongswan/crypto/prfs/hmac_prf.c
new file mode 100644
index 000000000..f315f880d
--- /dev/null
+++ b/src/libstrongswan/crypto/prfs/hmac_prf.c
@@ -0,0 +1,118 @@
+/**
+ * @file hmac_prf.c
+ *
+ * @brief Implementation for hmac_prf_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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)
+{
+ this->hmac->destroy(this->hmac);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+hmac_prf_t *hmac_prf_create(hash_algorithm_t hash_algorithm)
+{
+ private_hmac_prf_t *this = malloc_thing(private_hmac_prf_t);
+
+ this->public.prf_interface.get_bytes = (void (*) (prf_t *,chunk_t,u_int8_t*))get_bytes;
+ this->public.prf_interface.allocate_bytes = (void (*) (prf_t*,chunk_t,chunk_t*))allocate_bytes;
+ this->public.prf_interface.get_block_size = (size_t (*) (prf_t*))get_block_size;
+ this->public.prf_interface.get_key_size = (size_t (*) (prf_t*))get_key_size;
+ this->public.prf_interface.set_key = (void (*) (prf_t *,chunk_t))set_key;
+ this->public.prf_interface.destroy = (void (*) (prf_t *))destroy;
+
+ this->hmac = hmac_create(hash_algorithm);
+ if (this->hmac == NULL)
+ {
+ free(this);
+ return NULL;
+ }
+
+ return &(this->public);
+}
diff --git a/src/libstrongswan/crypto/prfs/hmac_prf.h b/src/libstrongswan/crypto/prfs/hmac_prf.h
new file mode 100644
index 000000000..9b06ee3a2
--- /dev/null
+++ b/src/libstrongswan/crypto/prfs/hmac_prf.h
@@ -0,0 +1,65 @@
+/**
+ * @file hmac_prf.h
+ *
+ * @brief Interface of hmac_prf_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef PRF_HMAC_H_
+#define PRF_HMAC_H_
+
+typedef struct hmac_prf_t hmac_prf_t;
+
+#include <library.h>
+#include <crypto/prfs/prf.h>
+#include <crypto/hashers/hasher.h>
+
+/**
+ * @brief Implementation of prf_t interface using the
+ * HMAC algorithm.
+ *
+ * This simply wraps a hmac_t in a prf_t. More a question of
+ * interface matching.
+ *
+ * @b Constructors:
+ * - hmac_prf_create()
+ *
+ * @ingroup prfs
+ */
+struct hmac_prf_t {
+
+ /**
+ * Generic prf_t interface for this hmac_prf_t class.
+ */
+ prf_t prf_interface;
+};
+
+/**
+ * @brief Creates a new hmac_prf_t object.
+ *
+ * @param hash_algorithm hmac's hash algorithm
+ * @return
+ * - hmac_prf_t object
+ * - NULL if hash not supported
+ *
+ * @ingroup prfs
+ */
+hmac_prf_t *hmac_prf_create(hash_algorithm_t hash_algorithm);
+
+#endif /*PRF_HMAC_SHA1_H_*/
diff --git a/src/libstrongswan/crypto/prfs/prf.c b/src/libstrongswan/crypto/prfs/prf.c
new file mode 100644
index 000000000..f803829af
--- /dev/null
+++ b/src/libstrongswan/crypto/prfs/prf.c
@@ -0,0 +1,70 @@
+/**
+ * @file prf.c
+ *
+ * @brief Generic constructor for all prf_t
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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>
+#include <crypto/prfs/fips_prf.h>
+
+ENUM_BEGIN(pseudo_random_function_names, PRF_UNDEFINED, PRF_FIPS_DES,
+ "PRF_UNDEFINED",
+ "PRF_FIPS_SHA1_160",
+ "PRF_FIPS_DES");
+ENUM_NEXT(pseudo_random_function_names, PRF_HMAC_MD5, PRF_HMAC_SHA2_512, PRF_FIPS_DES,
+ "PRF_HMAC_MD5",
+ "PRF_HMAC_SHA1",
+ "PRF_HMAC_TIGER",
+ "PRF_AES128_CBC",
+ "PRF_HMAC_SHA2_256",
+ "PRF_HMAC_SHA2_384",
+ "PRF_HMAC_SHA2_512");
+ENUM_END(pseudo_random_function_names, PRF_HMAC_SHA2_512);
+
+/*
+ * Described in header.
+ */
+prf_t *prf_create(pseudo_random_function_t pseudo_random_function)
+{
+ switch (pseudo_random_function)
+ {
+ case PRF_HMAC_SHA1:
+ return (prf_t*)hmac_prf_create(HASH_SHA1);
+ case PRF_HMAC_MD5:
+ return (prf_t*)hmac_prf_create(HASH_MD5);
+ case PRF_HMAC_SHA2_256:
+ return (prf_t*)hmac_prf_create(HASH_SHA256);
+ case PRF_HMAC_SHA2_384:
+ return (prf_t*)hmac_prf_create(HASH_SHA384);
+ case PRF_HMAC_SHA2_512:
+ return (prf_t*)hmac_prf_create(HASH_SHA512);
+ case PRF_FIPS_SHA1_160:
+ return (prf_t*)fips_prf_create(20, g_sha1);
+ case PRF_FIPS_DES:
+ case PRF_HMAC_TIGER:
+ case PRF_AES128_CBC:
+ default:
+ return NULL;
+ }
+}
diff --git a/src/libstrongswan/crypto/prfs/prf.h b/src/libstrongswan/crypto/prfs/prf.h
new file mode 100644
index 000000000..8560a4a9c
--- /dev/null
+++ b/src/libstrongswan/crypto/prfs/prf.h
@@ -0,0 +1,142 @@
+/**
+ * @file prf.h
+ *
+ * @brief Interface prf_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef enum pseudo_random_function_t pseudo_random_function_t;
+typedef struct prf_t prf_t;
+
+#include <library.h>
+
+/**
+ * @brief Pseudo random function, as in IKEv2 RFC 3.3.2.
+ *
+ * PRF algorithms not defined in IKEv2 are allocated in "private use"
+ * space.
+ *
+ * @ingroup prfs
+ */
+enum pseudo_random_function_t {
+ PRF_UNDEFINED = 1024,
+ /** Implemented via hmac_prf_t. */
+ PRF_HMAC_MD5 = 1,
+ /** Implemented via hmac_prf_t. */
+ PRF_HMAC_SHA1 = 2,
+ PRF_HMAC_TIGER = 3,
+ PRF_AES128_CBC = 4,
+ /** Implemented via hmac_prf_t. */
+ PRF_HMAC_SHA2_256 = 5,
+ /** Implemented via hmac_prf_t. */
+ PRF_HMAC_SHA2_384 = 6,
+ /** Implemented via hmac_prf_t. */
+ PRF_HMAC_SHA2_512 = 7,
+ /** Implemented via fips_prf_t, other output sizes would be possible */
+ PRF_FIPS_SHA1_160 = 1025,
+ /** Could be implemented via fips_prf_t, uses fixed output size of 160bit */
+ PRF_FIPS_DES = 1026,
+};
+
+/**
+ * enum name for encryption_algorithm_t.
+ */
+extern enum_name_t *pseudo_random_function_names;
+
+/**
+ * @brief Generic interface for pseudo-random-functions.
+ *
+ * @b Constructors:
+ * - prf_create()
+ * - hmac_prf_create()
+ *
+ * @todo Implement more prf algorithms
+ *
+ * @ingroup prfs
+ */
+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.
+ *
+ * This is a suggestion only, all implemented PRFs accept variable key
+ * length.
+ *
+ * @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/src/libstrongswan/crypto/rsa/rsa_private_key.c b/src/libstrongswan/crypto/rsa/rsa_private_key.c
new file mode 100644
index 000000000..5b1647965
--- /dev/null
+++ b/src/libstrongswan/crypto/rsa/rsa_private_key.c
@@ -0,0 +1,774 @@
+/**
+ * @file rsa_private_key.c
+ *
+ * @brief Implementation of rsa_private_key_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 "rsa_private_key.h"
+
+#include <asn1/asn1.h>
+#include <asn1/pem.h>
+#include <utils/randomizer.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];
+
+
+/**
+ * defined in rsa_public_key.c
+ */
+extern chunk_t rsa_public_key_info_to_asn1(const mpz_t n, const mpz_t e);
+
+
+/**
+ * Public exponent to use for key generation.
+ */
+#define PUBLIC_EXPONENT 0x10001
+
+
+typedef struct private_rsa_private_key_t private_rsa_private_key_t;
+
+/**
+ * Private data of a rsa_private_key_t object.
+ */
+struct private_rsa_private_key_t {
+ /**
+ * Public interface for this signer.
+ */
+ rsa_private_key_t public;
+
+ /**
+ * Version of key, as encoded in PKCS#1
+ */
+ u_int version;
+
+ /**
+ * Public modulus.
+ */
+ mpz_t n;
+
+ /**
+ * Public exponent.
+ */
+ mpz_t e;
+
+ /**
+ * Private prime 1.
+ */
+ mpz_t p;
+
+ /**
+ * Private Prime 2.
+ */
+ mpz_t q;
+
+ /**
+ * Private exponent.
+ */
+ mpz_t d;
+
+ /**
+ * Private exponent 1.
+ */
+ mpz_t exp1;
+
+ /**
+ * Private exponent 2.
+ */
+ mpz_t exp2;
+
+ /**
+ * Private coefficient.
+ */
+ mpz_t coeff;
+
+ /**
+ * Keysize in bytes.
+ */
+ size_t k;
+
+ /**
+ * Keyid formed as a SHA-1 hash of a publicKeyInfo object
+ */
+ chunk_t keyid;
+
+
+ /**
+ * @brief Implements the RSADP algorithm specified in PKCS#1.
+ *
+ * @param this calling object
+ * @param data data to process
+ * @return processed data
+ */
+ chunk_t (*rsadp) (private_rsa_private_key_t *this, chunk_t data);
+
+ /**
+ * @brief Implements the RSASP1 algorithm specified in PKCS#1.
+ * @param this calling object
+ * @param data data to process
+ * @return processed data
+ */
+ chunk_t (*rsasp1) (private_rsa_private_key_t *this, chunk_t data);
+
+ /**
+ * @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(void);
+
+/**
+ * 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 em;
+ chunk_t oid;
+
+ /* 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)
+{
+ return chunk_equals(this->keyid, public->get_keyid(public));
+}
+
+/**
+ * Check the loaded key if it is valid and usable
+ * TODO: Log errors
+ */
+static status_t check(private_rsa_private_key_t *this)
+{
+ mpz_t t, u, q1;
+ status_t status = SUCCESS;
+
+ /* PKCS#1 1.5 section 6 requires modulus to have at least 12 octets.
+ * We actually require more (for security).
+ */
+ if (this->k < 512/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->keyid = chunk_clone(this->keyid);
+ 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->keyid.ptr);
+ free(this);
+}
+
+/**
+ * Internal generic constructor
+ */
+static private_rsa_private_key_t *rsa_private_key_create_empty(void)
+{
+ private_rsa_private_key_t *this = malloc_thing(private_rsa_private_key_t);
+
+ /* public functions */
+ this->public.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, TRUE);
+
+ while (objectID < PRIV_KEY_ROOF)
+ {
+ if (!extract_object(privkey_objects, &objectID, &object, &level, &ctx))
+ {
+ destroy(this);
+ return FALSE;
+ }
+ switch (objectID)
+ {
+ case PRIV_KEY_VERSION:
+ if (object.len > 0 && *object.ptr != 0)
+ {
+ destroy(this);
+ return NULL;
+ }
+ break;
+ case PRIV_KEY_MODULUS:
+ mpz_import(this->n, object.len, 1, 1, 1, 0, object.ptr);
+ break;
+ case PRIV_KEY_PUB_EXP:
+ mpz_import(this->e, object.len, 1, 1, 1, 0, object.ptr);
+ break;
+ case PRIV_KEY_PRIV_EXP:
+ mpz_import(this->d, object.len, 1, 1, 1, 0, object.ptr);
+ break;
+ case PRIV_KEY_PRIME1:
+ mpz_import(this->p, object.len, 1, 1, 1, 0, object.ptr);
+ break;
+ case PRIV_KEY_PRIME2:
+ mpz_import(this->q, object.len, 1, 1, 1, 0, object.ptr);
+ break;
+ case PRIV_KEY_EXP1:
+ mpz_import(this->exp1, object.len, 1, 1, 1, 0, object.ptr);
+ break;
+ case PRIV_KEY_EXP2:
+ mpz_import(this->exp2, object.len, 1, 1, 1, 0, object.ptr);
+ break;
+ case PRIV_KEY_COEFF:
+ mpz_import(this->coeff, object.len, 1, 1, 1, 0, object.ptr);
+ break;
+ }
+ objectID++;
+ }
+
+ this->k = (mpz_sizeinbase(this->n, 2) + 7) / 8;
+
+ /* form the keyid as a SHA-1 hash of a publicKeyInfo object */
+ {
+ chunk_t publicKeyInfo = rsa_public_key_info_to_asn1(this->n, this->e);
+ hasher_t *hasher = hasher_create(HASH_SHA1);
+
+ hasher->allocate_hash(hasher, publicKeyInfo, &this->keyid);
+ hasher->destroy(hasher);
+ free(publicKeyInfo.ptr);
+ }
+
+ if (check(this) != SUCCESS)
+ {
+ destroy(this);
+ return NULL;
+ }
+ else
+ {
+ return &this->public;
+ }
+}
+
+/*
+ * see header
+ */
+rsa_private_key_t *rsa_private_key_create_from_file(char *filename, chunk_t *passphrase)
+{
+ bool pgp = FALSE;
+ chunk_t chunk = chunk_empty;
+ rsa_private_key_t *key = NULL;
+
+ if (!pem_asn1_load_file(filename, passphrase, "private key", &chunk, &pgp))
+ return NULL;
+
+ key = rsa_private_key_create_from_chunk(chunk);
+ free(chunk.ptr);
+ return key;
+}
diff --git a/src/libstrongswan/crypto/rsa/rsa_private_key.h b/src/libstrongswan/crypto/rsa/rsa_private_key.h
new file mode 100644
index 000000000..9ec07704e
--- /dev/null
+++ b/src/libstrongswan/crypto/rsa/rsa_private_key.h
@@ -0,0 +1,184 @@
+/**
+ * @file rsa_private_key.h
+ *
+ * @brief Interface of rsa_private_key_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct rsa_private_key_t rsa_private_key_t;
+
+#include <library.h>
+#include <crypto/rsa/rsa_public_key.h>
+#include <crypto/hashers/hasher.h>
+
+/**
+ * @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 length.
+ *
+ * @param key_size size of the key in bits
+ * @return generated rsa_private_key_t.
+ *
+ * @ingroup rsa
+ */
+rsa_private_key_t *rsa_private_key_create(size_t key_size);
+
+/**
+ * @brief Load an RSA private key from a chunk.
+ *
+ * Load a key from a chunk, encoded as described in PKCS#1
+ * (ASN1 DER encoded).
+ *
+ * @param chunk chunk containing the DER encoded key
+ * @return loaded rsa_private_key_t, or NULL
+ *
+ * @ingroup rsa
+ */
+rsa_private_key_t *rsa_private_key_create_from_chunk(chunk_t chunk);
+
+/**
+ * @brief Load an RSA private key from a file.
+ *
+ * Load a key from a file, which is either in a unencrypted binary
+ * format (DER), or in a (encrypted) PEM format. The supplied
+ * passphrase is used to decrypt an ecrypted key.
+ *
+ * @param filename filename which holds the key
+ * @param passphrase optional passphase for decryption, can be NULL
+ * @return loaded rsa_private_key_t, or NULL
+ *
+ * @todo Implement PEM file loading
+ * @todo Implement key decryption
+ *
+ * @ingroup rsa
+ */
+rsa_private_key_t *rsa_private_key_create_from_file(char *filename, chunk_t *passphrase);
+
+#endif /*RSA_PRIVATE_KEY_H_*/
diff --git a/src/libstrongswan/crypto/rsa/rsa_public_key.c b/src/libstrongswan/crypto/rsa/rsa_public_key.c
new file mode 100644
index 000000000..38899670f
--- /dev/null
+++ b/src/libstrongswan/crypto/rsa/rsa_public_key.c
@@ -0,0 +1,497 @@
+/**
+ * @file rsa_public_key.c
+ *
+ * @brief Implementation of rsa_public_key_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <stdio.h>
+#include <string.h>
+
+#include "rsa_public_key.h"
+
+#include <crypto/hashers/hasher.h>
+#include <asn1/asn1.h>
+#include <asn1/pem.h>
+
+/*
+ * For simplicity, we use these predefined values for hash algorithm OIDs
+ * These also contain the length of the appended hash
+ * These values are also used in rsa_private_key.c.
+ */
+
+const u_int8_t md2_oid[] = {
+ 0x30,0x20,
+ 0x30,0x0c,
+ 0x06,0x08,
+ 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x02,
+ 0x05,0x00,
+ 0x04,0x10
+};
+
+const u_int8_t md5_oid[] = {
+ 0x30,0x20,
+ 0x30,0x0c,
+ 0x06,0x08,
+ 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,
+ 0x05,0x00,
+ 0x04,0x10
+};
+
+const u_int8_t sha1_oid[] = {
+ 0x30,0x21,
+ 0x30,0x09,
+ 0x06,0x05,
+ 0x2b,0x0e,0x03,0x02,0x1a,
+ 0x05,0x00,
+ 0x04,0x14
+};
+
+const u_int8_t sha256_oid[] = {
+ 0x30,0x31,
+ 0x30,0x0d,
+ 0x06,0x09,
+ 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,
+ 0x05,0x00,
+ 0x04,0x20
+};
+
+const u_int8_t sha384_oid[] = {
+ 0x30,0x41,
+ 0x30,0x0d,
+ 0x06,0x09,
+ 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02,
+ 0x05,0x00,
+ 0x04,0x30
+};
+
+const u_int8_t sha512_oid[] = {
+ 0x30,0x51,
+ 0x30,0x0d,
+ 0x06,0x09,
+ 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,
+ 0x05,0x00,
+ 0x04,0x40
+};
+
+#define LARGEST_HASH_OID_SIZE sizeof(sha512_oid)
+
+/* 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;
+
+ /**
+ * Keyid formed as a SHA-1 hash of a publicKeyInfo object
+ */
+ chunk_t keyid;
+
+ /**
+ * @brief Implements the RSAEP algorithm specified in PKCS#1.
+ *
+ * @param this calling object
+ * @param data data to process
+ * @return processed data
+ */
+ chunk_t (*rsaep) (const private_rsa_public_key_t *this, chunk_t data);
+
+ /**
+ * @brief Implements the RSASVP1 algorithm specified in PKCS#1.
+ *
+ * @param this calling object
+ * @param data data to process
+ * @return processed data
+ */
+ chunk_t (*rsavp1) (const private_rsa_public_key_t *this, chunk_t data);
+};
+
+private_rsa_public_key_t *rsa_public_key_create_empty(void);
+
+/**
+ * Implementation of private_rsa_public_key_t.rsaep and private_rsa_public_key_t.rsavp1
+ */
+static chunk_t rsaep(const private_rsa_public_key_t *this, chunk_t data)
+{
+ mpz_t m, c;
+ chunk_t encrypted;
+
+ mpz_init(c);
+ mpz_init(m);
+
+ mpz_import(m, data.len, 1, 1, 1, 0, data.ptr);
+
+ mpz_powm(c, m, this->e, this->n);
+
+ encrypted.len = this->k;
+ encrypted.ptr = mpz_export(NULL, NULL, 1, encrypted.len, 1, 0, c);
+
+ mpz_clear(c);
+ mpz_clear(m);
+
+ return encrypted;
+}
+
+/**
+ * Implementation of rsa_public_key.verify_emsa_pkcs1_signature.
+ */
+static status_t verify_emsa_pkcs1_signature(const 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;
+ status_t res = FAILED;
+
+ /* remove any preceding 0-bytes from signature */
+ while (signature.len && *(signature.ptr) == 0x00)
+ {
+ signature.len -= 1;
+ signature.ptr++;
+ }
+
+ if (signature.len > this->k)
+ {
+ return INVALID_ARG;
+ }
+
+ /* unpack signature */
+ em = 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))
+ {
+ goto end;
+ }
+
+ /* 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 ?!*/
+ goto end;
+ }
+ pos++;
+ }
+
+ if (pos + LARGEST_HASH_OID_SIZE > em.ptr + em.len)
+ {
+ /* not enought room for oid compare */
+ goto end;
+ }
+
+ if (memeq(md2_oid, pos, sizeof(md2_oid)))
+ {
+ hasher = hasher_create(HASH_MD2);
+ pos += sizeof(md2_oid);
+ }
+ else if (memeq(md5_oid, pos, sizeof(md5_oid)))
+ {
+ hasher = hasher_create(HASH_MD5);
+ pos += sizeof(md5_oid);
+ }
+ else if (memeq(sha1_oid, pos, sizeof(sha1_oid)))
+ {
+ hasher = hasher_create(HASH_SHA1);
+ pos += sizeof(sha1_oid);
+ }
+ else if (memeq(sha256_oid, pos, sizeof(sha256_oid)))
+ {
+ hasher = hasher_create(HASH_SHA256);
+ pos += sizeof(sha256_oid);
+ }
+ else if (memeq(sha384_oid, pos, sizeof(sha384_oid)))
+ {
+ hasher = hasher_create(HASH_SHA384);
+ pos += sizeof(sha384_oid);
+ }
+ else if (memeq(sha512_oid, pos, sizeof(sha512_oid)))
+ {
+ hasher = hasher_create(HASH_SHA512);
+ pos += sizeof(sha512_oid);
+ }
+
+ if (hasher == NULL)
+ {
+ /* unsupported hash algorithm */
+ res = NOT_SUPPORTED;;
+ goto end;
+ }
+
+ if (pos + hasher->get_hash_size(hasher) != em.ptr + em.len)
+ {
+ /* bad length */
+ hasher->destroy(hasher);
+ goto end;
+ }
+
+ /* build our own hash */
+ hasher->allocate_hash(hasher, data, &hash);
+ hasher->destroy(hasher);
+
+ /* compare the hashes */
+ res = memeq(hash.ptr, pos, hash.len) ? SUCCESS : FAILED;
+ free(hash.ptr);
+
+end:
+ free(em.ptr);
+ return res;
+}
+
+/**
+ * Implementation of rsa_public_key.get_key.
+ */
+static status_t get_key(const 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(const private_rsa_public_key_t *this, char *file)
+{
+ return NOT_SUPPORTED;
+}
+
+/**
+ * Implementation of rsa_public_key.get_modulus.
+ */
+static mpz_t *get_modulus(const private_rsa_public_key_t *this)
+{
+ return (mpz_t*)&this->n;
+}
+
+/**
+ * Implementation of rsa_public_key.get_keysize.
+ */
+static size_t get_keysize(const private_rsa_public_key_t *this)
+{
+ return this->k;
+}
+
+/**
+ * Implementation of rsa_public_key.get_keyid.
+ */
+static chunk_t get_keyid(const private_rsa_public_key_t *this)
+{
+ return this->keyid;
+}
+
+/**
+ * Implementation of rsa_public_key.clone.
+ */
+static rsa_public_key_t* _clone(const private_rsa_public_key_t *this)
+{
+ private_rsa_public_key_t *clone = rsa_public_key_create_empty();
+
+ mpz_init_set(clone->n, this->n);
+ mpz_init_set(clone->e, this->e);
+ clone->keyid = chunk_clone(this->keyid);
+ clone->k = this->k;
+
+ return &clone->public;
+}
+
+/**
+ * Implementation of rsa_public_key.destroy.
+ */
+static void destroy(private_rsa_public_key_t *this)
+{
+ mpz_clear(this->n);
+ mpz_clear(this->e);
+ free(this->keyid.ptr);
+ free(this);
+}
+
+/**
+ * Generic private constructor
+ */
+private_rsa_public_key_t *rsa_public_key_create_empty(void)
+{
+ private_rsa_public_key_t *this = malloc_thing(private_rsa_public_key_t);
+
+ /* public functions */
+ this->public.verify_emsa_pkcs1_signature = (status_t (*) (const rsa_public_key_t*,chunk_t,chunk_t))verify_emsa_pkcs1_signature;
+ this->public.get_key = (status_t (*) (const rsa_public_key_t*,chunk_t*))get_key;
+ this->public.save_key = (status_t (*) (const rsa_public_key_t*,char*))save_key;
+ this->public.get_modulus = (mpz_t *(*) (const rsa_public_key_t*))get_modulus;
+ this->public.get_keysize = (size_t (*) (const rsa_public_key_t*))get_keysize;
+ this->public.get_keyid = (chunk_t (*) (const rsa_public_key_t*))get_keyid;
+ this->public.clone = (rsa_public_key_t* (*) (const rsa_public_key_t*))_clone;
+ this->public.destroy = (void (*) (rsa_public_key_t*))destroy;
+
+ /* private functions */
+ this->rsaep = rsaep;
+ this->rsavp1 = rsaep; /* same algorithm */
+
+ return this;
+}
+
+/**
+ * Build a DER-encoded publicKeyInfo object from an RSA public key.
+ * Also used in rsa_private_key.c.
+ */
+chunk_t rsa_public_key_info_to_asn1(const mpz_t n, const mpz_t e)
+{
+ chunk_t rawKey = asn1_wrap(ASN1_SEQUENCE, "mm",
+ asn1_integer_from_mpz(n),
+ asn1_integer_from_mpz(e));
+ chunk_t publicKey;
+
+ u_char *pos = build_asn1_object(&publicKey, ASN1_BIT_STRING, 1 + rawKey.len);
+
+ *pos++ = 0x00;
+ memcpy(pos, rawKey.ptr, rawKey.len);
+ free(rawKey.ptr);
+
+ return asn1_wrap(ASN1_SEQUENCE, "cm", ASN1_rsaEncryption_id,
+ publicKey);
+}
+
+/*
+ * See header
+ */
+rsa_public_key_t *rsa_public_key_create_from_chunk(chunk_t blob)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+
+ private_rsa_public_key_t *this = rsa_public_key_create_empty();
+
+ mpz_init(this->n);
+ mpz_init(this->e);
+
+ asn1_init(&ctx, blob, 0, FALSE, FALSE);
+
+ while (objectID < PUB_KEY_ROOF)
+ {
+ if (!extract_object(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;
+
+ /* form the keyid as a SHA-1 hash of a publicKeyInfo object */
+ {
+ chunk_t publicKeyInfo = rsa_public_key_info_to_asn1(this->n, this->e);
+ hasher_t *hasher = hasher_create(HASH_SHA1);
+
+ hasher->allocate_hash(hasher, publicKeyInfo, &this->keyid);
+ hasher->destroy(hasher);
+ free(publicKeyInfo.ptr);
+ }
+
+ return &this->public;
+}
+
+/*
+ * See header
+ */
+rsa_public_key_t *rsa_public_key_create_from_file(char *filename)
+{
+ bool pgp = FALSE;
+ chunk_t chunk = chunk_empty;
+ rsa_public_key_t *pubkey = NULL;
+
+ if (!pem_asn1_load_file(filename, NULL, "public key", &chunk, &pgp))
+ return NULL;
+
+ pubkey = rsa_public_key_create_from_chunk(chunk);
+ free(chunk.ptr);
+ return pubkey;
+}
diff --git a/src/libstrongswan/crypto/rsa/rsa_public_key.h b/src/libstrongswan/crypto/rsa/rsa_public_key.h
new file mode 100644
index 000000000..1ee54dcc3
--- /dev/null
+++ b/src/libstrongswan/crypto/rsa/rsa_public_key.h
@@ -0,0 +1,164 @@
+/**
+ * @file rsa_public_key.h
+ *
+ * @brief Interface of rsa_public_key_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct rsa_public_key_t rsa_public_key_t;
+
+#include <gmp.h>
+
+#include <library.h>
+
+/**
+ * @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) (const 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) (const 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) (const 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) (const rsa_public_key_t *this);
+
+ /**
+ * @brief Get the size of the modulus in bytes.
+ *
+ * @param this calling object
+ * @return size of the modulus (n) in bytes
+ */
+ size_t (*get_keysize) (const rsa_public_key_t *this);
+
+ /**
+ * @brief Get the keyid formed as the SHA-1 hash of a publicKeyInfo object.
+ *
+ * @param this calling object
+ * @return keyid in the form of a SHA-1 hash
+ */
+ chunk_t (*get_keyid) (const rsa_public_key_t *this);
+
+ /**
+ * @brief Clone the public key.
+ *
+ * @param this public key to clone
+ * @return clone of this
+ */
+ rsa_public_key_t *(*clone) (const rsa_public_key_t *this);
+
+ /**
+ * @brief Destroys the public key.
+ *
+ * @param this public key to destroy
+ */
+ void (*destroy) (rsa_public_key_t *this);
+};
+
+/**
+ * @brief Load an RSA public key from a chunk.
+ *
+ * Load a key from a chunk, encoded in the more frequently
+ * used publicKeyInfo object (ASN1 DER encoded).
+ *
+ * @param chunk chunk containing the DER encoded key
+ * @return loaded rsa_public_key_t, or NULL
+ *
+ * @ingroup rsa
+ */
+rsa_public_key_t *rsa_public_key_create_from_chunk(chunk_t chunk);
+
+/**
+ * @brief Load an RSA public key from a file.
+ *
+ * Load a key from a file, which is either in binary
+ * format (DER), or in PEM format.
+ *
+ * @param filename filename which holds the key
+ * @return loaded rsa_public_key_t, or NULL
+ *
+ * @ingroup rsa
+ */
+rsa_public_key_t *rsa_public_key_create_from_file(char *filename);
+
+#endif /*RSA_PUBLIC_KEY_H_*/
diff --git a/src/libstrongswan/crypto/signers/hmac_signer.c b/src/libstrongswan/crypto/signers/hmac_signer.c
new file mode 100644
index 000000000..76e1ce50e
--- /dev/null
+++ b/src/libstrongswan/crypto/signers/hmac_signer.c
@@ -0,0 +1,174 @@
+/**
+ * @file hmac_signer.c
+ *
+ * @brief Implementation of hmac_signer_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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>
+
+typedef struct private_hmac_signer_t private_hmac_signer_t;
+
+/**
+ * Private data structure with signing context.
+ */
+struct private_hmac_signer_t {
+ /**
+ * Public interface of hmac_signer_t.
+ */
+ hmac_signer_t public;
+
+ /**
+ * Assigned hmac function.
+ */
+ prf_t *hmac_prf;
+
+ /**
+ * Block size (truncation of HMAC Hash)
+ */
+ size_t block_size;
+};
+
+/**
+ * Implementation of signer_t.get_signature.
+ */
+static void get_signature (private_hmac_signer_t *this, chunk_t data, u_int8_t *buffer)
+{
+ 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 depending on truncation */
+ memcpy(buffer, full_mac, this->block_size);
+}
+
+/**
+ * Implementation of signer_t.allocate_signature.
+ */
+static void allocate_signature (private_hmac_signer_t *this, chunk_t data, chunk_t *chunk)
+{
+ chunk_t signature;
+ u_int8_t full_mac[this->hmac_prf->get_block_size(this->hmac_prf)];
+
+ this->hmac_prf->get_bytes(this->hmac_prf,data,full_mac);
+
+ signature.ptr = malloc(this->block_size);
+ signature.len = this->block_size;
+
+ /* copy signature */
+ memcpy(signature.ptr, full_mac, this->block_size);
+
+ *chunk = signature;
+}
+
+/**
+ * Implementation of signer_t.verify_signature.
+ */
+static bool verify_signature(private_hmac_signer_t *this, chunk_t data, chunk_t signature)
+{
+ u_int8_t full_mac[this->hmac_prf->get_block_size(this->hmac_prf)];
+
+ this->hmac_prf->get_bytes(this->hmac_prf, data, full_mac);
+
+ if (signature.len != this->block_size)
+ {
+ return FALSE;
+ }
+
+ /* compare mac aka signature :-) */
+ if (memcmp(signature.ptr, full_mac, this->block_size) == 0)
+ {
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+/**
+ * Implementation of signer_t.get_key_size.
+ */
+static size_t get_key_size(private_hmac_signer_t *this)
+{
+ /* for HMAC signer, IKEv2 uses block size as key size */
+ return this->hmac_prf->get_block_size(this->hmac_prf);
+}
+
+/**
+ * Implementation of signer_t.get_block_size.
+ */
+static size_t get_block_size(private_hmac_signer_t *this)
+{
+ return this->block_size;
+}
+
+/**
+ * Implementation of signer_t.set_key.
+ */
+static void set_key(private_hmac_signer_t *this, chunk_t key)
+{
+ this->hmac_prf->set_key(this->hmac_prf, key);
+}
+
+/**
+ * Implementation of signer_t.destroy.
+ */
+static status_t destroy(private_hmac_signer_t *this)
+{
+ this->hmac_prf->destroy(this->hmac_prf);
+ free(this);
+ return SUCCESS;
+}
+
+/*
+ * Described in header
+ */
+hmac_signer_t *hmac_signer_create(hash_algorithm_t hash_algoritm, size_t block_size)
+{
+ size_t hmac_block_size;
+ private_hmac_signer_t *this = malloc_thing(private_hmac_signer_t);
+
+ this->hmac_prf = (prf_t *) hmac_prf_create(hash_algoritm);
+ if (this->hmac_prf == NULL)
+ {
+ /* algorithm not supported */
+ free(this);
+ return NULL;
+ }
+
+ /* prevent invalid truncation */
+ hmac_block_size = this->hmac_prf->get_block_size(this->hmac_prf);
+ this->block_size = min(block_size, hmac_block_size);
+
+ /* interface functions */
+ this->public.signer_interface.get_signature = (void (*) (signer_t*, chunk_t, u_int8_t*))get_signature;
+ this->public.signer_interface.allocate_signature = (void (*) (signer_t*, chunk_t, chunk_t*))allocate_signature;
+ this->public.signer_interface.verify_signature = (bool (*) (signer_t*, chunk_t, chunk_t))verify_signature;
+ this->public.signer_interface.get_key_size = (size_t (*) (signer_t*))get_key_size;
+ this->public.signer_interface.get_block_size = (size_t (*) (signer_t*))get_block_size;
+ this->public.signer_interface.set_key = (void (*) (signer_t*,chunk_t))set_key;
+ this->public.signer_interface.destroy = (void (*) (signer_t*))destroy;
+
+ return &(this->public);
+}
diff --git a/src/libstrongswan/crypto/signers/hmac_signer.h b/src/libstrongswan/crypto/signers/hmac_signer.h
new file mode 100644
index 000000000..2449069bd
--- /dev/null
+++ b/src/libstrongswan/crypto/signers/hmac_signer.h
@@ -0,0 +1,68 @@
+/**
+ * @file hmac_signer.h
+ *
+ * @brief Interface of hmac_signer_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef HMAC_SIGNER_H_
+#define HMAC_SIGNER_H_
+
+typedef struct hmac_signer_t hmac_signer_t;
+
+#include <crypto/signers/signer.h>
+#include <crypto/hashers/hasher.h>
+
+/**
+ * @brief Implementation of signer_t interface using HMAC.
+ *
+ * HMAC uses a standard hash function implemented in a hasher_t to build
+ * a MAC.
+ *
+ * @ingroup signers
+ */
+struct hmac_signer_t {
+
+ /**
+ * generic signer_t interface for this signer
+ */
+ signer_t signer_interface;
+};
+
+/**
+ * @brief Creates a new hmac_signer_t.
+ *
+ * HMAC signatures are often truncated to shorten them to a more usable, but
+ * still secure enough length.
+ * Block size must be equal or smaller then the hash algorithms
+ * hash.
+ *
+ * @param hash_algoritm Hash algorithm to use with signer
+ * @param block_size Size of resulting signature (truncated to block_size)
+ * @return
+ * - hmac_signer_t
+ * - NULL if hash algorithm not supported
+ *
+ * @ingroup signers
+ */
+hmac_signer_t *hmac_signer_create(hash_algorithm_t hash_algoritm,
+ size_t block_size);
+
+
+#endif /*HMAC_SIGNER_H_*/
diff --git a/src/libstrongswan/crypto/signers/signer.c b/src/libstrongswan/crypto/signers/signer.c
new file mode 100644
index 000000000..747bc5efa
--- /dev/null
+++ b/src/libstrongswan/crypto/signers/signer.c
@@ -0,0 +1,65 @@
+/**
+ * @file signer.c
+ *
+ * @brief Implementation of generic signer_t constructor.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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>
+
+ENUM_BEGIN(integrity_algorithm_names, AUTH_UNDEFINED, AUTH_HMAC_SHA1_128,
+ "UNDEFINED",
+ "AUTH_HMAC_SHA1_128");
+ENUM_NEXT(integrity_algorithm_names, AUTH_HMAC_MD5_96, AUTH_AES_XCBC_96, AUTH_HMAC_SHA1_128,
+ "HMAC_MD5_96",
+ "HMAC_SHA1_96",
+ "DES_MAC",
+ "KPDK_MD5",
+ "AES_XCBC_96");
+ENUM_NEXT(integrity_algorithm_names, AUTH_HMAC_SHA2_256_128, AUTH_HMAC_SHA2_512_256, AUTH_AES_XCBC_96,
+ "AUTH_HMAC_SHA2_256_128",
+ "AUTH_HMAC_SHA2_384_192",
+ "AUTH_HMAC_SHA2_512_256");
+ENUM_END(integrity_algorithm_names, AUTH_HMAC_SHA2_512_256);
+
+/*
+ * Described in header.
+ */
+signer_t *signer_create(integrity_algorithm_t integrity_algorithm)
+{
+ switch(integrity_algorithm)
+ {
+ case AUTH_HMAC_SHA1_96:
+ return (signer_t *)hmac_signer_create(HASH_SHA1, 12);
+ case AUTH_HMAC_SHA1_128:
+ return (signer_t *)hmac_signer_create(HASH_SHA1, 16);
+ case AUTH_HMAC_MD5_96:
+ return (signer_t *)hmac_signer_create(HASH_MD5, 12);
+ case AUTH_HMAC_SHA2_256_128:
+ return (signer_t *)hmac_signer_create(HASH_SHA256, 16);
+ case AUTH_HMAC_SHA2_384_192:
+ return (signer_t *)hmac_signer_create(HASH_SHA384, 24);
+ case AUTH_HMAC_SHA2_512_256:
+ return (signer_t *)hmac_signer_create(HASH_SHA512, 32);
+ default:
+ return NULL;
+ }
+}
diff --git a/src/libstrongswan/crypto/signers/signer.h b/src/libstrongswan/crypto/signers/signer.h
new file mode 100644
index 000000000..0f3709712
--- /dev/null
+++ b/src/libstrongswan/crypto/signers/signer.h
@@ -0,0 +1,147 @@
+/**
+ * @file signer.h
+ *
+ * @brief Interface for signer_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef enum integrity_algorithm_t integrity_algorithm_t;
+typedef struct signer_t signer_t;
+
+#include <library.h>
+
+/**
+ * @brief Integrity algorithm, as in IKEv2 RFC 3.3.2.
+ *
+ * Algorithms not specified in IKEv2 are allocated in private use space.
+ *
+ * @ingroup signers
+ */
+enum integrity_algorithm_t {
+ AUTH_UNDEFINED = 1024,
+ /** Implemented via hmac_signer_t */
+ AUTH_HMAC_MD5_96 = 1,
+ /** Implemented via hmac_signer_t */
+ AUTH_HMAC_SHA1_96 = 2,
+ AUTH_DES_MAC = 3,
+ AUTH_KPDK_MD5 = 4,
+ AUTH_AES_XCBC_96 = 5,
+ /** Implemented via hmac_signer_t */
+ AUTH_HMAC_SHA2_256_128 = 12,
+ /** Implemented via hmac_signer_t */
+ AUTH_HMAC_SHA2_384_192 = 13,
+ /** Implemented via hmac_signer_t */
+ AUTH_HMAC_SHA2_512_256 = 14,
+ /** Implemented via hmac_signer_t */
+ AUTH_HMAC_SHA1_128 = 1025,
+};
+
+/**
+ * enum names for integrity_algorithm_t.
+ */
+extern enum_name_t *integrity_algorithm_names;
+
+/**
+ * @brief Generig interface for a symmetric signature algorithm.
+ *
+ * @b Constructors:
+ * - signer_create()
+ * - hmac_signer_create()
+ *
+ * @todo Implement more integrity algorithms
+ *
+ * @ingroup signers
+ */
+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/src/libstrongswan/crypto/x509.c b/src/libstrongswan/crypto/x509.c
new file mode 100755
index 000000000..58fcff16d
--- /dev/null
+++ b/src/libstrongswan/crypto/x509.c
@@ -0,0 +1,1354 @@
+/**
+ * @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 <stdio.h>
+
+#include "x509.h"
+#include "hashers/hasher.h"
+#include <library.h>
+#include <debug.h>
+#include <asn1/oid.h>
+#include <asn1/asn1.h>
+#include <asn1/pem.h>
+#include <utils/linked_list.h>
+#include <utils/identification.h>
+
+#define CERT_WARNING_INTERVAL 30 /* days */
+
+/**
+ * Different kinds of generalNames
+ */
+typedef enum generalNames_t generalNames_t;
+
+enum generalNames_t {
+ GN_OTHER_NAME = 0,
+ GN_RFC822_NAME = 1,
+ GN_DNS_NAME = 2,
+ GN_X400_ADDRESS = 3,
+ GN_DIRECTORY_NAME = 4,
+ GN_EDI_PARTY_NAME = 5,
+ GN_URI = 6,
+ GN_IP_ADDRESS = 7,
+ GN_REGISTERED_ID = 8,
+};
+
+typedef struct private_x509_t private_x509_t;
+
+/**
+ * Private data of a x509_t object.
+ */
+struct private_x509_t {
+ /**
+ * Public interface for this certificate.
+ */
+ x509_t public;
+
+ /**
+ * Time when certificate was installed
+ */
+ time_t installed;
+
+ /**
+ * Time until certificate can be trusted
+ */
+ time_t until;
+
+ /**
+ * Certificate status
+ */
+ cert_status_t status;
+
+ /**
+ * Authority flags
+ */
+ u_int authority_flags;
+
+ /**
+ * X.509 Certificate in DER format
+ */
+ chunk_t certificate;
+
+ /**
+ * X.509 certificate body over which signature is computed
+ */
+ chunk_t tbsCertificate;
+
+ /**
+ * Version of the X.509 certificate
+ */
+ u_int version;
+
+ /**
+ * Serial number of the X.509 certificate
+ */
+ chunk_t serialNumber;
+
+ /**
+ * Signature algorithm
+ */
+ int sigAlg;
+
+ /**
+ * ID representing the certificate issuer
+ */
+ identification_t *issuer;
+
+ /**
+ * Start time of certificate validity
+ */
+ time_t notBefore;
+
+ /**
+ * End time of certificate validity
+ */
+ time_t notAfter;
+
+ /**
+ * ID representing the certificate subject
+ */
+ identification_t *subject;
+
+ /**
+ * List of identification_t's representing subjectAltNames
+ */
+ linked_list_t *subjectAltNames;
+
+ /**
+ * List of identification_t's representing crlDistributionPoints
+ */
+ linked_list_t *crlDistributionPoints;
+
+ /**
+ * List of identification_t's representing ocspAccessLocations
+ */
+ linked_list_t *ocspAccessLocations;
+
+ /**
+ * Subject public key
+ */
+ chunk_t subjectPublicKey;
+
+ /**
+ * Subject RSA public key, if subjectPublicKeyAlgorithm == RSA
+ */
+ rsa_public_key_t *public_key;
+
+ /**
+ * Subject Key Identifier
+ */
+ chunk_t subjectKeyID;
+
+ /**
+ * Authority Key Identifier
+ */
+ chunk_t authKeyID;
+
+ /**
+ * Authority Key Serial Number
+ */
+ chunk_t authKeySerialNumber;
+
+ /**
+ * CA basic constraints flag
+ */
+ bool isCA;
+
+ /**
+ * OCSPSigner extended key usage flag
+ */
+ bool isOcspSigner;
+
+ /**
+ * Signature algorithm (must be identical to sigAlg)
+ */
+ int algorithm;
+
+ /**
+ * Signature
+ */
+ chunk_t signature;
+
+};
+
+/**
+ * ASN.1 definition of generalName
+ */
+static const asn1Object_t generalNameObjects[] = {
+ { 0, "otherName", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_BODY }, /* 0 */
+ { 0, "end choice", ASN1_EOC, ASN1_END }, /* 1 */
+ { 0, "rfc822Name", ASN1_CONTEXT_S_1, ASN1_OPT|ASN1_BODY }, /* 2 */
+ { 0, "end choice", ASN1_EOC, ASN1_END }, /* 3 */
+ { 0, "dnsName", ASN1_CONTEXT_S_2, ASN1_OPT|ASN1_BODY }, /* 4 */
+ { 0, "end choice", ASN1_EOC, ASN1_END }, /* 5 */
+ { 0, "x400Address", ASN1_CONTEXT_S_3, ASN1_OPT|ASN1_BODY }, /* 6 */
+ { 0, "end choice", ASN1_EOC, ASN1_END }, /* 7 */
+ { 0, "directoryName", ASN1_CONTEXT_C_4, ASN1_OPT|ASN1_BODY }, /* 8 */
+ { 0, "end choice", ASN1_EOC, ASN1_END }, /* 9 */
+ { 0, "ediPartyName", ASN1_CONTEXT_C_5, ASN1_OPT|ASN1_BODY }, /* 10 */
+ { 0, "end choice", ASN1_EOC, ASN1_END }, /* 11 */
+ { 0, "URI", ASN1_CONTEXT_S_6, ASN1_OPT|ASN1_BODY }, /* 12 */
+ { 0, "end choice", ASN1_EOC, ASN1_END }, /* 13 */
+ { 0, "ipAddress", ASN1_CONTEXT_S_7, ASN1_OPT|ASN1_BODY }, /* 14 */
+ { 0, "end choice", ASN1_EOC, ASN1_END }, /* 15 */
+ { 0, "registeredID", ASN1_CONTEXT_S_8, ASN1_OPT|ASN1_BODY }, /* 16 */
+ { 0, "end choice", ASN1_EOC, ASN1_END } /* 17 */
+};
+#define GN_OBJ_OTHER_NAME 0
+#define GN_OBJ_RFC822_NAME 2
+#define GN_OBJ_DNS_NAME 4
+#define GN_OBJ_X400_ADDRESS 6
+#define GN_OBJ_DIRECTORY_NAME 8
+#define GN_OBJ_EDI_PARTY_NAME 10
+#define GN_OBJ_URI 12
+#define GN_OBJ_IP_ADDRESS 14
+#define GN_OBJ_REGISTERED_ID 16
+#define GN_OBJ_ROOF 18
+
+/**
+ * ASN.1 definition of otherName
+ */
+static const asn1Object_t otherNameObjects[] = {
+ {0, "type-id", ASN1_OID, ASN1_BODY }, /* 0 */
+ {0, "value", ASN1_CONTEXT_C_0, ASN1_BODY } /* 1 */
+};
+#define ON_OBJ_ID_TYPE 0
+#define ON_OBJ_VALUE 1
+#define ON_OBJ_ROOF 2
+/**
+ * ASN.1 definition of a basicConstraints extension
+ */
+static const asn1Object_t basicConstraintsObjects[] = {
+ { 0, "basicConstraints", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "CA", ASN1_BOOLEAN, ASN1_DEF|ASN1_BODY }, /* 1 */
+ { 1, "pathLenConstraint", ASN1_INTEGER, ASN1_OPT|ASN1_BODY }, /* 2 */
+ { 1, "end opt", ASN1_EOC, ASN1_END } /* 3 */
+};
+#define BASIC_CONSTRAINTS_CA 1
+#define BASIC_CONSTRAINTS_ROOF 4
+
+/**
+ * ASN.1 definition of 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(const private_x509_t *this, const private_x509_t *other)
+{
+ return chunk_equals(this->signature, other->signature);
+}
+
+/**
+ * extracts the basicConstraints extension
+ */
+static bool parse_basicConstraints(chunk_t blob, int level0)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+ bool isCA = FALSE;
+
+ asn1_init(&ctx, blob, level0, FALSE, FALSE);
+
+ while (objectID < BASIC_CONSTRAINTS_ROOF) {
+
+ if (!extract_object(basicConstraintsObjects, &objectID, &object,&level, &ctx))
+ {
+ break;
+ }
+ if (objectID == BASIC_CONSTRAINTS_CA)
+ {
+ isCA = object.len && *object.ptr;
+ DBG2(" %s", isCA ? "TRUE" : "FALSE");
+ }
+ objectID++;
+ }
+ return isCA;
+}
+
+/*
+ * extracts an otherName
+ */
+static bool
+parse_otherName(chunk_t blob, int level0)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ int objectID = 0;
+ u_int level;
+ int oid = OID_UNKNOWN;
+
+ asn1_init(&ctx, blob, level0, FALSE, FALSE);
+
+ while (objectID < ON_OBJ_ROOF)
+ {
+ if (!extract_object(otherNameObjects, &objectID, &object, &level, &ctx))
+ return FALSE;
+
+ switch (objectID)
+ {
+ case ON_OBJ_ID_TYPE:
+ oid = known_oid(object);
+ break;
+ case ON_OBJ_VALUE:
+ if (oid == OID_XMPP_ADDR)
+ {
+ if (!parse_asn1_simple_object(&object, ASN1_UTF8STRING, level + 1, "xmppAddr"))
+ return FALSE;
+ }
+ break;
+ default:
+ break;
+ }
+ objectID++;
+ }
+ return TRUE;
+}
+
+/*
+ * extracts a generalName
+ */
+static identification_t *parse_generalName(chunk_t blob, int level0)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ int objectID = 0;
+ u_int level;
+
+ asn1_init(&ctx, blob, level0, FALSE, FALSE);
+
+ while (objectID < GN_OBJ_ROOF)
+ {
+ id_type_t id_type = ID_ANY;
+
+ if (!extract_object(generalNameObjects, &objectID, &object, &level, &ctx))
+ return NULL;
+
+ switch (objectID)
+ {
+ case GN_OBJ_RFC822_NAME:
+ id_type = ID_RFC822_ADDR;
+ break;
+ case GN_OBJ_DNS_NAME:
+ id_type = ID_FQDN;
+ break;
+ case GN_OBJ_URI:
+ id_type = ID_DER_ASN1_GN_URI;
+ break;
+ case GN_OBJ_DIRECTORY_NAME:
+ id_type = ID_DER_ASN1_DN;
+ break;
+ case GN_OBJ_IP_ADDRESS:
+ id_type = ID_IPV4_ADDR;
+ break;
+ case GN_OBJ_OTHER_NAME:
+ if (!parse_otherName(object, level + 1))
+ return NULL;
+ break;
+ case GN_OBJ_X400_ADDRESS:
+ case GN_OBJ_EDI_PARTY_NAME:
+ case GN_OBJ_REGISTERED_ID:
+ break;
+ default:
+ break;
+ }
+
+ if (id_type != ID_ANY)
+ {
+ identification_t *gn = identification_create_from_encoding(id_type, object);
+ DBG2(" '%D'", gn);
+ return gn;
+ }
+ objectID++;
+ }
+ return NULL;
+}
+
+
+/**
+ * extracts one or several GNs and puts them into a chained list
+ */
+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, FALSE);
+
+ while (objectID < GENERAL_NAMES_ROOF)
+ {
+ if (!extract_object(generalNamesObjects, &objectID, &object, &level, &ctx))
+ return;
+
+ if (objectID == GENERAL_NAMES_GN)
+ {
+ identification_t *gn = parse_generalName(object, level+1);
+
+ if (gn != NULL)
+ list->insert_last(list, (void *)gn);
+ }
+ objectID++;
+ }
+ return;
+}
+
+/**
+ * extracts 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, 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, FALSE);
+
+ 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, FALSE);
+ while (objectID < AUTH_KEY_ID_ROOF)
+ {
+ if (!extract_object(authorityKeyIdentifierObjects, &objectID, &object, &level, &ctx))
+ {
+ return;
+ }
+ switch (objectID)
+ {
+ case AUTH_KEY_ID_KEY_ID:
+ *authKeyID = parse_keyIdentifier(object, level+1, TRUE);
+ break;
+ case AUTH_KEY_ID_CERT_ISSUER:
+ {
+ /* TODO: parse_generalNames(object, level+1, TRUE); */
+ break;
+ }
+ case AUTH_KEY_ID_CERT_SERIAL:
+ *authKeySerialNumber = object;
+ break;
+ default:
+ break;
+ }
+ objectID++;
+ }
+}
+
+/**
+ * extracts an authorityInfoAcess location
+ */
+static void parse_authorityInfoAccess(chunk_t blob, int level0, linked_list_t *list)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+
+ u_int accessMethod = OID_UNKNOWN;
+
+ asn1_init(&ctx, blob, level0, FALSE, FALSE);
+ while (objectID < AUTH_INFO_ACCESS_ROOF)
+ {
+ if (!extract_object(authorityInfoAccessObjects, &objectID, &object, &level, &ctx))
+ {
+ return;
+ }
+ switch (objectID)
+ {
+ case AUTH_INFO_ACCESS_METHOD:
+ accessMethod = known_oid(object);
+ break;
+ case AUTH_INFO_ACCESS_LOCATION:
+ {
+ switch (accessMethod)
+ {
+ case OID_OCSP:
+ if (*object.ptr == ASN1_CONTEXT_S_6)
+ {
+ identification_t *accessLocation;
+
+ if (asn1_length(&object) == ASN1_INVALID_LENGTH)
+ return;
+ DBG2(" '%.*s'",(int)object.len, object.ptr);
+ accessLocation = identification_create_from_encoding(ID_DER_ASN1_GN_URI, object);
+ list->insert_last(list, (void *)accessLocation);
+ }
+ break;
+ default:
+ /* unkown accessMethod, ignoring */
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ objectID++;
+ }
+}
+
+/**
+ * extracts extendedKeyUsage OIDs
+ */
+static bool parse_extendedKeyUsage(chunk_t blob, int level0)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+
+ asn1_init(&ctx, blob, level0, FALSE, FALSE);
+ while (objectID < EXT_KEY_USAGE_ROOF)
+ {
+ if (!extract_object(extendedKeyUsageObjects, &objectID, &object, &level, &ctx))
+ {
+ return FALSE;
+ }
+ if (objectID == EXT_KEY_USAGE_PURPOSE_ID &&
+ known_oid(object) == OID_OCSP_SIGNING)
+ {
+ return TRUE;
+ }
+ objectID++;
+ }
+ return FALSE;
+}
+
+/**
+ * extracts one or several crlDistributionPoints and puts them into
+ * a chained list
+ */
+static void parse_crlDistributionPoints(chunk_t blob, int level0, linked_list_t *list)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+
+ asn1_init(&ctx, blob, level0, FALSE, FALSE);
+ while (objectID < CRL_DIST_POINTS_ROOF)
+ {
+ if (!extract_object(crlDistributionPointsObjects, &objectID, &object, &level, &ctx))
+ {
+ return;
+ }
+ if (objectID == CRL_DIST_POINTS_FULLNAME)
+ {
+ /* append extracted generalNames to existing chained list */
+ parse_generalNames(object, level+1, TRUE, list);
+
+ }
+ objectID++;
+ }
+}
+
+
+/**
+ * Parses an X.509v3 certificate
+ */
+static bool parse_certificate(chunk_t blob, u_int level0, private_x509_t *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, 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->certificate = 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;
+ DBG2(" 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);
+ DBG2(" '%D'", cert->issuer);
+ 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);
+ DBG2(" '%D'", cert->subject);
+ break;
+ case X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM:
+ if (parse_algorithmIdentifier(object, level, NULL) != OID_RSA_ENCRYPTION)
+ {
+ DBG2(" 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
+ {
+ DBG2(" 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;
+ DBG2(" %s", critical ? "TRUE" : "FALSE");
+ break;
+ case X509_OBJ_EXTN_VALUE:
+ {
+ switch (extn_oid) {
+ case OID_SUBJECT_KEY_ID:
+ cert->subjectKeyID = chunk_clone(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->ocspAccessLocations);
+ 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++;
+ }
+
+ if (cert->subjectKeyID.ptr == NULL)
+ {
+ hasher_t *hasher = hasher_create(HASH_SHA1);
+
+ hasher->allocate_hash(hasher, cert->subjectPublicKey, &cert->subjectKeyID);
+ hasher->destroy(hasher);
+ }
+
+ time(&cert->installed);
+ return TRUE;
+}
+
+/**
+ * Implements x509_t.is_valid
+ */
+static err_t is_valid(const private_x509_t *this, time_t *until)
+{
+ time_t current_time = time(NULL);
+
+ DBG2(" not before : %T", &this->notBefore);
+ DBG2(" current time: %T", &current_time);
+ DBG2(" not after : %T", &this->notAfter);
+
+ if (until != NULL &&
+ (*until == UNDEFINED_TIME || this->notAfter < *until))
+ {
+ *until = this->notAfter;
+ }
+ if (current_time < this->notBefore)
+ {
+ return "is not valid yet";
+ }
+ if (current_time > this->notAfter)
+ {
+ return "has expired";
+ }
+ DBG2(" certificate is valid");
+ return NULL;
+}
+
+/**
+ * Implements x509_t.is_ca
+ */
+static bool is_ca(const private_x509_t *this)
+{
+ return this->isCA;
+}
+
+/**
+ * Implements x509_t.is_ocsp_signer
+ */
+static bool is_ocsp_signer(const private_x509_t *this)
+{
+ return this->isOcspSigner;
+}
+
+/**
+ * Implements x509_t.is_self_signed
+ */
+static bool is_self_signed(const private_x509_t *this)
+{
+ return this->subject->equals(this->subject, this->issuer);
+}
+
+/**
+ * Implements x509_t.equals_subjectAltName
+ */
+static bool equals_subjectAltName(const private_x509_t *this, identification_t *id)
+{
+ bool found = FALSE;
+ identification_t *subjectAltName;
+ iterator_t *iterator;
+
+ iterator = this->subjectAltNames->create_iterator(this->subjectAltNames, TRUE);
+ while (iterator->iterate(iterator, (void**)&subjectAltName))
+ {
+ if (id->equals(id, subjectAltName))
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ return found;
+}
+
+/**
+ * Implements x509_t.is_issuer
+ */
+static bool is_issuer(const private_x509_t *this, const private_x509_t *issuer)
+{
+ return (this->authKeyID.ptr)
+ ? chunk_equals(this->authKeyID, issuer->subjectKeyID)
+ : (this->issuer->equals(this->issuer, issuer->subject)
+ && chunk_equals_or_null(this->authKeySerialNumber, issuer->serialNumber));
+}
+
+/**
+ * Implements x509_t.get_certificate
+ */
+static chunk_t get_certificate(const private_x509_t *this)
+{
+ return this->certificate;
+}
+
+/**
+ * Implements x509_t.get_public_key
+ */
+static rsa_public_key_t *get_public_key(const private_x509_t *this)
+{
+ return this->public_key;
+}
+
+/**
+ * Implements x509_t.get_serialNumber
+ */
+static chunk_t get_serialNumber(const private_x509_t *this)
+{
+ return this->serialNumber;
+}
+
+/**
+ * Implements x509_t.get_subjectKeyID
+ */
+static chunk_t get_subjectKeyID(const private_x509_t *this)
+{
+ return this->subjectKeyID;
+}
+
+/**
+ * Implements x509_t.get_keyid
+ */
+static chunk_t get_keyid(const private_x509_t *this)
+{
+ return this->public_key->get_keyid(this->public_key);
+}
+
+/**
+ * Implements x509_t.get_issuer
+ */
+static identification_t *get_issuer(const private_x509_t *this)
+{
+ return this->issuer;
+}
+
+/**
+ * Implements x509_t.get_subject
+ */
+static identification_t *get_subject(const private_x509_t *this)
+{
+ return this->subject;
+}
+
+/**
+ * Implements x509_t.set_until
+ */
+static void set_until(private_x509_t *this, time_t until)
+{
+ this->until = until;
+}
+
+/**
+ * Implements x509_t.get_until
+ */
+static time_t get_until(const private_x509_t *this)
+{
+ return this->until;
+}
+
+/**
+ * Implements x509_t.set_status
+ */
+static void set_status(private_x509_t *this, cert_status_t status)
+{
+ this->status = status;
+}
+
+/**
+ * Implements x509_t.get_status
+ */
+static cert_status_t get_status(const private_x509_t *this)
+{
+ return this->status;
+}
+
+/**
+ * Implements x509_t.add_authority_flags
+ */
+static void add_authority_flags(private_x509_t *this, u_int flags)
+{
+ this->authority_flags |= flags;
+}
+
+/**
+ * Implements x509_t.add_authority_flags
+ */
+static u_int get_authority_flags(private_x509_t *this)
+{
+ return this->authority_flags;
+}
+
+/**
+ * Implements x509_t.has_authority_flag
+ */
+static bool has_authority_flag(private_x509_t *this, u_int flags)
+{
+ return (this->authority_flags & flags) != AUTH_NONE;
+}
+
+/**
+ * Implements x509_t.create_crluri_iterator
+ */
+static iterator_t *create_crluri_iterator(const private_x509_t *this)
+{
+ return this->crlDistributionPoints->create_iterator(this->crlDistributionPoints, TRUE);
+}
+
+/**
+ * Implements x509_t.create_crluri_iterator
+ */
+static iterator_t *create_ocspuri_iterator(const private_x509_t *this)
+{
+ return this->ocspAccessLocations->create_iterator(this->ocspAccessLocations, TRUE);
+}
+
+/**
+ * Implements x509_t.verify
+ */
+static bool verify(const private_x509_t *this, const rsa_public_key_t *signer)
+{
+ return signer->verify_emsa_pkcs1_signature(signer, this->tbsCertificate, this->signature) == SUCCESS;
+}
+
+/**
+ * output handler in printf()
+ */
+static int print(FILE *stream, const struct printf_info *info,
+ const void *const *args)
+{
+ private_x509_t *this = *((private_x509_t**)(args[0]));
+ iterator_t *iterator;
+ bool utc = TRUE;
+ int written = 0;
+
+ if (info->alt)
+ {
+ utc = *((bool*)(args[1]));
+ }
+
+ if (this == NULL)
+ {
+ return fprintf(stream, "(null)");
+ }
+
+ /* determine the current time */
+ time_t now = time(NULL);
+
+ written += fprintf(stream, "%#T\n", &this->installed, utc);
+
+ if (this->subjectAltNames->get_count(this->subjectAltNames))
+ {
+ identification_t *subjectAltName;
+ bool first = TRUE;
+
+ written += fprintf(stream, " altNames: ");
+ iterator = this->subjectAltNames->create_iterator(this->subjectAltNames, TRUE);
+ while (iterator->iterate(iterator, (void**)&subjectAltName))
+ {
+ if (first)
+ {
+ first = FALSE;
+ }
+ else
+ {
+ written += fprintf(stream, ", ");
+ }
+ written += fprintf(stream, "'%D'", subjectAltName);
+ }
+ iterator->destroy(iterator);
+ written += fprintf(stream, "\n");
+ }
+ written += fprintf(stream, " subject: '%D'\n", this->subject);
+ written += fprintf(stream, " issuer: '%D'\n", this->issuer);
+ written += fprintf(stream, " serial: %#B\n", &this->serialNumber);
+ written += fprintf(stream, " validity: not before %#T, ", &this->notBefore, utc);
+ if (now < this->notBefore)
+ {
+ written += fprintf(stream, "not valid yet (valid in %V)\n", &now, &this->notBefore);
+ }
+ else
+ {
+ written += fprintf(stream, "ok\n");
+ }
+
+ written += fprintf(stream, " not after %#T, ", &this->notAfter, utc);
+ if (now > this->notAfter)
+ {
+ written += fprintf(stream, "expired (%V ago)\n", &now, &this->notAfter);
+ }
+ else
+ {
+ written += fprintf(stream, "ok");
+ if (now > this->notAfter - CERT_WARNING_INTERVAL * 60 * 60 * 24)
+ {
+ written += fprintf(stream, " (expires in %V)", &now, &this->notAfter);
+ }
+ written += fprintf(stream, " \n");
+ }
+
+ {
+ chunk_t keyid = this->public_key->get_keyid(this->public_key);
+ written += fprintf(stream, " keyid: %#B\n", &keyid);
+ }
+
+ if (this->subjectKeyID.ptr)
+ {
+ written += fprintf(stream, " subjkey: %#B\n", &this->subjectKeyID);
+ }
+ if (this->authKeyID.ptr)
+ {
+ written += fprintf(stream, " authkey: %#B\n", &this->authKeyID);
+ }
+ if (this->authKeySerialNumber.ptr)
+ {
+ written += fprintf(stream, " aserial: %#B\n", &this->authKeySerialNumber);
+ }
+
+ written += fprintf(stream, " pubkey: RSA %d bits", BITS_PER_BYTE *
+ this->public_key->get_keysize(this->public_key));
+ written += fprintf(stream, ", status %N",
+ cert_status_names, this->status);
+
+ switch (this->status)
+ {
+ case CERT_GOOD:
+ written += fprintf(stream, " until %#T", &this->until, utc);
+ break;
+ case CERT_REVOKED:
+ written += fprintf(stream, " on %#T", &this->until, utc);
+ break;
+ case CERT_UNKNOWN:
+ case CERT_UNDEFINED:
+ case CERT_UNTRUSTED:
+ default:
+ break;
+ }
+ return written;
+}
+
+/**
+ * register printf() handlers
+ */
+static void __attribute__ ((constructor))print_register()
+{
+ register_printf_function(PRINTF_X509, print, arginfo_ptr_alt_ptr_int);
+}
+
+/**
+ * Implements x509_t.destroy
+ */
+static void destroy(private_x509_t *this)
+{
+ this->subjectAltNames->destroy_offset(this->subjectAltNames,
+ offsetof(identification_t, destroy));
+ this->crlDistributionPoints->destroy_offset(this->crlDistributionPoints,
+ offsetof(identification_t, destroy));
+ this->ocspAccessLocations->destroy_offset(this->ocspAccessLocations,
+ offsetof(identification_t, destroy));
+ DESTROY_IF(this->issuer);
+ DESTROY_IF(this->subject);
+ DESTROY_IF(this->public_key);
+ free(this->subjectKeyID.ptr);
+ free(this->certificate.ptr);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+x509_t *x509_create_from_chunk(chunk_t chunk, u_int level)
+{
+ private_x509_t *this = malloc_thing(private_x509_t);
+
+ /* initialize */
+ this->subjectPublicKey = chunk_empty;
+ this->public_key = NULL;
+ this->subject = NULL;
+ this->issuer = NULL;
+ this->subjectAltNames = linked_list_create();
+ this->crlDistributionPoints = linked_list_create();
+ this->ocspAccessLocations = linked_list_create();
+ this->subjectKeyID = chunk_empty;
+ this->authKeyID = chunk_empty;
+ this->authKeySerialNumber = chunk_empty;
+ this->authority_flags = AUTH_NONE;
+
+ /* public functions */
+ this->public.equals = (bool (*) (const x509_t*,const x509_t*))equals;
+ this->public.equals_subjectAltName = (bool (*) (const x509_t*,identification_t*))equals_subjectAltName;
+ this->public.is_issuer = (bool (*) (const x509_t*,const x509_t*))is_issuer;
+ this->public.is_valid = (err_t (*) (const x509_t*,time_t*))is_valid;
+ this->public.is_ca = (bool (*) (const x509_t*))is_ca;
+ this->public.is_self_signed = (bool (*) (const x509_t*))is_self_signed;
+ this->public.is_ocsp_signer = (bool (*) (const x509_t*))is_ocsp_signer;
+ this->public.get_certificate = (chunk_t (*) (const x509_t*))get_certificate;
+ this->public.get_public_key = (rsa_public_key_t* (*) (const x509_t*))get_public_key;
+ this->public.get_serialNumber = (chunk_t (*) (const x509_t*))get_serialNumber;
+ this->public.get_subjectKeyID = (chunk_t (*) (const x509_t*))get_subjectKeyID;
+ this->public.get_keyid = (chunk_t (*) (const x509_t*))get_keyid;
+ this->public.get_issuer = (identification_t* (*) (const x509_t*))get_issuer;
+ this->public.get_subject = (identification_t* (*) (const x509_t*))get_subject;
+ this->public.set_until = (void (*) (x509_t*,time_t))set_until;
+ this->public.get_until = (time_t (*) (const x509_t*))get_until;
+ this->public.set_status = (void (*) (x509_t*,cert_status_t))set_status;
+ this->public.get_status = (cert_status_t (*) (const x509_t*))get_status;
+ this->public.add_authority_flags = (void (*) (x509_t*,u_int))add_authority_flags;
+ this->public.get_authority_flags = (u_int (*) (x509_t*))get_authority_flags;
+ this->public.has_authority_flag = (bool (*) (x509_t*,u_int))has_authority_flag;
+ this->public.create_crluri_iterator = (iterator_t* (*) (const x509_t*))create_crluri_iterator;
+ this->public.create_ocspuri_iterator = (iterator_t* (*) (const x509_t*))create_ocspuri_iterator;
+ this->public.verify = (bool (*) (const x509_t*,const rsa_public_key_t*))verify;
+ this->public.destroy = (void (*) (x509_t*))destroy;
+
+ if (!parse_certificate(chunk, level, this))
+ {
+ destroy(this);
+ return NULL;
+ }
+
+ /* extract public key from certificate */
+ this->public_key = rsa_public_key_create_from_chunk(this->subjectPublicKey);
+ if (this->public_key == NULL)
+ {
+ destroy(this);
+ return NULL;
+ }
+ /* set trusted lifetime of public key to notAfter */
+ this->status = is_self_signed(this)? CERT_GOOD:CERT_UNDEFINED;
+ this->until = this->notAfter;
+ return &this->public;
+}
+
+/*
+ * Described in header.
+ */
+x509_t *x509_create_from_file(const char *filename, const char *label)
+{
+ bool pgp = FALSE;
+ chunk_t chunk = chunk_empty;
+ x509_t *cert = NULL;
+ char cert_label[BUF_LEN];
+
+ snprintf(cert_label, BUF_LEN, "%s certificate", label);
+
+ if (!pem_asn1_load_file(filename, NULL, cert_label, &chunk, &pgp))
+ return NULL;
+
+ cert = x509_create_from_chunk(chunk, 0);
+
+ if (cert == NULL)
+ free(chunk.ptr);
+ return cert;
+}
diff --git a/src/libstrongswan/crypto/x509.h b/src/libstrongswan/crypto/x509.h
new file mode 100755
index 000000000..a949d99d2
--- /dev/null
+++ b/src/libstrongswan/crypto/x509.h
@@ -0,0 +1,290 @@
+/**
+ * @file x509.h
+ *
+ * @brief Interface of x509_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2006 Martin Willi, Andreas Steffen
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct x509_t x509_t;
+
+#include <library.h>
+#include <crypto/rsa/rsa_public_key.h>
+#include <crypto/certinfo.h>
+#include <utils/identification.h>
+#include <utils/iterator.h>
+
+/* authority flags */
+
+#define AUTH_NONE 0x00 /* no authorities */
+#define AUTH_CA 0x01 /* certification authority */
+#define AUTH_AA 0x02 /* authorization authority */
+#define AUTH_OCSP 0x04 /* ocsp signing authority */
+
+/**
+ * @brief X.509 certificate.
+ *
+ * @b Constructors:
+ * - x509_create_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 Set trusted public key life.
+ *
+ * @param this calling object
+ * @param until time until public key is trusted
+ */
+ void (*set_until) (x509_t *this, time_t until);
+
+ /**
+ * @brief Get trusted public key life.
+ *
+ * @param this calling object
+ * @return time until public key is trusted
+ */
+ time_t (*get_until) (const x509_t *this);
+
+ /**
+ * @brief Set the certificate status
+ *
+ * @param this calling object
+ * @param status certificate status
+ */
+ void (*set_status) (x509_t *this, cert_status_t status);
+
+ /**
+ * @brief Get the certificate status
+ *
+ * @param this calling object
+ * @return certificate status
+ */
+ cert_status_t (*get_status) (const x509_t *this);
+
+ /**
+ * @brief Add authority flags
+ *
+ * @param this calling object
+ * @param flag flags to be added
+ */
+ void (*add_authority_flags) (x509_t *this, u_int flags);
+
+ /**
+ * @brief Get authority flags
+ *
+ * @param this calling object
+ * @return authority flags
+ */
+ u_int (*get_authority_flags) (x509_t *this);
+
+ /**
+ * @brief Check a specific authority flag
+ *
+ * @param this calling object
+ * @param flag flag to be checked
+ * @return TRUE if flag is present
+ */
+ bool (*has_authority_flag) (x509_t *this, u_int flag);
+
+ /**
+ * @brief Get the DER-encoded X.509 certificate body
+ *
+ * @param this calling object
+ * @return DER-encoded X.509 certificate
+ */
+ chunk_t (*get_certificate) (const x509_t *this);
+
+ /**
+ * @brief Get the RSA public key from the certificate.
+ *
+ * @param this calling object
+ * @return public_key
+ */
+ rsa_public_key_t *(*get_public_key) (const x509_t *this);
+
+ /**
+ * @brief Get serial number from the certificate.
+ *
+ * @param this calling object
+ * @return serialNumber
+ */
+ chunk_t (*get_serialNumber) (const x509_t *this);
+
+ /**
+ * @brief Get subjectKeyID from the certificate.
+ *
+ * @param this calling object
+ * @return subjectKeyID
+ */
+ chunk_t (*get_subjectKeyID) (const x509_t *this);
+
+ /**
+ * @brief Get keyid from the certificate's public key.
+ *
+ * @param this calling object
+ * @return keyid
+ */
+ chunk_t (*get_keyid) (const x509_t *this);
+
+ /**
+ * @brief Get the certificate issuer's ID.
+ *
+ * The resulting ID is always a identification_t
+ * of type ID_DER_ASN1_DN.
+ *
+ * @param this calling object
+ * @return issuers ID
+ */
+ identification_t *(*get_issuer) (const x509_t *this);
+
+ /**
+ * @brief Get the subjectDistinguisheName.
+ *
+ * The resulting ID is always a identification_t
+ * of type ID_DER_ASN1_DN.
+ *
+ * @param this calling object
+ * @return subjects ID
+ */
+ identification_t *(*get_subject) (const x509_t *this);
+
+ /**
+ * @brief Create an iterator for the crlDistributionPoints.
+ *
+ * @param this calling object
+ * @return iterator for crlDistributionPoints
+ */
+ iterator_t *(*create_crluri_iterator) (const x509_t *this);
+
+ /**
+ * @brief Create an iterator for the ocspAccessLocations.
+ *
+ * @param this calling object
+ * @return iterator for ocspAccessLocations
+ */
+ iterator_t *(*create_ocspuri_iterator) (const x509_t *this);
+
+ /**
+ * @brief Check if a certificate is trustworthy
+ *
+ * @param this calling object
+ * @param signer signer's RSA public key
+ */
+ bool (*verify) (const x509_t *this, const rsa_public_key_t *signer);
+
+ /**
+ * @brief Compare two certificates.
+ *
+ * Comparison is done via the certificates signature.
+ *
+ * @param this first cert for compare
+ * @param other second cert for compare
+ * @return TRUE if signature is equal
+ */
+ bool (*equals) (const x509_t *this, const x509_t *that);
+
+ /**
+ * @brief Checks if the certificate contains a subjectAltName equal to id.
+ *
+ * @param this certificate being examined
+ * @param id id which is being compared to the subjectAltNames
+ * @return TRUE if a match is found
+ */
+ bool (*equals_subjectAltName) (const x509_t *this, identification_t *id);
+
+ /**
+ * @brief Checks if the subject of the other cert is the issuer of this cert.
+ *
+ * @param this certificate
+ * @param issuer potential issuer certificate
+ * @return TRUE if issuer is found
+ */
+ bool (*is_issuer) (const x509_t *this, const x509_t *issuer);
+
+ /**
+ * @brief Checks the validity interval of the certificate
+ *
+ * @param this certificate being examined
+ * @param until until = min(until, notAfter)
+ * @return NULL if the certificate is valid
+ */
+ err_t (*is_valid) (const x509_t *this, time_t *until);
+
+ /**
+ * @brief Returns the CA basic constraints flag
+ *
+ * @param this certificate being examined
+ * @return TRUE if the CA flag is set
+ */
+ bool (*is_ca) (const x509_t *this);
+
+ /**
+ * @brief Returns the OCSPSigner extended key usage flag
+ *
+ * @param this certificate being examined
+ * @return TRUE if the OCSPSigner flag is set
+ */
+ bool (*is_ocsp_signer) (const x509_t *this);
+
+ /**
+ * @brief Checks if the certificate is self-signed (subject equals issuer)
+ *
+ * @param this certificate being examined
+ * @return TRUE if self-signed
+ */
+ bool (*is_self_signed) (const x509_t *this);
+
+ /**
+ * @brief 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 invlid.
+ *
+ * @ingroup transforms
+ */
+x509_t *x509_create_from_chunk(chunk_t chunk, u_int level);
+
+/**
+ * @brief Read a x509 certificate from a DER encoded file.
+ *
+ * @param filename file containing DER encoded data
+ * @param label label describing kind of certificate
+ * @return created x509_t certificate, or NULL if invalid.
+ *
+ * @ingroup transforms
+ */
+x509_t *x509_create_from_file(const char *filename, const char *label);
+
+#endif /* X509_H_ */
diff --git a/src/libstrongswan/debug.c b/src/libstrongswan/debug.c
new file mode 100644
index 000000000..996cae502
--- /dev/null
+++ b/src/libstrongswan/debug.c
@@ -0,0 +1,41 @@
+/**
+ * @file library.c
+ *
+ * @brief Logging functions for the library.
+ *
+ */
+
+/*
+ * 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 <stdarg.h>
+#include <stdio.h>
+
+#include "debug.h"
+
+/**
+ * default dbg function which printf all to stderr
+ */
+static void dbg_stderr(int level, char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n");
+ va_end(args);
+}
+
+void (*dbg) (int level, char *fmt, ...) = dbg_stderr;
diff --git a/src/libstrongswan/debug.h b/src/libstrongswan/debug.h
new file mode 100644
index 000000000..c424a1c11
--- /dev/null
+++ b/src/libstrongswan/debug.h
@@ -0,0 +1,60 @@
+/**
+ * @file log.h
+ *
+ * @brief Logging functions for the library.
+ *
+ */
+
+/*
+ * 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 DEBUG_H_
+#define DEBUG_H_
+
+#ifndef DEBUG_LEVEL
+# define DEBUG_LEVEL 4
+#endif /* DEBUG_LEVEL */
+
+/** debug macros, they call the dbg function hook */
+#if DEBUG_LEVEL >= 1
+# define DBG1(fmt, ...) dbg(1, fmt, ##__VA_ARGS__)
+#endif /* DEBUG_LEVEL */
+#if DEBUG_LEVEL >= 2
+# define DBG2(fmt, ...) dbg(2, fmt, ##__VA_ARGS__)
+#endif /* DEBUG_LEVEL */
+#if DEBUG_LEVEL >= 3
+# define DBG3(fmt, ...) dbg(3, fmt, ##__VA_ARGS__)
+#endif /* DEBUG_LEVEL */
+#if DEBUG_LEVEL >= 4
+# define DBG4(fmt, ...) dbg(4, fmt, ##__VA_ARGS__)
+#endif /* DEBUG_LEVEL */
+
+#ifndef DBG1
+# define DBG1(...) {}
+#endif
+#ifndef DBG2
+# define DBG2(...) {}
+#endif
+#ifndef DBG3
+# define DBG3(...) {}
+#endif
+#ifndef DBG4
+# define DBG4(...) {}
+#endif
+
+/** dbg function hook, uses stderr logger by default */
+extern void (*dbg) (int level, char *fmt, ...);
+
+#endif /* DEBUG_H_ */
diff --git a/src/libstrongswan/enum.c b/src/libstrongswan/enum.c
new file mode 100644
index 000000000..ade7c16a1
--- /dev/null
+++ b/src/libstrongswan/enum.c
@@ -0,0 +1,73 @@
+/**
+ * @file library.c
+ *
+ * @brief enum value to string conversion functions.
+ *
+ */
+
+/*
+ * 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 <stdio.h>
+
+#include "enum.h"
+
+#include <printf_hook.h>
+
+/**
+ * get the name of an enum value in a enum_name_t list
+ */
+static char *enum_name(enum_name_t *e, int val)
+{
+ do
+ {
+ if (val >= e->first && val <= e->last)
+ {
+ return e->names[val - e->first];
+ }
+ }
+ while ((e = e->next));
+ return NULL;
+}
+
+/**
+ * output handler in printf() for enum names
+ */
+static int print_enum(FILE *stream, const struct printf_info *info,
+ const void *const *args)
+{
+ enum_name_t *ed = *((enum_name_t**)(args[0]));
+ int val = *((int*)(args[1]));
+
+ char *name = enum_name(ed, val);
+
+ if (name == NULL)
+ {
+ return fprintf(stream, "(%d)", val);
+ }
+ else
+ {
+ return fprintf(stream, "%s", name);
+ }
+}
+
+/**
+ * register printf() handlers
+ */
+static void __attribute__ ((constructor))print_register()
+{
+ register_printf_function(PRINTF_ENUM, print_enum, arginfo_ptr_int);
+}
diff --git a/src/libstrongswan/enum.h b/src/libstrongswan/enum.h
new file mode 100644
index 000000000..cd06e424b
--- /dev/null
+++ b/src/libstrongswan/enum.h
@@ -0,0 +1,106 @@
+/**
+ * @file enum.h
+ *
+ * @brief enum value to string conversion functions.
+ *
+ */
+
+/*
+ * 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 ENUM_H_
+#define ENUM_H_
+
+typedef struct enum_name_t enum_name_t;
+
+/**
+ * @brief Struct to store names for enums.
+ *
+ * To print the string representation of enumeration values, the strings
+ * are stored in these structures. Every enum_name contains a range
+ * of strings, multiple ranges are linked together.
+ * Use the convenience macros to define these linked ranges.
+ *
+ * For a single range, use:
+ * ENUM(name, first, last, string1, string2, ...)
+ *
+ * For multiple linked ranges, use:
+ * ENUM_BEGIN(name, first, last, string1, string2, ...)
+ * ENUM_NEXT(name, first, last, last_from_previous, string3, ...)
+ * ENUM_NEXT(name, first, last, last_from_previous, string4, ...)
+ * ENUM_END(name, last_from_previous)
+ *
+ * The ENUM and the ENUM_END define a enum_name_t pointer with the name supplied
+ * in "name".
+ *
+ * Resolving of enum names is done using a printf hook. A printf fromat
+ * character %N is replaced by the enum string. Printf needs two arguments to
+ * resolve a %N, the enum_name_t* (the defined name in ENUM_BEGIN) followed
+ * by the numerical enum value.
+ */
+struct enum_name_t {
+ /** value of the first enum string */
+ int first;
+ /** value of the last enum string */
+ int last;
+ /** next enum_name_t in list */
+ enum_name_t *next;
+ /** array of strings containing names from first to last */
+ char *names[];
+};
+
+/**
+ * @brief Begin a new enum_name list.
+ *
+ * @param name name of the enum_name list
+ * @param first enum value of the first enum string
+ * @param last enum value of the last enum string
+ * @param ... a list of strings
+ */
+#define ENUM_BEGIN(name, first, last, ...) static enum_name_t name##last = {first, last, NULL, { __VA_ARGS__ }}
+
+/**
+ * @brief Continue a enum name list startetd with ENUM_BEGIN.
+ *
+ * @param name name of the enum_name list
+ * @param first enum value of the first enum string
+ * @param last enum value of the last enum string
+ * @param prev enum value of the "last" defined in ENUM_BEGIN/previous ENUM_NEXT
+ * @param ... a list of strings
+ */
+#define ENUM_NEXT(name, first, last, prev, ...) static enum_name_t name##last = {first, last, &name##prev, { __VA_ARGS__ }}
+
+/**
+ * @brief Complete enum name list started with ENUM_BEGIN.
+ *
+ * @param name name of the enum_name list
+ * @param prev enum value of the "last" defined in ENUM_BEGIN/previous ENUM_NEXT
+ */
+#define ENUM_END(name, prev) enum_name_t *name = &name##prev;
+
+/**
+ * @brief Define a enum name with only one range.
+ *
+ * This is a convenience macro to use when a enum_name list contains only
+ * one range, and is equal as defining ENUM_BEGIN followed by ENUM_END.
+ *
+ * @param name name of the enum_name list
+ * @param first enum value of the first enum string
+ * @param last enum value of the last enum string
+ * @param ... a list of strings
+ */
+#define ENUM(name, first, last, ...) ENUM_BEGIN(name, first, last, __VA_ARGS__); ENUM_END(name, last)
+
+#endif /* ENUM_H_ */
diff --git a/src/libstrongswan/library.c b/src/libstrongswan/library.c
new file mode 100644
index 000000000..9f96d119c
--- /dev/null
+++ b/src/libstrongswan/library.c
@@ -0,0 +1,184 @@
+/**
+ * @file library.c
+ *
+ * @brief Helper functions and definitions.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <time.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <pthread.h>
+
+#include "library.h"
+
+#include <printf_hook.h>
+
+ENUM(status_names, SUCCESS, DESTROY_ME,
+ "SUCCESS",
+ "FAILED",
+ "OUT_OF_RES",
+ "ALREADY_DONE",
+ "NOT_SUPPORTED",
+ "INVALID_ARG",
+ "NOT_FOUND",
+ "PARSE_ERROR",
+ "VERIFY_ERROR",
+ "INVALID_STATE",
+ "DESTROY_ME",
+ "NEED_MORE",
+);
+
+/**
+ * Described in header.
+ */
+void *clalloc(void * pointer, size_t size)
+{
+ void *data;
+ data = malloc(size);
+
+ memcpy(data, pointer,size);
+
+ return (data);
+}
+
+/**
+ * Described in header.
+ */
+void memxor(u_int8_t dest[], u_int8_t src[], size_t n)
+{
+ size_t i;
+ for (i = 0; i < n; i++)
+ {
+ dest[i] ^= src[i];
+ }
+}
+
+/**
+ * We use a single mutex for all refcount variables. This
+ * is not optimal for performance, but the critical section
+ * is not that long...
+ * TODO: Consider to include a mutex in each refcount_t variable.
+ */
+static pthread_mutex_t ref_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/**
+ * Described in header.
+ *
+ * TODO: May be implemented with atomic CPU instructions
+ * instead of a mutex.
+ */
+void ref_get(refcount_t *ref)
+{
+ pthread_mutex_lock(&ref_mutex);
+ (*ref)++;
+ pthread_mutex_unlock(&ref_mutex);
+}
+
+/**
+ * Described in header.
+ *
+ * TODO: May be implemented with atomic CPU instructions
+ * instead of a mutex.
+ */
+bool ref_put(refcount_t *ref)
+{
+ bool more_refs;
+
+ pthread_mutex_lock(&ref_mutex);
+ more_refs = --(*ref);
+ pthread_mutex_unlock(&ref_mutex);
+ return !more_refs;
+}
+
+/**
+ * output handler in printf() for time_t
+ */
+static int print_time(FILE *stream, const struct printf_info *info,
+ const void *const *args)
+{
+ static const char* months[] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+ time_t *time = *((time_t**)(args[0]));
+ bool utc = TRUE;
+ struct tm t;
+
+ if (info->alt)
+ {
+ utc = *((bool*)(args[1]));
+ }
+ if (time == UNDEFINED_TIME)
+ {
+ return fprintf(stream, "--- -- --:--:--%s----",
+ info->alt ? " UTC " : " ");
+ }
+ if (utc)
+ {
+ gmtime_r(time, &t);
+ }
+ else
+ {
+ localtime_r(time, &t);
+ }
+ return fprintf(stream, "%s %02d %02d:%02d:%02d%s%04d",
+ months[t.tm_mon], t.tm_mday, t.tm_hour, t.tm_min,
+ t.tm_sec, utc ? " UTC " : " ", t.tm_year + 1900);
+}
+
+/**
+ * output handler in printf() for time deltas
+ */
+static int print_time_delta(FILE *stream, const struct printf_info *info,
+ const void *const *args)
+{
+ time_t *start = *((time_t**)(args[0]));
+ time_t *end = *((time_t**)(args[1]));
+ u_int delta = abs(*end - *start);
+
+ char* unit = "second";
+
+ if (delta > 2 * 60 * 60 * 24)
+ {
+ delta /= 60 * 60 * 24;
+ unit = "day";
+ }
+ else if (delta > 2 * 60 * 60)
+ {
+ delta /= 60 * 60;
+ unit = "hour";
+ }
+ else if (delta > 2 * 60)
+ {
+ delta /= 60;
+ unit = "minute";
+ }
+ return fprintf(stream, "%d %s%s", delta, unit, (delta == 1)? "":"s");
+}
+
+/**
+ * register printf() handlers for time_t
+ */
+static void __attribute__ ((constructor))print_register()
+{
+ register_printf_function(PRINTF_TIME, print_time, arginfo_ptr_alt_ptr_int);
+ register_printf_function(PRINTF_TIME_DELTA, print_time_delta, arginfo_ptr_ptr);
+}
diff --git a/src/libstrongswan/library.h b/src/libstrongswan/library.h
new file mode 100644
index 000000000..7c7f087f0
--- /dev/null
+++ b/src/libstrongswan/library.h
@@ -0,0 +1,301 @@
+/**
+ * @file library.h
+ *
+ * @brief Helper functions and definitions.
+ *
+ */
+
+/*
+ * 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 libstrongswan libstrongswan
+ *
+ * libstrongswan: library with various crypto related things.
+ */
+
+/**
+ * @defgroup asn1 asn1
+ *
+ * ASN1 definitions, parser and generator functions.
+ *
+ * @ingroup libstrongswan
+ */
+
+/**
+ * @defgroup crypto crypto
+ *
+ * Crypto algorithms of different kind.
+ *
+ * @ingroup libstrongswan
+ */
+
+/**
+ * @defgroup crypters crypters
+ *
+ * Symmetric encryption algorithms, used for
+ * encryption and decryption.
+ *
+ * @ingroup crypto
+ */
+
+/**
+ * @defgroup hashers hashers
+ *
+ * Hashing algorithms, such as MD5 or SHA1
+ *
+ * @ingroup crypto
+ */
+
+/**
+ * @defgroup prfs prfs
+ *
+ * Pseudo random functions, used to generate
+ * pseude random byte sequences.
+ *
+ * @ingroup crypto
+ */
+
+/**
+ * @defgroup rsa rsa
+ *
+ * RSA private/public key algorithm.
+ *
+ * @ingroup crypto
+ */
+
+/**
+ * @defgroup signers signers
+ *
+ * Symmetric signing algorithms,
+ * used to ensure message integrity.
+ *
+ * @ingroup crypto
+ */
+
+/**
+ * @defgroup utils utils
+ *
+ * Generic helper classes.
+ *
+ * @ingroup libstrongswan
+ */
+
+#include <gmp.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <printf.h>
+
+#include <enum.h>
+
+/**
+ * Number of bits in a byte
+ */
+#define BITS_PER_BYTE 8
+
+/**
+ * Default length for various auxiliary text buffers
+ */
+#define BUF_LEN 512
+
+/**
+ * Macro compares two strings for equality
+ */
+#define streq(x,y) (strcmp(x, y) == 0)
+
+/**
+ * Macro compares two binary blobs for equality
+ */
+#define memeq(x,y,len) (memcmp(x, y, len) == 0)
+
+/**
+ * Macro gives back larger of two values.
+ */
+#define max(x,y) ((x) > (y) ? (x):(y))
+
+/**
+ * Macro gives back smaller of two values.
+ */
+#define min(x,y) ((x) < (y) ? (x):(y))
+
+/**
+ * Call destructor of a object if object != NULL
+ */
+#define DESTROY_IF(obj) if (obj) obj->destroy(obj)
+
+/**
+ * Debug macro to follow control flow
+ */
+#define POS printf("%s, line %d\n", __FILE__, __LINE__)
+
+/**
+ * Macro to allocate a sized type.
+ */
+#define malloc_thing(thing) ((thing*)malloc(sizeof(thing)))
+
+/**
+ * Assign a function as a class method
+ */
+#define ASSIGN(method, function) (method = (typeof(method))function)
+
+/**
+ * time_t not defined
+ */
+#define UNDEFINED_TIME 0
+
+/**
+ * General purpose boolean type.
+ */
+typedef int bool;
+#define FALSE 0
+#define TRUE 1
+
+typedef enum status_t status_t;
+
+/**
+ * Return values of function calls.
+ */
+enum status_t {
+ /**
+ * Call succeeded.
+ */
+ SUCCESS,
+
+ /**
+ * Call failed.
+ */
+ FAILED,
+
+ /**
+ * Out of resources.
+ */
+ OUT_OF_RES,
+
+ /**
+ * The suggested operation is already done
+ */
+ ALREADY_DONE,
+
+ /**
+ * Not supported.
+ */
+ NOT_SUPPORTED,
+
+ /**
+ * One of the arguments is invalid.
+ */
+ INVALID_ARG,
+
+ /**
+ * Something could not be found.
+ */
+ NOT_FOUND,
+
+ /**
+ * Error while parsing.
+ */
+ PARSE_ERROR,
+
+ /**
+ * Error while verifying.
+ */
+ VERIFY_ERROR,
+
+ /**
+ * Object in invalid state.
+ */
+ INVALID_STATE,
+
+ /**
+ * Destroy object which called method belongs to.
+ */
+ DESTROY_ME,
+
+ /**
+ * Another call to the method is required.
+ */
+ NEED_MORE,
+};
+
+/**
+ * enum_names for type status_t.
+ */
+extern enum_name_t *status_names;
+
+/**
+ * deprecated pluto style return value:
+ * error message, NULL for success
+ */
+typedef const char *err_t;
+
+/**
+ * Handle struct timeval like an own type.
+ */
+typedef struct timeval timeval_t;
+
+/**
+ * Handle struct timespec like an own type.
+ */
+typedef struct timespec timespec_t;
+
+/**
+ * Handle struct chunk_t like an own type.
+ */
+typedef struct sockaddr sockaddr_t;
+
+/**
+ * Clone a data to a newly allocated buffer
+ */
+void *clalloc(void *pointer, size_t size);
+
+/**
+ * Same as memcpy, but XORs src into dst instead of copy
+ */
+void memxor(u_int8_t dest[], u_int8_t src[], size_t n);
+
+/**
+ * Special type to count references
+ */
+typedef volatile u_int refcount_t;
+
+/**
+ * @brief Get a new reference.
+ *
+ * Increments the reference counter atomic.
+ *
+ * @param ref pointer to ref counter
+ */
+void ref_get(refcount_t *ref);
+
+/**
+ * @brief Put back a unused reference.
+ *
+ * Decrements the reference counter atomic and
+ * says if more references available.
+ *
+ * @param ref pointer to ref counter
+ * @return TRUE if no more references counted
+ */
+bool ref_put(refcount_t *ref);
+
+
+#include <chunk.h>
+#include <printf_hook.h>
+
+#endif /* LIBRARY_H_ */
diff --git a/src/libstrongswan/printf_hook.c b/src/libstrongswan/printf_hook.c
new file mode 100644
index 000000000..0407e8c82
--- /dev/null
+++ b/src/libstrongswan/printf_hook.c
@@ -0,0 +1,118 @@
+/**
+ * @file printf_hook.c
+ *
+ * @brief Printf hook definitions and arginfo functions.
+ *
+ */
+
+/*
+ * 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 "printf_hook.h"
+
+/**
+ * arginfo handler in printf() pointer
+ */
+int arginfo_ptr(const struct printf_info *info, size_t n, int *argtypes)
+{
+ if (n > 0)
+ {
+ argtypes[0] = PA_POINTER;
+ }
+ return 1;
+}
+
+/**
+ * arginfo handler for two prt arguments
+ */
+int arginfo_ptr_ptr(const struct printf_info *info, size_t n, int *argtypes)
+{
+ if (n > 1)
+ {
+ argtypes[0] = PA_POINTER;
+ argtypes[1] = PA_POINTER;
+ }
+ return 2;
+}
+
+/**
+ * arginfo handler for one ptr, one int
+ */
+int arginfo_ptr_int(const struct printf_info *info, size_t n, int *argtypes)
+{
+ if (n > 1)
+ {
+ argtypes[0] = PA_POINTER;
+ argtypes[1] = PA_INT;
+ }
+ return 2;
+}
+
+/**
+ * arginfo handler for two int arguments
+ */
+int arginfo_int_int(const struct printf_info *info, size_t n, int *argtypes)
+{
+ if (n > 1)
+ {
+ argtypes[0] = PA_INT;
+ argtypes[1] = PA_INT;
+ }
+ return 2;
+}
+
+/**
+ * special arginfo handler respecting alt flag
+ */
+int arginfo_int_alt_int_int(const struct printf_info *info, size_t n, int *argtypes)
+{
+ if (info->alt)
+ {
+ if (n > 1)
+ {
+ argtypes[0] = PA_INT;
+ argtypes[1] = PA_INT;
+ }
+ return 2;
+ }
+
+ if (n > 0)
+ {
+ argtypes[0] = PA_INT;
+ }
+ return 1;
+}
+
+/**
+ * special arginfo handler respecting alt flag
+ */
+int arginfo_ptr_alt_ptr_int(const struct printf_info *info, size_t n, int *argtypes)
+{
+ if (info->alt)
+ {
+ if (n > 1)
+ {
+ argtypes[0] = PA_POINTER;
+ argtypes[1] = PA_INT;
+ }
+ return 2;
+ }
+
+ if (n > 0)
+ {
+ argtypes[0] = PA_POINTER;
+ }
+ return 1;
+}
diff --git a/src/libstrongswan/printf_hook.h b/src/libstrongswan/printf_hook.h
new file mode 100644
index 000000000..45184a8f0
--- /dev/null
+++ b/src/libstrongswan/printf_hook.h
@@ -0,0 +1,76 @@
+/**
+ * @file printf_hook.h
+ *
+ * @brief Printf hook definitions and arginfo functions.
+ *
+ */
+
+/*
+ * 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 PRINTF_HOOK_H_
+#define PRINTF_HOOK_H_
+
+#include <printf.h>
+
+/**
+ * Printf() hook characters.
+ * We define all characters here to have them on a central place.
+ */
+
+/** 2 arguments: u_char *buffer, int size */
+#define PRINTF_BYTES 'b'
+/** 1 argument: chunk_t *chunk; use #-modifier to print inline */
+#define PRINTF_CHUNK 'B'
+/** 1 argument: identification_t *id */
+#define PRINTF_IDENTIFICATION 'D'
+/** 1 argumnet: host_t *host; use #-modifier to include port number */
+#define PRINTF_HOST 'H'
+/** 1 argument: ike_sa_id_t *id */
+#define PRINTF_IKE_SA_ID 'J'
+/** 1 argument: ike_sa_t *ike_sa */
+#define PRINTF_IKE_SA 'K'
+/** 1 argument: message_t *message */
+#define PRINTF_MESSAGE 'M'
+/** 2 arguments: enum_name_t *name, long value */
+#define PRINTF_ENUM 'N'
+/** 1 argument: child_sa_t *child_sa */
+#define PRINTF_CHILD_SA 'P'
+/** 1 argument: traffic_selector_t *ts */
+#define PRINTF_TRAFFIC_SELECTOR 'R'
+/** 1 argument: time_t *time; with #-modifier 2 arguments: time_t *time, bool utc */
+#define PRINTF_TIME 'T'
+/** 1 argument: x509_t *cert; with #-modifier 2 arguments: x509_t *cert, bool utc */
+#define PRINTF_X509 'Q'
+/** 1 argument: crl_t *crl; with #-modifier 2 arguments: crl_t *crl, bool utc */
+#define PRINTF_CRL 'U'
+/** 2 arguments: time_t *begin, time_t *end */
+#define PRINTF_TIME_DELTA 'V'
+/** 1 argument: ca_info_t *ca_info; with #-modifier 2 arguments: ca_info_t *ca_info, bool utc */
+#define PRINTF_CAINFO 'W'
+/** 1 argument: certinfo_t *certinfo; with #-modifier 2 arguments: certinfo_t *certinfo, bool utc */
+#define PRINTF_CERTINFO 'Y'
+
+/**
+ * Generic arginfo handlers for printf() hooks
+ */
+int arginfo_ptr(const struct printf_info *info, size_t n, int *argtypes);
+int arginfo_ptr_ptr(const struct printf_info *info, size_t n, int *argtypes);
+int arginfo_ptr_int(const struct printf_info *info, size_t n, int *argtypes);
+int arginfo_int_int(const struct printf_info *info, size_t n, int *argtypes);
+int arginfo_ptr_alt_ptr_int(const struct printf_info *info, size_t n, int *argtypes);
+int arginfo_int_alt_int_int(const struct printf_info *info, size_t n, int *argtypes);
+
+#endif /* PRINTF_HOOK_H_ */
diff --git a/src/libstrongswan/utils/fetcher.c b/src/libstrongswan/utils/fetcher.c
new file mode 100644
index 000000000..6165cc1e1
--- /dev/null
+++ b/src/libstrongswan/utils/fetcher.c
@@ -0,0 +1,421 @@
+/**
+ * @file fetcher.c
+ *
+ * @brief Implementation of fetcher_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <fetcher://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifdef LIBCURL
+#include <curl/curl.h>
+#endif /* LIBCURL */
+
+#ifdef LIBLDAP
+#include <ldap.h>
+#endif /* LIBLDAP */
+
+#include <library.h>
+#include <debug.h>
+
+#include "fetcher.h"
+
+typedef struct private_fetcher_t private_fetcher_t;
+
+/**
+ * @brief Private Data of a fetcher_t object.
+ */
+struct private_fetcher_t {
+ /**
+ * Public data
+ */
+ fetcher_t public;
+
+ /**
+ * URI of the information source
+ */
+ const char *uri;
+
+#ifdef LIBCURL
+ /**
+ * we use libcurl from http://curl.haxx.se/ as a fetcher
+ */
+ CURL* curl;
+#endif /* LIBCURL */
+
+#ifdef LIBLDAP
+ /**
+ * we use libldap from http://www.openssl.org/ as a fetcher
+ */
+ LDAP *ldap;
+ LDAPURLDesc *lurl;
+#endif /* LIBLDAP */
+};
+
+/**
+ * writes data into a dynamically resizeable chunk_t
+ * needed for libcurl responses
+ */
+static size_t curl_write_buffer(void *ptr, size_t size, size_t nmemb, void *data)
+{
+ size_t realsize = size * nmemb;
+ chunk_t *mem = (chunk_t*)data;
+
+ mem->ptr = (u_char *)realloc(mem->ptr, mem->len + realsize);
+ if (mem->ptr) {
+ memcpy(&(mem->ptr[mem->len]), ptr, realsize);
+ mem->len += realsize;
+ }
+ return realsize;
+}
+
+/**
+ * Implements fetcher_t.get for curl methods
+ */
+static chunk_t curl_get(private_fetcher_t *this)
+{
+ chunk_t response = chunk_empty;
+
+#ifdef LIBCURL
+ if (this->curl)
+ {
+ CURLcode res;
+ chunk_t curl_response = chunk_empty;
+ char curl_error_buffer[CURL_ERROR_SIZE];
+
+ curl_easy_setopt(this->curl, CURLOPT_URL, this->uri);
+ curl_easy_setopt(this->curl, CURLOPT_WRITEFUNCTION, curl_write_buffer);
+ curl_easy_setopt(this->curl, CURLOPT_WRITEDATA, (void *)&curl_response);
+ curl_easy_setopt(this->curl, CURLOPT_ERRORBUFFER, &curl_error_buffer);
+ curl_easy_setopt(this->curl, CURLOPT_FAILONERROR, TRUE);
+ curl_easy_setopt(this->curl, CURLOPT_CONNECTTIMEOUT, FETCHER_TIMEOUT);
+ curl_easy_setopt(this->curl, CURLOPT_NOSIGNAL, TRUE);
+
+ DBG1("sending curl request to '%s'...", this->uri);
+ res = curl_easy_perform(this->curl);
+
+ if (res == CURLE_OK)
+ {
+ DBG1("received valid curl response");
+ response = chunk_clone(curl_response);
+ }
+ else
+ {
+ DBG1("curl request failed: %s", curl_error_buffer);
+ }
+ curl_free(curl_response.ptr);
+ }
+#else
+ DBG1("warning: libcurl fetching not compiled in");
+#endif /* LIBCURL */
+ return response;
+}
+
+/**
+ * Implements fetcher_t.post.
+ */
+static chunk_t http_post(private_fetcher_t *this, const char *request_type, chunk_t request)
+{
+ chunk_t response = chunk_empty;
+
+#ifdef LIBCURL
+ if (this->curl)
+ {
+ CURLcode res;
+ struct curl_slist *headers = NULL;
+ chunk_t curl_response = chunk_empty;
+ char curl_error_buffer[CURL_ERROR_SIZE];
+ char content_type[BUF_LEN];
+
+ /* set content type header */
+ snprintf(content_type, BUF_LEN, "Content-Type: %s", request_type);
+ headers = curl_slist_append(headers, content_type);
+
+ /* set options */
+ curl_easy_setopt(this->curl, CURLOPT_HTTPHEADER, headers);
+ curl_easy_setopt(this->curl, CURLOPT_URL, this->uri);
+ curl_easy_setopt(this->curl, CURLOPT_WRITEFUNCTION, curl_write_buffer);
+ curl_easy_setopt(this->curl, CURLOPT_WRITEDATA, (void *)&curl_response);
+ curl_easy_setopt(this->curl, CURLOPT_POSTFIELDS, request.ptr);
+ curl_easy_setopt(this->curl, CURLOPT_POSTFIELDSIZE, request.len);
+ curl_easy_setopt(this->curl, CURLOPT_ERRORBUFFER, &curl_error_buffer);
+ curl_easy_setopt(this->curl, CURLOPT_FAILONERROR, TRUE);
+ curl_easy_setopt(this->curl, CURLOPT_CONNECTTIMEOUT, FETCHER_TIMEOUT);
+ curl_easy_setopt(this->curl, CURLOPT_NOSIGNAL, TRUE);
+
+ DBG1("sending http post request to '%s'...", this->uri);
+ res = curl_easy_perform(this->curl);
+
+ if (res == CURLE_OK)
+ {
+ DBG1("received valid http response");
+ response = chunk_clone(curl_response);
+ }
+ else
+ {
+ DBG1("http post request using libcurl failed: %s", curl_error_buffer);
+ }
+ curl_slist_free_all(headers);
+ curl_free(curl_response.ptr);
+ }
+#else
+ DBG1("warning: libcurl fetching not compiled in");
+#endif /* LIBCURL */
+ return response;
+}
+
+#ifdef LIBLDAP
+/**
+ * Parses the result returned by an ldap query
+ */
+static chunk_t ldap_parse(LDAP *ldap, LDAPMessage *result)
+{
+ chunk_t response = chunk_empty;
+ err_t ugh = NULL;
+
+ LDAPMessage *entry = ldap_first_entry(ldap, result);
+
+ if (entry != NULL)
+ {
+ BerElement *ber = NULL;
+ char *attr;
+
+ attr = ldap_first_attribute(ldap, entry, &ber);
+
+ if (attr != NULL)
+ {
+ struct berval **values = ldap_get_values_len(ldap, entry, attr);
+
+ if (values != NULL)
+ {
+ if (values[0] != NULL)
+ {
+ response.len = values[0]->bv_len;
+ response.ptr = malloc(response.len);
+ memcpy(response.ptr, values[0]->bv_val, response.len);
+
+ if (values[1] != NULL)
+ {
+ ugh = "more than one value was fetched - first selected";
+ }
+ }
+ else
+ {
+ ugh = "no values in attribute";
+ }
+ ldap_value_free_len(values);
+ }
+ else
+ {
+ ugh = ldap_err2string(ldap_result2error(ldap, entry, 0));
+ }
+ ldap_memfree(attr);
+ }
+ else
+ {
+ ugh = ldap_err2string(ldap_result2error(ldap, entry, 0));
+ }
+ ber_free(ber, 0);
+ }
+ else
+ {
+ ugh = ldap_err2string(ldap_result2error(ldap, result, 0));
+ }
+ if (ugh)
+ {
+ DBG1("ldap request failed: %s", ugh);
+ }
+ return response;
+}
+#endif /* LIBLDAP */
+
+/**
+ * Implements fetcher_t.get for curl methods
+ */
+static chunk_t ldap_get(private_fetcher_t *this)
+{
+ chunk_t response = chunk_empty;
+
+#ifdef LIBLDAP
+ if (this->ldap)
+ {
+ err_t ugh = NULL;
+ int rc;
+ int ldap_version = LDAP_VERSION3;
+
+ struct timeval timeout;
+
+ timeout.tv_sec = FETCHER_TIMEOUT;
+ timeout.tv_usec = 0;
+
+ ldap_set_option(this->ldap, LDAP_OPT_PROTOCOL_VERSION, &ldap_version);
+ ldap_set_option(this->ldap, LDAP_OPT_NETWORK_TIMEOUT, &timeout);
+
+ DBG1("sending ldap request to '%s'...", this->uri);
+
+ rc = ldap_simple_bind_s(this->ldap, NULL, NULL);
+ if (rc == LDAP_SUCCESS)
+ {
+ LDAPMessage *result;
+
+ timeout.tv_sec = FETCHER_TIMEOUT;
+ timeout.tv_usec = 0;
+
+ rc = ldap_search_st(this->ldap, this->lurl->lud_dn,
+ this->lurl->lud_scope,
+ this->lurl->lud_filter,
+ this->lurl->lud_attrs,
+ 0, &timeout, &result);
+
+ if (rc == LDAP_SUCCESS)
+ {
+ response = ldap_parse(this->ldap, result);
+ if (response.ptr)
+ {
+ DBG1("received valid ldap response");
+ }
+ ldap_msgfree(result);
+ }
+ else
+ {
+ ugh = ldap_err2string(rc);
+ }
+ }
+ else
+ {
+ ugh = ldap_err2string(rc);
+ }
+ ldap_unbind_s(this->ldap);
+
+ if (ugh)
+ {
+ DBG1("ldap request failed: %s", ugh);
+ }
+ }
+#else /* !LIBLDAP */
+ DBG1("warning: libldap fetching not compiled in");
+#endif /* !LIBLDAP */
+ return response;
+}
+
+/**
+ * Implements fetcher_t.destroy
+ */
+static void destroy(private_fetcher_t *this)
+{
+#ifdef LIBCURL
+ if (this->curl)
+ {
+ curl_easy_cleanup(this->curl);
+ }
+#endif /* LIBCURL */
+
+#ifdef LIBLDAP
+ if (this->lurl)
+ {
+ ldap_free_urldesc(this->lurl);
+ }
+#endif /* LIBLDAP */
+
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+fetcher_t *fetcher_create(const char *uri)
+{
+ private_fetcher_t *this = malloc_thing(private_fetcher_t);
+
+ /* initialize */
+ this->uri = uri;
+
+#ifdef LIBCURL
+ this->curl = NULL;
+#endif /* LIBCURL */
+
+#ifdef LIBLDAP
+ this->lurl = NULL;
+ this->ldap = NULL;
+#endif /* LIBLDAP */
+
+ if (strlen(uri) >= 4 && strncasecmp(uri, "ldap", 4) == 0)
+ {
+#ifdef LIBLDAP
+ int rc = ldap_url_parse(uri, &this->lurl);
+
+ if (rc == LDAP_SUCCESS)
+ {
+ this->ldap = ldap_init(this->lurl->lud_host,
+ this->lurl->lud_port);
+ }
+ else
+ {
+ DBG1("ldap: %s", ldap_err2string(rc));
+ this->ldap = NULL;
+ }
+#endif /* LIBLDAP */
+ this->public.get = (chunk_t (*) (fetcher_t*))ldap_get;
+ }
+ else
+ {
+#ifdef LIBCURL
+ this->curl = curl_easy_init();
+ if (this->curl == NULL)
+ {
+ DBG1("curl_easy_init_failed()");
+ }
+#endif /* LIBCURL */
+ this->public.get = (chunk_t (*) (fetcher_t*))curl_get;
+ }
+
+ /* public functions */
+ this->public.post = (chunk_t (*) (fetcher_t*,const char*,chunk_t))http_post;
+ this->public.destroy = (void (*) (fetcher_t*))destroy;
+
+ return &this->public;
+}
+
+/**
+ * Described in header.
+ */
+void fetcher_initialize(void)
+{
+#ifdef LIBCURL
+ CURLcode res;
+
+ /* initialize libcurl */
+ DBG1("initializing libcurl");
+ res = curl_global_init(CURL_GLOBAL_NOTHING);
+ if (res != CURLE_OK)
+ {
+ DBG1("libcurl could not be initialized: %s", curl_easy_strerror(res));
+ }
+#endif /* LIBCURL */
+}
+
+/**
+ * Described in header.
+ */
+void fetcher_finalize(void)
+{
+#ifdef LIBCURL
+ /* finalize libcurl */
+ DBG1("finalizing libcurl");
+ curl_global_cleanup();
+#endif /* LIBCURL */
+}
+
diff --git a/src/libstrongswan/utils/fetcher.h b/src/libstrongswan/utils/fetcher.h
new file mode 100644
index 000000000..47b43a0b7
--- /dev/null
+++ b/src/libstrongswan/utils/fetcher.h
@@ -0,0 +1,95 @@
+/**
+ * @file fetcher.h
+ *
+ * @brief Interface of fetcher_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <fetcher://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef FETCHER_H_
+#define FETCHER_H_
+
+typedef struct fetcher_t fetcher_t;
+
+#include <chunk.h>
+
+#define FETCHER_TIMEOUT 10 /* seconds */
+
+/**
+ * @brief Fetches information from an URI (http, file, ftp, etc.)
+ *
+ * @ingroup utils
+ */
+struct fetcher_t {
+
+ /**
+ * @brief Get information via a get request.
+ *
+ * @param this calling object
+ * @param uri uri specifying the information source
+ * @return chunk_t containing the information
+ */
+ chunk_t (*get) (fetcher_t *this);
+
+ /**
+ * @brief Get information via a get request.
+ *
+ * @param this calling object
+ * @param uri uri specifying the information source
+ * @param type content type of http post request
+ * @param request binary data for http post request
+ * @return chunk_t containing the information
+ */
+ chunk_t (*post) (fetcher_t *this, const char *type, chunk_t request);
+
+ /**
+ * @brief Destroys the fetcher_t object.
+ *
+ * @param this fetcher_t to destroy
+ */
+ void (*destroy) (fetcher_t *this);
+
+};
+
+/**
+ * @brief Create a fetcher_t object.
+ *
+ * @return created fetcher_t object
+ *
+ * @ingroup utils
+ */
+fetcher_t* fetcher_create(const char *uri);
+
+/**
+ * @brief Initializes the fetcher_t class
+ *
+ * call this function only once in the main program
+ *
+ * @ingroup utils
+ */
+void fetcher_initialize(void);
+
+/**
+ * @brief Finalizes the fetcher_t class
+ *
+ * call this function only once befor exiting the main program
+ *
+ * @ingroup utils
+ */
+void fetcher_finalize(void);
+
+#endif /*FETCHER_H_*/
diff --git a/src/libstrongswan/utils/host.c b/src/libstrongswan/utils/host.c
new file mode 100644
index 000000000..8cbfd6ab8
--- /dev/null
+++ b/src/libstrongswan/utils/host.c
@@ -0,0 +1,526 @@
+/**
+ * @file host.c
+ *
+ * @brief Implementation of host_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2006-2007 Tobias Brunner
+ * Copyright (C) 2006 Daniel Roethlisberger
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <printf.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;
+
+ /**
+ * low-lewel structure, wich stores the address
+ */
+ union {
+ /** generic type */
+ struct sockaddr address;
+ /** maximum sockaddr size */
+ struct sockaddr_storage address_max;
+ /** IPv4 address */
+ struct sockaddr_in address4;
+ /** IPv6 address */
+ struct sockaddr_in6 address6;
+ };
+ /**
+ * 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_anyaddr.
+ */
+static bool is_anyaddr(private_host_t *this)
+{
+ switch (this->address.sa_family)
+ {
+ case AF_INET:
+ {
+ u_int8_t default_route[4];
+ memset(default_route, 0, sizeof(default_route));
+ return memeq(default_route, &(this->address4.sin_addr.s_addr),
+ sizeof(default_route));
+ }
+ case AF_INET6:
+ {
+ u_int8_t default_route[16];
+ memset(default_route, 0, sizeof(default_route));
+ return memeq(default_route, &(this->address6.sin6_addr.s6_addr),
+ sizeof(default_route));
+ }
+ default:
+ {
+ return FALSE;
+ }
+ }
+}
+
+/**
+ * output handler in printf()
+ */
+static int print(FILE *stream, const struct printf_info *info,
+ const void *const *args)
+{
+ private_host_t *this = *((private_host_t**)(args[0]));
+ char buffer[INET6_ADDRSTRLEN];
+ void *address;
+ u_int16_t port;
+
+ if (this == NULL)
+ {
+ return fprintf(stream, "(null)");
+ }
+
+ if (is_anyaddr(this))
+ {
+ return fprintf(stream, "%%any");
+ }
+
+ switch (this->address.sa_family)
+ {
+ case AF_INET:
+ address = &this->address4.sin_addr;
+ port = this->address4.sin_port;
+ break;
+ case AF_INET6:
+ address = &this->address6.sin6_addr;
+ port = this->address6.sin6_port;
+ break;
+ default:
+ return fprintf(stream, "(family not supported)");
+ }
+
+ if (inet_ntop(this->address.sa_family, address,
+ buffer, sizeof(buffer)) == NULL)
+ {
+ return fprintf(stream, "(address conversion failed)");
+ }
+
+ if (info->alt)
+ {
+ return fprintf(stream, "%s[%d]", buffer, ntohs(port));
+ }
+ else
+ {
+ return fprintf(stream, "%s", buffer);
+ }
+}
+
+/**
+ * register printf() handlers
+ */
+static void __attribute__ ((constructor))print_register()
+{
+ register_printf_function(PRINTF_HOST, print, arginfo_ptr);
+}
+
+/**
+ * Implementation of host_t.get_address.
+ */
+static chunk_t get_address(private_host_t *this)
+{
+ chunk_t address = chunk_empty;
+
+ switch (this->address.sa_family)
+ {
+ case AF_INET:
+ {
+ address.ptr = (char*)&(this->address4.sin_addr.s_addr);
+ address.len = 4;
+ return address;
+ }
+ case AF_INET6:
+ {
+ address.ptr = (char*)&(this->address6.sin6_addr.s6_addr);
+ address.len = 16;
+ return address;
+ }
+ default:
+ {
+ /* return empty chunk */
+ return address;
+ }
+ }
+}
+
+/**
+ * implements host_t.get_family
+ */
+static int get_family(private_host_t *this)
+{
+ return this->address.sa_family;
+}
+
+/**
+ * implements host_t.get_port
+ */
+static u_int16_t get_port(private_host_t *this)
+{
+ switch (this->address.sa_family)
+ {
+ case AF_INET:
+ {
+ return ntohs(this->address4.sin_port);
+ }
+ case AF_INET6:
+ {
+ return ntohs(this->address6.sin6_port);
+ }
+ default:
+ {
+ return 0;
+ }
+ }
+}
+
+/**
+ * implements host_t.set_port
+ */
+static void set_port(private_host_t *this, u_int16_t port)
+{
+ switch (this->address.sa_family)
+ {
+ case AF_INET:
+ {
+ this->address4.sin_port = htons(port);
+ break;
+ }
+ case AF_INET6:
+ {
+ this->address6.sin6_port = htons(port);
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+}
+
+/**
+ * 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));
+ return new;
+}
+
+/**
+ * Impelements host_t.ip_equals
+ */
+static bool ip_equals(private_host_t *this, private_host_t *other)
+{
+ if (this->address.sa_family != other->address.sa_family)
+ {
+ /* 0.0.0.0 and ::0 are equal */
+ if (is_anyaddr(this) && is_anyaddr(other))
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+ switch (this->address.sa_family)
+ {
+ case AF_INET:
+ {
+ if (memeq(&this->address4.sin_addr, &other->address4.sin_addr,
+ sizeof(this->address4.sin_addr)))
+ {
+ return TRUE;
+ }
+ break;
+ }
+ case AF_INET6:
+ {
+ if (memeq(&this->address6.sin6_addr, &other->address6.sin6_addr,
+ sizeof(this->address6.sin6_addr)))
+ {
+ return TRUE;
+ }
+ }
+ default:
+ break;
+ }
+ return FALSE;
+}
+
+/**
+ * Implements host_t.get_differences
+ */
+static host_diff_t get_differences(host_t *this, host_t *other)
+{
+ host_diff_t ret = HOST_DIFF_NONE;
+
+ if (!this->ip_equals(this, other))
+ {
+ ret |= HOST_DIFF_ADDR;
+ }
+
+ if (this->get_port(this) != other->get_port(other))
+ {
+ ret |= HOST_DIFF_PORT;
+ }
+
+ return ret;
+}
+
+/**
+ * Impelements host_t.equals
+ */
+static bool equals(private_host_t *this, private_host_t *other)
+{
+ if (!ip_equals(this, other))
+ {
+ return FAILED;
+ }
+
+ switch (this->address.sa_family)
+ {
+ case AF_INET:
+ {
+ if (this->address4.sin_port == other->address4.sin_port)
+ {
+ return TRUE;
+ }
+ break;
+ }
+ case AF_INET6:
+ {
+ if (this->address6.sin6_port == other->address6.sin6_port)
+ {
+ return TRUE;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return FALSE;
+}
+
+/**
+ * Implements host_t.destroy
+ */
+static void destroy(private_host_t *this)
+{
+ free(this);
+}
+
+/**
+ * Creates an empty host_t object
+ */
+static private_host_t *host_create_empty(void)
+{
+ 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_address = (chunk_t (*) (host_t *)) get_address;
+ this->public.get_port = (u_int16_t (*) (host_t *))get_port;
+ this->public.set_port = (void (*) (host_t *,u_int16_t))set_port;
+ this->public.get_differences = get_differences;
+ this->public.ip_equals = (bool (*) (host_t *,host_t *)) ip_equals;
+ this->public.equals = (bool (*) (host_t *,host_t *)) equals;
+ this->public.is_anyaddr = (bool (*) (host_t *)) is_anyaddr;
+ this->public.destroy = (void (*) (host_t*))destroy;
+
+ return this;
+}
+
+/*
+ * Described in header.
+ */
+host_t *host_create_from_string(char *string, u_int16_t port)
+{
+ private_host_t *this = host_create_empty();
+
+ if (strchr(string, '.'))
+ {
+ this->address.sa_family = AF_INET;
+ }
+ else
+ {
+ this->address.sa_family = AF_INET6;
+ }
+
+ switch (this->address.sa_family)
+ {
+ case AF_INET:
+ {
+ if (inet_pton(AF_INET, string, &this->address4.sin_addr) <=0)
+ {
+ break;
+ }
+ this->address4.sin_port = htons(port);
+ this->socklen = sizeof(struct sockaddr_in);
+ return &this->public;
+ }
+ case AF_INET6:
+ {
+ if (inet_pton(AF_INET6, string, &this->address6.sin6_addr) <=0)
+ {
+ break;
+ }
+ this->address6.sin6_port = htons(port);
+ this->socklen = sizeof(struct sockaddr_in6);
+ return &this->public;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ 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->address.sa_family = family;
+ switch (family)
+ {
+ case AF_INET:
+ {
+ if (address.len != 4)
+ {
+ break;
+ }
+ 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);
+ }
+ case AF_INET6:
+ {
+ if (address.len != 16)
+ {
+ break;
+ }
+ memcpy(&(this->address6.sin6_addr.s6_addr), address.ptr, 16);
+ this->address6.sin6_port = htons(port);
+ this->socklen = sizeof(struct sockaddr_in6);
+ return &this->public;
+ }
+ default:
+ break;
+ }
+ free(this);
+ return NULL;
+}
+
+/*
+ * Described in header.
+ */
+host_t *host_create_from_sockaddr(sockaddr_t *sockaddr)
+{
+ private_host_t *this = host_create_empty();
+
+ switch (sockaddr->sa_family)
+ {
+ case AF_INET:
+ {
+ memcpy(&this->address4, sockaddr, sizeof(struct sockaddr_in));
+ this->socklen = sizeof(struct sockaddr_in);
+ return &this->public;
+ }
+ case AF_INET6:
+ {
+ memcpy(&this->address6, sockaddr, sizeof(struct sockaddr_in6));
+ this->socklen = sizeof(struct sockaddr_in6);
+ return &this->public;
+ }
+ default:
+ break;
+ }
+ free(this);
+ return NULL;
+}
+
+/*
+ * Described in header.
+ */
+host_t *host_create_any(int family)
+{
+ private_host_t *this = host_create_empty();
+
+ memset(&this->address_max, 0, sizeof(struct sockaddr_storage));
+ this->address.sa_family = family;
+
+ switch (family)
+ {
+ case AF_INET:
+ {
+ this->socklen = sizeof(struct sockaddr_in);
+ return &(this->public);
+ }
+ case AF_INET6:
+ {
+ this->socklen = sizeof(struct sockaddr_in6);
+ return &this->public;
+ }
+ default:
+ break;
+ }
+ return NULL;
+}
diff --git a/src/libstrongswan/utils/host.h b/src/libstrongswan/utils/host.h
new file mode 100644
index 000000000..ee9aa457f
--- /dev/null
+++ b/src/libstrongswan/utils/host.h
@@ -0,0 +1,231 @@
+/**
+ * @file host.h
+ *
+ * @brief Interface of host_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2006-2007 Tobias Brunner
+ * Copyright (C) 2006 Daniel Roethlisberger
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef enum host_diff_t host_diff_t;
+typedef struct host_t host_t;
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <library.h>
+
+/**
+ * Differences between two hosts. They differ in
+ * address, port, or both.
+ */
+enum host_diff_t {
+ HOST_DIFF_NONE = 0,
+ HOST_DIFF_ADDR = 1,
+ HOST_DIFF_PORT = 2,
+};
+
+/**
+ * @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 utils
+ */
+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.
+ *
+ * Depending 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 family of the address
+ *
+ * @param this calling object
+ * @return family
+ */
+ int (*get_family) (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_anyaddr) (host_t *this);
+
+ /**
+ * @brief get the address of this host as chunk_t
+ *
+ * Returned chunk points to internal data.
+ *
+ * @param this object
+ * @return address string,
+ */
+ chunk_t (*get_address) (host_t *this);
+
+ /**
+ * @brief get the port of this host
+ *
+ * @param this object to clone
+ * @return port number
+ */
+ u_int16_t (*get_port) (host_t *this);
+
+ /**
+ * @brief set the port of this host
+ *
+ * @param this object to clone
+ * @param port port numer
+ */
+ void (*set_port) (host_t *this, u_int16_t port);
+
+ /**
+ * @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 Compare two hosts and return the differences.
+ *
+ * @param this object to compare
+ * @param other the other to compare
+ * @return differences in a combination of host_diff_t's
+ */
+ host_diff_t (*get_differences) (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.
+ *
+ * @param string string of an address, such as "152.96.193.130"
+ * @param port port number
+ * @return
+ * - host_t object
+ * - NULL, if string not an address.
+ *
+ * @ingroup network
+ */
+host_t *host_create_from_string(char *string, u_int16_t port);
+
+/**
+ * @brief Constructor to create a host_t object from an address chunk
+ *
+ * @param family Address family to use for this object, such as AF_INET or AF_INET6
+ * @param address address as 4 byte chunk_t in networ order
+ * @param 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
+ *
+ * @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);
+
+/**
+ * @brief Create a host without an address, a "any" host.
+ *
+ * @param family family of the any host
+ * @return
+ * - host_t object
+ * - NULL, if family not supported.
+ *
+ * @ingroup network
+ */
+host_t *host_create_any(int family);
+
+#endif /*HOST_H_*/
diff --git a/src/libstrongswan/utils/identification.c b/src/libstrongswan/utils/identification.c
new file mode 100644
index 000000000..341af39c0
--- /dev/null
+++ b/src/libstrongswan/utils/identification.c
@@ -0,0 +1,1144 @@
+/**
+ * @file identification.c
+ *
+ * @brief Implementation of identification_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <printf.h>
+
+#include "identification.h"
+
+#include <asn1/asn1.h>
+
+ENUM_BEGIN(id_type_names, ID_ANY, ID_KEY_ID,
+ "ID_ANY",
+ "ID_IPV4_ADDR",
+ "ID_FQDN",
+ "ID_RFC822_ADDR",
+ "ID_IPV4_ADDR_SUBNET",
+ "ID_IPV6_ADDR",
+ "ID_IPV6_ADDR_SUBNET",
+ "ID_IPV4_ADDR_RANGE",
+ "ID_IPV6_ADDR_RANGE",
+ "ID_DER_ASN1_DN",
+ "ID_DER_ASN1_GN",
+ "ID_KEY_ID");
+ENUM_NEXT(id_type_names, ID_DER_ASN1_GN_URI, ID_DER_ASN1_GN_URI, ID_KEY_ID,
+ "ID_DER_ASN1_GN_URI");
+ENUM_END(id_type_names, ID_DER_ASN1_GN_URI);
+
+
+/**
+ * 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
+
+/**
+ * maximum number of RDNs in atodn()
+ */
+#define RDN_MAX 20
+
+
+typedef struct private_identification_t private_identification_t;
+
+/**
+ * Private data of an identification_t object.
+ */
+struct private_identification_t {
+ /**
+ * Public interface.
+ */
+ identification_t public;
+
+ /**
+ * Encoded representation of this ID.
+ */
+ chunk_t encoded;
+
+ /**
+ * Type of this ID.
+ */
+ id_type_t type;
+};
+
+static private_identification_t *identification_create(void);
+
+/**
+ * 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++));
+ }
+}
+
+/**
+ * Remove any malicious characters from a chunk. We are very restrictive, but
+ * whe use these strings only to present it to the user.
+ */
+static chunk_t sanitize_chunk(chunk_t chunk)
+{
+ char *pos;
+ chunk_t clone = chunk_clone(chunk);
+
+ for (pos = clone.ptr; pos < (char*)(clone.ptr + clone.len); pos++)
+ {
+ switch (*pos)
+ {
+ case '\0':
+ case ' ':
+ case '*':
+ case '-':
+ case '.':
+ case '/':
+ case '0' ... '9':
+ case ':':
+ case '=':
+ case '@':
+ case 'A' ... 'Z':
+ case '_':
+ case 'a' ... 'z':
+ break;
+ default:
+ *pos = '?';
+ }
+ }
+ return clone;
+}
+
+/**
+ * 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_empty;
+ *attribute = chunk_empty;
+
+ /* 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_empty;
+ *value = chunk_empty;
+
+ /* 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, proper;
+ asn1_t type;
+ int oid_code;
+ bool next;
+ bool first = TRUE;
+
+ status_t status = init_rdn(dn, &rdn, &attribute, &next);
+
+ if (status != SUCCESS)
+ return status;
+
+ while (next)
+ {
+ status = get_next_rdn(&rdn, &attribute, &oid, &value, &type, &next);
+
+ if (status != SUCCESS)
+ 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 */
+ proper = sanitize_chunk(value);
+ update_chunk(str, snprintf(str->ptr,str->len,"=%.*s", (int)proper.len, proper.ptr));
+ chunk_free(&proper);
+ }
+ 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 (memeq(a.ptr, b.ptr, b.len))
+ return TRUE;
+
+ /* initialize DN parsing */
+ if (init_rdn(a, &rdn_a, &attribute_a, &next_a) != SUCCESS
+ || init_rdn(b, &rdn_b, &attribute_b, &next_b) != SUCCESS)
+ {
+ 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 */
+ if (wildcards)
+ {
+ *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 == '*')
+ {
+ if (wildcards)
+ {
+ (*wildcards)++;
+ }
+ continue;
+ }
+ /* same lengths for values */
+ if (value_a.len != value_b.len)
+ return FALSE;
+
+ /* printableStrings and email RDNs require uppercase comparison */
+ if (type_a == type_b && (type_a == ASN1_PRINTABLESTRING
+ || (type_a == ASN1_IA5STRING && known_oid(oid_a) == OID_PKCS9_EMAIL)))
+ {
+ if (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! */
+ if (wildcards)
+ {
+ *wildcards = min(*wildcards, MAX_WILDCARDS);
+ }
+ return TRUE;
+}
+
+/**
+ * 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;
+
+ chunk_t oid = chunk_empty;
+ chunk_t name = chunk_empty;
+ chunk_t rdns[RDN_MAX];
+ int rdn_count = 0;
+ int dn_len = 0;
+ int whitespace = 0;
+ int i = 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 (i = 0; i < X501_RDN_ROOF; i++)
+ {
+ if (strlen(x501rdns[i].name) == oid.len
+ && strncasecmp(x501rdns[i].name, oid.ptr, oid.len) == 0)
+ {
+ break; /* found a valid OID */
+ }
+ }
+ if (i == X501_RDN_ROOF)
+ {
+ status = NOT_SUPPORTED;
+ state = UNKNOWN_OID;
+ break;
+ }
+ /* reset oid and change state */
+ oid = chunk_empty;
+ 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[i].type == ASN1_PRINTABLESTRING
+ && !is_printablestring(name))? ASN1_T61STRING : x501rdns[i].type;
+
+ if (rdn_count < RDN_MAX)
+ {
+ rdns[rdn_count] =
+ asn1_wrap(ASN1_SET, "m",
+ asn1_wrap(ASN1_SEQUENCE, "mm",
+ asn1_wrap(ASN1_OID, "c", x501rdns[i].oid),
+ asn1_wrap(rdn_type, "c", name)
+ )
+ );
+ dn_len += rdns[rdn_count++].len;
+ }
+ else
+ {
+ status = OUT_OF_RES;
+ }
+ /* reset name and change state */
+ name = chunk_empty;
+ state = SEARCH_OID;
+ }
+ break;
+ case UNKNOWN_OID:
+ break;
+ }
+ } while (*src++ != '\0');
+
+ /* build the distinguished name sequence */
+ {
+ int i;
+ u_char *pos = build_asn1_object(dn, ASN1_SEQUENCE, dn_len);
+
+ for (i = 0; i < rdn_count; i++)
+ {
+ memcpy(pos, rdns[i].ptr, rdns[i].len);
+ pos += rdns[i].len;
+ free(rdns[i].ptr);
+ }
+ }
+
+ if (status != SUCCESS)
+ {
+ free(dn->ptr);
+ *dn = chunk_empty;
+ }
+ 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.contains_wildcards.
+ */
+static bool contains_wildcards(private_identification_t *this)
+{
+ switch (this->type)
+ {
+ case ID_ANY:
+ return TRUE;
+ case ID_FQDN:
+ case ID_RFC822_ADDR:
+ return memchr(this->encoded.ptr, '*', this->encoded.len) != NULL;
+ case ID_DER_ASN1_DN:
+ /* TODO */
+ default:
+ return FALSE;
+
+ }
+}
+
+/**
+ * Default implementation of identification_t.equals.
+ * compares encoded chunk for equality.
+ */
+static bool equals_binary(private_identification_t *this, private_identification_t *other)
+{
+ return this->type == other->type &&
+ chunk_equals(this->encoded, other->encoded);
+}
+
+/**
+ * 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);
+}
+
+/**
+ * Default implementation of identification_t.matches.
+ */
+static bool matches_binary(private_identification_t *this,
+ private_identification_t *other, int *wildcards)
+{
+ if (other->type == ID_ANY)
+ {
+ if (wildcards)
+ {
+ *wildcards = MAX_WILDCARDS;
+ }
+ return TRUE;
+ }
+ if (wildcards)
+ {
+ *wildcards = 0;
+ }
+ return this->type == other->type &&
+ chunk_equals(this->encoded, other->encoded);
+}
+
+/**
+ * Special implementation of identification_t.matches for ID_RFC822_ADDR/ID_FQDN.
+ * Checks for a wildcard in other-string, and compares it against this-string.
+ */
+static bool matches_string(private_identification_t *this,
+ private_identification_t *other, int *wildcards)
+{
+ u_int len = other->encoded.len;
+
+ if (other->type == ID_ANY)
+ {
+ if (wildcards)
+ {
+ *wildcards = MAX_WILDCARDS;
+ }
+ return TRUE;
+ }
+
+ if (this->type != other->type)
+ return FALSE;
+
+ /* try a binary comparison first */
+ if (equals_binary(this, other))
+ {
+ if (wildcards)
+ {
+ *wildcards = 0;
+ }
+ return TRUE;
+ }
+
+ if (len == 0 || this->encoded.len < len)
+ return FALSE;
+
+ /* check for single wildcard at the head of the string */
+ if (*other->encoded.ptr == '*')
+ {
+ if (wildcards)
+ {
+ *wildcards = 1;
+ }
+
+ /* single asterisk matches any string */
+ if (len-- == 1)
+ return TRUE;
+
+ if (memeq(this->encoded.ptr + this->encoded.len - len, other->encoded.ptr + 1, len))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ * Special implementation of identification_t.matches for ID_ANY.
+ * ANY matches only another ANY, but nothing other
+ */
+static bool matches_any(private_identification_t *this,
+ private_identification_t *other, int *wildcards)
+{
+ if (wildcards)
+ {
+ *wildcards = 0;
+ }
+ return other->type == ID_ANY;
+}
+
+/**
+ * Special implementation of identification_t.matches for ID_DER_ASN1_DN.
+ * ANY matches any, even ANY, thats why its there...
+ */
+static bool matches_dn(private_identification_t *this,
+ private_identification_t *other, int *wildcards)
+{
+ if (other->type == ID_ANY)
+ {
+ if (wildcards)
+ {
+ *wildcards = MAX_WILDCARDS;
+ }
+ return TRUE;
+ }
+
+ if (this->type == other->type)
+ {
+ return match_dn(this->encoded, other->encoded, wildcards);
+ }
+ return FALSE;
+}
+
+/**
+ * output handler in printf()
+ */
+static int print(FILE *stream, const struct printf_info *info,
+ const void *const *args)
+{
+ private_identification_t *this = *((private_identification_t**)(args[0]));
+ char buf[BUF_LEN];
+ chunk_t proper, buf_chunk = chunk_from_buf(buf);
+ int written;
+
+ if (this == NULL)
+ {
+ return fprintf(stream, "(null)");
+ }
+
+ switch (this->type)
+ {
+ case ID_ANY:
+ return fprintf(stream, "%%any");
+ case ID_IPV4_ADDR:
+ if (this->encoded.len < sizeof(struct in_addr) ||
+ inet_ntop(AF_INET, this->encoded.ptr, buf, sizeof(buf)) == NULL)
+ {
+ return fprintf(stream, "(invalid ID_IPV4_ADDR)");
+ }
+ else
+ {
+ return fprintf(stream, "%s", buf);
+ }
+ case ID_IPV6_ADDR:
+ if (this->encoded.len < sizeof(struct in6_addr) ||
+ inet_ntop(AF_INET6, this->encoded.ptr, buf, INET6_ADDRSTRLEN) == NULL)
+ {
+ return fprintf(stream, "(invalid ID_IPV6_ADDR)");
+ }
+ else
+ {
+ return fprintf(stream, "%s", buf);
+ }
+ case ID_FQDN:
+ {
+ proper = sanitize_chunk(this->encoded);
+ written = fprintf(stream, "@%.*s", proper.len, proper.ptr);
+ chunk_free(&proper);
+ return written;
+ }
+ case ID_RFC822_ADDR:
+ {
+ proper = sanitize_chunk(this->encoded);
+ written = fprintf(stream, "%.*s", proper.len, proper.ptr);
+ chunk_free(&proper);
+ return written;
+ }
+ case ID_DER_ASN1_DN:
+ {
+ snprintf(buf, sizeof(buf), "%.*s", this->encoded.len, this->encoded.ptr);
+ /* TODO: whats returned on failure?*/
+ dntoa(this->encoded, &buf_chunk);
+ return fprintf(stream, "%s", buf);
+ }
+ case ID_DER_ASN1_GN:
+ return fprintf(stream, "(ASN.1 general Name");
+ case ID_KEY_ID:
+ return fprintf(stream, "(KEY_ID)");
+ case ID_DER_ASN1_GN_URI:
+ {
+ proper = sanitize_chunk(this->encoded);
+ written = fprintf(stream, "%.*s", proper.len, proper.ptr);
+ chunk_free(&proper);
+ return written;
+ }
+ default:
+ return fprintf(stream, "(unknown ID type: %d)", this->type);
+ }
+}
+
+/**
+ * register printf() handlers
+ */
+static void __attribute__ ((constructor))print_register()
+{
+ register_printf_function(PRINTF_IDENTIFICATION, print, arginfo_ptr);
+}
+
+/**
+ * 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->public.equals = this->public.equals;
+ clone->public.matches = this->public.matches;
+
+ return &clone->public;
+}
+
+/**
+ * Implementation of identification_t.destroy.
+ */
+static void destroy(private_identification_t *this)
+{
+ chunk_free(&this->encoded);
+ free(this);
+}
+
+/**
+ * Generic constructor used for the other constructors.
+ */
+static private_identification_t *identification_create(void)
+{
+ 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.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.matches = (bool (*) (identification_t*,identification_t*,int*))matches_binary;
+
+ this->encoded = chunk_empty;
+
+ return this;
+}
+
+/*
+ * Described in header.
+ */
+identification_t *identification_create_from_string(char *string)
+{
+ private_identification_t *this = identification_create();
+
+ if (string == NULL)
+ {
+ string = "%any";
+ }
+ 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
+ */
+ if (atodn(string, &this->encoded) != SUCCESS)
+ {
+ free(this);
+ return NULL;
+ }
+ this->type = ID_DER_ASN1_DN;
+ this->public.equals = (bool (*) (identification_t*,identification_t*))equals_dn;
+ this->public.matches = (bool (*) (identification_t*,identification_t*,int*))matches_dn;
+ return &this->public;
+ }
+ else if (strchr(string, '@') == NULL)
+ {
+ if (streq(string, "%any")
+ || streq(string, "0.0.0.0")
+ || streq(string, "*")
+ || streq(string, "::")
+ || streq(string, "0::0"))
+ {
+ /* any ID will be accepted */
+ this->type = ID_ANY;
+ this->public.matches = (bool (*)
+ (identification_t*,identification_t*,int*))matches_any;
+ return &this->public;
+ }
+ else
+ {
+ 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->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->type = ID_IPV6_ADDR;
+ return &(this->public);
+ }
+ }
+ }
+ else
+ {
+ if (*string == '@')
+ {
+ if (*(string + 1) == '#')
+ {
+ /* TODO: Pluto handles '#' as hex encoded ID_KEY_ID. */
+ free(this);
+ return NULL;
+ }
+ else
+ {
+ this->type = ID_FQDN;
+ this->encoded.ptr = strdup(string + 1);
+ this->encoded.len = strlen(string + 1);
+ this->public.matches = (bool (*)
+ (identification_t*,identification_t*,int*))matches_string;
+ return &(this->public);
+ }
+ }
+ else
+ {
+ this->type = ID_RFC822_ADDR;
+ this->encoded.ptr = strdup(string);
+ this->encoded.len = strlen(string);
+ this->public.matches = (bool (*)
+ (identification_t*,identification_t*,int*))matches_string;
+ 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();
+ this->type = type;
+ switch (type)
+ {
+ case ID_ANY:
+ this->public.matches = (bool (*)
+ (identification_t*,identification_t*,int*))matches_any;
+ break;
+ case ID_FQDN:
+ this->public.matches = (bool (*)
+ (identification_t*,identification_t*,int*))matches_string;
+ break;
+ case ID_RFC822_ADDR:
+ this->public.matches = (bool (*)
+ (identification_t*,identification_t*,int*))matches_string;
+ break;
+ case ID_DER_ASN1_DN:
+ this->public.equals = (bool (*)
+ (identification_t*,identification_t*))equals_dn;
+ this->public.matches = (bool (*)
+ (identification_t*,identification_t*,int*))matches_dn;
+ break;
+ case ID_IPV4_ADDR:
+ case ID_IPV6_ADDR:
+ case ID_DER_ASN1_GN:
+ case ID_KEY_ID:
+ case ID_DER_ASN1_GN_URI:
+ default:
+ break;
+ }
+
+ /* apply encoded chunk */
+ if (type != ID_ANY)
+ {
+ this->encoded = chunk_clone(encoded);
+ }
+ return &(this->public);
+}
diff --git a/src/libstrongswan/utils/identification.h b/src/libstrongswan/utils/identification.h
new file mode 100644
index 000000000..59c568eaf
--- /dev/null
+++ b/src/libstrongswan/utils/identification.h
@@ -0,0 +1,261 @@
+/**
+ * @file identification.h
+ *
+ * @brief Interface of identification_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef enum id_type_t id_type_t;
+typedef struct identification_t identification_t;
+
+#include <library.h>
+
+#define MAX_WILDCARDS 14
+
+/**
+ * @brief ID Types in a ID payload.
+ *
+ * @ingroup utils
+ */
+enum id_type_t {
+
+ /**
+ * private type which matches any other id.
+ */
+ ID_ANY = 0,
+
+ /**
+ * 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 an ID_RFC822_ADDR is "jsmith@example.com".
+ * The string MUST NOT contain any terminators.
+ */
+ ID_RFC822_ADDR = 3,
+
+ /**
+ * ID data is an IPv4 subnet (IKEv1 only)
+ */
+ ID_IPV4_ADDR_SUBNET = 4,
+
+ /**
+ * ID data is a single sixteen (16) octet IPv6 address.
+ */
+ ID_IPV6_ADDR = 5,
+
+ /**
+ * ID data is an IPv6 subnet (IKEv1 only)
+ */
+ ID_IPV6_ADDR_SUBNET = 6,
+
+ /**
+ * ID data is an IPv4 address range (IKEv1 only)
+ */
+ ID_IPV4_ADDR_RANGE = 7,
+
+ /**
+ * ID data is an IPv6 address range (IKEv1 only)
+ */
+ ID_IPV6_ADDR_RANGE = 8,
+
+ /**
+ * ID data is the binary DER encoding of an ASN.1 X.501 Distinguished Name
+ */
+ ID_DER_ASN1_DN = 9,
+
+ /**
+ * ID data is the binary DER encoding of an ASN.1 X.509 GeneralName
+ */
+ 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,
+
+ /**
+ * private type which represents a GeneralName of type URI
+ */
+ ID_DER_ASN1_GN_URI = 201,
+
+};
+
+/**
+ * enum names for id_type_t.
+ */
+extern enum_name_t *id_type_names;
+
+/**
+ * @brief Generic identification, such as used in ID payload.
+ *
+ * The following types are possible:
+ * - ID_IPV4_ADDR
+ * - ID_FQDN
+ * - ID_RFC822_ADDR
+ * - ID_IPV6_ADDR
+ * - ID_DER_ASN1_DN
+ * - ID_DER_ASN1_GN
+ * - ID_KEY_ID
+ * - ID_DER_ASN1_GN_URI
+ *
+ * @b Constructors:
+ * - identification_create_from_string()
+ * - identification_create_from_encoding()
+ *
+ * @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 Check if two identification_t objects are equal.
+ *
+ * @param this the identification_t object
+ * @param other other identification_t object
+ * @return TRUE if the IDs are equal
+ */
+ bool (*equals) (identification_t *this, identification_t *other);
+
+ /**
+ * @brief Check if an ID matches a wildcard ID.
+ *
+ * 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
+ * @param wildcards returns the number of wildcards, may be NULL
+ * @return TRUE if match is found
+ */
+ bool (*matches) (identification_t *this, identification_t *other, int *wildcards);
+
+ /**
+ * @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 string representation fails.
+ *
+ * @ingroup utils
+ */
+identification_t * identification_create_from_encoding(id_type_t type, chunk_t encoded);
+
+#endif /* IDENTIFICATION_H_ */
diff --git a/src/libstrongswan/utils/iterator.h b/src/libstrongswan/utils/iterator.h
new file mode 100644
index 000000000..02a15c534
--- /dev/null
+++ b/src/libstrongswan/utils/iterator.h
@@ -0,0 +1,166 @@
+/**
+ * @file iterator.h
+ *
+ * @brief Interface iterator_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+#include <library.h>
+
+/**
+ * @brief Iterator hook function prototype.
+ *
+ * @param param user supplied parameter
+ * @param in the value the hook receives from the iterator
+ * @param out the value supplied as a result to the iterator
+ * @return TRUE to return "out", FALSE to skip this value
+ */
+typedef bool (iterator_hook_t)(void *param, void *in, void **out);
+
+
+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 Return number of list items.
+ *
+ * @param this calling object
+ * @return number of list items
+ */
+ int (*get_count) (iterator_t *this);
+
+ /**
+ * @brief Iterate over all items.
+ *
+ * The easy way to iterate over items.
+ *
+ * @param this calling object
+ * @param[out] value item
+ * @return
+ * - TRUE, if there was an element available,
+ * - FALSE otherwise
+ */
+ bool (*iterate) (iterator_t *this, void** value);
+
+ /**
+ * @brief Hook a function into the iterator.
+ *
+ * Sometimes it is useful to hook in an iterator. The hook function is
+ * called before any successful return of iterate(). It takes the
+ * iterator value, may manipulate it (or the references object), and returns
+ * the value that the iterate() function returns.
+ * A value of NULL deactivates the iterator hook.
+ *
+ * @param this calling object
+ * @param hook iterator hook which manipulates the iterated value
+ * @param param user supplied parameter to pass back to the hook
+ */
+ void (*set_iterator_hook) (iterator_t *this, iterator_hook_t *hook,
+ void *param);
+
+ /**
+ * @brief Inserts a new item before the given iterator position.
+ *
+ * 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 iterator is set the the following position:
+ * - to the item before, if available
+ * - it gets reseted, otherwise
+ *
+ * @param this calling object
+ * @return
+ * - SUCCESS
+ * - FAILED if iterator is on an invalid position
+ */
+ status_t (*remove) (iterator_t *this);
+
+ /**
+ * @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/src/libstrongswan/utils/leak_detective.c b/src/libstrongswan/utils/leak_detective.c
new file mode 100644
index 000000000..b8a023270
--- /dev/null
+++ b/src/libstrongswan/utils/leak_detective.c
@@ -0,0 +1,459 @@
+/**
+ * @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 <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 <netdb.h>
+#include <printf.h>
+#ifdef HAVE_BACKTRACE
+# include <execinfo.h>
+#endif /* HAVE_BACKTRACE */
+
+#include "leak_detective.h"
+
+#include <library.h>
+#include <debug.h>
+
+#ifdef LEAK_DETECTIVE
+
+/**
+ * Magic value which helps to detect memory corruption. Yummy!
+ */
+#define MEMORY_HEADER_MAGIC 0x7ac0be11
+
+/**
+ * Pattern which is filled in memory before freeing it
+ */
+#define MEMORY_FREE_PATTERN 0xFF
+
+/**
+ * Pattern which is filled in newly allocated memory
+ */
+#define MEMORY_ALLOC_PATTERN 0xEE
+
+
+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 u_int count_malloc = 0;
+static u_int count_free = 0;
+static u_int count_realloc = 0;
+
+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
+};
+
+/**
+ * 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. This could be done with
+ * the addr2line utility or the GNU BFD Library...
+ */
+static void log_stack_frames(void **stack_frames, int stack_frame_count)
+{
+#ifdef HAVE_BACKTRACE
+ char **strings;
+ size_t i;
+
+ strings = backtrace_symbols (stack_frames, stack_frame_count);
+
+ DBG1(" dumping %d stack frame addresses", stack_frame_count);
+
+ for (i = 0; i < stack_frame_count; i++)
+ {
+ DBG1(" %s", strings[i]);
+ }
+ free (strings);
+#endif /* HAVE_BACKTRACE */
+}
+
+/**
+ * Whitelist, which contains address ranges in stack frames ignored when leaking.
+ *
+ * This is necessary, as some function use allocation hacks (static buffers)
+ * and so on, which we want to suppress on leak reports.
+ *
+ * The range_size is calculated using the readelf utility, e.g.:
+ * readelf -s /lib/glibc.so.6
+ * The values are for glibc-2.4 and may or may not be correct on other systems.
+ */
+typedef struct whitelist_t whitelist_t;
+
+struct whitelist_t {
+ void* range_start;
+ size_t range_size;
+};
+
+#ifdef LIBCURL
+/* dummy declaration for whitelisting */
+void *Curl_getaddrinfo(void);
+#endif /* LIBCURL */
+
+whitelist_t whitelist[] = {
+ {pthread_create, 2542},
+ {pthread_setspecific, 217},
+ {mktime, 60},
+ {tzset, 123},
+ {inet_ntoa, 249},
+ {strerror, 180},
+ {getprotobynumber, 291},
+ {getservbyport, 311},
+ {register_printf_function, 159},
+ {syslog, 45},
+ {dlopen, 109},
+# ifdef LIBCURL
+ /* from /usr/lib/libcurl.so.3 */
+ {Curl_getaddrinfo, 480},
+# endif /* LIBCURL */
+};
+
+/**
+ * Check if this stack frame is whitelisted.
+ */
+static bool is_whitelisted(void **stack_frames, int stack_frame_count)
+{
+ int i, j;
+
+ for (i=0; i< stack_frame_count; i++)
+ {
+ for (j=0; j<sizeof(whitelist)/sizeof(whitelist_t); j++)
+ {
+ if (stack_frames[i] >= whitelist[j].range_start &&
+ stack_frames[i] <= (whitelist[j].range_start + whitelist[j].range_size))
+ {
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+/**
+ * Report leaks at library destruction
+ */
+void report_leaks()
+{
+ memory_header_t *hdr;
+ int leaks = 0;
+
+ for (hdr = first_header.next; hdr != NULL; hdr = hdr->next)
+ {
+ if (!is_whitelisted(hdr->stack_frames, hdr->stack_frame_count))
+ {
+ DBG1("Leak (%d bytes at %p):", hdr->bytes, hdr + 1);
+ log_stack_frames(hdr->stack_frames, hdr->stack_frame_count);
+ leaks++;
+ }
+ }
+
+ switch (leaks)
+ {
+ case 0:
+ DBG1("No leaks detected");
+ break;
+ case 1:
+ DBG1("One leak detected");
+ break;
+ default:
+ DBG1("%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);
+ count_malloc++;
+ uninstall_hooks();
+ hdr = malloc(bytes + sizeof(memory_header_t));
+ /* set to something which causes crashes */
+ memset(hdr, MEMORY_ALLOC_PATTERN, bytes + sizeof(memory_header_t));
+
+ hdr->magic = MEMORY_HEADER_MAGIC;
+ hdr->bytes = bytes;
+ hdr->stack_frame_count = backtrace(hdr->stack_frames, STACK_FRAMES_COUNT);
+ install_hooks();
+
+ /* 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;
+ 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);
+ count_free++;
+ uninstall_hooks();
+ if (hdr->magic != MEMORY_HEADER_MAGIC)
+ {
+ DBG1("freeing of invalid memory (%p, MAGIC 0x%x != 0x%x):",
+ ptr, hdr->magic, MEMORY_HEADER_MAGIC);
+ stack_frame_count = backtrace(stack_frames, STACK_FRAMES_COUNT);
+ log_stack_frames(stack_frames, stack_frame_count);
+ install_hooks();
+ pthread_mutex_unlock(&mutex);
+ return;
+ }
+
+ /* remove item from list */
+ if (hdr->next)
+ {
+ hdr->next->previous = hdr->previous;
+ }
+ hdr->previous->next = hdr->next;
+
+ /* clear MAGIC, set mem to something remarkable */
+ memset(hdr, MEMORY_FREE_PATTERN, hdr->bytes + sizeof(memory_header_t));
+
+ free(hdr);
+ install_hooks();
+ pthread_mutex_unlock(&mutex);
+}
+
+/**
+ * Hook function for realloc()
+ */
+void *realloc_hook(void *old, size_t bytes, const void *caller)
+{
+ memory_header_t *hdr;
+ void *stack_frames[STACK_FRAMES_COUNT];
+ int stack_frame_count;
+
+ /* allow reallocation of NULL */
+ if (old == NULL)
+ {
+ return malloc_hook(bytes, caller);
+ }
+
+ hdr = old - sizeof(memory_header_t);
+
+ pthread_mutex_lock(&mutex);
+ count_realloc++;
+ uninstall_hooks();
+ if (hdr->magic != MEMORY_HEADER_MAGIC)
+ {
+ DBG1("reallocation of invalid memory (%p):", old);
+ stack_frame_count = backtrace(stack_frames, STACK_FRAMES_COUNT);
+ log_stack_frames(stack_frames, stack_frame_count);
+ install_hooks();
+ pthread_mutex_unlock(&mutex);
+ raise(SIGKILL);
+ return NULL;
+ }
+
+ hdr = realloc(hdr, bytes + sizeof(memory_header_t));
+
+ /* update statistics */
+ hdr->bytes = bytes;
+ hdr->stack_frame_count = backtrace(hdr->stack_frames, STACK_FRAMES_COUNT);
+
+ /* update header of linked list neighbours */
+ if (hdr->next)
+ {
+ hdr->next->previous = hdr;
+ }
+ hdr->previous->next = hdr;
+ install_hooks();
+ pthread_mutex_unlock(&mutex);
+ return hdr + 1;
+}
+
+/**
+ * Setup leak detective
+ */
+void __attribute__ ((constructor)) leak_detective_init()
+{
+ install_hooks();
+}
+
+/**
+ * Clean up leak detective
+ */
+void __attribute__ ((destructor)) leak_detective_cleanup()
+{
+ uninstall_hooks();
+ report_leaks();
+}
+
+/**
+ * Log memory allocation statistics
+ */
+void leak_detective_status(FILE *stream)
+{
+ u_int blocks = 0;
+ size_t bytes = 0;
+ memory_header_t *hdr = &first_header;
+
+ pthread_mutex_lock(&mutex);
+ while ((hdr = hdr->next))
+ {
+ blocks++;
+ bytes += hdr->bytes;
+ }
+ pthread_mutex_unlock(&mutex);
+
+ fprintf(stream, "allocation statistics:\n");
+ fprintf(stream, " call stats: malloc: %d, free: %d, realloc: %d\n",
+ count_malloc, count_free, count_realloc);
+ fprintf(stream, " allocated %d blocks, total size %d bytes (avg. %d bytes)\n",
+ blocks, bytes, bytes/blocks);
+}
+
+#else /* !LEAK_DETECTION */
+
+/**
+ * Dummy when !using LEAK_DETECTIVE
+ */
+void leak_detective_status(FILE *stream)
+{
+
+}
+
+#endif /* LEAK_DETECTION */
diff --git a/src/libstrongswan/utils/leak_detective.h b/src/libstrongswan/utils/leak_detective.h
new file mode 100644
index 000000000..d4016b06e
--- /dev/null
+++ b/src/libstrongswan/utils/leak_detective.h
@@ -0,0 +1,35 @@
+/**
+ * @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_
+
+/**
+ * Log status information about allocation
+ */
+void leak_detective_status(FILE *stream);
+
+/**
+ * Max number of stack frames to include in a backtrace.
+ */
+#define STACK_FRAMES_COUNT 30
+
+#endif /* LEAK_DETECTIVE_H_ */
diff --git a/src/libstrongswan/utils/lexparser.c b/src/libstrongswan/utils/lexparser.c
new file mode 100644
index 000000000..9d3f06593
--- /dev/null
+++ b/src/libstrongswan/utils/lexparser.c
@@ -0,0 +1,137 @@
+/**
+ * @file lexparser.c
+ *
+ * @brief lexical parser for text-based configuration files
+ *
+ */
+
+/*
+ * Copyright (C) 2001-2006 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.
+ */
+
+#include <string.h>
+
+#include "lexparser.h"
+
+
+/**
+ * eat whitespace
+ */
+bool eat_whitespace(chunk_t *src)
+{
+ while (src->len > 0 && (*src->ptr == ' ' || *src->ptr == '\t'))
+ {
+ src->ptr++; src->len--;
+ }
+ return src->len > 0 && *src->ptr != '#';
+}
+
+/**
+ * compare string with chunk
+ */
+bool match(const char *pattern, const chunk_t *ch)
+{
+ return ch->len == strlen(pattern) && strncmp(pattern, ch->ptr, ch->len) == 0;
+}
+
+/**
+ * extracts a token ending with a given termination symbol
+ */
+bool extract_token(chunk_t *token, const char termination, chunk_t *src)
+{
+ u_char *eot = memchr(src->ptr, termination, src->len);
+
+ /* initialize empty token */
+ *token = chunk_empty;
+
+ 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;
+}
+
+/**
+ * fetches a new line terminated by \n or \r\n
+ */
+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;
+}
+
+err_t extract_value(chunk_t *value, chunk_t *line)
+{
+ char delimiter = ' ';
+
+ if (!eat_whitespace(line))
+ {
+ *value = chunk_empty;
+ return NULL;
+ }
+ if (*line->ptr == '\'' || *line->ptr == '"')
+ {
+ delimiter = *line->ptr;
+ line->ptr++; line->len--;
+ }
+ if (!extract_token(value, delimiter, line))
+ {
+ if (delimiter == ' ')
+ {
+ *value = *line;
+ line->len = 0;
+ }
+ else
+ {
+ return "missing second delimiter";
+ }
+ }
+ return NULL;
+}
+
+/**
+ * extracts a parameter: value pair
+ */
+err_t extract_parameter_value(chunk_t *name, chunk_t *value, chunk_t *line)
+{
+ /* extract name */
+ if (!extract_token(name,':', line))
+ {
+ return "missing ':'";
+ }
+
+ /* extract value */
+ return extract_value(value, line);
+}
diff --git a/src/libstrongswan/utils/lexparser.h b/src/libstrongswan/utils/lexparser.h
new file mode 100644
index 000000000..e3c2c4c70
--- /dev/null
+++ b/src/libstrongswan/utils/lexparser.h
@@ -0,0 +1,57 @@
+/**
+ * @file lexparser.h
+ *
+ * @brief lexical parser for text-based configuration files
+ *
+ */
+
+/*
+ * Copyright (C) 2001-2006 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.
+ */
+
+#include <library.h>
+
+/**
+ * @brief Eats whitespace
+ */
+bool eat_whitespace(chunk_t *src);
+
+/**
+ * @brief Compare null-terminated pattern with chunk
+ */
+bool match(const char *pattern, const chunk_t *ch);
+
+/**
+ * @brief Extracts a token ending with a given termination symbol
+ */
+bool extract_token(chunk_t *token, const char termination, chunk_t *src);
+
+/**
+ * @brief Fetches a new text line terminated by \n or \r\n
+ */
+bool fetchline(chunk_t *src, chunk_t *line);
+
+/**
+ * @brief Extracts a value that might be single or double quoted
+ */
+err_t extract_value(chunk_t *value, chunk_t *line);
+
+/**
+ * @brief extracts a name: value pair from a text line
+ */
+err_t extract_name_value(chunk_t *name, chunk_t *value, chunk_t *line);
+
+/**
+ * @brief extracts a parameter: value from a text line
+ */
+err_t extract_parameter_value(chunk_t *name, chunk_t *value, chunk_t *line);
diff --git a/src/libstrongswan/utils/linked_list.c b/src/libstrongswan/utils/linked_list.c
new file mode 100644
index 000000000..de043a02e
--- /dev/null
+++ b/src/libstrongswan/utils/linked_list.c
@@ -0,0 +1,763 @@
+/**
+ * @file linked_list.c
+ *
+ * @brief Implementation of linked_list_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 element_t element_t;
+
+/**
+ * This element holds a pointer to the value it represents.
+ */
+struct element_t {
+
+ /**
+ * Value of a list item.
+ */
+ void *value;
+
+ /**
+ * Previous list element.
+ *
+ * NULL if first element in list.
+ */
+ element_t *previous;
+
+ /**
+ * Next list element.
+ *
+ * NULL if last element in list.
+ */
+ element_t *next;
+};
+
+/**
+ * Creates an empty linked list object.
+ */
+element_t *element_create(void *value)
+{
+ element_t *this = malloc_thing(element_t);
+
+ 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.
+ */
+ element_t *first;
+
+ /**
+ * Last element in list.
+ * NULL if no elements in 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.
+ */
+ element_t *current;
+
+ /**
+ * Direction of iterator.
+ */
+ bool forward;
+
+ /**
+ * Mutex to use to synchronize access
+ */
+ pthread_mutex_t *mutex;
+
+ /**
+ * iteration hook
+ */
+ iterator_hook_t *hook;
+
+ /**
+ * user parameter for iterator hook
+ */
+ void *hook_param;
+};
+
+/**
+ * Implementation of iterator_t.get_count.
+ */
+static int get_list_count(private_iterator_t *this)
+{
+ return this->list->count;
+}
+
+/**
+ * default iterator hook which does nothing
+ */
+static bool iterator_hook(void *param, void *in, void **out)
+{
+ *out = in;
+ return TRUE;
+}
+
+/**
+ * Implementation of iterator_t.set_iterator_hook.
+ */
+static void set_iterator_hook(private_iterator_t *this, iterator_hook_t *hook,
+ void* param)
+{
+ if (hook == NULL)
+ {
+ this->hook = iterator_hook;
+ this->hook_param = NULL;
+ }
+ else
+ {
+ this->hook = hook;
+ this->hook_param = param;
+ }
+}
+
+/**
+ * Implementation of iterator_t.iterate.
+ */
+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;
+ if (!this->hook(this->hook_param, this->current->value, value))
+ {
+ return iterate(this, value);
+ }
+ return TRUE;
+ }
+ if (this->forward)
+ {
+ if (this->current->next == NULL)
+ {
+ return FALSE;
+ }
+ this->current = this->current->next;
+ if (!this->hook(this->hook_param, this->current->value, value))
+ {
+ return iterate(this, value);
+ }
+ return TRUE;
+ }
+ if (this->current->previous == NULL)
+ {
+ return FALSE;
+ }
+ this->current = this->current->previous;
+ if (!this->hook(this->hook_param, this->current->value, value))
+ {
+ return iterate(this, value);
+ }
+ return TRUE;
+}
+
+/**
+ * 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)
+{
+ 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, depending on iterator direction */
+ if (this->forward && this->current->previous != NULL)
+ {
+ new_current = this->current->previous;
+ }
+ else if (!this->forward && 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--;
+ free(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);
+ }
+
+ element_t *element = 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;
+ }
+
+ element_t *element = 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)
+{
+ if (this->mutex)
+ {
+ pthread_mutex_unlock(this->mutex);
+ }
+ 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.insert_first.
+ */
+static void insert_first(private_linked_list_t *this, void *item)
+{
+ element_t *element;
+
+ element = element_create(item);
+ if (this->count == 0)
+ {
+ /* first entry in list */
+ this->first = element;
+ this->last = element;
+ element->previous = NULL;
+ element->next = NULL;
+ }
+ else
+ {
+ 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)
+{
+ element_t *element = this->first;
+
+ if (element == NULL)
+ {
+ return NOT_FOUND;
+ }
+ if (element->next != NULL)
+ {
+ element->next->previous = NULL;
+ }
+ this->first = element->next;
+
+ if (item != NULL)
+ {
+ *item = element->value;
+ }
+ if (--this->count == 0)
+ {
+ this->last = NULL;
+ }
+
+ free(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)
+{
+ element_t *element = element_create(item);
+
+ if (this->count == 0)
+ {
+ /* first entry in list */
+ this->first = element;
+ this->last = element;
+ element->previous = NULL;
+ element->next = NULL;
+ }
+ else
+ {
+ 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)
+{
+ element_t *element = this->last;
+
+ if (element == NULL)
+ {
+ return NOT_FOUND;
+ }
+ if (element->previous != NULL)
+ {
+ element->previous->next = NULL;
+ }
+ this->last = element->previous;
+
+ if (item != NULL)
+ {
+ *item = element->value;
+ }
+ if (--this->count == 0)
+ {
+ this->first = NULL;
+ }
+
+ free(element);
+
+ 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)
+{
+ 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;
+ }
+
+ element_t *element = element_create(item);
+ if (current_element->previous == NULL)
+ {
+ current_element->previous = element;
+ element->next = current_element;
+ this->first = element;
+ }
+ else
+ {
+ current_element->previous->next = element;
+ element->previous = current_element->previous;
+ current_element->previous = element;
+ element->next = current_element;
+ }
+
+
+ this->count++;
+ return SUCCESS;
+}
+
+/**
+ * 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->iterate(iterator, item);
+ for (i = 0; i < position; i++)
+ {
+ if (!iterator->iterate(iterator, item))
+ {
+ iterator->destroy(iterator);
+ return INVALID_ARG;
+ }
+ }
+ iterator->remove(iterator);
+ iterator->destroy(iterator);
+
+ return SUCCESS;
+}
+
+/**
+ * Implementation of linked_list_t.get_at_position.
+ */
+static status_t get_at_position(private_linked_list_t *this,size_t position, void **item)
+{
+ int i;
+ iterator_t *iterator;
+
+ if (this->count <= position)
+ {
+ return INVALID_ARG;
+ }
+
+ iterator = this->public.create_iterator(&(this->public),TRUE);
+ iterator->iterate(iterator, item);
+ for (i = 0; i < position; i++)
+ {
+ if (!iterator->iterate(iterator, item))
+ {
+ iterator->destroy(iterator);
+ return INVALID_ARG;
+ }
+ }
+ iterator->destroy(iterator);
+ return SUCCESS;
+}
+
+/**
+ * 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.invoke.
+ */
+static void invoke(private_linked_list_t *this, size_t offset)
+{
+ element_t *current = this->first;
+
+ while (current)
+ {
+ void (**method)(void*) = current->value + offset;
+ (*method)(current->value);
+ current = current->next;
+ }
+}
+
+/**
+ * Implementation of linked_list_t.destroy.
+ */
+static void destroy(private_linked_list_t *this)
+{
+ void *value;
+ /* Remove all list items before destroying list */
+ while (this->public.remove_first(&(this->public), &value) == SUCCESS)
+ {
+ /* values are not destroyed so memory leaks are possible
+ * if list is not empty when deleting */
+ }
+ free(this);
+}
+
+/**
+ * Implementation of linked_list_t.destroy_offset.
+ */
+static void destroy_offset(private_linked_list_t *this, size_t offset)
+{
+ element_t *current = this->first, *next;
+
+ while (current)
+ {
+ void (**method)(void*) = current->value + offset;
+ (*method)(current->value);
+ next = current->next;
+ free(current);
+ current = next;
+ }
+ free(this);
+}
+
+/**
+ * Implementation of linked_list_t.destroy_function.
+ */
+static void destroy_function(private_linked_list_t *this, void (*fn)(void*))
+{
+ element_t *current = this->first, *next;
+
+ while (current)
+ {
+ fn(current->value);
+ next = current->next;
+ free(current);
+ current = next;
+ }
+ free(this);
+}
+
+/**
+ * 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.get_count = (int (*) (iterator_t*)) get_list_count;
+ this->public.iterate = (bool (*) (iterator_t*, void **value)) iterate;
+ this->public.set_iterator_hook = (void(*)(iterator_t*, iterator_hook_t*, void*))set_iterator_hook;
+ this->public.insert_before = (void (*) (iterator_t*, void *item)) insert_before;
+ this->public.insert_after = (void (*) (iterator_t*, void *item)) insert_after;
+ this->public.replace = (status_t (*) (iterator_t*, void **, void *)) replace;
+ this->public.remove = (status_t (*) (iterator_t*)) remove_;
+ this->public.reset = (void (*) (iterator_t*)) iterator_reset;
+ this->public.destroy = (void (*) (iterator_t*)) iterator_destroy;
+
+ this->forward = forward;
+ this->current = NULL;
+ this->list = linked_list;
+ this->mutex = NULL;
+ this->hook = iterator_hook;
+
+ return &this->public;
+}
+
+/**
+ * Implementation of linked_list_t.create_iterator_locked.
+ */
+static iterator_t *create_iterator_locked(private_linked_list_t *linked_list,
+ pthread_mutex_t *mutex)
+{
+ private_iterator_t *this = (private_iterator_t*)create_iterator(linked_list, TRUE);
+ this->mutex = mutex;
+
+ pthread_mutex_lock(mutex);
+
+ return &this->public;
+}
+
+/*
+ * 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.create_iterator_locked = (iterator_t * (*) (linked_list_t *,pthread_mutex_t*))create_iterator_locked;
+ 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.invoke = (void (*)(linked_list_t*,size_t))invoke;
+ this->public.destroy = (void (*) (linked_list_t *))destroy;
+ this->public.destroy_offset = (void (*) (linked_list_t *,size_t))destroy_offset;
+ this->public.destroy_function = (void (*)(linked_list_t*,void(*)(void*)))destroy_function;
+
+ this->count = 0;
+ this->first = NULL;
+ this->last = NULL;
+
+ return &this->public;
+}
diff --git a/src/libstrongswan/utils/linked_list.h b/src/libstrongswan/utils/linked_list.h
new file mode 100644
index 000000000..58bcbbdaa
--- /dev/null
+++ b/src/libstrongswan/utils/linked_list.h
@@ -0,0 +1,232 @@
+/**
+ * @file linked_list.h
+ *
+ * @brief Interface of linked_list_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct linked_list_t linked_list_t;
+
+#include <pthread.h>
+
+#include <library.h>
+#include <utils/iterator.h>
+
+/**
+ * @brief Class implementing a double linked list.
+ *
+ * General purpose linked list. This list is not synchronized.
+ *
+ * @b Costructors:
+ * - linked_list_create()
+ *
+ * @ingroup utils
+ */
+struct linked_list_t {
+
+ /**
+ * @brief Gets the count of items in the list.
+ *
+ * @param this calling object
+ * @return number of items in list
+ */
+ int (*get_count) (linked_list_t *this);
+
+ /**
+ * @brief Creates a iterator for the given list.
+ *
+ * @warning Created iterator_t object has to get destroyed by the caller.
+ *
+ * @param this calling object
+ * @param forward iterator direction (TRUE: front to end)
+ * @return new iterator_t object
+ */
+ iterator_t *(*create_iterator) (linked_list_t *this, bool forward);
+
+ /**
+ * @brief Creates a iterator, locking a mutex.
+ *
+ * The supplied mutex is acquired immediately, and released
+ * when the iterator gets destroyed.
+ *
+ * @param this calling object
+ * @param mutex mutex to use for exclusive access
+ * @return new iterator_t object
+ */
+ iterator_t *(*create_iterator_locked) (linked_list_t *this,
+ pthread_mutex_t *mutex);
+
+ /**
+ * @brief Inserts a new item at the beginning of the list.
+ *
+ * @param this calling object
+ * @param[in] item item value to insert in list
+ */
+ void (*insert_first) (linked_list_t *this, void *item);
+
+ /**
+ * @brief Removes the first item in the list and returns its value.
+ *
+ * @param this 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 *this, void **item);
+
+ /**
+ * @brief Returns the value of the first list item without removing it.
+ *
+ * @param this calling object
+ * @param[out] item returned value of first item
+ * @return
+ * - SUCCESS
+ * - NOT_FOUND, if list is empty
+ */
+ status_t (*get_first) (linked_list_t *this, void **item);
+
+ /**
+ * @brief Inserts a new item at the end of the list.
+ *
+ * @param this calling object
+ * @param[in] item value to insert into list
+ */
+ void (*insert_last) (linked_list_t *this, void *item);
+
+ /**
+ * @brief Inserts a new item at a given position in the list.
+ *
+ * @param this calling object
+ * @param position position starting at 0 to insert new entry
+ * @param[in] item value to insert into list
+ * @return
+ * - SUCCESS
+ * - INVALID_ARG if position not existing
+ */
+ status_t (*insert_at_position) (linked_list_t *this,size_t position, void *item);
+
+ /**
+ * @brief Removes an item from a given position in the list.
+ *
+ * @param this calling object
+ * @param position position starting at 0 to remove entry from
+ * @param[out] item removed item will be stored at this location
+ * @return
+ * - SUCCESS
+ * - INVALID_ARG if position not existing
+ */
+ status_t (*remove_at_position) (linked_list_t *this, size_t position, void **item);
+
+ /**
+ * @brief Get an item from a given position in the list.
+ *
+ * @param this calling object
+ * @param position position starting at 0 to get entry from
+ * @param[out] item item will be stored at this location
+ * @return
+ * - SUCCESS
+ * - INVALID_ARG if position not existing
+ */
+ status_t (*get_at_position) (linked_list_t *this, size_t position, void **item);
+
+ /**
+ * @brief Removes the last item in the list and returns its value.
+ *
+ * @param this calling object
+ * @param[out] item returned value of last item, or NULL
+ * @return
+ * - SUCCESS
+ * - NOT_FOUND if list is empty
+ */
+ status_t (*remove_last) (linked_list_t *this, void **item);
+
+ /**
+ * @brief Returns the value of the last list item without removing it.
+ *
+ * @param this calling object
+ * @param[out] item returned value of last item
+ * @return
+ * - SUCCESS
+ * - NOT_FOUND if list is empty
+ */
+ status_t (*get_last) (linked_list_t *this, void **item);
+
+ /**
+ * @brief Invoke a method on all of the contained objects.
+ *
+ * If a linked list contains objects with function pointers,
+ * invoke() can call a method on each of the objects. The
+ * method is specified by an offset of the function pointer,
+ * which can be evalutated at compile time using the offsetof
+ * macro, e.g.: list->invoke(list, offsetof(object_t, method));
+ *
+ * @param this calling object
+ * @param offset offset of the method to invoke on objects
+ */
+ void (*invoke) (linked_list_t *this, size_t offset);
+
+ /**
+ * @brief Destroys a linked_list object.
+ *
+ * @param this calling object
+ */
+ void (*destroy) (linked_list_t *this);
+
+ /**
+ * @brief Destroys a list and its objects using the destructor.
+ *
+ * If a linked list and the contained objects should be destroyed, use
+ * destroy_offset. The supplied offset specifies the destructor to
+ * call on each object. The offset may be calculated using the offsetof
+ * macro, e.g.: list->destroy_offset(list, offsetof(object_t, destroy));
+ *
+ * @param this calling object
+ * @param offset offset of the objects destructor
+ */
+ void (*destroy_offset) (linked_list_t *this, size_t offset);
+
+ /**
+ * @brief Destroys a list and its contents using a a cleanup function.
+ *
+ * If a linked list and its contents should get destroyed using a specific
+ * cleanup function, use destroy_function. This is useful when the
+ * list contains malloc()-ed blocks which should get freed,
+ * e.g.: list->destroy_function(list, free);
+ *
+ * @param this calling object
+ * @param function function to call on each object
+ */
+ void (*destroy_function) (linked_list_t *this, void (*)(void*));
+};
+
+/**
+ * @brief Creates an empty linked list object.
+ *
+ * @return linked_list_t object.
+ *
+ * @ingroup utils
+ */
+linked_list_t *linked_list_create(void);
+
+
+#endif /*LINKED_LIST_H_*/
diff --git a/src/libstrongswan/utils/randomizer.c b/src/libstrongswan/utils/randomizer.c
new file mode 100644
index 000000000..c15d108c7
--- /dev/null
+++ b/src/libstrongswan/utils/randomizer.c
@@ -0,0 +1,165 @@
+/**
+ * @file randomizer.c
+ *
+ * @brief Implementation of randomizer_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 ? DEV_URANDOM : DEV_RANDOM;
+
+ 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/src/libstrongswan/utils/randomizer.h b/src/libstrongswan/utils/randomizer.h
new file mode 100644
index 000000000..afbade059
--- /dev/null
+++ b/src/libstrongswan/utils/randomizer.h
@@ -0,0 +1,114 @@
+/**
+ * @file randomizer.h
+ *
+ * @brief Interface of randomizer_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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_
+
+typedef struct randomizer_t randomizer_t;
+
+#include <library.h>
+
+#ifndef DEV_RANDOM
+/**
+ * Device to read real random bytes
+ */
+# define DEV_RANDOM "/dev/random"
+#endif
+
+#ifndef DEV_URANDOM
+/**
+ * Device to read pseudo random bytes
+ */
+# define DEV_URANDOM "/dev/urandom"
+#endif
+
+/**
+ * @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(void);
+
+#endif /*RANDOMIZER_H_*/
diff --git a/src/openac/Makefile.am b/src/openac/Makefile.am
new file mode 100644
index 000000000..c1e2a593a
--- /dev/null
+++ b/src/openac/Makefile.am
@@ -0,0 +1,98 @@
+ipsec_PROGRAMS = openac
+openac_SOURCES = openac.c build.c build.h loglite.c
+
+INCLUDES = \
+-I$(top_srcdir)/src/libfreeswan \
+-I$(top_srcdir)/src/pluto \
+-I$(top_srcdir)/src/libcrypto \
+-I$(top_srcdir)/src/whack
+
+AM_CFLAGS = -DDEBUG -DNO_PLUTO -DIPSEC_CONFDIR=\"${confdir}\"
+openac_LDADD = ac.o asn1.o ca.o certs.o constants.o crl.o defs.o mp_defs.o fetch.o id.o keys.o lex.o \
+ md2.o md5.o ocsp.o oid.o pem.o pgp.o pkcs1.o rnd.o sha1.o smartcard.o x509.o \
+ $(top_srcdir)/src/libfreeswan/libfreeswan.a $(top_srcdir)/src/libcrypto/libcrypto.a \
+ -lgmp
+
+# This compile option activates dynamic URL fetching using libcurl
+if USE_LIBCURL
+ openac_LDADD += -lcurl
+endif
+
+# This compile option activates smartcard support
+if USE_SMARTCARD
+ openac_LDADD += -ldl
+endif
+
+dist_man_MANS = openac.8
+
+PLUTODIR=$(top_srcdir)/src/pluto
+
+ac.o : $(PLUTODIR)/ac.c $(PLUTODIR)/ac.h
+ $(COMPILE) -c -o $@ $<
+
+asn1.o : $(PLUTODIR)/asn1.c $(PLUTODIR)/asn1.h
+ $(COMPILE) -c -o $@ $<
+
+ca.o : $(PLUTODIR)/ca.c $(PLUTODIR)/ca.h
+ $(COMPILE) -c -o $@ $<
+
+certs.o : $(PLUTODIR)/certs.c $(PLUTODIR)/certs.h
+ $(COMPILE) -c -o $@ $<
+
+constants.o : $(PLUTODIR)/constants.c $(PLUTODIR)/constants.h
+ $(COMPILE) -c -o $@ $<
+
+crl.o : $(PLUTODIR)/crl.c $(PLUTODIR)/crl.h
+ $(COMPILE) -c -o $@ $<
+
+defs.o : $(PLUTODIR)/defs.c $(PLUTODIR)/defs.h
+ $(COMPILE) -c -o $@ $<
+
+mp_defs.o : $(PLUTODIR)/mp_defs.c $(PLUTODIR)/mp_defs.h
+ $(COMPILE) -c -o $@ $<
+
+fetch.o : $(PLUTODIR)/fetch.c $(PLUTODIR)/fetch.h
+ $(COMPILE) -c -o $@ $<
+
+id.o : $(PLUTODIR)/id.c $(PLUTODIR)/id.h
+ $(COMPILE) -c -o $@ $<
+
+keys.o : $(PLUTODIR)/keys.c $(PLUTODIR)/keys.h
+ $(COMPILE) -c -o $@ $<
+
+lex.o : $(PLUTODIR)/lex.c $(PLUTODIR)/lex.h
+ $(COMPILE) -c -o $@ $<
+
+md2.o : $(PLUTODIR)/md2.c $(PLUTODIR)/md2.h
+ $(COMPILE) -c -o $@ $<
+
+md5.o : $(PLUTODIR)/md5.c $(PLUTODIR)/md5.h
+ $(COMPILE) -c -o $@ $<
+
+ocsp.o : $(PLUTODIR)/ocsp.c $(PLUTODIR)/ocsp.h
+ $(COMPILE) -c -o $@ $<
+
+oid.o : $(PLUTODIR)/oid.c $(PLUTODIR)/oid.h
+ $(COMPILE) -c -o $@ $<
+
+pem.o : $(PLUTODIR)/pem.c $(PLUTODIR)/pem.h
+ $(COMPILE) -c -o $@ $<
+
+pgp.o : $(PLUTODIR)/pgp.c $(PLUTODIR)/pgp.h
+ $(COMPILE) -c -o $@ $<
+
+pkcs1.o : $(PLUTODIR)/pkcs1.c $(PLUTODIR)/pkcs1.h
+ $(COMPILE) -c -o $@ $<
+
+rnd.o : $(PLUTODIR)/rnd.c $(PLUTODIR)/rnd.h
+ $(COMPILE) -c -o $@ $<
+
+sha1.o : $(PLUTODIR)/sha1.c $(PLUTODIR)/sha1.h
+ $(COMPILE) -c -o $@ $<
+
+smartcard.o : $(PLUTODIR)/smartcard.c $(PLUTODIR)/smartcard.h
+ $(COMPILE) -c -o $@ $<
+
+x509.o : $(PLUTODIR)/x509.c $(PLUTODIR)/x509.h
+ $(COMPILE) -c -o $@ $<
+
diff --git a/src/openac/Makefile.in b/src/openac/Makefile.in
new file mode 100644
index 000000000..8a2bee51f
--- /dev/null
+++ b/src/openac/Makefile.in
@@ -0,0 +1,624 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+ipsec_PROGRAMS = openac$(EXEEXT)
+
+# This compile option activates dynamic URL fetching using libcurl
+@USE_LIBCURL_TRUE@am__append_1 = -lcurl
+
+# This compile option activates smartcard support
+@USE_SMARTCARD_TRUE@am__append_2 = -ldl
+subdir = src/openac
+DIST_COMMON = $(dist_man_MANS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_CLEAN_FILES =
+am__installdirs = "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(man8dir)"
+ipsecPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(ipsec_PROGRAMS)
+am_openac_OBJECTS = openac.$(OBJEXT) build.$(OBJEXT) loglite.$(OBJEXT)
+openac_OBJECTS = $(am_openac_OBJECTS)
+am__DEPENDENCIES_1 =
+openac_DEPENDENCIES = ac.o asn1.o ca.o certs.o constants.o crl.o \
+ defs.o mp_defs.o fetch.o id.o keys.o lex.o md2.o md5.o ocsp.o \
+ oid.o pem.o pgp.o pkcs1.o rnd.o sha1.o smartcard.o x509.o \
+ $(top_srcdir)/src/libfreeswan/libfreeswan.a \
+ $(top_srcdir)/src/libcrypto/libcrypto.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+DEFAULT_INCLUDES = -I. -I$(srcdir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(openac_SOURCES)
+DIST_SOURCES = $(openac_SOURCES)
+man8dir = $(mandir)/man8
+NROFF = nroff
+MANS = $(dist_man_MANS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_EAP_SIM_FALSE = @BUILD_EAP_SIM_FALSE@
+BUILD_EAP_SIM_TRUE = @BUILD_EAP_SIM_TRUE@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GPERF = @GPERF@
+GREP = @GREP@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+USE_CISCO_QUIRKS_FALSE = @USE_CISCO_QUIRKS_FALSE@
+USE_CISCO_QUIRKS_TRUE = @USE_CISCO_QUIRKS_TRUE@
+USE_LEAK_DETECTIVE_FALSE = @USE_LEAK_DETECTIVE_FALSE@
+USE_LEAK_DETECTIVE_TRUE = @USE_LEAK_DETECTIVE_TRUE@
+USE_LIBCURL_FALSE = @USE_LIBCURL_FALSE@
+USE_LIBCURL_TRUE = @USE_LIBCURL_TRUE@
+USE_LIBLDAP_FALSE = @USE_LIBLDAP_FALSE@
+USE_LIBLDAP_TRUE = @USE_LIBLDAP_TRUE@
+USE_NAT_TRANSPORT_FALSE = @USE_NAT_TRANSPORT_FALSE@
+USE_NAT_TRANSPORT_TRUE = @USE_NAT_TRANSPORT_TRUE@
+USE_SMARTCARD_FALSE = @USE_SMARTCARD_FALSE@
+USE_SMARTCARD_TRUE = @USE_SMARTCARD_TRUE@
+USE_VENDORID_FALSE = @USE_VENDORID_FALSE@
+USE_VENDORID_TRUE = @USE_VENDORID_TRUE@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+confdir = @confdir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+eapdir = @eapdir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+ipsecdir = @ipsecdir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+piddir = @piddir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+openac_SOURCES = openac.c build.c build.h loglite.c
+INCLUDES = \
+-I$(top_srcdir)/src/libfreeswan \
+-I$(top_srcdir)/src/pluto \
+-I$(top_srcdir)/src/libcrypto \
+-I$(top_srcdir)/src/whack
+
+AM_CFLAGS = -DDEBUG -DNO_PLUTO -DIPSEC_CONFDIR=\"${confdir}\"
+openac_LDADD = ac.o asn1.o ca.o certs.o constants.o crl.o defs.o \
+ mp_defs.o fetch.o id.o keys.o lex.o md2.o md5.o ocsp.o oid.o \
+ pem.o pgp.o pkcs1.o rnd.o sha1.o smartcard.o x509.o \
+ $(top_srcdir)/src/libfreeswan/libfreeswan.a \
+ $(top_srcdir)/src/libcrypto/libcrypto.a -lgmp $(am__append_1) \
+ $(am__append_2)
+dist_man_MANS = openac.8
+PLUTODIR = $(top_srcdir)/src/pluto
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/openac/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/openac/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-ipsecPROGRAMS: $(ipsec_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(ipsecdir)" || $(mkdir_p) "$(DESTDIR)$(ipsecdir)"
+ @list='$(ipsec_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ || test -f $$p1 \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(ipsecPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(ipsecdir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(ipsecPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(ipsecdir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-ipsecPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(ipsec_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(ipsecdir)/$$f'"; \
+ rm -f "$(DESTDIR)$(ipsecdir)/$$f"; \
+ done
+
+clean-ipsecPROGRAMS:
+ @list='$(ipsec_PROGRAMS)'; for p in $$list; do \
+ f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f $$p $$f"; \
+ rm -f $$p $$f ; \
+ done
+openac$(EXEEXT): $(openac_OBJECTS) $(openac_DEPENDENCIES)
+ @rm -f openac$(EXEEXT)
+ $(LINK) $(openac_LDFLAGS) $(openac_OBJECTS) $(openac_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/build.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/loglite.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openac.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+install-man8: $(man8_MANS) $(man_MANS)
+ @$(NORMAL_INSTALL)
+ test -z "$(man8dir)" || $(mkdir_p) "$(DESTDIR)$(man8dir)"
+ @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 8*) ;; \
+ *) ext='8' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst"; \
+ done
+uninstall-man8:
+ @$(NORMAL_UNINSTALL)
+ @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 8*) ;; \
+ *) ext='8' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f '$(DESTDIR)$(man8dir)/$$inst'"; \
+ rm -f "$(DESTDIR)$(man8dir)/$$inst"; \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS) $(MANS)
+installdirs:
+ for dir in "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(man8dir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-ipsecPROGRAMS clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-ipsecPROGRAMS install-man
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man: install-man8
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-ipsecPROGRAMS uninstall-man
+
+uninstall-man: uninstall-man8
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-ipsecPROGRAMS clean-libtool ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am \
+ install-ipsecPROGRAMS install-man install-man8 install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-info-am \
+ uninstall-ipsecPROGRAMS uninstall-man uninstall-man8
+
+
+ac.o : $(PLUTODIR)/ac.c $(PLUTODIR)/ac.h
+ $(COMPILE) -c -o $@ $<
+
+asn1.o : $(PLUTODIR)/asn1.c $(PLUTODIR)/asn1.h
+ $(COMPILE) -c -o $@ $<
+
+ca.o : $(PLUTODIR)/ca.c $(PLUTODIR)/ca.h
+ $(COMPILE) -c -o $@ $<
+
+certs.o : $(PLUTODIR)/certs.c $(PLUTODIR)/certs.h
+ $(COMPILE) -c -o $@ $<
+
+constants.o : $(PLUTODIR)/constants.c $(PLUTODIR)/constants.h
+ $(COMPILE) -c -o $@ $<
+
+crl.o : $(PLUTODIR)/crl.c $(PLUTODIR)/crl.h
+ $(COMPILE) -c -o $@ $<
+
+defs.o : $(PLUTODIR)/defs.c $(PLUTODIR)/defs.h
+ $(COMPILE) -c -o $@ $<
+
+mp_defs.o : $(PLUTODIR)/mp_defs.c $(PLUTODIR)/mp_defs.h
+ $(COMPILE) -c -o $@ $<
+
+fetch.o : $(PLUTODIR)/fetch.c $(PLUTODIR)/fetch.h
+ $(COMPILE) -c -o $@ $<
+
+id.o : $(PLUTODIR)/id.c $(PLUTODIR)/id.h
+ $(COMPILE) -c -o $@ $<
+
+keys.o : $(PLUTODIR)/keys.c $(PLUTODIR)/keys.h
+ $(COMPILE) -c -o $@ $<
+
+lex.o : $(PLUTODIR)/lex.c $(PLUTODIR)/lex.h
+ $(COMPILE) -c -o $@ $<
+
+md2.o : $(PLUTODIR)/md2.c $(PLUTODIR)/md2.h
+ $(COMPILE) -c -o $@ $<
+
+md5.o : $(PLUTODIR)/md5.c $(PLUTODIR)/md5.h
+ $(COMPILE) -c -o $@ $<
+
+ocsp.o : $(PLUTODIR)/ocsp.c $(PLUTODIR)/ocsp.h
+ $(COMPILE) -c -o $@ $<
+
+oid.o : $(PLUTODIR)/oid.c $(PLUTODIR)/oid.h
+ $(COMPILE) -c -o $@ $<
+
+pem.o : $(PLUTODIR)/pem.c $(PLUTODIR)/pem.h
+ $(COMPILE) -c -o $@ $<
+
+pgp.o : $(PLUTODIR)/pgp.c $(PLUTODIR)/pgp.h
+ $(COMPILE) -c -o $@ $<
+
+pkcs1.o : $(PLUTODIR)/pkcs1.c $(PLUTODIR)/pkcs1.h
+ $(COMPILE) -c -o $@ $<
+
+rnd.o : $(PLUTODIR)/rnd.c $(PLUTODIR)/rnd.h
+ $(COMPILE) -c -o $@ $<
+
+sha1.o : $(PLUTODIR)/sha1.c $(PLUTODIR)/sha1.h
+ $(COMPILE) -c -o $@ $<
+
+smartcard.o : $(PLUTODIR)/smartcard.c $(PLUTODIR)/smartcard.h
+ $(COMPILE) -c -o $@ $<
+
+x509.o : $(PLUTODIR)/x509.c $(PLUTODIR)/x509.h
+ $(COMPILE) -c -o $@ $<
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/openac/build.c b/src/openac/build.c
new file mode 100644
index 000000000..bd3df6fee
--- /dev/null
+++ b/src/openac/build.c
@@ -0,0 +1,242 @@
+/* Build a X.509 attribute certificate
+ * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler
+ * Copyright (C) 2004 Andreas Steffen
+ * Zuercher Hochschule Winterthur, Switzerland
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: build.c,v 1.14 2005/09/06 11:47:57 as Exp $
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <freeswan.h>
+
+#include "../pluto/constants.h"
+#include "../pluto/defs.h"
+#include "../pluto/oid.h"
+#include "../pluto/asn1.h"
+#include "../pluto/x509.h"
+#include "../pluto/log.h"
+
+#include "build.h"
+
+static u_char ASN1_group_oid_str[] = {
+ 0x06, 0x08,
+ 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x0a ,0x04
+};
+
+static const chunk_t ASN1_group_oid = strchunk(ASN1_group_oid_str);
+
+static u_char ASN1_authorityKeyIdentifier_oid_str[] = {
+ 0x06, 0x03,
+ 0x55, 0x1d, 0x23
+};
+
+static const chunk_t ASN1_authorityKeyIdentifier_oid
+ = strchunk(ASN1_authorityKeyIdentifier_oid_str);
+
+static u_char ASN1_noRevAvail_ext_str[] = {
+ 0x30, 0x09,
+ 0x06, 0x03,
+ 0x55, 0x1d, 0x38,
+ 0x04, 0x02,
+ 0x05, 0x00
+};
+
+static const chunk_t ASN1_noRevAvail_ext = strchunk(ASN1_noRevAvail_ext_str);
+
+/*
+ * build directoryName
+ */
+static chunk_t
+build_directoryName(asn1_t tag, chunk_t name)
+{
+ return asn1_wrap(tag, "m"
+ , asn1_simple_object(ASN1_CONTEXT_C_4, name));
+}
+
+/*
+ * build holder
+ */
+static chunk_t
+build_holder(void)
+{
+ return asn1_wrap(ASN1_SEQUENCE, "mm"
+ , asn1_wrap(ASN1_CONTEXT_C_0, "mm"
+ , build_directoryName(ASN1_SEQUENCE, user->issuer)
+ , asn1_simple_object(ASN1_INTEGER, user->serialNumber)
+ )
+ , build_directoryName(ASN1_CONTEXT_C_1, user->subject));
+}
+
+/*
+ * build v2Form
+ */
+static chunk_t
+build_v2_form(void)
+{
+ return asn1_wrap(ASN1_CONTEXT_C_0, "m"
+ , build_directoryName(ASN1_SEQUENCE, signer->subject));
+}
+
+/*
+ * build attrCertValidityPeriod
+ */
+static chunk_t
+build_attr_cert_validity(void)
+{
+ return asn1_wrap(ASN1_SEQUENCE, "mm"
+ , timetoasn1(&notBefore, ASN1_GENERALIZEDTIME)
+ , timetoasn1(&notAfter, ASN1_GENERALIZEDTIME));
+}
+
+/*
+ * build attributes
+ */
+static chunk_t
+build_ietfAttributes(ietfAttrList_t *list)
+{
+ chunk_t ietfAttributes;
+ ietfAttrList_t *item = list;
+ size_t size = 0;
+ u_char *pos;
+
+ /* precalculate the total size of all values */
+ while (item != NULL)
+ {
+ size_t len = item->attr->value.len;
+
+ size += 1 + (len > 0) + (len >= 128) + (len >= 256) + (len >= 65536) + len;
+ item = item->next;
+ }
+ pos = build_asn1_object(&ietfAttributes, ASN1_SEQUENCE, size);
+
+ while (list != NULL)
+ {
+ ietfAttr_t *attr = list->attr;
+ asn1_t type = ASN1_NULL;
+
+ switch (attr->kind)
+ {
+ case IETF_ATTRIBUTE_OCTETS:
+ type = ASN1_OCTET_STRING;
+ break;
+ case IETF_ATTRIBUTE_STRING:
+ type = ASN1_UTF8STRING;
+ break;
+ case IETF_ATTRIBUTE_OID:
+ type = ASN1_OID;
+ break;
+ }
+ mv_chunk(&pos, asn1_simple_object(type, attr->value));
+
+ list = list->next;
+ }
+
+ return asn1_wrap(ASN1_SEQUENCE, "m", ietfAttributes);
+}
+
+/*
+ * build attribute type
+ */
+static chunk_t
+build_attribute_type(const chunk_t type, chunk_t content)
+{
+ return asn1_wrap(ASN1_SEQUENCE, "cm"
+ , type
+ , asn1_wrap(ASN1_SET, "m", content));
+}
+
+/*
+ * build attributes
+ */
+static chunk_t
+build_attributes(void)
+{
+ return asn1_wrap(ASN1_SEQUENCE, "m"
+ , build_attribute_type(ASN1_group_oid
+ , build_ietfAttributes(groups)));
+}
+
+/*
+ * build authorityKeyIdentifier
+ */
+static chunk_t
+build_authorityKeyID(x509cert_t *signer)
+{
+ chunk_t keyIdentifier = (signer->subjectKeyID.ptr == NULL)
+ ? empty_chunk
+ : asn1_simple_object(ASN1_CONTEXT_S_0
+ , signer->subjectKeyID);
+
+ chunk_t authorityCertIssuer = build_directoryName(ASN1_CONTEXT_C_1
+ , signer->issuer);
+
+ chunk_t authorityCertSerialNumber = asn1_simple_object(ASN1_CONTEXT_S_2
+ , signer->serialNumber);
+
+ return asn1_wrap(ASN1_SEQUENCE, "cm"
+ , ASN1_authorityKeyIdentifier_oid
+ , asn1_wrap(ASN1_OCTET_STRING, "m"
+ , asn1_wrap(ASN1_SEQUENCE, "mmm"
+ , keyIdentifier
+ , authorityCertIssuer
+ , authorityCertSerialNumber
+ )
+ )
+ );
+}
+
+/*
+ * build extensions
+ */
+static chunk_t
+build_extensions(void)
+{
+ return asn1_wrap(ASN1_SEQUENCE, "mc"
+ , build_authorityKeyID(signer)
+ , ASN1_noRevAvail_ext);
+}
+
+/*
+ * build attributeCertificateInfo
+ */
+static chunk_t
+build_attr_cert_info(void)
+{
+ return asn1_wrap(ASN1_SEQUENCE, "cmmcmmmm"
+ , ASN1_INTEGER_1
+ , build_holder()
+ , build_v2_form()
+ , ASN1_sha1WithRSA_id
+ , asn1_simple_object(ASN1_INTEGER, serial)
+ , build_attr_cert_validity()
+ , build_attributes()
+ , build_extensions());
+}
+
+/*
+ * build an X.509 attribute certificate
+ */
+chunk_t
+build_attr_cert(void)
+{
+ chunk_t attributeCertificateInfo = build_attr_cert_info();
+ chunk_t signatureValue = pkcs1_build_signature(attributeCertificateInfo
+ , OID_SHA1, signerkey, TRUE);
+
+ return asn1_wrap(ASN1_SEQUENCE, "mcm"
+ , attributeCertificateInfo
+ , ASN1_sha1WithRSA_id
+ , signatureValue);
+}
diff --git a/src/openac/build.h b/src/openac/build.h
new file mode 100644
index 000000000..deeddda04
--- /dev/null
+++ b/src/openac/build.h
@@ -0,0 +1,47 @@
+/* Build a X.509 attribute certificate
+ * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler
+ * Copyright (C) 2004 Andreas Steffen
+ * Zuercher Hochschule Winterthur, Switzerland
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: build.h,v 1.4 2004/11/03 14:28:52 as Exp $
+ */
+
+#ifndef _BUILD_H
+#define _BUILD_H
+
+#include <time.h>
+
+#include "../pluto/x509.h"
+#include "../pluto/keys.h"
+#include "../pluto/ac.h"
+
+/*
+ * global variables accessible by both main() and build.c
+ */
+extern x509cert_t *user;
+extern x509cert_t *signer;
+
+extern ietfAttrList_t *groups;
+extern struct RSA_private_key *signerkey;
+
+extern time_t notBefore;
+extern time_t notAfter;
+
+extern chunk_t serial;
+
+/*
+ * exported functions
+ */
+extern chunk_t build_attr_cert(void);
+
+#endif /* _BUILD_H */
diff --git a/src/openac/loglite.c b/src/openac/loglite.c
new file mode 100644
index 000000000..4219eb707
--- /dev/null
+++ b/src/openac/loglite.c
@@ -0,0 +1,295 @@
+/* error logging functions
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: loglite.c,v 1.2 2005/07/11 18:38:16 as Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h> /* used only if MSG_NOSIGNAL not defined */
+#include <libgen.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <freeswan.h>
+
+#include <constants.h>
+#include <defs.h>
+#include <log.h>
+#include <whack.h>
+
+bool
+ log_to_stderr = FALSE, /* should log go to stderr? */
+ log_to_syslog = TRUE; /* should log go to syslog? */
+
+void
+init_log(const char *program)
+{
+ if (log_to_stderr)
+ setbuf(stderr, NULL);
+ if (log_to_syslog)
+ openlog(program, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_AUTHPRIV);
+}
+
+void
+close_log(void)
+{
+ if (log_to_syslog)
+ closelog();
+}
+
+void
+plog(const char *message, ...)
+{
+ va_list args;
+ char m[LOG_WIDTH]; /* longer messages will be truncated */
+
+ va_start(args, message);
+ vsnprintf(m, sizeof(m), message, args);
+ va_end(args);
+
+ if (log_to_stderr)
+ fprintf(stderr, "%s\n", m);
+ if (log_to_syslog)
+ syslog(LOG_WARNING, "%s", m);
+}
+
+void
+loglog(int mess_no, const char *message, ...)
+{
+ va_list args;
+ char m[LOG_WIDTH]; /* longer messages will be truncated */
+
+ va_start(args, message);
+ vsnprintf(m, sizeof(m), message, args);
+ va_end(args);
+
+ if (log_to_stderr)
+ fprintf(stderr, "%s\n", m);
+ if (log_to_syslog)
+ syslog(LOG_WARNING, "%s", m);
+}
+
+void
+log_errno_routine(int e, const char *message, ...)
+{
+ va_list args;
+ char m[LOG_WIDTH]; /* longer messages will be truncated */
+
+ va_start(args, message);
+ vsnprintf(m, sizeof(m), message, args);
+ va_end(args);
+
+ if (log_to_stderr)
+ fprintf(stderr, "ERROR: %s. Errno %d: %s\n", m, e, strerror(e));
+ if (log_to_syslog)
+ syslog(LOG_ERR, "ERROR: %s. Errno %d: %s", m, e, strerror(e));
+}
+
+void
+exit_log(const char *message, ...)
+{
+ va_list args;
+ char m[LOG_WIDTH]; /* longer messages will be truncated */
+
+ va_start(args, message);
+ vsnprintf(m, sizeof(m), message, args);
+ va_end(args);
+
+ if (log_to_stderr)
+ fprintf(stderr, "FATAL ERROR: %s\n", m);
+ if (log_to_syslog)
+ syslog(LOG_ERR, "FATAL ERROR: %s", m);
+ exit(1);
+}
+
+void
+exit_log_errno_routine(int e, const char *message, ...)
+{
+ va_list args;
+ char m[LOG_WIDTH]; /* longer messages will be truncated */
+
+ va_start(args, message);
+ vsnprintf(m, sizeof(m), message, args);
+ va_end(args);
+
+ if (log_to_stderr)
+ fprintf(stderr, "FATAL ERROR: %s. Errno %d: %s\n", m, e, strerror(e));
+ if (log_to_syslog)
+ syslog(LOG_ERR, "FATAL ERROR: %s. Errno %d: %s", m, e, strerror(e));
+ exit(1);
+}
+
+void
+whack_log(int mess_no, const char *message, ...)
+{
+ va_list args;
+ char m[LOG_WIDTH]; /* longer messages will be truncated */
+
+ va_start(args, message);
+ vsnprintf(m, sizeof(m), message, args);
+ va_end(args);
+
+ fprintf(stderr, "%s\n", m);
+}
+
+/* Build up a diagnostic in a static buffer.
+ * Although this would be a generally useful function, it is very
+ * hard to come up with a discipline that prevents different uses
+ * from interfering. It is intended that by limiting it to building
+ * diagnostics, we will avoid this problem.
+ * Juggling is performed to allow an argument to be a previous
+ * result: the new string may safely depend on the old one. This
+ * restriction is not checked in any way: violators will produce
+ * confusing results (without crashing!).
+ */
+char diag_space[sizeof(diag_space)];
+
+err_t
+builddiag(const char *fmt, ...)
+{
+ static char diag_space[LOG_WIDTH]; /* longer messages will be truncated */
+ char t[sizeof(diag_space)]; /* build result here first */
+ va_list args;
+
+ va_start(args, fmt);
+ t[0] = '\0'; /* in case nothing terminates string */
+ vsnprintf(t, sizeof(t), fmt, args);
+ va_end(args);
+ strcpy(diag_space, t);
+ return diag_space;
+}
+
+/* Debugging message support */
+
+#ifdef DEBUG
+
+void
+switch_fail(int n, const char *file_str, unsigned long line_no)
+{
+ char buf[30];
+
+ snprintf(buf, sizeof(buf), "case %d unexpected", n);
+ passert_fail(buf, file_str, line_no);
+}
+
+void
+passert_fail(const char *pred_str, const char *file_str, unsigned long line_no)
+{
+ /* we will get a possibly unplanned prefix. Hope it works */
+ loglog(RC_LOG_SERIOUS, "ASSERTION FAILED at %s:%lu: %s", file_str, line_no, pred_str);
+ abort(); /* exiting correctly doesn't always work */
+}
+
+lset_t
+ base_debugging = DBG_NONE, /* default to reporting nothing */
+ cur_debugging = DBG_NONE;
+
+void
+pexpect_log(const char *pred_str, const char *file_str, unsigned long line_no)
+{
+ /* we will get a possibly unplanned prefix. Hope it works */
+ loglog(RC_LOG_SERIOUS, "EXPECTATION FAILED at %s:%lu: %s", file_str, line_no, pred_str);
+}
+
+/* log a debugging message (prefixed by "| ") */
+
+void
+DBG_log(const char *message, ...)
+{
+ va_list args;
+ char m[LOG_WIDTH]; /* longer messages will be truncated */
+
+ va_start(args, message);
+ vsnprintf(m, sizeof(m), message, args);
+ va_end(args);
+
+ if (log_to_stderr)
+ fprintf(stderr, "| %s\n", m);
+ if (log_to_syslog)
+ syslog(LOG_DEBUG, "| %s", m);
+}
+
+/* dump raw bytes in hex to stderr (for lack of any better destination) */
+
+void
+DBG_dump(const char *label, const void *p, size_t len)
+{
+# define DUMP_LABEL_WIDTH 20 /* arbitrary modest boundary */
+# define DUMP_WIDTH (4 * (1 + 4 * 3) + 1)
+ char buf[DUMP_LABEL_WIDTH + DUMP_WIDTH];
+ char *bp;
+ const unsigned char *cp = p;
+
+ bp = buf;
+
+ if (label != NULL && label[0] != '\0')
+ {
+ /* Handle the label. Care must be taken to avoid buffer overrun. */
+ size_t llen = strlen(label);
+
+ if (llen + 1 > sizeof(buf))
+ {
+ DBG_log("%s", label);
+ }
+ else
+ {
+ strcpy(buf, label);
+ if (buf[llen-1] == '\n')
+ {
+ buf[llen-1] = '\0'; /* get rid of newline */
+ DBG_log("%s", buf);
+ }
+ else if (llen < DUMP_LABEL_WIDTH)
+ {
+ bp = buf + llen;
+ }
+ else
+ {
+ DBG_log("%s", buf);
+ }
+ }
+ }
+
+ do {
+ int i, j;
+
+ for (i = 0; len!=0 && i!=4; i++)
+ {
+ *bp++ = ' ';
+ for (j = 0; len!=0 && j!=4; len--, j++)
+ {
+ static const char hexdig[] = "0123456789abcdef";
+
+ *bp++ = ' ';
+ *bp++ = hexdig[(*cp >> 4) & 0xF];
+ *bp++ = hexdig[*cp & 0xF];
+ cp++;
+ }
+ }
+ *bp = '\0';
+ DBG_log("%s", buf);
+ bp = buf;
+ } while (len != 0);
+# undef DUMP_LABEL_WIDTH
+# undef DUMP_WIDTH
+}
+
+#endif /* DEBUG */
diff --git a/src/openac/openac.8 b/src/openac/openac.8
new file mode 100644
index 000000000..8e609a1b1
--- /dev/null
+++ b/src/openac/openac.8
@@ -0,0 +1,180 @@
+.TH IPSEC_OPENAC 8 "29 September 2005"
+.SH NAME
+ipsec openac \- Generation of X.509 attribute certificates
+.SH SYNOPSIS
+.B ipsec
+.B openac
+[
+.B \-\-help
+] [
+.B \-\-version
+] [
+.B \-\-optionsfrom
+\fIfilename\fP
+] [
+.B \-\-quiet
+]
+.br
+\ \ \ [
+.B \-\-debug\(hyall
+] [
+.B \-\-debug\(hyparsing
+] [
+.B \-\-debug\(hyraw
+] [
+.B \-\-debug\(hyprivate
+]
+.br
+\ \ \ [
+.B \-\-days
+\fIdays\fP
+] [
+.B \-\-hours
+\fIhours\fP
+]
+.br
+\ \ \ [
+.B \-\-startdate
+\fIYYYYMMDDHHMMSSZ\fP
+] [
+.B \-\-stopdate
+\fIYYYYMMDDHHMMSSZ\fP
+]
+.br
+.B \ \ \ \-\-cert
+\fIcertfile\fP
+.B \-\-key
+\fIkeyfile\fP
+[
+.B \-\-password
+\fIpassword\fP
+]
+.br
+.B \ \ \ \-\-usercert
+\fIcertfile\fP
+.B \-\-groups
+\fIattr1,attr2,...\fP
+.B \-\-out
+\fIfilename\fP
+.SH DESCRIPTION
+.BR openac
+is intended to be used by an Authorization Authority (AA) to generate and sign
+X.509 attribute certificates. Currently only the inclusion of one ore several group
+attributes is supported. An attribute certificate is linked to a holder by
+including the issuer and serial number of the holder's X.509 certificate.
+.SH OPTIONS
+.TP
+\fB\-\-help\fP
+display the usage message.
+.TP
+\fB\-\-version\fP
+display the version of \fBopenac\fP.
+.TP
+\fB\-\-optionsfrom\fP\ \fIfilename\fP
+adds the contents of the file to the argument list.
+If \fIfilename\fP is a relative path then the file is searched in the directory
+\fI/etc/openac\fP.
+.TP
+\fB\-\-quiet\fP
+By default \fBopenac\fP logs all control output both to syslog and stderr.
+With the \fB\-\-quiet\fP option no output is written to stderr.
+.TP
+\fB\-\-days\fP\ \fIdays\fP
+Validity of the X.509 attribute certificate in days. If neiter the \fB\-\-days\fP\ nor
+the \fB\-\-hours\fP\ option is specified then a default validity interval of 1 day is assumed.
+The \fB\-\-days\fP\ option can be combined with the \fB\-\-hours\fP\ option.
+.TP
+\fB\-\-hours\fP\ \fIhours\fP
+Validity of the X.509 attribute certificate in hours. If neiter the \fB\-\-hours\fP\ nor
+the \fB\-\-days\fP\ option is specified then a default validity interval of 24 hours is assumed.
+The \fB\-\-hours\fP\ option can be combined with the \fB\-\-days\fP\ option.
+.TP
+\fB\-\-startdate\fP\ \fIYYYYMMDDHHMMSSZ\fP
+defines the \fBnotBefore\fP date when the X.509 attribute certificate becomes valid.
+The date \fIYYYYMMDDHHMMSS\fP must be specified in UTC (\fIZ\fPulu time).
+If the \fB\-\-startdate\fP option is not specified then the current date is taken as a default.
+
+.TP
+\fB\-\-stopdate\fP\ \fIYYYYMMDDHHMMSSZ\fP
+defines the \fBnotAfter\fP date when the X.509 attribute certificate will expire.
+The date \fIYYYYMMDDHHMMSS\fP must be specified in UTC (\fIZ\fPulu time).
+If the \fB\-\-stopdate\fP option is not specified then the default \fBnotAfter\fP value is computed
+by adding the validity interval specified by the \fB\-\-days\fP\ and/or \fB\-\-days\fP\ options
+to the \fBnotBefore\fP date.
+.TP
+\fB\-\-cert\fP\ \fIcertfile\fP
+specifies the file containing the X.509 certificate of the Authorization Authority.
+The certificate is stored either in PEM or DER format.
+.TP
+\fB\-\-key\fP\ \fIkeyfile\fP
+specifies the encrypted file containing the private RSA key of the Authoritzation
+Authority. The private key is stored in PKCS#1 format.
+.TP
+\fB\-\-password\fP\ \fIpassword\fP
+specifies the password with which the private RSA keyfile defined by the
+\fB\-\-key\fP option has been protected. If the option is missing then the
+password is prompted for on the command line.
+.TP
+\fB\-\-usercert\fP\ \fIcertfile\fP
+specifies file containing the X.509 certificate of the user to which the generated attribute
+certificate will apply. The certificate file is stored either in PEM or DER format.
+.TP
+\fB\-\-groups\fP\ \fIattr1,attr2\fP
+specifies a comma-separated list of group attributes that will go into the
+X.509 attribute certificate.
+.TP
+\fB\-\-out\fP\ \fIfilename\fP
+specifies the file where the generated X.509 attribute certificate will be stored to.
+.SS Debugging
+.LP
+\fBopenac\fP produces a prodigious amount of debugging information. To do so,
+it must be compiled with \-DDEBUG. There are several classes of debugging output,
+and \fBopenac\fP may be directed to produce a selection of them. All lines of
+debugging output are prefixed with ``|\ '' to distinguish them from error messages.
+.LP
+When \fBopenac\fP is invoked, it may be given arguments to specify
+which classes to output. The current options are:
+.TP
+\fB\-\-debug-raw\fP
+show the raw bytes of the parsed user and authorization authority certificates
+as well as of the generated X.509 attribute certificate.
+.TP
+\fB\-\-debug-parsing\fP
+show the parsed structure of user and authorization authority certificats
+as well as of the generated X.509 attribute certificate.
+.TP
+\fB\-\-debug-all\fP
+all of the above.
+.TP
+\fB\-\-debug-private\fP
+enables debugging output of the authorization authority's private key.
+.SH EXIT STATUS
+.LP
+The execution of \fBopenac\fP terminates with one of the following two exit codes:
+.TP
+0
+means that the attribute certificate was successfully generated and stored.
+.TP
+1
+means that something went wrong.
+.SH FILES
+\fI/etc/openac/serial\fP\ \ \ serial number of latest attribute certificate
+.SH SEE ALSO
+.LP
+The X.509 attribute certificates generated with \fBopenac\fP can be used to
+enforce group policies defined by \fIipsec.conf\fP(5). Use \fIipsec_auto\fP(8)
+to load and list X.509 attribute certificates.
+.LP
+For more information on X.509 attribute certificates, refer to the following
+IETF RFC:
+.IP
+RFC 3281 An Internet Attribute Certificate Profile for Authorization
+.SH HISTORY
+The \fBopenac\fP program was originally written by Ariane Seiler and Ueli Galizzi.
+The software was recoded by Andreas Steffen using strongSwan's X.509 library and
+the ASN.1 code synthesis functions written by Christoph Gysin and Christoph Zwahlen.
+All authors were with the Zurich University of Applied Sciences in Winterthur,
+Switzerland.
+.LP
+.SH BUGS
+Bugs should be reported to the <users@lists.strongswan.org> mailing list.
diff --git a/src/openac/openac.c b/src/openac/openac.c
new file mode 100755
index 000000000..00f287b3a
--- /dev/null
+++ b/src/openac/openac.c
@@ -0,0 +1,438 @@
+/* Generation of X.509 attribute certificates
+ * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler
+ * Copyright (C) 2004 Andreas Steffen
+ * Zuercher Hochschule Winterthur, Switzerland
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: openac.c,v 1.18 2006/01/04 21:12:33 as Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <ctype.h>
+#include <time.h>
+#include <gmp.h>
+
+#include <freeswan.h>
+
+#include "../pluto/constants.h"
+#include "../pluto/defs.h"
+#include "../pluto/mp_defs.h"
+#include "../pluto/log.h"
+#include "../pluto/asn1.h"
+#include "../pluto/certs.h"
+#include "../pluto/x509.h"
+#include "../pluto/crl.h"
+#include "../pluto/keys.h"
+#include "../pluto/ac.h"
+
+#include "build.h"
+
+#define OPENAC_PATH IPSEC_CONFDIR "/openac"
+#define OPENAC_SERIAL IPSEC_CONFDIR "/openac/serial"
+
+const char openac_version[] = "openac 0.3";
+
+/* by default the CRL policy is lenient */
+bool strict_crl_policy = FALSE;
+
+/* by default pluto does not check crls dynamically */
+long crl_check_interval = 0;
+
+/* by default pluto logs out after every smartcard use */
+bool pkcs11_keep_state = FALSE;
+
+static void
+usage(const char *mess)
+{
+ if (mess != NULL && *mess != '\0')
+ fprintf(stderr, "%s\n", mess);
+ fprintf(stderr
+ , "Usage: openac"
+ " [--help]"
+ " [--version]"
+ " [--optionsfrom <filename>]"
+ " [--quiet]"
+#ifdef DEBUG
+ " \\\n\t"
+ " [--debug-all]"
+ " [--debug-parsing]"
+ " [--debug-raw]"
+ " [--debug-private]"
+#endif
+ " \\\n\t"
+ " [--days <days>]"
+ " [--hours <hours>]"
+ " \\\n\t"
+ " [--startdate <YYYYMMDDHHMMSSZ>]"
+ " [--enddate <YYYYMMDDHHMMSSZ>]"
+ " \\\n\t"
+ " --cert <certfile>"
+ " --key <keyfile>"
+ " [--password <password>]"
+ " \\\n\t"
+ " --usercert <certfile>"
+ " --groups <attr1,attr2,..>"
+ " --out <filename>"
+ "\n"
+ );
+ exit(mess == NULL? 0 : 1);
+}
+
+/*
+ * read the last serial number from file
+ */
+static chunk_t
+read_serial(void)
+{
+ MP_INT number;
+
+ char buf[BUF_LEN];
+ char bytes[BUF_LEN];
+
+ FILE *fd = fopen(OPENAC_SERIAL, "r");
+
+ /* serial number defaults to 0 */
+ size_t len = 1;
+ bytes[0] = 0x00;
+
+ if (fd)
+ {
+ if (fscanf(fd, "%s", buf))
+ {
+ err_t ugh = ttodata(buf, 0, 16, bytes, BUF_LEN, &len);
+
+ if (ugh != NULL)
+ plog(" error reading serial number from %s: %s"
+ , OPENAC_SERIAL, ugh);
+ }
+ fclose(fd);
+ }
+ else
+ plog(" file '%s' does not exist yet - serial number set to 01"
+ , OPENAC_SERIAL);
+
+ /* conversion of read serial number to a multiprecision integer
+ * and incrementing it by one
+ * and representing it as a two's complement octet string
+ */
+ n_to_mpz(&number, bytes, len);
+ mpz_add_ui(&number, &number, 0x01);
+ serial = mpz_to_n(&number, 1 + mpz_sizeinbase(&number, 2)/BITS_PER_BYTE);
+ mpz_clear(&number);
+
+ return serial;
+}
+
+/*
+ * write back the last serial number to file
+ */
+static void
+write_serial(chunk_t serial)
+{
+ char buf[BUF_LEN];
+
+ FILE *fd = fopen(OPENAC_SERIAL, "w");
+
+ if (fd)
+ {
+ datatot(serial.ptr, serial.len, 16, buf, BUF_LEN);
+ plog(" serial number is %s", buf);
+ fprintf(fd, "%s\n", buf);
+ fclose(fd);
+ }
+ else
+ plog(" could not open file '%s' for writing", OPENAC_SERIAL);
+}
+
+/*
+ * global variables accessible by both main() and build.c
+ */
+x509cert_t *user = NULL;
+x509cert_t *signer = NULL;
+
+ietfAttrList_t *groups = NULL;
+struct RSA_private_key *signerkey = NULL;
+
+time_t notBefore = 0;
+time_t notAfter = 0;
+
+chunk_t serial;
+
+
+int
+main(int argc, char **argv)
+{
+ char *keyfile = NULL;
+ char *certfile = NULL;
+ char *usercertfile = NULL;
+ char *outfile = NULL;
+
+ cert_t signercert = empty_cert;
+ cert_t usercert = empty_cert;
+
+ chunk_t attr_cert = empty_chunk;
+ x509acert_t *ac = NULL;
+
+ const time_t default_validity = 24*3600; /* 24 hours */
+ time_t validity = 0;
+
+ prompt_pass_t pass;
+
+ pass.secret[0] = '\0';
+ pass.prompt = TRUE;
+ pass.fd = STDIN_FILENO;
+
+ log_to_stderr = TRUE;
+
+ /* handle arguments */
+ for (;;)
+ {
+# define DBG_OFFSET 256
+ static const struct option long_opts[] = {
+ /* name, has_arg, flag, val */
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'v' },
+ { "optionsfrom", required_argument, NULL, '+' },
+ { "quiet", no_argument, NULL, 'q' },
+ { "cert", required_argument, NULL, 'c' },
+ { "key", required_argument, NULL, 'k' },
+ { "password", required_argument, NULL, 'p' },
+ { "usercert", required_argument, NULL, 'u' },
+ { "groups", required_argument, NULL, 'g' },
+ { "days", required_argument, NULL, 'D' },
+ { "hours", required_argument, NULL, 'H' },
+ { "startdate", required_argument, NULL, 'S' },
+ { "enddate", required_argument, NULL, 'E' },
+ { "out", required_argument, NULL, 'o' },
+#ifdef DEBUG
+ { "debug-all", no_argument, NULL, 'A' },
+ { "debug-raw", no_argument, NULL, DBG_RAW + DBG_OFFSET },
+ { "debug-parsing", no_argument, NULL, DBG_PARSING + DBG_OFFSET },
+ { "debug-private", no_argument, NULL, DBG_PRIVATE + DBG_OFFSET },
+#endif
+ { 0,0,0,0 }
+ };
+
+ int c = getopt_long(argc, argv, "hv+:qc:k:p;u:g:D:H:S:E:o:", long_opts, NULL);
+
+ /* Note: "breaking" from case terminates loop */
+ switch (c)
+ {
+ case EOF: /* end of flags */
+ break;
+
+ case 0: /* long option already handled */
+ continue;
+
+ case ':': /* diagnostic already printed by getopt_long */
+ case '?': /* diagnostic already printed by getopt_long */
+ usage(NULL);
+ break; /* not actually reached */
+
+ case 'h': /* --help */
+ usage(NULL);
+ break; /* not actually reached */
+
+ case 'v': /* --version */
+ printf("%s\n", openac_version);
+ exit(0);
+ break; /* not actually reached */
+
+ case '+': /* --optionsfrom <filename> */
+ {
+ char path[BUF_LEN];
+
+ if (*optarg == '/') /* absolute pathname */
+ strncpy(path, optarg, BUF_LEN);
+ else /* relative pathname */
+ snprintf(path, BUF_LEN, "%s/%s", OPENAC_PATH, optarg);
+ optionsfrom(path, &argc, &argv, optind, stderr);
+ /* does not return on error */
+ }
+ continue;
+
+ case 'q': /* --quiet */
+ log_to_stderr = TRUE;
+ continue;
+
+ case 'c': /* --cert */
+ certfile = optarg;
+ continue;
+
+ case 'k': /* --key */
+ keyfile = optarg;
+ continue;
+
+ case 'p': /* --key */
+ pass.prompt = FALSE;
+ strncpy(pass.secret, optarg, sizeof(pass.secret));
+ continue;
+
+ case 'u': /* --usercert */
+ usercertfile = optarg;
+ continue;
+
+ case 'g': /* --groups */
+ decode_groups(optarg, &groups);
+ continue;
+
+ case 'D': /* --days */
+ if (optarg == NULL || !isdigit(optarg[0]))
+ usage("missing number of days");
+ {
+ char *endptr;
+ long days = strtol(optarg, &endptr, 0);
+
+ if (*endptr != '\0' || endptr == optarg
+ || days <= 0)
+ usage("<days> must be a positive number");
+ validity += 24*3600*days;
+ }
+ continue;
+
+ case 'H': /* --hours */
+ if (optarg == NULL || !isdigit(optarg[0]))
+ usage("missing number of hours");
+ {
+ char *endptr;
+ long hours = strtol(optarg, &endptr, 0);
+
+ if (*endptr != '\0' || endptr == optarg
+ || hours <= 0)
+ usage("<hours> must be a positive number");
+ validity += 3600*hours;
+ }
+ continue;
+
+ case 'S': /* --startdate */
+ if (optarg == NULL || strlen(optarg) != 15 || optarg[14] != 'Z')
+ usage("date format must be YYYYMMDDHHMMSSZ");
+ {
+ chunk_t date = { optarg, 15 };
+ notBefore = asn1totime(&date, ASN1_GENERALIZEDTIME);
+ }
+ continue;
+
+ case 'E': /* --enddate */
+ if (optarg == NULL || strlen(optarg) != 15 || optarg[14] != 'Z')
+ usage("date format must be YYYYMMDDHHMMSSZ");
+ {
+ chunk_t date = { optarg, 15 };
+ notAfter = asn1totime(&date, ASN1_GENERALIZEDTIME);
+ }
+ continue;
+
+ case 'o': /* --outt */
+ outfile = optarg;
+ continue ;
+
+#ifdef DEBUG
+ case 'A': /* --debug-all */
+ base_debugging = DBG_ALL;
+ continue;
+#endif
+ default:
+#ifdef DEBUG
+ if (c >= DBG_OFFSET)
+ {
+ base_debugging |= c - DBG_OFFSET;
+ continue;
+ }
+#undef DBG_OFFSET
+#endif
+ bad_case(c);
+ }
+ break;
+ }
+
+ init_log("openac");
+ cur_debugging = base_debugging;
+
+ if (optind != argc)
+ usage("unexpected argument");
+
+ /* load the signer's RSA private key */
+ if (keyfile != NULL)
+ {
+ err_t ugh = NULL;
+
+ signerkey = alloc_thing(RSA_private_key_t, "RSA private key");
+ ugh = load_rsa_private_key(keyfile, &pass, signerkey);
+
+ if (ugh != NULL)
+ {
+ free_RSA_private_content(signerkey);
+ pfree(signerkey);
+ plog("%s", ugh);
+ exit(1);
+ }
+ }
+
+ /* load the signer's X.509 certificate */
+ if (certfile != NULL)
+ {
+ if (!load_cert(certfile, "signer cert", &signercert))
+ exit(1);
+ signer = signercert.u.x509;
+ }
+
+ /* load the users's X.509 certificate */
+ if (usercertfile != NULL)
+ {
+ if (!load_cert(usercertfile, "user cert", &usercert))
+ exit(1);
+ user = usercert.u.x509;
+ }
+
+ /* compute validity interval */
+ validity = (validity)? validity : default_validity;
+ notBefore = (notBefore) ? notBefore : time(NULL);
+ notAfter = (notAfter) ? notAfter : notBefore + validity;
+
+ /* build and parse attribute certificate */
+ if (user != NULL && signer != NULL && signerkey != NULL)
+ {
+ /* read the serial number and increment it by one */
+ serial = read_serial();
+
+ attr_cert = build_attr_cert();
+ ac = alloc_thing(x509acert_t, "x509acert");
+ *ac = empty_ac;
+ parse_ac(attr_cert, ac);
+
+ /* write the attribute certificate to file */
+ if (write_chunk(outfile, "attribute cert", attr_cert, 0022, TRUE))
+ write_serial(serial);
+ }
+
+ /* delete all dynamic objects */
+ if (signerkey != NULL)
+ {
+ free_RSA_private_content(signerkey);
+ pfree(signerkey);
+ }
+ free_x509cert(signercert.u.x509);
+ free_x509cert(usercert.u.x509);
+ free_ietfAttrList(groups);
+ free_acert(ac);
+ pfree(serial.ptr);
+
+#ifdef LEAK_DETECTIVE
+ report_leaks();
+#endif /* LEAK_DETECTIVE */
+ close_log();
+ exit(0);
+}
diff --git a/src/pluto/Makefile.am b/src/pluto/Makefile.am
new file mode 100644
index 000000000..b1b848c76
--- /dev/null
+++ b/src/pluto/Makefile.am
@@ -0,0 +1,140 @@
+# Makefile.am was ported from the old Makefile the most
+# painless way. Only the most important options are included,
+# further work may be necessary here...
+
+ipsec_PROGRAMS = pluto _pluto_adns
+
+pluto_SOURCES = \
+ac.c ac.h \
+alg_info.c alg_info.h \
+asn1.c asn1.h \
+ca.c ca.h \
+certs.c certs.h \
+connections.c connections.h \
+constants.c constants.h \
+cookie.c cookie.h \
+crl.c crl.h \
+crypto.c crypto.h \
+db_ops.c db_ops.h \
+defs.c defs.h \
+demux.c demux.h \
+dnskey.c dnskey.h \
+dsa.c dsa.h \
+elgamal.c elgamal.h \
+fetch.c fetch.h \
+foodgroups.c foodgroups.h \
+gcryptfix.c gcryptfix.h \
+id.c id.h \
+ike_alg.c ike_alg.h \
+ipsec_doi.c ipsec_doi.h \
+kameipsec.h \
+kernel.c kernel.h \
+kernel_alg.c kernel_alg.h \
+kernel_netlink.c kernel_netlink.h \
+kernel_noklips.c kernel_noklips.h \
+kernel_pfkey.c kernel_pfkey.h \
+keys.c keys.h \
+lex.c lex.h \
+log.c log.h \
+md2.c md2.h \
+md5.c md5.h \
+modecfg.c modecfg.h \
+mp_defs.c mp_defs.h \
+nat_traversal.c nat_traversal.h \
+ocsp.c ocsp.h \
+oid.c oid.h \
+packet.c packet.h \
+pem.c pem.h \
+pgp.c pgp.h \
+pkcs1.c pkcs1.h \
+pkcs7.c pkcs7.h \
+plutomain.c \
+primegen.c smallprime.c \
+rcv_whack.c rcv_whack.h \
+rnd.c rnd.h \
+server.c server.h \
+sha1.c sha1.h \
+smartcard.c smartcard.h \
+spdb.c spdb.h \
+state.c state.h \
+timer.c timer.h \
+vendor.c vendor.h \
+virtual.c virtual.h \
+xauth.c xauth.h \
+x509.c x509.h \
+alg/ike_alg_aes.c alg/ike_alg_blowfish.c alg/ike_alg_twofish.c \
+alg/ike_alg_serpent.c alg/ike_alg_sha2.c alg/ike_alginit.c \
+linux26/netlink.h linux26/rtnetlink.h linux26/xfrm.h \
+rsaref/pkcs11t.h rsaref/pkcs11.h rsaref/unix.h rsaref/pkcs11f.h
+
+_pluto_adns_SOURCES = adns.c adns.h
+
+INCLUDES = \
+-I$(top_srcdir)/src/libfreeswan \
+-I$(top_srcdir)/src/libcrypto \
+-I$(top_srcdir)/src/whack
+
+AM_CFLAGS = \
+-DIPSEC_DIR=\"${ipsecdir}\" \
+-DIPSEC_CONFDIR=\"${confdir}\" \
+-DIPSEC_PIDDIR=\"${piddir}\" \
+-DSHARED_SECRETS_FILE=\"${confdir}/ipsec.secrets\" \
+-DKERNEL26_SUPPORT -DKERNEL26_HAS_KAME_DUPLICATES \
+-DPLUTO -DKLIPS -DDEBUG -DTHREADS
+
+pluto_LDADD = \
+$(top_srcdir)/src/libfreeswan/libfreeswan.a \
+$(top_srcdir)/src/libcrypto/libcrypto.a \
+-lgmp -lresolv -lpthread -ldl
+
+_pluto_adns_LDADD = \
+$(top_srcdir)/src/libfreeswan/libfreeswan.a \
+-lresolv -ldl
+
+dist_man_MANS = pluto.8 ipsec.secrets.5
+EXTRA_DIST = oid.pl oid.txt
+BUILT_SOURCES = oid.c oid.h
+MAINTAINERCLEANFILES = oid.c oid.h
+
+oid.c: oid.txt oid.pl
+ $(PERL) oid.pl
+
+oid.h: oid.txt oid.pl
+ $(PERL) oid.pl
+
+# This compile option activates the sending of a strongSwan VID
+if USE_VENDORID
+ AM_CFLAGS += -DVENDORID
+endif
+
+# This compile option activates the support of the Cisco VPN client
+if USE_CISCO_QUIRKS
+ AM_CFLAGS += -DCISCO_QUIRKS
+endif
+
+# This compile option activates NAT traversal with IPSec transport mode
+if USE_NAT_TRANSPORT
+ AM_CFLAGS += -DI_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT
+endif
+
+# This compile option activates dynamic URL fetching using libcurl
+if USE_LIBCURL
+ pluto_LDADD += -lcurl
+endif
+
+# This compile option activates dynamic LDAP CRL fetching
+if USE_LIBLDAP
+ pluto_LDADD += -lldap -llber
+endif
+
+install-exec-local :
+ mkdir -p -m 755 $(confdir)/ipsec.d
+ mkdir -p -m 755 $(confdir)/ipsec.d/cacerts
+ mkdir -p -m 755 $(confdir)/ipsec.d/ocspcerts
+ mkdir -p -m 755 $(confdir)/ipsec.d/certs
+ mkdir -p -m 755 $(confdir)/ipsec.d/acerts
+ mkdir -p -m 755 $(confdir)/ipsec.d/aacerts
+ mkdir -p -m 755 $(confdir)/ipsec.d/crls
+ mkdir -p -m 755 $(confdir)/ipsec.d/reqs
+ mkdir -p -m 700 $(confdir)/ipsec.d/private
+
diff --git a/src/pluto/Makefile.in b/src/pluto/Makefile.in
new file mode 100644
index 000000000..1f996a065
--- /dev/null
+++ b/src/pluto/Makefile.in
@@ -0,0 +1,878 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Makefile.am was ported from the old Makefile the most
+# painless way. Only the most important options are included,
+# further work may be necessary here...
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+ipsec_PROGRAMS = pluto$(EXEEXT) _pluto_adns$(EXEEXT)
+
+# This compile option activates the sending of a strongSwan VID
+@USE_VENDORID_TRUE@am__append_1 = -DVENDORID
+
+# This compile option activates the support of the Cisco VPN client
+@USE_CISCO_QUIRKS_TRUE@am__append_2 = -DCISCO_QUIRKS
+
+# This compile option activates NAT traversal with IPSec transport mode
+@USE_NAT_TRANSPORT_TRUE@am__append_3 = -DI_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT
+
+# This compile option activates dynamic URL fetching using libcurl
+@USE_LIBCURL_TRUE@am__append_4 = -lcurl
+
+# This compile option activates dynamic LDAP CRL fetching
+@USE_LIBLDAP_TRUE@am__append_5 = -lldap -llber
+subdir = src/pluto
+DIST_COMMON = $(dist_man_MANS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in TODO
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_CLEAN_FILES =
+am__installdirs = "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(man5dir)" \
+ "$(DESTDIR)$(man8dir)"
+ipsecPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(ipsec_PROGRAMS)
+am__pluto_adns_OBJECTS = adns.$(OBJEXT)
+_pluto_adns_OBJECTS = $(am__pluto_adns_OBJECTS)
+_pluto_adns_DEPENDENCIES = \
+ $(top_srcdir)/src/libfreeswan/libfreeswan.a
+am_pluto_OBJECTS = ac.$(OBJEXT) alg_info.$(OBJEXT) asn1.$(OBJEXT) \
+ ca.$(OBJEXT) certs.$(OBJEXT) connections.$(OBJEXT) \
+ constants.$(OBJEXT) cookie.$(OBJEXT) crl.$(OBJEXT) \
+ crypto.$(OBJEXT) db_ops.$(OBJEXT) defs.$(OBJEXT) \
+ demux.$(OBJEXT) dnskey.$(OBJEXT) dsa.$(OBJEXT) \
+ elgamal.$(OBJEXT) fetch.$(OBJEXT) foodgroups.$(OBJEXT) \
+ gcryptfix.$(OBJEXT) id.$(OBJEXT) ike_alg.$(OBJEXT) \
+ ipsec_doi.$(OBJEXT) kernel.$(OBJEXT) kernel_alg.$(OBJEXT) \
+ kernel_netlink.$(OBJEXT) kernel_noklips.$(OBJEXT) \
+ kernel_pfkey.$(OBJEXT) keys.$(OBJEXT) lex.$(OBJEXT) \
+ log.$(OBJEXT) md2.$(OBJEXT) md5.$(OBJEXT) modecfg.$(OBJEXT) \
+ mp_defs.$(OBJEXT) nat_traversal.$(OBJEXT) ocsp.$(OBJEXT) \
+ oid.$(OBJEXT) packet.$(OBJEXT) pem.$(OBJEXT) pgp.$(OBJEXT) \
+ pkcs1.$(OBJEXT) pkcs7.$(OBJEXT) plutomain.$(OBJEXT) \
+ primegen.$(OBJEXT) smallprime.$(OBJEXT) rcv_whack.$(OBJEXT) \
+ rnd.$(OBJEXT) server.$(OBJEXT) sha1.$(OBJEXT) \
+ smartcard.$(OBJEXT) spdb.$(OBJEXT) state.$(OBJEXT) \
+ timer.$(OBJEXT) vendor.$(OBJEXT) virtual.$(OBJEXT) \
+ xauth.$(OBJEXT) x509.$(OBJEXT) ike_alg_aes.$(OBJEXT) \
+ ike_alg_blowfish.$(OBJEXT) ike_alg_twofish.$(OBJEXT) \
+ ike_alg_serpent.$(OBJEXT) ike_alg_sha2.$(OBJEXT) \
+ ike_alginit.$(OBJEXT)
+pluto_OBJECTS = $(am_pluto_OBJECTS)
+am__DEPENDENCIES_1 =
+pluto_DEPENDENCIES = $(top_srcdir)/src/libfreeswan/libfreeswan.a \
+ $(top_srcdir)/src/libcrypto/libcrypto.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+DEFAULT_INCLUDES = -I. -I$(srcdir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(_pluto_adns_SOURCES) $(pluto_SOURCES)
+DIST_SOURCES = $(_pluto_adns_SOURCES) $(pluto_SOURCES)
+man5dir = $(mandir)/man5
+man8dir = $(mandir)/man8
+NROFF = nroff
+MANS = $(dist_man_MANS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_EAP_SIM_FALSE = @BUILD_EAP_SIM_FALSE@
+BUILD_EAP_SIM_TRUE = @BUILD_EAP_SIM_TRUE@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GPERF = @GPERF@
+GREP = @GREP@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+USE_CISCO_QUIRKS_FALSE = @USE_CISCO_QUIRKS_FALSE@
+USE_CISCO_QUIRKS_TRUE = @USE_CISCO_QUIRKS_TRUE@
+USE_LEAK_DETECTIVE_FALSE = @USE_LEAK_DETECTIVE_FALSE@
+USE_LEAK_DETECTIVE_TRUE = @USE_LEAK_DETECTIVE_TRUE@
+USE_LIBCURL_FALSE = @USE_LIBCURL_FALSE@
+USE_LIBCURL_TRUE = @USE_LIBCURL_TRUE@
+USE_LIBLDAP_FALSE = @USE_LIBLDAP_FALSE@
+USE_LIBLDAP_TRUE = @USE_LIBLDAP_TRUE@
+USE_NAT_TRANSPORT_FALSE = @USE_NAT_TRANSPORT_FALSE@
+USE_NAT_TRANSPORT_TRUE = @USE_NAT_TRANSPORT_TRUE@
+USE_SMARTCARD_FALSE = @USE_SMARTCARD_FALSE@
+USE_SMARTCARD_TRUE = @USE_SMARTCARD_TRUE@
+USE_VENDORID_FALSE = @USE_VENDORID_FALSE@
+USE_VENDORID_TRUE = @USE_VENDORID_TRUE@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+confdir = @confdir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+eapdir = @eapdir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+ipsecdir = @ipsecdir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+piddir = @piddir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+pluto_SOURCES = \
+ac.c ac.h \
+alg_info.c alg_info.h \
+asn1.c asn1.h \
+ca.c ca.h \
+certs.c certs.h \
+connections.c connections.h \
+constants.c constants.h \
+cookie.c cookie.h \
+crl.c crl.h \
+crypto.c crypto.h \
+db_ops.c db_ops.h \
+defs.c defs.h \
+demux.c demux.h \
+dnskey.c dnskey.h \
+dsa.c dsa.h \
+elgamal.c elgamal.h \
+fetch.c fetch.h \
+foodgroups.c foodgroups.h \
+gcryptfix.c gcryptfix.h \
+id.c id.h \
+ike_alg.c ike_alg.h \
+ipsec_doi.c ipsec_doi.h \
+kameipsec.h \
+kernel.c kernel.h \
+kernel_alg.c kernel_alg.h \
+kernel_netlink.c kernel_netlink.h \
+kernel_noklips.c kernel_noklips.h \
+kernel_pfkey.c kernel_pfkey.h \
+keys.c keys.h \
+lex.c lex.h \
+log.c log.h \
+md2.c md2.h \
+md5.c md5.h \
+modecfg.c modecfg.h \
+mp_defs.c mp_defs.h \
+nat_traversal.c nat_traversal.h \
+ocsp.c ocsp.h \
+oid.c oid.h \
+packet.c packet.h \
+pem.c pem.h \
+pgp.c pgp.h \
+pkcs1.c pkcs1.h \
+pkcs7.c pkcs7.h \
+plutomain.c \
+primegen.c smallprime.c \
+rcv_whack.c rcv_whack.h \
+rnd.c rnd.h \
+server.c server.h \
+sha1.c sha1.h \
+smartcard.c smartcard.h \
+spdb.c spdb.h \
+state.c state.h \
+timer.c timer.h \
+vendor.c vendor.h \
+virtual.c virtual.h \
+xauth.c xauth.h \
+x509.c x509.h \
+alg/ike_alg_aes.c alg/ike_alg_blowfish.c alg/ike_alg_twofish.c \
+alg/ike_alg_serpent.c alg/ike_alg_sha2.c alg/ike_alginit.c \
+linux26/netlink.h linux26/rtnetlink.h linux26/xfrm.h \
+rsaref/pkcs11t.h rsaref/pkcs11.h rsaref/unix.h rsaref/pkcs11f.h
+
+_pluto_adns_SOURCES = adns.c adns.h
+INCLUDES = \
+-I$(top_srcdir)/src/libfreeswan \
+-I$(top_srcdir)/src/libcrypto \
+-I$(top_srcdir)/src/whack
+
+AM_CFLAGS = -DIPSEC_DIR=\"${ipsecdir}\" -DIPSEC_CONFDIR=\"${confdir}\" \
+ -DIPSEC_PIDDIR=\"${piddir}\" \
+ -DSHARED_SECRETS_FILE=\"${confdir}/ipsec.secrets\" \
+ -DKERNEL26_SUPPORT -DKERNEL26_HAS_KAME_DUPLICATES -DPLUTO \
+ -DKLIPS -DDEBUG -DTHREADS $(am__append_1) $(am__append_2) \
+ $(am__append_3)
+pluto_LDADD = $(top_srcdir)/src/libfreeswan/libfreeswan.a \
+ $(top_srcdir)/src/libcrypto/libcrypto.a -lgmp -lresolv \
+ -lpthread -ldl $(am__append_4) $(am__append_5)
+_pluto_adns_LDADD = \
+$(top_srcdir)/src/libfreeswan/libfreeswan.a \
+-lresolv -ldl
+
+dist_man_MANS = pluto.8 ipsec.secrets.5
+EXTRA_DIST = oid.pl oid.txt
+BUILT_SOURCES = oid.c oid.h
+MAINTAINERCLEANFILES = oid.c oid.h
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/pluto/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/pluto/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-ipsecPROGRAMS: $(ipsec_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(ipsecdir)" || $(mkdir_p) "$(DESTDIR)$(ipsecdir)"
+ @list='$(ipsec_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ || test -f $$p1 \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(ipsecPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(ipsecdir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(ipsecPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(ipsecdir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-ipsecPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(ipsec_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(ipsecdir)/$$f'"; \
+ rm -f "$(DESTDIR)$(ipsecdir)/$$f"; \
+ done
+
+clean-ipsecPROGRAMS:
+ @list='$(ipsec_PROGRAMS)'; for p in $$list; do \
+ f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f $$p $$f"; \
+ rm -f $$p $$f ; \
+ done
+_pluto_adns$(EXEEXT): $(_pluto_adns_OBJECTS) $(_pluto_adns_DEPENDENCIES)
+ @rm -f _pluto_adns$(EXEEXT)
+ $(LINK) $(_pluto_adns_LDFLAGS) $(_pluto_adns_OBJECTS) $(_pluto_adns_LDADD) $(LIBS)
+pluto$(EXEEXT): $(pluto_OBJECTS) $(pluto_DEPENDENCIES)
+ @rm -f pluto$(EXEEXT)
+ $(LINK) $(pluto_LDFLAGS) $(pluto_OBJECTS) $(pluto_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ac.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/adns.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alg_info.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ca.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/certs.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/connections.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/constants.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cookie.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crl.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crypto.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/db_ops.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/defs.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/demux.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnskey.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dsa.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elgamal.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fetch.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/foodgroups.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gcryptfix.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/id.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_alg.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_alg_aes.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_alg_blowfish.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_alg_serpent.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_alg_sha2.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_alg_twofish.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_alginit.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipsec_doi.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kernel.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kernel_alg.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kernel_netlink.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kernel_noklips.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kernel_pfkey.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keys.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lex.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md2.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/modecfg.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mp_defs.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nat_traversal.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ocsp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oid.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/packet.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pem.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pgp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pkcs1.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pkcs7.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plutomain.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/primegen.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rcv_whack.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rnd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha1.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/smallprime.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/smartcard.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spdb.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/state.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vendor.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/virtual.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/x509.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xauth.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+ike_alg_aes.o: alg/ike_alg_aes.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_alg_aes.o -MD -MP -MF "$(DEPDIR)/ike_alg_aes.Tpo" -c -o ike_alg_aes.o `test -f 'alg/ike_alg_aes.c' || echo '$(srcdir)/'`alg/ike_alg_aes.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_alg_aes.Tpo" "$(DEPDIR)/ike_alg_aes.Po"; else rm -f "$(DEPDIR)/ike_alg_aes.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alg/ike_alg_aes.c' object='ike_alg_aes.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_alg_aes.o `test -f 'alg/ike_alg_aes.c' || echo '$(srcdir)/'`alg/ike_alg_aes.c
+
+ike_alg_aes.obj: alg/ike_alg_aes.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_alg_aes.obj -MD -MP -MF "$(DEPDIR)/ike_alg_aes.Tpo" -c -o ike_alg_aes.obj `if test -f 'alg/ike_alg_aes.c'; then $(CYGPATH_W) 'alg/ike_alg_aes.c'; else $(CYGPATH_W) '$(srcdir)/alg/ike_alg_aes.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_alg_aes.Tpo" "$(DEPDIR)/ike_alg_aes.Po"; else rm -f "$(DEPDIR)/ike_alg_aes.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alg/ike_alg_aes.c' object='ike_alg_aes.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_alg_aes.obj `if test -f 'alg/ike_alg_aes.c'; then $(CYGPATH_W) 'alg/ike_alg_aes.c'; else $(CYGPATH_W) '$(srcdir)/alg/ike_alg_aes.c'; fi`
+
+ike_alg_blowfish.o: alg/ike_alg_blowfish.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_alg_blowfish.o -MD -MP -MF "$(DEPDIR)/ike_alg_blowfish.Tpo" -c -o ike_alg_blowfish.o `test -f 'alg/ike_alg_blowfish.c' || echo '$(srcdir)/'`alg/ike_alg_blowfish.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_alg_blowfish.Tpo" "$(DEPDIR)/ike_alg_blowfish.Po"; else rm -f "$(DEPDIR)/ike_alg_blowfish.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alg/ike_alg_blowfish.c' object='ike_alg_blowfish.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_alg_blowfish.o `test -f 'alg/ike_alg_blowfish.c' || echo '$(srcdir)/'`alg/ike_alg_blowfish.c
+
+ike_alg_blowfish.obj: alg/ike_alg_blowfish.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_alg_blowfish.obj -MD -MP -MF "$(DEPDIR)/ike_alg_blowfish.Tpo" -c -o ike_alg_blowfish.obj `if test -f 'alg/ike_alg_blowfish.c'; then $(CYGPATH_W) 'alg/ike_alg_blowfish.c'; else $(CYGPATH_W) '$(srcdir)/alg/ike_alg_blowfish.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_alg_blowfish.Tpo" "$(DEPDIR)/ike_alg_blowfish.Po"; else rm -f "$(DEPDIR)/ike_alg_blowfish.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alg/ike_alg_blowfish.c' object='ike_alg_blowfish.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_alg_blowfish.obj `if test -f 'alg/ike_alg_blowfish.c'; then $(CYGPATH_W) 'alg/ike_alg_blowfish.c'; else $(CYGPATH_W) '$(srcdir)/alg/ike_alg_blowfish.c'; fi`
+
+ike_alg_twofish.o: alg/ike_alg_twofish.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_alg_twofish.o -MD -MP -MF "$(DEPDIR)/ike_alg_twofish.Tpo" -c -o ike_alg_twofish.o `test -f 'alg/ike_alg_twofish.c' || echo '$(srcdir)/'`alg/ike_alg_twofish.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_alg_twofish.Tpo" "$(DEPDIR)/ike_alg_twofish.Po"; else rm -f "$(DEPDIR)/ike_alg_twofish.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alg/ike_alg_twofish.c' object='ike_alg_twofish.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_alg_twofish.o `test -f 'alg/ike_alg_twofish.c' || echo '$(srcdir)/'`alg/ike_alg_twofish.c
+
+ike_alg_twofish.obj: alg/ike_alg_twofish.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_alg_twofish.obj -MD -MP -MF "$(DEPDIR)/ike_alg_twofish.Tpo" -c -o ike_alg_twofish.obj `if test -f 'alg/ike_alg_twofish.c'; then $(CYGPATH_W) 'alg/ike_alg_twofish.c'; else $(CYGPATH_W) '$(srcdir)/alg/ike_alg_twofish.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_alg_twofish.Tpo" "$(DEPDIR)/ike_alg_twofish.Po"; else rm -f "$(DEPDIR)/ike_alg_twofish.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alg/ike_alg_twofish.c' object='ike_alg_twofish.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_alg_twofish.obj `if test -f 'alg/ike_alg_twofish.c'; then $(CYGPATH_W) 'alg/ike_alg_twofish.c'; else $(CYGPATH_W) '$(srcdir)/alg/ike_alg_twofish.c'; fi`
+
+ike_alg_serpent.o: alg/ike_alg_serpent.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_alg_serpent.o -MD -MP -MF "$(DEPDIR)/ike_alg_serpent.Tpo" -c -o ike_alg_serpent.o `test -f 'alg/ike_alg_serpent.c' || echo '$(srcdir)/'`alg/ike_alg_serpent.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_alg_serpent.Tpo" "$(DEPDIR)/ike_alg_serpent.Po"; else rm -f "$(DEPDIR)/ike_alg_serpent.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alg/ike_alg_serpent.c' object='ike_alg_serpent.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_alg_serpent.o `test -f 'alg/ike_alg_serpent.c' || echo '$(srcdir)/'`alg/ike_alg_serpent.c
+
+ike_alg_serpent.obj: alg/ike_alg_serpent.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_alg_serpent.obj -MD -MP -MF "$(DEPDIR)/ike_alg_serpent.Tpo" -c -o ike_alg_serpent.obj `if test -f 'alg/ike_alg_serpent.c'; then $(CYGPATH_W) 'alg/ike_alg_serpent.c'; else $(CYGPATH_W) '$(srcdir)/alg/ike_alg_serpent.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_alg_serpent.Tpo" "$(DEPDIR)/ike_alg_serpent.Po"; else rm -f "$(DEPDIR)/ike_alg_serpent.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alg/ike_alg_serpent.c' object='ike_alg_serpent.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_alg_serpent.obj `if test -f 'alg/ike_alg_serpent.c'; then $(CYGPATH_W) 'alg/ike_alg_serpent.c'; else $(CYGPATH_W) '$(srcdir)/alg/ike_alg_serpent.c'; fi`
+
+ike_alg_sha2.o: alg/ike_alg_sha2.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_alg_sha2.o -MD -MP -MF "$(DEPDIR)/ike_alg_sha2.Tpo" -c -o ike_alg_sha2.o `test -f 'alg/ike_alg_sha2.c' || echo '$(srcdir)/'`alg/ike_alg_sha2.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_alg_sha2.Tpo" "$(DEPDIR)/ike_alg_sha2.Po"; else rm -f "$(DEPDIR)/ike_alg_sha2.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alg/ike_alg_sha2.c' object='ike_alg_sha2.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_alg_sha2.o `test -f 'alg/ike_alg_sha2.c' || echo '$(srcdir)/'`alg/ike_alg_sha2.c
+
+ike_alg_sha2.obj: alg/ike_alg_sha2.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_alg_sha2.obj -MD -MP -MF "$(DEPDIR)/ike_alg_sha2.Tpo" -c -o ike_alg_sha2.obj `if test -f 'alg/ike_alg_sha2.c'; then $(CYGPATH_W) 'alg/ike_alg_sha2.c'; else $(CYGPATH_W) '$(srcdir)/alg/ike_alg_sha2.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_alg_sha2.Tpo" "$(DEPDIR)/ike_alg_sha2.Po"; else rm -f "$(DEPDIR)/ike_alg_sha2.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alg/ike_alg_sha2.c' object='ike_alg_sha2.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_alg_sha2.obj `if test -f 'alg/ike_alg_sha2.c'; then $(CYGPATH_W) 'alg/ike_alg_sha2.c'; else $(CYGPATH_W) '$(srcdir)/alg/ike_alg_sha2.c'; fi`
+
+ike_alginit.o: alg/ike_alginit.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_alginit.o -MD -MP -MF "$(DEPDIR)/ike_alginit.Tpo" -c -o ike_alginit.o `test -f 'alg/ike_alginit.c' || echo '$(srcdir)/'`alg/ike_alginit.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_alginit.Tpo" "$(DEPDIR)/ike_alginit.Po"; else rm -f "$(DEPDIR)/ike_alginit.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alg/ike_alginit.c' object='ike_alginit.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_alginit.o `test -f 'alg/ike_alginit.c' || echo '$(srcdir)/'`alg/ike_alginit.c
+
+ike_alginit.obj: alg/ike_alginit.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_alginit.obj -MD -MP -MF "$(DEPDIR)/ike_alginit.Tpo" -c -o ike_alginit.obj `if test -f 'alg/ike_alginit.c'; then $(CYGPATH_W) 'alg/ike_alginit.c'; else $(CYGPATH_W) '$(srcdir)/alg/ike_alginit.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_alginit.Tpo" "$(DEPDIR)/ike_alginit.Po"; else rm -f "$(DEPDIR)/ike_alginit.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alg/ike_alginit.c' object='ike_alginit.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_alginit.obj `if test -f 'alg/ike_alginit.c'; then $(CYGPATH_W) 'alg/ike_alginit.c'; else $(CYGPATH_W) '$(srcdir)/alg/ike_alginit.c'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+install-man5: $(man5_MANS) $(man_MANS)
+ @$(NORMAL_INSTALL)
+ test -z "$(man5dir)" || $(mkdir_p) "$(DESTDIR)$(man5dir)"
+ @list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.5*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 5*) ;; \
+ *) ext='5' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst"; \
+ done
+uninstall-man5:
+ @$(NORMAL_UNINSTALL)
+ @list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.5*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 5*) ;; \
+ *) ext='5' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f '$(DESTDIR)$(man5dir)/$$inst'"; \
+ rm -f "$(DESTDIR)$(man5dir)/$$inst"; \
+ done
+install-man8: $(man8_MANS) $(man_MANS)
+ @$(NORMAL_INSTALL)
+ test -z "$(man8dir)" || $(mkdir_p) "$(DESTDIR)$(man8dir)"
+ @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 8*) ;; \
+ *) ext='8' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst"; \
+ done
+uninstall-man8:
+ @$(NORMAL_UNINSTALL)
+ @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 8*) ;; \
+ *) ext='8' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f '$(DESTDIR)$(man8dir)/$$inst'"; \
+ rm -f "$(DESTDIR)$(man8dir)/$$inst"; \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(PROGRAMS) $(MANS)
+installdirs:
+ for dir in "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(man8dir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic clean-ipsecPROGRAMS clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-ipsecPROGRAMS install-man
+
+install-exec-am: install-exec-local
+
+install-info: install-info-am
+
+install-man: install-man5 install-man8
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-ipsecPROGRAMS uninstall-man
+
+uninstall-man: uninstall-man5 uninstall-man8
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-ipsecPROGRAMS clean-libtool ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-exec \
+ install-exec-am install-exec-local install-info \
+ install-info-am install-ipsecPROGRAMS install-man install-man5 \
+ install-man8 install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \
+ uninstall-am uninstall-info-am uninstall-ipsecPROGRAMS \
+ uninstall-man uninstall-man5 uninstall-man8
+
+
+oid.c: oid.txt oid.pl
+ $(PERL) oid.pl
+
+oid.h: oid.txt oid.pl
+ $(PERL) oid.pl
+
+install-exec-local :
+ mkdir -p -m 755 $(confdir)/ipsec.d
+ mkdir -p -m 755 $(confdir)/ipsec.d/cacerts
+ mkdir -p -m 755 $(confdir)/ipsec.d/ocspcerts
+ mkdir -p -m 755 $(confdir)/ipsec.d/certs
+ mkdir -p -m 755 $(confdir)/ipsec.d/acerts
+ mkdir -p -m 755 $(confdir)/ipsec.d/aacerts
+ mkdir -p -m 755 $(confdir)/ipsec.d/crls
+ mkdir -p -m 755 $(confdir)/ipsec.d/reqs
+ mkdir -p -m 700 $(confdir)/ipsec.d/private
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/pluto/TODO b/src/pluto/TODO
new file mode 100644
index 000000000..7db4a9ebc
--- /dev/null
+++ b/src/pluto/TODO
@@ -0,0 +1,129 @@
+Pluto TODO list
+===============
+RCSID $Id: TODO,v 1.1 2004/03/15 20:35:28 as Exp $
+
+- should all log entries that are for errors say ERROR?
+
+- Add a "plug-in" facility so that others can add features without
+ changing the mainline code. This is how X509/LDAP/biometric stuff
+ might be added.
+
+- (internal change only) routines for outputting payloads should plug
+ "np" into the previous payload so that a payload generating routine
+ need not know what the next payload will be. This may be more bother
+ than it is worth.
+
+- notifications, in and out
+ + delete
+ + first contact
+ + last contact? (not part of drafts, but would be nice)
+
+- Make DNS usage for asynchronous (non-blocking)
+ + looking up KEY and TXT records during negotiation
+ + perhaps not for whack command arguments and ipsec.secrets since the
+ library code uses gethostbyname
+
+- check that ipsec auto and whack to agree on what is worth reporting
+
+- Should Pluto (rather than ipsec manual) install %passthrough conns?
+ That way Pluto would know of them.
+
+- For responding to Road Warriors, how can we decide if the RW has
+ gone away? The rekeying event is perhaps too imprecise. Even if
+ rekeying event is good enough, how do we know if the route should be
+ torn down? Perhaps limiting a Phase 1 ID to one IP address would
+ help (limiting a client subnet to one peer already helps). Perhaps
+ (in some rate-limited way) we can take an ICMP host unreachable
+ as a hint to do some authenticated and reliable probe.
+
+- it is annoying that Pluto and auto have different models for public keys.
+ + auto specifies one per connection
+ + Pluto allows one to be specified per id
+ Two connections with the same id are going to use the same key:
+ the one of the last conn to be added!
+
+ I think auto ought to be fixed. It is hard for Pluto to warn when
+ there is a conflict since the deletion of a connection doesn't
+ prompt auto to tell pluto to delete the public key.
+
+- different connections with the same host IP addresses are randomly
+ interchangeable until the ID payload is received. At least for the
+ Responder case (and eventually for the opportunistic Initiator).
+ Worse, all Road Warriors must be considered to have the
+ indistinguishable IP addresses. This affects ISAKMP SA negotiation.
+ Currently, there is little flexibility in this negotiation, so the
+ problem is limited to the specification of acceptable authentication
+ method(s). Correct, but more work than seems worthwhile, would be
+ to select the conn based on what is proposed.
+
+ Warning about such confusion at connection definition time isn't great
+ because there is no confusion when explicitly initiated (a particular
+ conn is specified). Warning for a Road Warrior conn is possible
+ since it cannot be initiated (and has been implemented).
+
+- characterize and ameliorate DOS attacks. Lots of rate limiting.
+
+- look at John Denker's wish list: http://www.quintillion.com/moat/wish.list
+
+- use of random numbers needs to be audited.
+
+- unknown (not just unimplemented) transforms cause a negotiation to
+ fail. Only the transform should be rejected.
+
+- we need better policy control. Our present flags need to be
+ modulated (forbid, allow, offer, require)
+
+- HS will specify how --copyright and --version should behave
+
+- HS will initiate project-wide terminology replacing ISAKMP SA, IPSEC
+ SA, Protection Suite, Phase 1, Main Mode, Phase 2, Quick Mode, ...
+ Simplicity and clarity will be a goal.
+
+- interface discovery ought to match what is specified in ipsec.conf.
+ This probably means grokking /proc/net/ipsec_tncfg. Documented in
+ ipsec_tncfg(5). This won't do for Hugh's debugging setup.
+
+
+Protocol Issues
+===============
+
+Notification and delete payloads seem to be "escape hatches" for the
+protocols. As such, anything implemented using them seems to be
+kludged without being well designed or well situated or well
+constrained in the protocols. Often the precise meaning (if any) or
+usage is under specified. An implementation is allowed to ignore
+them, so they cannot really matter (but they too often do). Their
+specification ought to be scrutinized by a protocol guru.
+
+Any extra payload in last main mode message is not protected (not
+authenticated by hash).
+
+Should notification payloads be interpreted before or after the normal
+payloads (i.e. understood in the context of, executed in the context of).
+
+What is the precise result of an INITIAL_CONNECTION? What is a
+"system" (eg. does Phase 1 Identity count)? What is "earlier" or
+"before" (simultaneous negotiation is possible, with time being only a
+partial order)? Could it be used for FINAL_CONTACT (needed too)?
+
+Blasting out a pile of UDP messages, especially to a particular
+destination, is likely to provoke message loss. The exchanges are
+just that, so they individually are self-throttling. But what about
+multiple exchanges simultaneously? What about notifications (example:
+when shutting down, a flurry of delete notifications are likely).
+Should the RFCs be designed to protect against this problem?
+
+draft-jenkins-ipsec-rekeying-03.txt rekeying is way too complicated.
+Our solution looks sound and simple (we have the Responder install the
+incoming IPSEC SA before sending its first reply). In "2.2.1.4
+Responder Pre-Set-up Security Hole", the draft claims that setting up
+the IPSEC SA early leaves the Responder open to replay attacks. I
+think that this is wrong: the Message Id, since it must not be reused,
+serves to prove that this isn't a replay.
+
+The details for notification messages suggested by
+draft-ietf-ipsec-notifymsg-02.txt are over-complicated, just to make
+them machine-comprehensible. I think this is over-engineering,
+justified only if another level of negotiation is contemplated (ugh!).
+Plain text is probably sufficient for informing humans (I admit that
+there is a problem with I18N).
diff --git a/src/pluto/ac.c b/src/pluto/ac.c
new file mode 100644
index 000000000..bcf5f80d1
--- /dev/null
+++ b/src/pluto/ac.c
@@ -0,0 +1,1018 @@
+/* Support of X.509 attribute certificates
+ * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler
+ * Copyright (C) 2003 Martin Berner, Lukas Suter
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: ac.c,v 1.12 2005/12/06 22:49:32 as Exp $
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <time.h>
+#include <sys/types.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "asn1.h"
+#include "oid.h"
+#include "ac.h"
+#include "x509.h"
+#include "crl.h"
+#include "ca.h"
+#include "certs.h"
+#include "log.h"
+#include "whack.h"
+#include "fetch.h"
+
+/* chained list of X.509 attribute certificates */
+
+static x509acert_t *x509acerts = NULL;
+
+/* chained list of ietfAttributes */
+
+static ietfAttrList_t *ietfAttributes = NULL;
+
+/* ASN.1 definition of ietfAttrSyntax */
+
+static const asn1Object_t ietfAttrSyntaxObjects[] =
+{
+ { 0, "ietfAttrSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "policyAuthority", ASN1_CONTEXT_C_0, ASN1_OPT |
+ ASN1_BODY }, /* 1 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */
+ { 1, "values", ASN1_SEQUENCE, ASN1_LOOP }, /* 3 */
+ { 2, "octets", ASN1_OCTET_STRING, ASN1_OPT |
+ ASN1_BODY }, /* 4 */
+ { 2, "end choice", ASN1_EOC, ASN1_END }, /* 5 */
+ { 2, "oid", ASN1_OID, ASN1_OPT |
+ ASN1_BODY }, /* 6 */
+ { 2, "end choice", ASN1_EOC, ASN1_END }, /* 7 */
+ { 2, "string", ASN1_UTF8STRING, ASN1_OPT |
+ ASN1_BODY }, /* 8 */
+ { 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */
+ { 1, "end loop", ASN1_EOC, ASN1_END } /* 10 */
+};
+
+#define IETF_ATTR_OCTETS 4
+#define IETF_ATTR_OID 6
+#define IETF_ATTR_STRING 8
+#define IETF_ATTR_ROOF 11
+
+/* ASN.1 definition of roleSyntax */
+
+static const asn1Object_t roleSyntaxObjects[] =
+{
+ { 0, "roleSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "roleAuthority", ASN1_CONTEXT_C_0, ASN1_OPT |
+ ASN1_OBJ }, /* 1 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */
+ { 1, "roleName", ASN1_CONTEXT_C_1, ASN1_OBJ } /* 3 */
+};
+
+#define ROLE_ROOF 4
+
+/* ASN.1 definition of an X509 attribute certificate */
+
+static const asn1Object_t acObjects[] =
+{
+ { 0, "AttributeCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
+ { 1, "AttributeCertificateInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
+ { 2, "version", ASN1_INTEGER, ASN1_DEF |
+ ASN1_BODY }, /* 2 */
+ { 2, "holder", ASN1_SEQUENCE, ASN1_NONE }, /* 3 */
+ { 3, "baseCertificateID", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 4 */
+ { 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */
+ { 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 6 */
+ { 4, "issuerUID", ASN1_BIT_STRING, ASN1_OPT |
+ ASN1_BODY }, /* 7 */
+ { 4, "end opt", ASN1_EOC, ASN1_END }, /* 8 */
+ { 3, "end opt", ASN1_EOC, ASN1_END }, /* 9 */
+ { 3, "entityName", ASN1_CONTEXT_C_1, ASN1_OPT |
+ ASN1_OBJ }, /* 10 */
+ { 3, "end opt", ASN1_EOC, ASN1_END }, /* 11 */
+ { 3, "objectDigestInfo", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 12 */
+ { 4, "digestedObjectType", ASN1_ENUMERATED, ASN1_BODY }, /* 13*/
+ { 4, "otherObjectTypeID", ASN1_OID, ASN1_OPT |
+ ASN1_BODY }, /* 14 */
+ { 4, "end opt", ASN1_EOC, ASN1_END }, /* 15*/
+ { 4, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 16 */
+ { 3, "end opt", ASN1_EOC, ASN1_END }, /* 17 */
+ { 2, "v2Form", ASN1_CONTEXT_C_0, ASN1_NONE }, /* 18 */
+ { 3, "issuerName", ASN1_SEQUENCE, ASN1_OPT |
+ ASN1_OBJ }, /* 19 */
+ { 3, "end opt", ASN1_EOC, ASN1_END }, /* 20 */
+ { 3, "baseCertificateID", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 21 */
+ { 4, "issuerSerial", ASN1_SEQUENCE, ASN1_NONE }, /* 22 */
+ { 5, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 23 */
+ { 5, "serial", ASN1_INTEGER, ASN1_BODY }, /* 24 */
+ { 5, "issuerUID", ASN1_BIT_STRING, ASN1_OPT |
+ ASN1_BODY }, /* 25 */
+ { 5, "end opt", ASN1_EOC, ASN1_END }, /* 26 */
+ { 3, "end opt", ASN1_EOC, ASN1_END }, /* 27 */
+ { 3, "objectDigestInfo", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 28 */
+ { 4, "digestInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 29 */
+ { 5, "digestedObjectType", ASN1_ENUMERATED, ASN1_BODY }, /* 30 */
+ { 5, "otherObjectTypeID", ASN1_OID, ASN1_OPT |
+ ASN1_BODY }, /* 31 */
+ { 5, "end opt", ASN1_EOC, ASN1_END }, /* 32 */
+ { 5, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 33 */
+ { 3, "end opt", ASN1_EOC, ASN1_END }, /* 34 */
+ { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 35 */
+ { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 36 */
+ { 2, "attrCertValidityPeriod", ASN1_SEQUENCE, ASN1_NONE }, /* 37 */
+ { 3, "notBeforeTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 38 */
+ { 3, "notAfterTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 39 */
+ { 2, "attributes", ASN1_SEQUENCE, ASN1_LOOP }, /* 40 */
+ { 3, "attribute", ASN1_SEQUENCE, ASN1_NONE }, /* 41 */
+ { 4, "type", ASN1_OID, ASN1_BODY }, /* 42 */
+ { 4, "values", ASN1_SET, ASN1_LOOP }, /* 43 */
+ { 5, "value", ASN1_EOC, ASN1_RAW }, /* 44 */
+ { 4, "end loop", ASN1_EOC, ASN1_END }, /* 45 */
+ { 2, "end loop", ASN1_EOC, ASN1_END }, /* 46 */
+ { 2, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 47 */
+ { 3, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 48 */
+ { 4, "extnID", ASN1_OID, ASN1_BODY }, /* 49 */
+ { 4, "critical", ASN1_BOOLEAN, ASN1_DEF |
+ ASN1_BODY }, /* 50 */
+ { 4, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 51 */
+ { 2, "end loop", ASN1_EOC, ASN1_END }, /* 52 */
+ { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 53 */
+ { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY } /* 54 */
+};
+
+#define AC_OBJ_CERTIFICATE 0
+#define AC_OBJ_CERTIFICATE_INFO 1
+#define AC_OBJ_VERSION 2
+#define AC_OBJ_HOLDER_ISSUER 5
+#define AC_OBJ_HOLDER_SERIAL 6
+#define AC_OBJ_ENTITY_NAME 10
+#define AC_OBJ_ISSUER_NAME 19
+#define AC_OBJ_ISSUER 23
+#define AC_OBJ_SIG_ALG 35
+#define AC_OBJ_SERIAL_NUMBER 36
+#define AC_OBJ_NOT_BEFORE 38
+#define AC_OBJ_NOT_AFTER 39
+#define AC_OBJ_ATTRIBUTE_TYPE 42
+#define AC_OBJ_ATTRIBUTE_VALUE 44
+#define AC_OBJ_EXTN_ID 49
+#define AC_OBJ_CRITICAL 50
+#define AC_OBJ_EXTN_VALUE 51
+#define AC_OBJ_ALGORITHM 53
+#define AC_OBJ_SIGNATURE 54
+#define AC_OBJ_ROOF 55
+
+const x509acert_t empty_ac = {
+ NULL , /* *next */
+ 0 , /* installed */
+ { NULL, 0 }, /* certificate */
+ { NULL, 0 }, /* certificateInfo */
+ 1 , /* version */
+ /* holder */
+ /* baseCertificateID */
+ { NULL, 0 }, /* holderIssuer */
+ { NULL, 0 }, /* holderSerial */
+ /* entityName */
+ { NULL, 0 }, /* generalNames */
+ /* v2Form */
+ { NULL, 0 }, /* issuerName */
+ /* signature */
+ OID_UNKNOWN, /* sigAlg */
+ { NULL, 0 }, /* serialNumber */
+ /* attrCertValidityPeriod */
+ 0 , /* notBefore */
+ 0 , /* notAfter */
+ /* attributes */
+ NULL , /* charging */
+ NULL , /* groups */
+ /* extensions */
+ { NULL, 0 }, /* authKeyID */
+ { NULL, 0 }, /* authKeySerialNumber */
+ FALSE , /* noRevAvail */
+ /* signatureAlgorithm */
+ OID_UNKNOWN, /* algorithm */
+ { NULL, 0 }, /* signature */
+};
+
+
+/* compare two ietfAttributes, returns zero if a equals b
+ * negative/positive if a is earlier/later in the alphabet than b
+ */
+static int
+cmp_ietfAttr(ietfAttr_t *a,ietfAttr_t *b)
+{
+ int cmp_len, len, cmp_value;
+
+ /* cannot compare OID with STRING or OCTETS attributes */
+ if (a->kind == IETF_ATTRIBUTE_OID && b->kind != IETF_ATTRIBUTE_OID)
+ return 1;
+
+ cmp_len = a->value.len - b->value.len;
+ len = (cmp_len < 0)? a->value.len : b->value.len;
+ cmp_value = memcmp(a->value.ptr, b->value.ptr, len);
+
+ return (cmp_value == 0)? cmp_len : cmp_value;
+}
+
+/*
+ * add an ietfAttribute to the chained list
+ */
+static ietfAttr_t*
+add_ietfAttr(ietfAttr_t *attr)
+{
+ ietfAttrList_t **listp = &ietfAttributes;
+ ietfAttrList_t *list = *listp;
+ int cmp = -1;
+
+ while (list != NULL)
+ {
+ cmp = cmp_ietfAttr(attr, list->attr);
+ if (cmp <= 0)
+ break;
+ listp = &list->next;
+ list = *listp;
+ }
+
+ if (cmp == 0)
+ {
+ /* attribute already exists, increase count */
+ pfree(attr);
+ list->attr->count++;
+ return list->attr;
+ }
+ else
+ {
+ ietfAttrList_t *el = alloc_thing(ietfAttrList_t, "ietfAttrList");
+
+ /* new attribute, unshare value */
+ attr->value.ptr = clone_bytes(attr->value.ptr, attr->value.len
+ , "attr value");
+ attr->count = 1;
+ time(&attr->installed);
+
+ el->attr = attr;
+ el->next = list;
+ *listp = el;
+
+ return attr;
+ }
+}
+
+/*
+ * decodes a comma separated list of group attributes
+ */
+void
+decode_groups(char *groups, ietfAttrList_t **listp)
+{
+ if (groups == NULL)
+ return;
+
+ while (strlen(groups) > 0)
+ {
+ char *end;
+ char *next = strchr(groups, ',');
+
+ if (next == NULL)
+ end = next = groups + strlen(groups);
+ else
+ end = next++;
+
+ /* eat preceeding whitespace */
+ while (groups < end && *groups == ' ')
+ groups++;
+
+ /* eat trailing whitespace */
+ while (end > groups && *(end-1) == ' ')
+ end--;
+
+ if (groups < end)
+ {
+ ietfAttr_t *attr = alloc_thing(ietfAttr_t, "ietfAttr");
+ ietfAttrList_t *el = alloc_thing(ietfAttrList_t, "ietfAttrList");
+
+ attr->kind = IETF_ATTRIBUTE_STRING;
+ attr->value.ptr = groups;
+ attr->value.len = end - groups;
+ attr->count = 0;
+
+ el->attr = add_ietfAttr(attr);
+ el->next = *listp;
+ *listp = el;
+ }
+
+ groups = next;
+ }
+}
+
+static bool
+same_attribute(const ietfAttr_t *a, const ietfAttr_t *b)
+{
+ return (a->kind == b->kind && a->value.len == b->value.len
+ && memcmp(a->value.ptr, b->value.ptr, b->value.len) == 0);
+}
+
+bool
+group_membership(const ietfAttrList_t *peer_list
+ , const char *conn
+ , const ietfAttrList_t *conn_list)
+{
+ if (conn_list == NULL)
+ return TRUE;
+
+ while (peer_list != NULL)
+ {
+ const ietfAttr_t *peer_attr = peer_list->attr;
+ const ietfAttrList_t *list = conn_list;
+
+ while (list != NULL)
+ {
+ ietfAttr_t *conn_attr = list->attr;
+
+ if (same_attribute(conn_attr, peer_attr))
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("%s: peer matches group '%.*s'"
+ , conn
+ , (int)peer_attr->value.len, peer_attr->value.ptr)
+ )
+ return TRUE;
+ }
+ list = list->next;
+ }
+ peer_list = peer_list->next;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("%s: peer doesn't match any group", conn)
+ )
+ return FALSE;
+}
+
+
+void
+unshare_ietfAttrList(ietfAttrList_t **listp)
+{
+ ietfAttrList_t *list = *listp;
+
+ while (list != NULL)
+ {
+ ietfAttrList_t *el = alloc_thing(ietfAttrList_t, "ietfAttrList");
+
+ el->attr = list->attr;
+ el->attr->count++;
+ el->next = NULL;
+ *listp = el;
+ listp = &el->next;
+ list = list->next;
+ }
+}
+
+/*
+ * parses ietfAttrSyntax
+ */
+static ietfAttrList_t*
+parse_ietfAttrSyntax(chunk_t blob, int level0)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+
+ ietfAttrList_t *list = NULL;
+
+ asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
+
+ while (objectID < IETF_ATTR_ROOF)
+ {
+ if (!extract_object(ietfAttrSyntaxObjects, &objectID, &object, &level, &ctx))
+ return NULL;
+
+ switch (objectID)
+ {
+ case IETF_ATTR_OCTETS:
+ case IETF_ATTR_OID:
+ case IETF_ATTR_STRING:
+ {
+ ietfAttr_t *attr = alloc_thing(ietfAttr_t, "ietfAttr");
+ ietfAttrList_t *el = alloc_thing(ietfAttrList_t, "ietfAttrList");
+
+ attr->kind = (objectID - IETF_ATTR_OCTETS) / 2;
+ attr->value = object;
+ attr->count = 0;
+
+ el->attr = add_ietfAttr(attr);
+ el->next = list;
+ list = el;
+ }
+ break;
+ default:
+ break;
+ }
+ objectID++;
+ }
+ return list;
+}
+/*
+ * parses roleSyntax
+ */
+static void
+parse_roleSyntax(chunk_t blob, int level0)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+
+ asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
+
+ while (objectID < ROLE_ROOF)
+ {
+ if (!extract_object(roleSyntaxObjects, &objectID, &object, &level, &ctx))
+ return;
+
+ switch (objectID) {
+ default:
+ break;
+ }
+ objectID++;
+ }
+}
+
+/*
+ * Parses an X.509 attribute certificate
+ */
+bool
+parse_ac(chunk_t blob, x509acert_t *ac)
+{
+ asn1_ctx_t ctx;
+ bool critical;
+ chunk_t object;
+ u_int level;
+ u_int type = OID_UNKNOWN;
+ u_int extn_oid = OID_UNKNOWN;
+ int objectID = 0;
+
+ asn1_init(&ctx, blob, 0, FALSE, DBG_RAW);
+
+ while (objectID < AC_OBJ_ROOF) {
+
+ if (!extract_object(acObjects, &objectID, &object, &level, &ctx))
+ return FALSE;
+
+ /* those objects which will parsed further need the next higher level */
+ level++;
+
+ switch (objectID)
+ {
+ case AC_OBJ_CERTIFICATE:
+ ac->certificate = object;
+ break;
+ case AC_OBJ_CERTIFICATE_INFO:
+ ac->certificateInfo = object;
+ break;
+ case AC_OBJ_VERSION:
+ ac->version = (object.len) ? (1 + (u_int)*object.ptr) : 1;
+ DBG(DBG_PARSING,
+ DBG_log(" v%d", ac->version);
+ )
+ if (ac->version != 2)
+ {
+ plog("v%d attribute certificates are not supported"
+ , ac->version);
+ return FALSE;
+ }
+ break;
+ case AC_OBJ_HOLDER_ISSUER:
+ ac->holderIssuer = get_directoryName(object, level, FALSE);
+ break;
+ case AC_OBJ_HOLDER_SERIAL:
+ ac->holderSerial = object;
+ break;
+ case AC_OBJ_ENTITY_NAME:
+ ac->entityName = get_directoryName(object, level, TRUE);
+ break;
+ case AC_OBJ_ISSUER_NAME:
+ ac->issuerName = get_directoryName(object, level, FALSE);
+ break;
+ case AC_OBJ_SIG_ALG:
+ ac->sigAlg = parse_algorithmIdentifier(object, level, NULL);
+ break;
+ case AC_OBJ_SERIAL_NUMBER:
+ ac->serialNumber = object;
+ break;
+ case AC_OBJ_NOT_BEFORE:
+ ac->notBefore = asn1totime(&object, ASN1_GENERALIZEDTIME);
+ break;
+ case AC_OBJ_NOT_AFTER:
+ ac->notAfter = asn1totime(&object, ASN1_GENERALIZEDTIME);
+ break;
+ case AC_OBJ_ATTRIBUTE_TYPE:
+ type = known_oid(object);
+ break;
+ case AC_OBJ_ATTRIBUTE_VALUE:
+ {
+ switch (type) {
+ case OID_AUTHENTICATION_INFO:
+ DBG(DBG_PARSING,
+ DBG_log(" need to parse authenticationInfo")
+ )
+ break;
+ case OID_ACCESS_IDENTITY:
+ DBG(DBG_PARSING,
+ DBG_log(" need to parse accessIdentity")
+ )
+ break;
+ case OID_CHARGING_IDENTITY:
+ ac->charging = parse_ietfAttrSyntax(object, level);
+ break;
+ case OID_GROUP:
+ ac->groups = parse_ietfAttrSyntax(object, level);
+ break;
+ case OID_ROLE:
+ parse_roleSyntax(object, level);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case AC_OBJ_EXTN_ID:
+ extn_oid = known_oid(object);
+ break;
+ case AC_OBJ_CRITICAL:
+ critical = object.len && *object.ptr;
+ DBG(DBG_PARSING,
+ DBG_log(" %s",(critical)?"TRUE":"FALSE");
+ )
+ break;
+ case AC_OBJ_EXTN_VALUE:
+ {
+ switch (extn_oid) {
+ case OID_CRL_DISTRIBUTION_POINTS:
+ DBG(DBG_PARSING,
+ DBG_log(" need to parse crlDistributionPoints")
+ )
+ break;
+ case OID_AUTHORITY_KEY_ID:
+ parse_authorityKeyIdentifier(object, level
+ , &ac->authKeyID, &ac->authKeySerialNumber);
+ break;
+ case OID_TARGET_INFORMATION:
+ DBG(DBG_PARSING,
+ DBG_log(" need to parse targetInformation")
+ )
+ break;
+ case OID_NO_REV_AVAIL:
+ ac->noRevAvail = TRUE;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case AC_OBJ_ALGORITHM:
+ ac->algorithm = parse_algorithmIdentifier(object, level, NULL);
+ break;
+ case AC_OBJ_SIGNATURE:
+ ac->signature = object;
+ break;
+
+ default:
+ break;
+ }
+ objectID++;
+ }
+ time(&ac->installed);
+ return TRUE;
+}
+
+/*
+ * compare two X.509 attribute certificates by comparing their signatures
+ */
+static bool
+same_x509acert(x509acert_t *a, x509acert_t *b)
+{
+ return a->signature.len == b->signature.len &&
+ memcmp(a->signature.ptr, b->signature.ptr, b->signature.len) == 0;
+}
+
+/*
+ * release an ietfAttribute, free it if count reaches zero
+ */
+static void
+release_ietfAttr(ietfAttr_t* attr)
+{
+ if (--attr->count == 0)
+ {
+ ietfAttrList_t **plist = &ietfAttributes;
+ ietfAttrList_t *list = *plist;
+
+ while (list->attr != attr)
+ {
+ plist = &list->next;
+ list = *plist;
+ }
+ *plist = list->next;
+
+ pfree(attr->value.ptr);
+ pfree(attr);
+ pfree(list);
+ }
+}
+
+/*
+ * free an ietfAttrList
+ */
+void
+free_ietfAttrList(ietfAttrList_t* list)
+{
+ while (list != NULL)
+ {
+ ietfAttrList_t *el = list;
+
+ release_ietfAttr(el->attr);
+ list = list->next;
+ pfree(el);
+ }
+}
+
+/*
+ * free a X.509 attribute certificate
+ */
+void
+free_acert(x509acert_t *ac)
+{
+ if (ac != NULL)
+ {
+ free_ietfAttrList(ac->charging);
+ free_ietfAttrList(ac->groups);
+ pfreeany(ac->certificate.ptr);
+ pfree(ac);
+ }
+}
+
+/*
+ * free first X.509 attribute certificate in the chained list
+ */
+static void
+free_first_acert(void)
+{
+ x509acert_t *first = x509acerts;
+ x509acerts = first->next;
+ free_acert(first);
+}
+
+/*
+ * Free all attribute certificates in the chained list
+ */
+void
+free_acerts(void)
+{
+ while (x509acerts != NULL)
+ free_first_acert();
+}
+
+/*
+ * get a X.509 attribute certificate for a given holder
+ */
+x509acert_t*
+get_x509acert(chunk_t issuer, chunk_t serial)
+{
+ x509acert_t *ac = x509acerts;
+ x509acert_t *prev_ac = NULL;
+
+ while (ac != NULL)
+ {
+ if (same_dn(issuer, ac->holderIssuer)
+ && same_serial(serial, ac->holderSerial))
+ {
+ if (ac!= x509acerts)
+ {
+ /* bring the certificate up front */
+ prev_ac->next = ac->next;
+ ac->next = x509acerts;
+ x509acerts = ac;
+ }
+ return ac;
+ }
+ prev_ac = ac;
+ ac = ac->next;
+ }
+ return NULL;
+}
+
+/*
+ * add a X.509 attribute certificate to the chained list
+ */
+static void
+add_acert(x509acert_t *ac)
+{
+ x509acert_t *old_ac = get_x509acert(ac->holderIssuer, ac->holderSerial);
+
+ if (old_ac != NULL)
+ {
+ if (ac->notBefore >old_ac->notBefore)
+ {
+ /* delete the old attribute cert */
+ free_first_acert();
+ DBG(DBG_CONTROL,
+ DBG_log("attribute cert is newer - existing cert deleted")
+ )
+ }
+ else
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("attribute cert is not newer - existing cert kept");
+ )
+ free_acert(ac);
+ return;
+ }
+ }
+ plog("attribute cert added");
+
+ /* insert new attribute cert at the root of the chain */
+ ac->next = x509acerts;
+ x509acerts = ac;
+}
+
+/* verify the validity of an attribute certificate by
+ * checking the notBefore and notAfter dates
+ */
+static err_t
+check_ac_validity(const x509acert_t *ac)
+{
+ time_t current_time;
+
+ time(&current_time);
+ DBG(DBG_CONTROL | DBG_PARSING,
+ DBG_log(" not before : %s", timetoa(&ac->notBefore, TRUE));
+ DBG_log(" current time: %s", timetoa(&current_time, TRUE));
+ DBG_log(" not after : %s", timetoa(&ac->notAfter, TRUE));
+ )
+
+ if (current_time < ac->notBefore)
+ return "attribute certificate is not valid yet";
+ if (current_time > ac->notAfter)
+ return "attribute certificate has expired";
+ else
+ return NULL;
+}
+
+/*
+ * verifies a X.509 attribute certificate
+ */
+bool
+verify_x509acert(x509acert_t *ac, bool strict)
+{
+ u_char buf[BUF_LEN];
+ x509cert_t *aacert;
+ err_t ugh = NULL;
+ time_t valid_until = ac->notAfter;
+
+ DBG(DBG_CONTROL,
+ dntoa(buf, BUF_LEN, ac->entityName);
+ DBG_log("holder: '%s'",buf);
+ dntoa(buf, BUF_LEN, ac->issuerName);
+ DBG_log("issuer: '%s'",buf);
+ )
+
+ ugh = check_ac_validity(ac);
+
+ if (ugh != NULL)
+ {
+ plog("%s", ugh);
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("attribute certificate is valid")
+ )
+
+ lock_authcert_list("verify_x509acert");
+ aacert = get_authcert(ac->issuerName, ac->authKeySerialNumber
+ , ac->authKeyID, AUTH_AA);
+ unlock_authcert_list("verify_x509acert");
+
+ if (aacert == NULL)
+ {
+ plog("issuer aacert not found");
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("issuer aacert found")
+ )
+
+ if (!check_signature(ac->certificateInfo, ac->signature
+ , ac->algorithm, ac->algorithm, aacert))
+ {
+ plog("attribute certificate signature is invalid");
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("attribute certificate signature is valid");
+ )
+
+ return verify_x509cert(aacert, strict, &valid_until);
+}
+
+/*
+ * Loads X.509 attribute certificates
+ */
+void
+load_acerts(void)
+{
+ u_char buf[BUF_LEN];
+
+ /* change directory to specified path */
+ u_char *save_dir = getcwd(buf, BUF_LEN);
+
+ if (!chdir(A_CERT_PATH))
+ {
+ struct dirent **filelist;
+ int n;
+
+ plog("Changing to directory '%s'",A_CERT_PATH);
+ n = scandir(A_CERT_PATH, &filelist, file_select, alphasort);
+
+ if (n > 0)
+ {
+ while (n--)
+ {
+ chunk_t blob = empty_chunk;
+ bool pgp = FALSE;
+
+ if (load_coded_file(filelist[n]->d_name, NULL, "acert", &blob, &pgp))
+ {
+ x509acert_t *ac = alloc_thing(x509acert_t, "x509acert");
+
+ *ac = empty_ac;
+
+ if (parse_ac(blob, ac)
+ && verify_x509acert(ac, FALSE))
+ add_acert(ac);
+ else
+ free_acert(ac);
+ }
+ free(filelist[n]);
+ }
+ free(filelist);
+ }
+ }
+ /* restore directory path */
+ chdir(save_dir);
+}
+
+/*
+ * lists group attributes separated by commas on a single line
+ */
+void
+format_groups(const ietfAttrList_t *list, char *buf, int len)
+{
+ bool first_group = TRUE;
+
+ while (list != NULL && len > 0)
+ {
+ ietfAttr_t *attr = list->attr;
+
+ if (attr->kind == IETF_ATTRIBUTE_OCTETS
+ || attr->kind == IETF_ATTRIBUTE_STRING)
+ {
+ int written = snprintf(buf, len, "%s%.*s"
+ , (first_group)? "" : ", "
+ , (int)attr->value.len, attr->value.ptr);
+
+ first_group = FALSE;
+
+ /* return value of snprintf() up to glibc 2.0.6 */
+ if (written < 0)
+ break;
+
+ buf += written;
+ len -= written;
+ }
+ list = list->next;
+ }
+}
+
+/*
+ * list all X.509 attribute certificates in the chained list
+ */
+void
+list_acerts(bool utc)
+{
+ x509acert_t *ac = x509acerts;
+ time_t now;
+
+ /* determine the current time */
+ time(&now);
+
+ if (ac != NULL)
+ {
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of X.509 Attribute Certificates:");
+ whack_log(RC_COMMENT, " ");
+ }
+
+ while (ac != NULL)
+ {
+ u_char buf[BUF_LEN];
+
+ whack_log(RC_COMMENT, "%s",timetoa(&ac->installed, utc));
+ if (ac->entityName.ptr != NULL)
+ {
+ dntoa(buf, BUF_LEN, ac->entityName);
+ whack_log(RC_COMMENT, " holder: '%s'", buf);
+ }
+ if (ac->holderIssuer.ptr != NULL)
+ {
+ dntoa(buf, BUF_LEN, ac->holderIssuer);
+ whack_log(RC_COMMENT, " hissuer: '%s'", buf);
+ }
+ if (ac->holderSerial.ptr != NULL)
+ {
+ datatot(ac->holderSerial.ptr, ac->holderSerial.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " hserial: %s", buf);
+ }
+ if (ac->groups != NULL)
+ {
+ format_groups(ac->groups, buf, BUF_LEN);
+ whack_log(RC_COMMENT, " groups: %s", buf);
+ }
+ dntoa(buf, BUF_LEN, ac->issuerName);
+ whack_log(RC_COMMENT, " issuer: '%s'", buf);
+ datatot(ac->serialNumber.ptr, ac->serialNumber.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " serial: %s", buf);
+ whack_log(RC_COMMENT, " validity: not before %s %s",
+ timetoa(&ac->notBefore, utc),
+ (ac->notBefore < now)?"ok":"fatal (not valid yet)");
+ whack_log(RC_COMMENT, " not after %s %s",
+ timetoa(&ac->notAfter, utc),
+ check_expiry(ac->notAfter, ACERT_WARNING_INTERVAL, TRUE));
+ if (ac->authKeyID.ptr != NULL)
+ {
+ datatot(ac->authKeyID.ptr, ac->authKeyID.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " authkey: %s", buf);
+ }
+ if (ac->authKeySerialNumber.ptr != NULL)
+ {
+ datatot(ac->authKeySerialNumber.ptr, ac->authKeySerialNumber.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " aserial: %s", buf);
+ }
+
+ ac = ac->next;
+ }
+}
+
+/*
+ * list all group attributes in alphabetical order
+ */
+void
+list_groups(bool utc)
+{
+ ietfAttrList_t *list = ietfAttributes;
+
+ if (list != NULL)
+ {
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of Group Attributes:");
+ whack_log(RC_COMMENT, " ");
+ }
+
+ while (list != NULL)
+ {
+ ietfAttr_t *attr = list->attr;
+
+ whack_log(RC_COMMENT, "%s, count: %d", timetoa(&attr->installed, utc),
+ attr->count);
+
+ switch (attr->kind)
+ {
+ case IETF_ATTRIBUTE_OCTETS:
+ case IETF_ATTRIBUTE_STRING:
+ whack_log(RC_COMMENT, " %.*s", (int)attr->value.len, attr->value.ptr);
+ break;
+ case IETF_ATTRIBUTE_OID:
+ whack_log(RC_COMMENT, " OID");
+ break;
+ default:
+ break;
+ }
+
+ list = list->next;
+ }
+}
diff --git a/src/pluto/ac.h b/src/pluto/ac.h
new file mode 100644
index 000000000..3913d745d
--- /dev/null
+++ b/src/pluto/ac.h
@@ -0,0 +1,103 @@
+/* Support of X.509 attribute certificates
+ * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler
+ * Copyright (C) 2003 Martin Berner, Lukas Suter
+
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: ac.h,v 1.8 2005/02/17 20:56:04 as Exp $
+ */
+
+#ifndef _AC_H
+#define _AC_H
+
+/* definition of ietfAttribute kinds */
+
+typedef enum {
+ IETF_ATTRIBUTE_OCTETS = 0,
+ IETF_ATTRIBUTE_OID = 1,
+ IETF_ATTRIBUTE_STRING = 2
+} ietfAttribute_t;
+
+/* access structure for an ietfAttribute */
+
+typedef struct ietfAttr ietfAttr_t;
+
+struct ietfAttr {
+ time_t installed;
+ int count;
+ ietfAttribute_t kind;
+ chunk_t value;
+};
+
+typedef struct ietfAttrList ietfAttrList_t;
+
+struct ietfAttrList {
+ ietfAttrList_t *next;
+ ietfAttr_t *attr;
+};
+
+
+/* access structure for an X.509 attribute certificate */
+
+typedef struct x509acert x509acert_t;
+
+struct x509acert {
+ x509acert_t *next;
+ time_t installed;
+ chunk_t certificate;
+ chunk_t certificateInfo;
+ u_int version;
+ /* holder */
+ /* baseCertificateID */
+ chunk_t holderIssuer;
+ chunk_t holderSerial;
+ chunk_t entityName;
+ /* v2Form */
+ chunk_t issuerName;
+ /* signature */
+ int sigAlg;
+ chunk_t serialNumber;
+ /* attrCertValidityPeriod */
+ time_t notBefore;
+ time_t notAfter;
+ /* attributes */
+ ietfAttrList_t *charging;
+ ietfAttrList_t *groups;
+ /* extensions */
+ chunk_t authKeyID;
+ chunk_t authKeySerialNumber;
+ bool noRevAvail;
+ /* signatureAlgorithm */
+ int algorithm;
+ chunk_t signature;
+};
+
+/* used for initialization */
+extern const x509acert_t empty_ac;
+
+extern void unshare_ietfAttrList(ietfAttrList_t **listp);
+extern void free_ietfAttrList(ietfAttrList_t *list);
+extern void decode_groups(char *groups, ietfAttrList_t **listp);
+extern bool group_membership(const ietfAttrList_t *my_list
+ , const char *conn, const ietfAttrList_t *conn_list);
+extern bool parse_ac(chunk_t blob, x509acert_t *ac);
+extern bool verify_x509acert(x509acert_t *ac, bool strict);
+extern x509acert_t* get_x509acert(chunk_t issuer, chunk_t serial);
+extern void load_acerts(void);
+extern void free_acert(x509acert_t *ac);
+extern void free_acerts(void);
+extern void list_acerts(bool utc);
+extern void list_groups(bool utc);
+extern void format_groups(const ietfAttrList_t *list, char *buf, int len);
+
+
+#endif /* _AH_H */
diff --git a/src/pluto/adns.c b/src/pluto/adns.c
new file mode 100644
index 000000000..c5977d23c
--- /dev/null
+++ b/src/pluto/adns.c
@@ -0,0 +1,615 @@
+/* Pluto Asynchronous DNS Helper Program -- for internal use only!
+ * Copyright (C) 2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: adns.c,v 1.1 2004/03/15 20:35:28 as Exp $
+ */
+
+#ifndef USE_LWRES /* whole file! */
+
+/* This program executes as multiple processes. The Master process
+ * receives queries (struct adns_query messages) from Pluto and distributes
+ * them amongst Worker processes. These Worker processes are created
+ * by the Master whenever a query arrives and no existing Worker is free.
+ * At most MAX_WORKERS will be created; after that, the Master will queue
+ * queries until a Worker becomes free. When a Worker has an answer from
+ * the resolver, it sends the answer as a struct adns_answer message to the
+ * Master. The Master then forwards the answer to Pluto, noting that
+ * the Worker is free to accept another query.
+ *
+ * The protocol is simple: Pluto sends a sequence of queries and receives
+ * a sequence of answers. select(2) is used by Pluto and by the Master
+ * process to decide when to read, but writes are done without checking
+ * for readiness. Communications is via pipes. Since only one process
+ * can write to each pipe, messages will not be interleaved. Fixed length
+ * records are used for simplicity.
+ *
+ * Pluto needs a way to indicate to the Master when to shut down
+ * and the Master needs to indicate this to each worker. EOF on the pipe
+ * signifies this.
+ *
+ * The interfaces between these components are considered private to
+ * Pluto. This allows us to get away with less checking. This is a
+ * reason to use pipes instead of TCP/IP.
+ *
+ * Although the code uses plain old UNIX processes, it could be modified
+ * to use threads. That might reduce resource requirements. It would
+ * preclude running on systems without thread-safe resolvers.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <netdb.h> /* ??? for h_errno */
+
+#include <freeswan.h>
+
+/* GCC magic! */
+#ifdef GCC_LINT
+# define UNUSED __attribute__ ((unused))
+#else
+# define UNUSED /* ignore */
+#endif
+
+#include "constants.h"
+#include "adns.h" /* needs <resolv.h> */
+
+/* shared by all processes */
+
+static const char *name; /* program name, for messages */
+
+static bool debug = FALSE;
+
+/* Read a variable-length record from a pipe (and no more!).
+ * First bytes must be a size_t containing the length.
+ * HES_CONTINUE if record read
+ * HES_OK if EOF
+ * HES_IO_ERROR_IN if errno tells the tale.
+ * Others are errors.
+ */
+static enum helper_exit_status
+read_pipe(int fd, unsigned char *stuff, size_t minlen, size_t maxlen)
+{
+ size_t n = 0;
+ size_t goal = minlen;
+
+ do {
+ ssize_t m = read(fd, stuff + n, goal - n);
+
+ if (m == -1)
+ {
+ if (errno != EINTR)
+ {
+ syslog(LOG_ERR, "Input error on pipe: %s", strerror(errno));
+ return HES_IO_ERROR_IN;
+ }
+ }
+ else if (m == 0)
+ {
+ return HES_OK; /* treat empty message as EOF */
+ }
+ else
+ {
+ n += m;
+ if (n >= sizeof(size_t))
+ {
+ goal = *(size_t *)(void *)stuff;
+ if (goal < minlen || maxlen < goal)
+ {
+ if (debug)
+ fprintf(stderr, "%lu : [%lu, %lu]\n"
+ , (unsigned long)goal
+ , (unsigned long)minlen, (unsigned long)maxlen);
+ return HES_BAD_LEN;
+ }
+ }
+ }
+ } while (n < goal);
+
+ return HES_CONTINUE;
+}
+
+/* Write a variable-length record to a pipe.
+ * First bytes must be a size_t containing the length.
+ * HES_CONTINUE if record written
+ * Others are errors.
+ */
+static enum helper_exit_status
+write_pipe(int fd, const unsigned char *stuff)
+{
+ size_t len = *(const size_t *)(const void *)stuff;
+ size_t n = 0;
+
+ do {
+ ssize_t m = write(fd, stuff + n, len - n);
+
+ if (m == -1)
+ {
+ /* error, but ignore and retry if EINTR */
+ if (errno != EINTR)
+ {
+ syslog(LOG_ERR, "Output error from master: %s", strerror(errno));
+ return HES_IO_ERROR_OUT;
+ }
+ }
+ else
+ {
+ n += m;
+ }
+ } while (n != len);
+ return HES_CONTINUE;
+}
+
+/**************** worker process ****************/
+
+/* The interface in RHL6.x and BIND distribution 8.2.2 are different,
+ * so we build some of our own :-(
+ */
+
+/* Support deprecated interface to allow for older releases of the resolver.
+ * Fake new interface!
+ * See resolver(3) bind distribution (should be in RHL6.1, but isn't).
+ * __RES was 19960801 in RHL6.2, an old resolver.
+ */
+
+#if (__RES) <= 19960801
+# define OLD_RESOLVER 1
+#endif
+
+#ifdef OLD_RESOLVER
+
+# define res_ninit(statp) res_init()
+# define res_nquery(statp, dname, class, type, answer, anslen) \
+ res_query(dname, class, type, answer, anslen)
+# define res_nclose(statp) res_close()
+
+static struct __res_state *statp = &_res;
+
+#else /* !OLD_RESOLVER */
+
+static struct __res_state my_res_state /* = { 0 } */;
+static res_state statp = &my_res_state;
+
+#endif /* !OLD_RESOLVER */
+
+static int
+worker(int qfd, int afd)
+{
+ {
+ int r = res_ninit(statp);
+
+ if (r != 0)
+ {
+ syslog(LOG_ERR, "cannot initialize resolver");
+ return HES_RES_INIT;
+ }
+#ifndef OLD_RESOLVER
+ statp->options |= RES_ROTATE;
+#endif
+ statp->options |= RES_DEBUG;
+ }
+
+ for (;;)
+ {
+ struct adns_query q;
+ struct adns_answer a;
+
+ enum helper_exit_status r = read_pipe(qfd, (unsigned char *)&q
+ , sizeof(q), sizeof(q));
+
+ if (r != HES_CONTINUE)
+ return r; /* some kind of exit */
+
+ if (q.qmagic != ADNS_Q_MAGIC)
+ {
+ syslog(LOG_ERR, "error in input from master: bad magic");
+ return HES_BAD_MAGIC;
+ }
+
+ a.amagic = ADNS_A_MAGIC;
+ a.serial = q.serial;
+
+ a.result = res_nquery(statp, q.name_buf, C_IN, q.type, a.ans, sizeof(a.ans));
+ a.h_errno_val = h_errno;
+
+ a.len = offsetof(struct adns_answer, ans) + (a.result < 0? 0 : a.result);
+
+#ifdef DEBUG
+ if (((q.debugging & IMPAIR_DELAY_ADNS_KEY_ANSWER) && q.type == T_KEY)
+ || ((q.debugging & IMPAIR_DELAY_ADNS_TXT_ANSWER) && q.type == T_TXT))
+ sleep(30); /* delay the answer */
+#endif
+
+ /* write answer, possibly a bit at a time */
+ r = write_pipe(afd, (const unsigned char *)&a);
+
+ if (r != HES_CONTINUE)
+ return r; /* some kind of exit */
+ }
+}
+
+/**************** master process ****************/
+
+bool eof_from_pluto = FALSE;
+#define PLUTO_QFD 0 /* queries come on stdin */
+#define PLUTO_AFD 1 /* answers go out on stdout */
+
+#ifndef MAX_WORKERS
+# define MAX_WORKERS 10 /* number of in-flight queries */
+#endif
+
+struct worker_info {
+ int qfd; /* query pipe's file descriptor */
+ int afd; /* answer pipe's file descriptor */
+ pid_t pid;
+ bool busy;
+ void *continuation; /* of outstanding request */
+};
+
+static struct worker_info wi[MAX_WORKERS];
+static struct worker_info *wi_roof = wi;
+
+/* request FIFO */
+
+struct query_list {
+ struct query_list *next;
+ struct adns_query aq;
+};
+
+static struct query_list *oldest_query = NULL;
+static struct query_list *newest_query; /* undefined when oldest == NULL */
+static struct query_list *free_queries = NULL;
+
+static bool
+spawn_worker(void)
+{
+ int qfds[2];
+ int afds[2];
+ pid_t p;
+
+ if (pipe(qfds) != 0 || pipe(afds) != 0)
+ {
+ syslog(LOG_ERR, "pipe(2) failed: %s", strerror(errno));
+ exit(HES_PIPE);
+ }
+
+ wi_roof->qfd = qfds[1]; /* write end of query pipe */
+ wi_roof->afd = afds[0]; /* read end of answer pipe */
+
+ p = fork();
+ if (p == -1)
+ {
+ /* fork failed: ignore if at least one worker exists */
+ if (wi_roof == wi)
+ {
+ syslog(LOG_ERR, "fork(2) error creating first worker: %s", strerror(errno));
+ exit(HES_FORK);
+ }
+ close(qfds[0]);
+ close(qfds[1]);
+ close(afds[0]);
+ close(afds[1]);
+ return FALSE;
+ }
+ else if (p == 0)
+ {
+ /* child */
+ struct worker_info *w;
+
+ close(PLUTO_QFD);
+ close(PLUTO_AFD);
+ /* close all master pipes, including ours */
+ for (w = wi; w <= wi_roof; w++)
+ {
+ close(w->qfd);
+ close(w->afd);
+ }
+ exit(worker(qfds[0], afds[1]));
+ }
+ else
+ {
+ /* parent */
+ struct worker_info *w = wi_roof++;
+
+ w->pid = p;
+ w->busy = FALSE;
+ close(qfds[0]);
+ close(afds[1]);
+ return TRUE;
+ }
+}
+
+static void
+send_eof(struct worker_info *w)
+{
+ pid_t p;
+ int status;
+
+ close(w->qfd);
+ w->qfd = NULL_FD;
+
+ close(w->afd);
+ w->afd = NULL_FD;
+
+ /* reap child */
+ p = waitpid(w->pid, &status, 0);
+ /* ignore result -- what could we do with it? */
+}
+
+static void
+forward_query(struct worker_info *w)
+{
+ struct query_list *q = oldest_query;
+
+ if (q == NULL)
+ {
+ if (eof_from_pluto)
+ send_eof(w);
+ }
+ else
+ {
+ enum helper_exit_status r
+ = write_pipe(w->qfd, (const unsigned char *) &q->aq);
+
+ if (r != HES_CONTINUE)
+ exit(r);
+
+ w->busy = TRUE;
+
+ oldest_query = q->next;
+ q->next = free_queries;
+ free_queries = q;
+ }
+}
+
+static void
+query(void)
+{
+ struct query_list *q = free_queries;
+ enum helper_exit_status r;
+
+ /* find an unused queue entry */
+ if (q == NULL)
+ {
+ q = malloc(sizeof(*q));
+ if (q == NULL)
+ {
+ syslog(LOG_ERR, "malloc(3) failed");
+ exit(HES_MALLOC);
+ }
+ }
+ else
+ {
+ free_queries = q->next;
+ }
+
+ r = read_pipe(PLUTO_QFD, (unsigned char *)&q->aq
+ , sizeof(q->aq), sizeof(q->aq));
+
+ if (r == HES_OK)
+ {
+ /* EOF: we're done, except for unanswered queries */
+ struct worker_info *w;
+
+ eof_from_pluto = TRUE;
+ q->next = free_queries;
+ free_queries = q;
+
+ /* Send bye-bye to unbusy processes.
+ * Note that if there are queued queries, there won't be
+ * any non-busy workers.
+ */
+ for (w = wi; w != wi_roof; w++)
+ if (!w->busy)
+ send_eof(w);
+ }
+ else if (r != HES_CONTINUE)
+ {
+ exit(r);
+ }
+ else if (q->aq.qmagic != ADNS_Q_MAGIC)
+ {
+ syslog(LOG_ERR, "error in query from Pluto: bad magic");
+ exit(HES_BAD_MAGIC);
+ }
+ else
+ {
+ struct worker_info *w;
+
+ /* got a query */
+
+ /* add it to FIFO */
+ q->next = NULL;
+ if (oldest_query == NULL)
+ oldest_query = q;
+ else
+ newest_query->next = q;
+ newest_query = q;
+
+ /* See if any worker available */
+ for (w = wi; ; w++)
+ {
+ if (w == wi_roof)
+ {
+ /* no free worker */
+ if (w == wi + MAX_WORKERS)
+ break; /* no more to be created */
+ /* make a new one */
+ if (!spawn_worker())
+ break; /* cannot create one at this time */
+ }
+ if (!w->busy)
+ {
+ /* assign first to free worker */
+ forward_query(w);
+ break;
+ }
+ }
+ }
+ return;
+}
+
+static void
+answer(struct worker_info *w)
+{
+ struct adns_answer a;
+ enum helper_exit_status r = read_pipe(w->afd, (unsigned char *)&a
+ , offsetof(struct adns_answer, ans), sizeof(a));
+
+ if (r == HES_OK)
+ {
+ /* unexpected EOF */
+ syslog(LOG_ERR, "unexpected EOF from worker");
+ exit(HES_IO_ERROR_IN);
+ }
+ else if (r != HES_CONTINUE)
+ {
+ exit(r);
+ }
+ else if (a.amagic != ADNS_A_MAGIC)
+ {
+ syslog(LOG_ERR, "Input from worker error: bad magic");
+ exit(HES_BAD_MAGIC);
+ }
+ else if (a.continuation != w->continuation)
+ {
+ /* answer doesn't match query */
+ syslog(LOG_ERR, "Input from worker error: continuation mismatch");
+ exit(HES_SYNC);
+ }
+ else
+ {
+ /* pass the answer on to Pluto */
+ enum helper_exit_status r
+ = write_pipe(PLUTO_AFD, (const unsigned char *) &a);
+
+ if (r != HES_CONTINUE)
+ exit(r);
+ w->busy = FALSE;
+ forward_query(w);
+ }
+}
+
+/* assumption: input limited; accept blocking on output */
+static int
+master(void)
+{
+ for (;;)
+ {
+ fd_set readfds;
+ int maxfd = PLUTO_QFD; /* approximate lower bound */
+ int ndes = 0;
+ struct worker_info *w;
+
+ FD_ZERO(&readfds);
+ if (!eof_from_pluto)
+ {
+ FD_SET(PLUTO_QFD, &readfds);
+ ndes++;
+ }
+ for (w = wi; w != wi_roof; w++)
+ {
+ if (w->busy)
+ {
+ FD_SET(w->afd, &readfds);
+ ndes++;
+ if (maxfd < w->afd)
+ maxfd = w->afd;
+ }
+ }
+
+ if (ndes == 0)
+ return HES_OK; /* done! */
+
+ do {
+ ndes = select(maxfd + 1, &readfds, NULL, NULL, NULL);
+ } while (ndes == -1 && errno == EINTR);
+ if (ndes == -1)
+ {
+ syslog(LOG_ERR, "select(2) error: %s", strerror(errno));
+ exit(HES_IO_ERROR_SELECT);
+ }
+ else if (ndes > 0)
+ {
+ if (FD_ISSET(PLUTO_QFD, &readfds))
+ {
+ query();
+ ndes--;
+ }
+ for (w = wi; ndes > 0 && w != wi_roof; w++)
+ {
+ if (w->busy && FD_ISSET(w->afd, &readfds))
+ {
+ answer(w);
+ ndes--;
+ }
+ }
+ }
+ }
+}
+
+/* Not to be invoked by strangers -- user hostile.
+ * Mandatory args: query-fd answer-fd
+ * Optional arg: -d, signifying "debug".
+ */
+
+static void
+adns_usage(const char *fmt, const char *arg)
+{
+ const char **sp = ipsec_copyright_notice();
+
+ fprintf(stderr, "INTERNAL TO PLUTO: DO NOT EXECUTE\n");
+
+ fprintf(stderr, fmt, arg);
+ fprintf(stderr, "\n%s\n", ipsec_version_string());
+
+ for (; *sp != NULL; sp++)
+ fprintf(stderr, "%s\n", *sp);
+
+ syslog(LOG_ERR, fmt, arg);
+ exit(HES_INVOCATION);
+}
+
+int
+main(int argc UNUSED, char **argv)
+{
+ int i = 1;
+
+ name = argv[0];
+
+ while (i < argc)
+ {
+ if (streq(argv[i], "-d"))
+ {
+ i++;
+ debug = TRUE;
+ }
+ else
+ {
+ adns_usage("unexpected argument \"%s\"", argv[i]);
+ /*NOTREACHED*/
+ }
+ }
+
+ return master();
+}
+
+#endif /* !USE_LWRES */
diff --git a/src/pluto/adns.h b/src/pluto/adns.h
new file mode 100644
index 000000000..00fc4ad07
--- /dev/null
+++ b/src/pluto/adns.h
@@ -0,0 +1,75 @@
+/* Pluto Asynchronous DNS Helper Program's Header
+ * Copyright (C) 2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: adns.h,v 1.1 2004/03/15 20:35:28 as Exp $
+ */
+
+#ifndef USE_LWRES /* whole file! */
+
+/* The interface in RHL6.x and BIND distribution 8.2.2 are different,
+ * so we build some of our own :-(
+ */
+
+# ifndef NS_MAXDNAME
+# define NS_MAXDNAME MAXDNAME /* I hope this is long enough for IPv6 */
+# endif
+
+# ifndef NS_PACKETSZ
+# define NS_PACKETSZ PACKETSZ
+# endif
+
+/* protocol version */
+
+#define ADNS_Q_MAGIC (((((('d' << 8) + 'n') << 8) + 's') << 8) + 4)
+#define ADNS_A_MAGIC (((((('d' << 8) + 'n') << 8) + 's') << 8) + 128 + 4)
+
+/* note: both struct adns_query and struct adns_answer must start with
+ * size_t len;
+ */
+
+struct adns_query {
+ size_t len;
+ unsigned int qmagic;
+ unsigned long serial;
+ lset_t debugging; /* only used #ifdef DEBUG, but don't want layout to change */
+ u_char name_buf[NS_MAXDNAME + 2];
+ int type; /* T_KEY or T_TXT */
+};
+
+struct adns_answer {
+ size_t len;
+ unsigned int amagic;
+ unsigned long serial;
+ struct adns_continuation *continuation;
+ int result;
+ int h_errno_val;
+ u_char ans[NS_PACKETSZ * 10]; /* very probably bigger than necessary */
+};
+
+enum helper_exit_status {
+ HES_CONTINUE = -1, /* not an exit */
+ HES_OK = 0, /* all's well that ends well (perhaps EOF) */
+ HES_INVOCATION, /* improper invocation */
+ HES_IO_ERROR_SELECT, /* IO error in select() */
+ HES_MALLOC, /* malloc failed */
+ HES_IO_ERROR_IN, /* error reading pipe */
+ HES_IO_ERROR_OUT, /* error reading pipe */
+ HES_PIPE, /* pipe(2) failed */
+ HES_SYNC, /* answer from worker doesn't match query */
+ HES_FORK, /* fork(2) failed */
+ HES_RES_INIT, /* resolver initialization failed */
+ HES_BAD_LEN, /* implausible .len field */
+ HES_BAD_MAGIC, /* .magic field wrong */
+};
+
+#endif /* !USE_LWRES */
diff --git a/src/pluto/alg/ike_alg_aes.c b/src/pluto/alg/ike_alg_aes.c
new file mode 100644
index 000000000..44de09b4c
--- /dev/null
+++ b/src/pluto/alg/ike_alg_aes.c
@@ -0,0 +1,68 @@
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "libaes/aes_cbc.h"
+#include "alg_info.h"
+#include "ike_alg.h"
+
+#define AES_CBC_BLOCK_SIZE (128/BITS_PER_BYTE)
+#define AES_KEY_MIN_LEN 128
+#define AES_KEY_DEF_LEN 128
+#define AES_KEY_MAX_LEN 256
+
+static void
+do_aes(u_int8_t *buf, size_t buf_len, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc)
+{
+ aes_context aes_ctx;
+ char iv_bak[AES_CBC_BLOCK_SIZE];
+ char *new_iv = NULL; /* logic will avoid copy to NULL */
+
+ aes_set_key(&aes_ctx, key, key_size, 0);
+
+ /*
+ * my AES cbc does not touch passed IV (optimization for
+ * ESP handling), so I must "emulate" des-like IV
+ * crunching
+ */
+ if (!enc)
+ memcpy(new_iv=iv_bak, (char*) buf + buf_len - AES_CBC_BLOCK_SIZE
+ , AES_CBC_BLOCK_SIZE);
+
+ AES_cbc_encrypt(&aes_ctx, buf, buf, buf_len, iv, enc);
+
+ if (enc)
+ new_iv = (char*) buf + buf_len-AES_CBC_BLOCK_SIZE;
+
+ memcpy(iv, new_iv, AES_CBC_BLOCK_SIZE);
+}
+
+struct encrypt_desc algo_aes =
+{
+ algo_type: IKE_ALG_ENCRYPT,
+ algo_id: OAKLEY_AES_CBC,
+ algo_next: NULL,
+ enc_ctxsize: sizeof(aes_context),
+ enc_blocksize: AES_CBC_BLOCK_SIZE,
+ keyminlen: AES_KEY_MIN_LEN,
+ keydeflen: AES_KEY_DEF_LEN,
+ keymaxlen: AES_KEY_MAX_LEN,
+ do_crypt: do_aes,
+};
+
+int ike_alg_aes_init(void);
+
+int
+ike_alg_aes_init(void)
+{
+ int ret = ike_alg_register_enc(&algo_aes);
+ return ret;
+}
+/*
+IKE_ALG_INIT_NAME: ike_alg_aes_init
+*/
diff --git a/src/pluto/alg/ike_alg_blowfish.c b/src/pluto/alg/ike_alg_blowfish.c
new file mode 100644
index 000000000..2bbef051b
--- /dev/null
+++ b/src/pluto/alg/ike_alg_blowfish.c
@@ -0,0 +1,52 @@
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "libblowfish/blowfish.h"
+#include "alg_info.h"
+#include "ike_alg.h"
+
+#define BLOWFISH_CBC_BLOCK_SIZE 8 /* block size */
+#define BLOWFISH_KEY_MIN_LEN 128
+#define BLOWFISH_KEY_MAX_LEN 448
+
+
+static void
+do_blowfish(u_int8_t *buf, size_t buf_len, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc)
+{
+ BF_KEY bf_ctx;
+
+ BF_set_key(&bf_ctx, key_size , key);
+ BF_cbc_encrypt(buf, buf, buf_len, &bf_ctx, iv, enc);
+}
+
+struct encrypt_desc algo_blowfish =
+{
+ algo_type: IKE_ALG_ENCRYPT,
+ algo_id: OAKLEY_BLOWFISH_CBC,
+ algo_next: NULL,
+ enc_ctxsize: sizeof(BF_KEY),
+ enc_blocksize: BLOWFISH_CBC_BLOCK_SIZE,
+ keyminlen: BLOWFISH_KEY_MIN_LEN,
+ keydeflen: BLOWFISH_KEY_MIN_LEN,
+ keymaxlen: BLOWFISH_KEY_MAX_LEN,
+ do_crypt: do_blowfish,
+};
+
+int ike_alg_blowfish_init(void);
+
+int
+ike_alg_blowfish_init(void)
+{
+ int ret = ike_alg_register_enc(&algo_blowfish);
+
+ return ret;
+}
+/*
+IKE_ALG_INIT_NAME: ike_alg_blowfish_init
+*/
diff --git a/src/pluto/alg/ike_alg_serpent.c b/src/pluto/alg/ike_alg_serpent.c
new file mode 100644
index 000000000..fb01caa41
--- /dev/null
+++ b/src/pluto/alg/ike_alg_serpent.c
@@ -0,0 +1,70 @@
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "libserpent/serpent_cbc.h"
+#include "alg_info.h"
+#include "ike_alg.h"
+
+#define SERPENT_CBC_BLOCK_SIZE (128/BITS_PER_BYTE)
+#define SERPENT_KEY_MIN_LEN 128
+#define SERPENT_KEY_DEF_LEN 128
+#define SERPENT_KEY_MAX_LEN 256
+
+static void
+do_serpent(u_int8_t *buf, size_t buf_size, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc)
+{
+ serpent_context serpent_ctx;
+ char iv_bak[SERPENT_CBC_BLOCK_SIZE];
+ char *new_iv = NULL; /* logic will avoid copy to NULL */
+
+
+ serpent_set_key(&serpent_ctx, key, key_size);
+ /*
+ * my SERPENT cbc does not touch passed IV (optimization for
+ * ESP handling), so I must "emulate" des-like IV
+ * crunching
+ */
+ if (!enc)
+ memcpy(new_iv=iv_bak,
+ (char*) buf + buf_size-SERPENT_CBC_BLOCK_SIZE,
+ SERPENT_CBC_BLOCK_SIZE);
+
+ serpent_cbc_encrypt(&serpent_ctx, buf, buf, buf_size, iv, enc);
+
+ if (enc)
+ new_iv = (char*) buf + buf_size-SERPENT_CBC_BLOCK_SIZE;
+
+ memcpy(iv, new_iv, SERPENT_CBC_BLOCK_SIZE);
+}
+
+struct encrypt_desc encrypt_desc_serpent =
+{
+ algo_type: IKE_ALG_ENCRYPT,
+ algo_id: OAKLEY_SERPENT_CBC,
+ algo_next: NULL,
+ enc_ctxsize: sizeof(struct serpent_context),
+ enc_blocksize: SERPENT_CBC_BLOCK_SIZE,
+ keyminlen: SERPENT_KEY_MIN_LEN,
+ keydeflen: SERPENT_KEY_DEF_LEN,
+ keymaxlen: SERPENT_KEY_MAX_LEN,
+ do_crypt: do_serpent,
+};
+
+int ike_alg_serpent_init(void);
+
+int
+ike_alg_serpent_init(void)
+{
+ int ret = ike_alg_register_enc(&encrypt_desc_serpent);
+
+ return ret;
+}
+/*
+IKE_ALG_INIT_NAME: ike_alg_serpent_init
+*/
diff --git a/src/pluto/alg/ike_alg_sha2.c b/src/pluto/alg/ike_alg_sha2.c
new file mode 100644
index 000000000..6b7c8438c
--- /dev/null
+++ b/src/pluto/alg/ike_alg_sha2.c
@@ -0,0 +1,634 @@
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "libsha2/sha2.h"
+#include "alg_info.h"
+#include "ike_alg.h"
+
+static void
+sha256_hash_final(u_char *hash, sha256_context *ctx)
+{
+ sha256_final(ctx);
+ memcpy(hash, ctx->sha_out, SHA2_256_DIGEST_SIZE);
+}
+
+static void
+sha384_hash_final(u_char *hash, sha512_context *ctx)
+{
+ sha512_final(ctx);
+ memcpy(hash, ctx->sha_out, SHA2_384_DIGEST_SIZE);
+}
+
+static void
+sha512_hash_final(u_char *hash, sha512_context *ctx)
+{
+ sha512_final(ctx);
+ memcpy(hash, ctx->sha_out, SHA2_512_DIGEST_SIZE);
+}
+
+/* SHA-256 hash test vectors
+ * from "The Secure Hash Algorithm Validation System (SHAVS)"
+ * July 22, 2004, Lawrence E. Bassham III, NIST
+ */
+
+static const u_char sha256_short2_msg[] = {
+ 0x19
+};
+
+static const u_char sha256_short2_msg_digest[] = {
+ 0x68, 0xaa, 0x2e, 0x2e, 0xe5, 0xdf, 0xf9, 0x6e,
+ 0x33, 0x55, 0xe6, 0xc7, 0xee, 0x37, 0x3e, 0x3d,
+ 0x6a, 0x4e, 0x17, 0xf7, 0x5f, 0x95, 0x18, 0xd8,
+ 0x43, 0x70, 0x9c, 0x0c, 0x9b, 0xc3, 0xe3, 0xd4
+};
+
+static const u_char sha256_short4_msg[] = {
+ 0xe3, 0xd7, 0x25, 0x70, 0xdc, 0xdd, 0x78, 0x7c,
+ 0xe3, 0x88, 0x7a, 0xb2, 0xcd, 0x68, 0x46, 0x52
+};
+
+static const u_char sha256_short4_msg_digest[] = {
+ 0x17, 0x5e, 0xe6, 0x9b, 0x02, 0xba, 0x9b, 0x58,
+ 0xe2, 0xb0, 0xa5, 0xfd, 0x13, 0x81, 0x9c, 0xea,
+ 0x57, 0x3f, 0x39, 0x40, 0xa9, 0x4f, 0x82, 0x51,
+ 0x28, 0xcf, 0x42, 0x09, 0xbe, 0xab, 0xb4, 0xe8
+};
+
+static const u_char sha256_long2_msg[] = {
+ 0x83, 0x26, 0x75, 0x4e, 0x22, 0x77, 0x37, 0x2f,
+ 0x4f, 0xc1, 0x2b, 0x20, 0x52, 0x7a, 0xfe, 0xf0,
+ 0x4d, 0x8a, 0x05, 0x69, 0x71, 0xb1, 0x1a, 0xd5,
+ 0x71, 0x23, 0xa7, 0xc1, 0x37, 0x76, 0x00, 0x00,
+ 0xd7, 0xbe, 0xf6, 0xf3, 0xc1, 0xf7, 0xa9, 0x08,
+ 0x3a, 0xa3, 0x9d, 0x81, 0x0d, 0xb3, 0x10, 0x77,
+ 0x7d, 0xab, 0x8b, 0x1e, 0x7f, 0x02, 0xb8, 0x4a,
+ 0x26, 0xc7, 0x73, 0x32, 0x5f, 0x8b, 0x23, 0x74,
+ 0xde, 0x7a, 0x4b, 0x5a, 0x58, 0xcb, 0x5c, 0x5c,
+ 0xf3, 0x5b, 0xce, 0xe6, 0xfb, 0x94, 0x6e, 0x5b,
+ 0xd6, 0x94, 0xfa, 0x59, 0x3a, 0x8b, 0xeb, 0x3f,
+ 0x9d, 0x65, 0x92, 0xec, 0xed, 0xaa, 0x66, 0xca,
+ 0x82, 0xa2, 0x9d, 0x0c, 0x51, 0xbc, 0xf9, 0x33,
+ 0x62, 0x30, 0xe5, 0xd7, 0x84, 0xe4, 0xc0, 0xa4,
+ 0x3f, 0x8d, 0x79, 0xa3, 0x0a, 0x16, 0x5c, 0xba,
+ 0xbe, 0x45, 0x2b, 0x77, 0x4b, 0x9c, 0x71, 0x09,
+ 0xa9, 0x7d, 0x13, 0x8f, 0x12, 0x92, 0x28, 0x96,
+ 0x6f, 0x6c, 0x0a, 0xdc, 0x10, 0x6a, 0xad, 0x5a,
+ 0x9f, 0xdd, 0x30, 0x82, 0x57, 0x69, 0xb2, 0xc6,
+ 0x71, 0xaf, 0x67, 0x59, 0xdf, 0x28, 0xeb, 0x39,
+ 0x3d, 0x54, 0xd6
+};
+
+static const u_char sha256_long2_msg_digest[] = {
+ 0x97, 0xdb, 0xca, 0x7d, 0xf4, 0x6d, 0x62, 0xc8,
+ 0xa4, 0x22, 0xc9, 0x41, 0xdd, 0x7e, 0x83, 0x5b,
+ 0x8a, 0xd3, 0x36, 0x17, 0x63, 0xf7, 0xe9, 0xb2,
+ 0xd9, 0x5f, 0x4f, 0x0d, 0xa6, 0xe1, 0xcc, 0xbc
+};
+
+static const hash_testvector_t sha256_hash_testvectors[] = {
+ { sizeof(sha256_short2_msg), sha256_short2_msg, sha256_short2_msg_digest },
+ { sizeof(sha256_short4_msg), sha256_short4_msg, sha256_short4_msg_digest },
+ { sizeof(sha256_long2_msg), sha256_long2_msg, sha256_long2_msg_digest },
+ { 0, NULL, NULL }
+};
+
+/* SHA-384 hash test vectors
+ * from "The Secure Hash Algorithm Validation System (SHAVS)"
+ * July 22, 2004, Lawrence E. Bassham III, NIST
+ */
+
+static const u_char sha384_short2_msg[] = {
+ 0xb9
+};
+
+static const u_char sha384_short2_msg_digest[] = {
+ 0xbc, 0x80, 0x89, 0xa1, 0x90, 0x07, 0xc0, 0xb1,
+ 0x41, 0x95, 0xf4, 0xec, 0xc7, 0x40, 0x94, 0xfe,
+ 0xc6, 0x4f, 0x01, 0xf9, 0x09, 0x29, 0x28, 0x2c,
+ 0x2f, 0xb3, 0x92, 0x88, 0x15, 0x78, 0x20, 0x8a,
+ 0xd4, 0x66, 0x82, 0x8b, 0x1c, 0x6c, 0x28, 0x3d,
+ 0x27, 0x22, 0xcf, 0x0a, 0xd1, 0xab, 0x69, 0x38
+};
+
+static const u_char sha384_short4_msg[] = {
+ 0xa4, 0x1c, 0x49, 0x77, 0x79, 0xc0, 0x37, 0x5f,
+ 0xf1, 0x0a, 0x7f, 0x4e, 0x08, 0x59, 0x17, 0x39
+};
+
+static const u_char sha384_short4_msg_digest[] = {
+ 0xc9, 0xa6, 0x84, 0x43, 0xa0, 0x05, 0x81, 0x22,
+ 0x56, 0xb8, 0xec, 0x76, 0xb0, 0x05, 0x16, 0xf0,
+ 0xdb, 0xb7, 0x4f, 0xab, 0x26, 0xd6, 0x65, 0x91,
+ 0x3f, 0x19, 0x4b, 0x6f, 0xfb, 0x0e, 0x91, 0xea,
+ 0x99, 0x67, 0x56, 0x6b, 0x58, 0x10, 0x9c, 0xbc,
+ 0x67, 0x5c, 0xc2, 0x08, 0xe4, 0xc8, 0x23, 0xf7
+};
+
+static const u_char sha384_long2_msg[] = {
+ 0x39, 0x96, 0x69, 0xe2, 0x8f, 0x6b, 0x9c, 0x6d,
+ 0xbc, 0xbb, 0x69, 0x12, 0xec, 0x10, 0xff, 0xcf,
+ 0x74, 0x79, 0x03, 0x49, 0xb7, 0xdc, 0x8f, 0xbe,
+ 0x4a, 0x8e, 0x7b, 0x3b, 0x56, 0x21, 0xdb, 0x0f,
+ 0x3e, 0x7d, 0xc8, 0x7f, 0x82, 0x32, 0x64, 0xbb,
+ 0xe4, 0x0d, 0x18, 0x11, 0xc9, 0xea, 0x20, 0x61,
+ 0xe1, 0xc8, 0x4a, 0xd1, 0x0a, 0x23, 0xfa, 0xc1,
+ 0x72, 0x7e, 0x72, 0x02, 0xfc, 0x3f, 0x50, 0x42,
+ 0xe6, 0xbf, 0x58, 0xcb, 0xa8, 0xa2, 0x74, 0x6e,
+ 0x1f, 0x64, 0xf9, 0xb9, 0xea, 0x35, 0x2c, 0x71,
+ 0x15, 0x07, 0x05, 0x3c, 0xf4, 0xe5, 0x33, 0x9d,
+ 0x52, 0x86, 0x5f, 0x25, 0xcc, 0x22, 0xb5, 0xe8,
+ 0x77, 0x84, 0xa1, 0x2f, 0xc9, 0x61, 0xd6, 0x6c,
+ 0xb6, 0xe8, 0x95, 0x73, 0x19, 0x9a, 0x2c, 0xe6,
+ 0x56, 0x5c, 0xbd, 0xf1, 0x3d, 0xca, 0x40, 0x38,
+ 0x32, 0xcf, 0xcb, 0x0e, 0x8b, 0x72, 0x11, 0xe8,
+ 0x3a, 0xf3, 0x2a, 0x11, 0xac, 0x17, 0x92, 0x9f,
+ 0xf1, 0xc0, 0x73, 0xa5, 0x1c, 0xc0, 0x27, 0xaa,
+ 0xed, 0xef, 0xf8, 0x5a, 0xad, 0x7c, 0x2b, 0x7c,
+ 0x5a, 0x80, 0x3e, 0x24, 0x04, 0xd9, 0x6d, 0x2a,
+ 0x77, 0x35, 0x7b, 0xda, 0x1a, 0x6d, 0xae, 0xed,
+ 0x17, 0x15, 0x1c, 0xb9, 0xbc, 0x51, 0x25, 0xa4,
+ 0x22, 0xe9, 0x41, 0xde, 0x0c, 0xa0, 0xfc, 0x50,
+ 0x11, 0xc2, 0x3e, 0xcf, 0xfe, 0xfd, 0xd0, 0x96,
+ 0x76, 0x71, 0x1c, 0xf3, 0xdb, 0x0a, 0x34, 0x40,
+ 0x72, 0x0e ,0x16, 0x15, 0xc1, 0xf2, 0x2f, 0xbc,
+ 0x3c, 0x72, 0x1d, 0xe5, 0x21, 0xe1, 0xb9, 0x9b,
+ 0xa1, 0xbd, 0x55, 0x77, 0x40, 0x86, 0x42, 0x14,
+ 0x7e, 0xd0, 0x96
+};
+
+static const u_char sha384_long2_msg_digest[] = {
+ 0x4f, 0x44, 0x0d, 0xb1, 0xe6, 0xed, 0xd2, 0x89,
+ 0x9f, 0xa3, 0x35, 0xf0, 0x95, 0x15, 0xaa, 0x02,
+ 0x5e, 0xe1, 0x77, 0xa7, 0x9f, 0x4b, 0x4a, 0xaf,
+ 0x38, 0xe4, 0x2b, 0x5c, 0x4d, 0xe6, 0x60, 0xf5,
+ 0xde, 0x8f, 0xb2, 0xa5, 0xb2, 0xfb, 0xd2, 0xa3,
+ 0xcb, 0xff, 0xd2, 0x0c, 0xff, 0x12, 0x88, 0xc0
+};
+
+static const hash_testvector_t sha384_hash_testvectors[] = {
+ { sizeof(sha384_short2_msg), sha384_short2_msg, sha384_short2_msg_digest },
+ { sizeof(sha384_short4_msg), sha384_short4_msg, sha384_short4_msg_digest },
+ { sizeof(sha384_long2_msg), sha384_long2_msg, sha384_long2_msg_digest },
+ { 0, NULL, NULL }
+};
+
+/* SHA-512 hash test vectors
+ * from "The Secure Hash Algorithm Validation System (SHAVS)"
+ * July 22, 2004, Lawrence E. Bassham III, NIST
+ */
+
+static const u_char sha512_short2_msg[] = {
+ 0xd0
+};
+
+static const u_char sha512_short2_msg_digest[] = {
+ 0x99, 0x92, 0x20, 0x29, 0x38, 0xe8, 0x82, 0xe7,
+ 0x3e, 0x20, 0xf6, 0xb6, 0x9e, 0x68, 0xa0, 0xa7,
+ 0x14, 0x90, 0x90, 0x42, 0x3d, 0x93, 0xc8, 0x1b,
+ 0xab, 0x3f, 0x21, 0x67, 0x8d, 0x4a, 0xce, 0xee,
+ 0xe5, 0x0e, 0x4e, 0x8c, 0xaf, 0xad, 0xa4, 0xc8,
+ 0x5a, 0x54, 0xea, 0x83, 0x06, 0x82, 0x6c, 0x4a,
+ 0xd6, 0xe7, 0x4c, 0xec, 0xe9, 0x63, 0x1b, 0xfa,
+ 0x8a, 0x54, 0x9b, 0x4a, 0xb3, 0xfb, 0xba, 0x15
+};
+
+static const u_char sha512_short4_msg[] = {
+ 0x8d, 0x4e, 0x3c, 0x0e, 0x38, 0x89, 0x19, 0x14,
+ 0x91, 0x81, 0x6e, 0x9d, 0x98, 0xbf, 0xf0, 0xa0
+};
+
+static const u_char sha512_short4_msg_digest[] = {
+ 0xcb, 0x0b, 0x67, 0xa4, 0xb8, 0x71, 0x2c, 0xd7,
+ 0x3c, 0x9a, 0xab, 0xc0, 0xb1, 0x99, 0xe9, 0x26,
+ 0x9b, 0x20, 0x84, 0x4a, 0xfb, 0x75, 0xac, 0xbd,
+ 0xd1, 0xc1, 0x53, 0xc9, 0x82, 0x89, 0x24, 0xc3,
+ 0xdd, 0xed, 0xaa, 0xfe, 0x66, 0x9c, 0x5f, 0xdd,
+ 0x0b, 0xc6, 0x6f, 0x63, 0x0f, 0x67, 0x73, 0x98,
+ 0x82, 0x13, 0xeb, 0x1b, 0x16, 0xf5, 0x17, 0xad,
+ 0x0d, 0xe4, 0xb2, 0xf0, 0xc9, 0x5c, 0x90, 0xf8
+};
+
+static const u_char sha512_long2_msg[] = {
+ 0xa5, 0x5f, 0x20, 0xc4, 0x11, 0xaa, 0xd1, 0x32,
+ 0x80, 0x7a, 0x50, 0x2d, 0x65, 0x82, 0x4e, 0x31,
+ 0xa2, 0x30, 0x54, 0x32, 0xaa, 0x3d, 0x06, 0xd3,
+ 0xe2, 0x82, 0xa8, 0xd8, 0x4e, 0x0d, 0xe1, 0xde,
+ 0x69, 0x74, 0xbf, 0x49, 0x54, 0x69, 0xfc, 0x7f,
+ 0x33, 0x8f, 0x80, 0x54, 0xd5, 0x8c, 0x26, 0xc4,
+ 0x93, 0x60, 0xc3, 0xe8, 0x7a, 0xf5, 0x65, 0x23,
+ 0xac, 0xf6, 0xd8, 0x9d, 0x03, 0xe5, 0x6f, 0xf2,
+ 0xf8, 0x68, 0x00, 0x2b, 0xc3, 0xe4, 0x31, 0xed,
+ 0xc4, 0x4d, 0xf2, 0xf0, 0x22, 0x3d, 0x4b, 0xb3,
+ 0xb2, 0x43, 0x58, 0x6e, 0x1a, 0x7d, 0x92, 0x49,
+ 0x36, 0x69, 0x4f, 0xcb, 0xba, 0xf8, 0x8d, 0x95,
+ 0x19, 0xe4, 0xeb, 0x50, 0xa6, 0x44, 0xf8, 0xe4,
+ 0xf9, 0x5e, 0xb0, 0xea, 0x95, 0xbc, 0x44, 0x65,
+ 0xc8, 0x82, 0x1a, 0xac, 0xd2, 0xfe, 0x15, 0xab,
+ 0x49, 0x81, 0x16, 0x4b, 0xbb, 0x6d, 0xc3, 0x2f,
+ 0x96, 0x90, 0x87, 0xa1, 0x45, 0xb0, 0xd9, 0xcc,
+ 0x9c, 0x67, 0xc2, 0x2b, 0x76, 0x32, 0x99, 0x41,
+ 0x9c, 0xc4, 0x12, 0x8b, 0xe9, 0xa0, 0x77, 0xb3,
+ 0xac, 0xe6, 0x34, 0x06, 0x4e, 0x6d, 0x99, 0x28,
+ 0x35, 0x13, 0xdc, 0x06, 0xe7, 0x51, 0x5d, 0x0d,
+ 0x73, 0x13, 0x2e, 0x9a, 0x0d, 0xc6, 0xd3, 0xb1,
+ 0xf8, 0xb2, 0x46, 0xf1, 0xa9, 0x8a, 0x3f, 0xc7,
+ 0x29, 0x41, 0xb1, 0xe3, 0xbb, 0x20, 0x98, 0xe8,
+ 0xbf, 0x16, 0xf2, 0x68, 0xd6, 0x4f, 0x0b, 0x0f,
+ 0x47, 0x07, 0xfe, 0x1e, 0xa1, 0xa1, 0x79, 0x1b,
+ 0xa2, 0xf3, 0xc0, 0xc7, 0x58, 0xe5, 0xf5, 0x51,
+ 0x86, 0x3a, 0x96, 0xc9, 0x49, 0xad, 0x47, 0xd7,
+ 0xfb, 0x40, 0xd2
+};
+
+static const u_char sha512_long2_msg_digest[] = {
+ 0xc6, 0x65, 0xbe, 0xfb, 0x36, 0xda, 0x18, 0x9d,
+ 0x78, 0x82, 0x2d, 0x10, 0x52, 0x8c, 0xbf, 0x3b,
+ 0x12, 0xb3, 0xee, 0xf7, 0x26, 0x03, 0x99, 0x09,
+ 0xc1, 0xa1, 0x6a, 0x27, 0x0d, 0x48, 0x71, 0x93,
+ 0x77, 0x96, 0x6b, 0x95, 0x7a, 0x87, 0x8e, 0x72,
+ 0x05, 0x84, 0x77, 0x9a, 0x62, 0x82, 0x5c, 0x18,
+ 0xda, 0x26, 0x41, 0x5e, 0x49, 0xa7, 0x17, 0x6a,
+ 0x89, 0x4e, 0x75, 0x10, 0xfd, 0x14, 0x51, 0xf5
+};
+
+static const hash_testvector_t sha512_hash_testvectors[] = {
+ { sizeof(sha512_short2_msg), sha512_short2_msg, sha512_short2_msg_digest },
+ { sizeof(sha512_short4_msg), sha512_short4_msg, sha512_short4_msg_digest },
+ { sizeof(sha512_long2_msg), sha512_long2_msg, sha512_long2_msg_digest },
+ { 0, NULL, NULL }
+};
+
+/* SHA-256, SHA-384, and SHA-512 hmac test vectors
+ * from RFC 4231 "Identifiers and Test Vectors for HMAC-SHA-224,
+ * HMAC-SHA-256, HMAC-SHA-384, and HMAC-SHA-512"
+ * December 2005, M. Nystrom, RSA Security
+ */
+
+static const u_char sha2_hmac1_key[] = {
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b
+};
+
+static const u_char sha2_hmac1_msg[] = {
+ 0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65
+};
+
+static const u_char sha2_hmac1_256[] = {
+ 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53,
+ 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0x0b, 0xf1, 0x2b,
+ 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7,
+ 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7
+};
+
+static const u_char sha2_hmac1_384[] = {
+ 0xaf, 0xd0, 0x39, 0x44, 0xd8, 0x48, 0x95, 0x62,
+ 0x6b, 0x08, 0x25, 0xf4, 0xab ,0x46, 0x90, 0x7f,
+ 0x15, 0xf9, 0xda, 0xdb, 0xe4, 0x10, 0x1e, 0xc6,
+ 0x82, 0xaa, 0x03, 0x4c, 0x7c, 0xeb, 0xc5, 0x9c,
+ 0xfa, 0xea, 0x9e, 0xa9, 0x07, 0x6e, 0xde, 0x7f,
+ 0x4a, 0xf1, 0x52, 0xe8, 0xb2, 0xfa, 0x9c, 0xb6
+};
+
+static const u_char sha2_hmac1_512[] = {
+ 0x87, 0xaa, 0x7c, 0xde, 0xa5, 0xef, 0x61, 0x9d,
+ 0x4f, 0xf0, 0xb4, 0x24, 0x1a, 0x1d, 0x6c, 0xb0,
+ 0x23, 0x79, 0xf4, 0xe2, 0xce, 0x4e, 0xc2, 0x78,
+ 0x7a, 0xd0, 0xb3, 0x05, 0x45, 0xe1, 0x7c, 0xde,
+ 0xda, 0xa8, 0x33, 0xb7, 0xd6, 0xb8, 0xa7, 0x02,
+ 0x03, 0x8b, 0x27, 0x4e, 0xae, 0xa3, 0xf4, 0xe4,
+ 0xbe, 0x9d, 0x91, 0x4e, 0xeb, 0x61, 0xf1, 0x70,
+ 0x2e, 0x69, 0x6c, 0x20, 0x3a, 0x12, 0x68, 0x54
+};
+
+static const u_char sha2_hmac2_key[] = {
+ 0x4a, 0x65, 0x66, 0x65
+};
+
+static const u_char sha2_hmac2_msg[] = {
+ 0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x20,
+ 0x79, 0x61, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x20,
+ 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x68,
+ 0x69, 0x6e, 0x67, 0x3f
+};
+
+static const u_char sha2_hmac2_256[] = {
+ 0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e,
+ 0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7,
+ 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83,
+ 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43
+};
+
+static const u_char sha2_hmac2_384[] = {
+ 0xaf, 0x45, 0xd2, 0xe3, 0x76, 0x48, 0x40, 0x31,
+ 0x61, 0x7f, 0x78, 0xd2, 0xb5, 0x8a, 0x6b, 0x1b,
+ 0x9c, 0x7e, 0xf4, 0x64, 0xf5, 0xa0, 0x1b, 0x47,
+ 0xe4, 0x2e, 0xc3, 0x73, 0x63, 0x22, 0x44, 0x5e,
+ 0x8e, 0x22, 0x40, 0xca, 0x5e, 0x69, 0xe2, 0xc7,
+ 0x8b, 0x32, 0x39, 0xec, 0xfa, 0xb2, 0x16, 0x49
+};
+
+static const u_char sha2_hmac2_512[] = {
+ 0x16, 0x4b, 0x7a, 0x7b, 0xfc, 0xf8, 0x19, 0xe2,
+ 0xe3, 0x95, 0xfb, 0xe7, 0x3b, 0x56, 0xe0, 0xa3,
+ 0x87, 0xbd, 0x64, 0x22, 0x2e, 0x83, 0x1f, 0xd6,
+ 0x10, 0x27, 0x0c, 0xd7, 0xea, 0x25, 0x05, 0x54,
+ 0x97, 0x58, 0xbf, 0x75, 0xc0, 0x5a, 0x99, 0x4a,
+ 0x6d, 0x03, 0x4f, 0x65, 0xf8, 0xf0, 0xe6, 0xfd,
+ 0xca, 0xea, 0xb1, 0xa3, 0x4d, 0x4a, 0x6b, 0x4b,
+ 0x63, 0x6e, 0x07, 0x0a, 0x38, 0xbc, 0xe7, 0x37
+};
+
+static const u_char sha2_hmac3_key[] = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa
+};
+
+static const u_char sha2_hmac3_msg[] = {
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd
+};
+
+static const u_char sha2_hmac3_256[] = {
+ 0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46,
+ 0x85, 0x4d, 0xb8, 0xeb, 0xd0, 0x91, 0x81, 0xa7,
+ 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22,
+ 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe
+};
+
+static const u_char sha2_hmac3_384[] = {
+ 0x88, 0x06, 0x26, 0x08, 0xd3, 0xe6, 0xad, 0x8a,
+ 0x0a, 0xa2, 0xac, 0xe0, 0x14, 0xc8, 0xa8, 0x6f,
+ 0x0a, 0xa6, 0x35, 0xd9, 0x47, 0xac, 0x9f, 0xeb,
+ 0xe8, 0x3e, 0xf4, 0xe5, 0x59, 0x66, 0x14, 0x4b,
+ 0x2a, 0x5a, 0xb3, 0x9d, 0xc1, 0x38, 0x14, 0xb9,
+ 0x4e, 0x3a, 0xb6, 0xe1, 0x01, 0xa3, 0x4f, 0x27
+};
+
+static const u_char sha2_hmac3_512[] = {
+ 0xfa, 0x73, 0xb0, 0x08, 0x9d, 0x56, 0xa2, 0x84,
+ 0xef, 0xb0, 0xf0, 0x75, 0x6c, 0x89, 0x0b, 0xe9,
+ 0xb1, 0xb5, 0xdb, 0xdd, 0x8e, 0xe8, 0x1a, 0x36,
+ 0x55, 0xf8, 0x3e, 0x33, 0xb2, 0x27, 0x9d, 0x39,
+ 0xbf, 0x3e, 0x84, 0x82, 0x79, 0xa7, 0x22, 0xc8,
+ 0x06, 0xb4, 0x85, 0xa4, 0x7e, 0x67, 0xc8, 0x07,
+ 0xb9, 0x46, 0xa3, 0x37, 0xbe, 0xe8, 0x94, 0x26,
+ 0x74, 0x27, 0x88, 0x59, 0xe1, 0x32, 0x92, 0xfb
+};
+
+static const u_char sha2_hmac4_key[] = {
+ 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
+};
+
+static const u_char sha2_hmac4_msg[] = {
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd
+};
+
+static const u_char sha2_hmac4_256[] = {
+ 0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e,
+ 0xa4, 0xcc, 0x81, 0x98, 0x99, 0xf2, 0x08, 0x3a,
+ 0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78, 0xf8, 0x07,
+ 0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b
+};
+
+static const u_char sha2_hmac4_384[] = {
+ 0x3e, 0x8a, 0x69, 0xb7, 0x78, 0x3c, 0x25, 0x85,
+ 0x19, 0x33, 0xab, 0x62, 0x90, 0xaf, 0x6c, 0xa7,
+ 0x7a, 0x99, 0x81, 0x48, 0x08, 0x50, 0x00, 0x9c,
+ 0xc5, 0x57, 0x7c, 0x6e, 0x1f, 0x57, 0x3b, 0x4e,
+ 0x68, 0x01, 0xdd, 0x23, 0xc4, 0xa7, 0xd6, 0x79,
+ 0xcc, 0xf8, 0xa3, 0x86, 0xc6, 0x74, 0xcf, 0xfb
+};
+
+static const u_char sha2_hmac4_512[] = {
+ 0xb0, 0xba, 0x46, 0x56, 0x37, 0x45, 0x8c, 0x69,
+ 0x90, 0xe5, 0xa8, 0xc5, 0xf6, 0x1d, 0x4a, 0xf7,
+ 0xe5, 0x76, 0xd9, 0x7f, 0xf9, 0x4b, 0x87, 0x2d,
+ 0xe7, 0x6f, 0x80, 0x50, 0x36, 0x1e, 0xe3, 0xdb,
+ 0xa9, 0x1c, 0xa5, 0xc1, 0x1a, 0xa2, 0x5e, 0xb4,
+ 0xd6, 0x79, 0x27, 0x5c, 0xc5, 0x78, 0x80, 0x63,
+ 0xa5, 0xf1, 0x97, 0x41, 0x12, 0x0c, 0x4f, 0x2d,
+ 0xe2, 0xad, 0xeb, 0xeb, 0x10, 0xa2, 0x98, 0xdd
+};
+
+static const u_char sha2_hmac6_key[] = {
+ 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,
+ 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
+};
+
+static const u_char sha2_hmac6_msg[] = {
+ 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69,
+ 0x6e, 0x67, 0x20, 0x4c, 0x61, 0x72, 0x67, 0x65,
+ 0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42,
+ 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a,
+ 0x65, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x2d, 0x20,
+ 0x48, 0x61, 0x73, 0x68, 0x20, 0x4b, 0x65, 0x79,
+ 0x20, 0x46, 0x69, 0x72, 0x73, 0x74
+};
+
+static const u_char sha2_hmac6_256[] = {
+ 0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f,
+ 0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5, 0xb7, 0x7f,
+ 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14,
+ 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54
+};
+
+static const u_char sha2_hmac6_384[] = {
+ 0x4e, 0xce, 0x08, 0x44, 0x85, 0x81, 0x3e, 0x90,
+ 0x88, 0xd2, 0xc6, 0x3a, 0x04, 0x1b, 0xc5, 0xb4,
+ 0x4f, 0x9e, 0xf1, 0x01, 0x2a, 0x2b, 0x58, 0x8f,
+ 0x3c, 0xd1, 0x1f, 0x05, 0x03, 0x3a, 0xc4, 0xc6,
+ 0x0c, 0x2e, 0xf6, 0xab, 0x40, 0x30, 0xfe, 0x82,
+ 0x96, 0x24, 0x8d, 0xf1, 0x63, 0xf4, 0x49, 0x52
+};
+
+static const u_char sha2_hmac6_512[] = {
+ 0x80, 0xb2, 0x42, 0x63, 0xc7, 0xc1, 0xa3, 0xeb,
+ 0xb7, 0x14, 0x93, 0xc1, 0xdd, 0x7b, 0xe8, 0xb4,
+ 0x9b, 0x46, 0xd1, 0xf4, 0x1b, 0x4a, 0xee, 0xc1,
+ 0x12, 0x1b, 0x01, 0x37, 0x83, 0xf8, 0xf3, 0x52,
+ 0x6b, 0x56, 0xd0, 0x37, 0xe0, 0x5f, 0x25, 0x98,
+ 0xbd, 0x0f, 0xd2, 0x21, 0x5d, 0x6a, 0x1e, 0x52,
+ 0x95, 0xe6, 0x4f, 0x73, 0xf6, 0x3f, 0x0a, 0xec,
+ 0x8b, 0x91, 0x5a, 0x98, 0x5d, 0x78, 0x65, 0x98
+};
+
+static const u_char sha2_hmac7_msg[] = {
+ 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
+ 0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x75,
+ 0x73, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x6c,
+ 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, 0x68,
+ 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
+ 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x6b, 0x65,
+ 0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20,
+ 0x6c, 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74,
+ 0x68, 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63,
+ 0x6b, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x64,
+ 0x61, 0x74, 0x61, 0x2e, 0x20, 0x54, 0x68, 0x65,
+ 0x20, 0x6b, 0x65, 0x79, 0x20, 0x6e, 0x65, 0x65,
+ 0x64, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65,
+ 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x64, 0x20,
+ 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x62,
+ 0x65, 0x69, 0x6e, 0x67, 0x20, 0x75, 0x73, 0x65,
+ 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65,
+ 0x20, 0x48, 0x4d, 0x41, 0x43, 0x20, 0x61, 0x6c,
+ 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x2e
+};
+
+static const u_char sha2_hmac7_256[] = {
+ 0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb,
+ 0x27, 0x63, 0x5f, 0xbc, 0xd5, 0xb0, 0xe9, 0x44,
+ 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93,
+ 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2
+};
+
+static const u_char sha2_hmac7_384[] = {
+ 0x66, 0x17, 0x17, 0x8e, 0x94, 0x1f, 0x02, 0x0d,
+ 0x35, 0x1e, 0x2f, 0x25, 0x4e, 0x8f, 0xd3, 0x2c,
+ 0x60, 0x24, 0x20, 0xfe, 0xb0, 0xb8, 0xfb, 0x9a,
+ 0xdc, 0xce, 0xbb, 0x82, 0x46, 0x1e, 0x99, 0xc5,
+ 0xa6, 0x78, 0xcc, 0x31, 0xe7, 0x99, 0x17, 0x6d,
+ 0x38, 0x60, 0xe6, 0x11, 0x0c, 0x46, 0x52, 0x3e
+};
+
+static const u_char sha2_hmac7_512[] = {
+ 0xe3, 0x7b, 0x6a, 0x77, 0x5d, 0xc8, 0x7d, 0xba,
+ 0xa4, 0xdf, 0xa9, 0xf9, 0x6e, 0x5e, 0x3f, 0xfd,
+ 0xde, 0xbd, 0x71, 0xf8, 0x86, 0x72, 0x89, 0x86,
+ 0x5d, 0xf5, 0xa3, 0x2d, 0x20, 0xcd, 0xc9, 0x44,
+ 0xb6, 0x02, 0x2c, 0xac, 0x3c, 0x49, 0x82, 0xb1,
+ 0x0d, 0x5e, 0xeb, 0x55, 0xc3, 0xe4, 0xde, 0x15,
+ 0x13, 0x46, 0x76, 0xfb, 0x6d, 0xe0, 0x44, 0x60,
+ 0x65, 0xc9, 0x74, 0x40, 0xfa, 0x8c, 0x6a, 0x58
+};
+
+static const hmac_testvector_t sha256_hmac_testvectors[] = {
+ { sizeof(sha2_hmac1_key), sha2_hmac1_key, sizeof(sha2_hmac1_msg), sha2_hmac1_msg, sha2_hmac1_256 },
+ { sizeof(sha2_hmac2_key), sha2_hmac2_key, sizeof(sha2_hmac2_msg), sha2_hmac2_msg, sha2_hmac2_256 },
+ { sizeof(sha2_hmac3_key), sha2_hmac3_key, sizeof(sha2_hmac3_msg), sha2_hmac3_msg, sha2_hmac3_256 },
+ { sizeof(sha2_hmac4_key), sha2_hmac4_key, sizeof(sha2_hmac4_msg), sha2_hmac4_msg, sha2_hmac4_256 },
+ { sizeof(sha2_hmac6_key), sha2_hmac6_key, sizeof(sha2_hmac6_msg), sha2_hmac6_msg, sha2_hmac6_256 },
+ { sizeof(sha2_hmac6_key), sha2_hmac6_key, sizeof(sha2_hmac7_msg), sha2_hmac7_msg, sha2_hmac7_256 },
+ { 0, NULL, 0, NULL, NULL }
+};
+
+static const hmac_testvector_t sha384_hmac_testvectors[] = {
+ { sizeof(sha2_hmac1_key), sha2_hmac1_key, sizeof(sha2_hmac1_msg), sha2_hmac1_msg, sha2_hmac1_384 },
+ { sizeof(sha2_hmac2_key), sha2_hmac2_key, sizeof(sha2_hmac2_msg), sha2_hmac2_msg, sha2_hmac2_384 },
+ { sizeof(sha2_hmac3_key), sha2_hmac3_key, sizeof(sha2_hmac3_msg), sha2_hmac3_msg, sha2_hmac3_384 },
+ { sizeof(sha2_hmac4_key), sha2_hmac4_key, sizeof(sha2_hmac4_msg), sha2_hmac4_msg, sha2_hmac4_384 },
+ { sizeof(sha2_hmac6_key), sha2_hmac6_key, sizeof(sha2_hmac6_msg), sha2_hmac6_msg, sha2_hmac6_384 },
+ { sizeof(sha2_hmac6_key), sha2_hmac6_key, sizeof(sha2_hmac7_msg), sha2_hmac7_msg, sha2_hmac7_384 },
+ { 0, NULL, 0, NULL, NULL }
+};
+
+static const hmac_testvector_t sha512_hmac_testvectors[] = {
+ { sizeof(sha2_hmac1_key), sha2_hmac1_key, sizeof(sha2_hmac1_msg), sha2_hmac1_msg, sha2_hmac1_512 },
+ { sizeof(sha2_hmac2_key), sha2_hmac2_key, sizeof(sha2_hmac2_msg), sha2_hmac2_msg, sha2_hmac2_512 },
+ { sizeof(sha2_hmac3_key), sha2_hmac3_key, sizeof(sha2_hmac3_msg), sha2_hmac3_msg, sha2_hmac3_512 },
+ { sizeof(sha2_hmac4_key), sha2_hmac4_key, sizeof(sha2_hmac4_msg), sha2_hmac4_msg, sha2_hmac4_512 },
+ { sizeof(sha2_hmac6_key), sha2_hmac6_key, sizeof(sha2_hmac6_msg), sha2_hmac6_msg, sha2_hmac6_512 },
+ { sizeof(sha2_hmac6_key), sha2_hmac6_key, sizeof(sha2_hmac7_msg), sha2_hmac7_msg, sha2_hmac7_512 },
+ { 0, NULL, 0, NULL, NULL }
+};
+
+struct hash_desc hash_desc_sha2_256 = {
+ algo_type: IKE_ALG_HASH,
+ algo_id: OAKLEY_SHA2_256,
+ algo_next: NULL,
+ hash_ctx_size: sizeof(sha256_context),
+ hash_block_size: SHA2_256_BLOCK_SIZE,
+ hash_digest_size: SHA2_256_DIGEST_SIZE,
+ hash_testvectors: sha256_hash_testvectors,
+ hmac_testvectors: sha256_hmac_testvectors,
+ hash_init: (void (*)(void *))sha256_init,
+ hash_update: (void (*)(void *, const u_char *, size_t ))sha256_write,
+ hash_final:(void (*)(u_char *, void *))sha256_hash_final
+};
+
+struct hash_desc hash_desc_sha2_384 = {
+ algo_type: IKE_ALG_HASH,
+ algo_id: OAKLEY_SHA2_384,
+ algo_next: NULL,
+ hash_ctx_size: sizeof(sha512_context),
+ hash_block_size: SHA2_384_BLOCK_SIZE,
+ hash_digest_size: SHA2_384_DIGEST_SIZE,
+ hash_testvectors: sha384_hash_testvectors,
+ hmac_testvectors: sha384_hmac_testvectors,
+ hash_init: (void (*)(void *))sha384_init,
+ hash_update: (void (*)(void *, const u_char *, size_t ))sha512_write,
+ hash_final:(void (*)(u_char *, void *))sha384_hash_final
+};
+
+struct hash_desc hash_desc_sha2_512 = {
+ algo_type: IKE_ALG_HASH,
+ algo_id: OAKLEY_SHA2_512,
+ algo_next: NULL,
+ hash_ctx_size: sizeof(sha512_context),
+ hash_block_size: SHA2_512_BLOCK_SIZE,
+ hash_digest_size: SHA2_512_DIGEST_SIZE,
+ hash_testvectors: sha512_hash_testvectors,
+ hmac_testvectors: sha512_hmac_testvectors,
+ hash_init: (void (*)(void *))sha512_init,
+ hash_update: (void (*)(void *, const u_char *, size_t ))sha512_write,
+ hash_final:(void (*)(u_char *, void *))sha512_hash_final
+};
+
+int ike_alg_sha2_init(void);
+
+int
+ike_alg_sha2_init(void)
+{
+ int ret
+;
+ ret = ike_alg_register_hash(&hash_desc_sha2_256);
+ if (ret)
+ goto out;
+ ret = ike_alg_register_hash(&hash_desc_sha2_384);
+ if (ret)
+ goto out;
+ ret = ike_alg_register_hash(&hash_desc_sha2_512);
+
+out:
+ return ret;
+}
+
+/*
+IKE_ALG_INIT_NAME: ike_alg_sha2_init
+*/
diff --git a/src/pluto/alg/ike_alg_twofish.c b/src/pluto/alg/ike_alg_twofish.c
new file mode 100644
index 000000000..1788bc394
--- /dev/null
+++ b/src/pluto/alg/ike_alg_twofish.c
@@ -0,0 +1,85 @@
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "libtwofish/twofish_cbc.h"
+#include "alg_info.h"
+#include "ike_alg.h"
+
+#define TWOFISH_CBC_BLOCK_SIZE (128/BITS_PER_BYTE)
+#define TWOFISH_KEY_MIN_LEN 128
+#define TWOFISH_KEY_DEF_LEN 128
+#define TWOFISH_KEY_MAX_LEN 256
+
+static void
+do_twofish(u_int8_t *buf, size_t buf_size, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc)
+{
+ twofish_context twofish_ctx;
+ char iv_bak[TWOFISH_CBC_BLOCK_SIZE];
+ char *new_iv = NULL; /* logic will avoid copy to NULL */
+
+ twofish_set_key(&twofish_ctx, key, key_size);
+ /*
+ * my TWOFISH cbc does not touch passed IV (optimization for
+ * ESP handling), so I must "emulate" des-like IV
+ * crunching
+ */
+ if (!enc)
+ memcpy(new_iv=iv_bak,
+ (char*) buf + buf_size-TWOFISH_CBC_BLOCK_SIZE,
+ TWOFISH_CBC_BLOCK_SIZE);
+
+ twofish_cbc_encrypt(&twofish_ctx, buf, buf, buf_size, iv, enc);
+
+ if (enc)
+ new_iv = (char*) buf + buf_size-TWOFISH_CBC_BLOCK_SIZE;
+
+ memcpy(iv, new_iv, TWOFISH_CBC_BLOCK_SIZE);
+}
+
+struct encrypt_desc encrypt_desc_twofish =
+{
+ algo_type: IKE_ALG_ENCRYPT,
+ algo_id: OAKLEY_TWOFISH_CBC,
+ algo_next: NULL,
+ enc_ctxsize: sizeof(twofish_context),
+ enc_blocksize: TWOFISH_CBC_BLOCK_SIZE,
+ keydeflen: TWOFISH_KEY_MIN_LEN,
+ keyminlen: TWOFISH_KEY_DEF_LEN,
+ keymaxlen: TWOFISH_KEY_MAX_LEN,
+ do_crypt: do_twofish,
+};
+
+struct encrypt_desc encrypt_desc_twofish_ssh =
+{
+ algo_type: IKE_ALG_ENCRYPT,
+ algo_id: OAKLEY_TWOFISH_CBC_SSH,
+ algo_next: NULL,
+ enc_ctxsize: sizeof(twofish_context),
+ enc_blocksize: TWOFISH_CBC_BLOCK_SIZE,
+ keydeflen: TWOFISH_KEY_MIN_LEN,
+ keyminlen: TWOFISH_KEY_DEF_LEN,
+ keymaxlen: TWOFISH_KEY_MAX_LEN,
+ do_crypt: do_twofish,
+};
+
+int ike_alg_twofish_init(void);
+
+int
+ike_alg_twofish_init(void)
+{
+ int ret = ike_alg_register_enc(&encrypt_desc_twofish);
+
+ if (ike_alg_register_enc(&encrypt_desc_twofish_ssh) < 0)
+ plog("ike_alg_twofish_init(): Experimental OAKLEY_TWOFISH_CBC_SSH activation failed");
+
+ return ret;
+}
+/*
+IKE_ALG_INIT_NAME: ike_alg_twofish_init
+*/
diff --git a/src/pluto/alg/ike_alginit.c b/src/pluto/alg/ike_alginit.c
new file mode 100644
index 000000000..8784bf31b
--- /dev/null
+++ b/src/pluto/alg/ike_alginit.c
@@ -0,0 +1,7 @@
+extern int ike_alg_init(void); int ike_alg_init(void) {
+{ extern int ike_alg_aes_init (void); ike_alg_aes_init();}
+{ extern int ike_alg_blowfish_init (void); ike_alg_blowfish_init();}
+{ extern int ike_alg_serpent_init (void); ike_alg_serpent_init();}
+{ extern int ike_alg_sha2_init (void); ike_alg_sha2_init();}
+{ extern int ike_alg_twofish_init (void); ike_alg_twofish_init();}
+return 0;}
diff --git a/src/pluto/alg_info.c b/src/pluto/alg_info.c
new file mode 100644
index 000000000..ac5d1672f
--- /dev/null
+++ b/src/pluto/alg_info.c
@@ -0,0 +1,1205 @@
+/*
+ * Algorithm info parsing and creation functions
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * $Id: alg_info.c,v 1.5 2004/09/29 22:42:49 as Exp $
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <freeswan.h>
+#include <ipsec_policy.h>
+#include <pfkeyv2.h>
+
+#include "alg_info.h"
+#include "constants.h"
+#ifndef NO_PLUTO
+#include "defs.h"
+#include "log.h"
+#include "whack.h"
+#include "sha1.h"
+#include "md5.h"
+#include "crypto.h"
+#include "kernel_alg.h"
+#include "ike_alg.h"
+#else
+/*
+ * macros/functions for compilation without pluto (eg: spi for manual conns)
+ */
+#include <assert.h>
+#define passert(x) assert(x)
+extern int debug; /* eg: spi.c */
+#define DBG(cond, action) { if (debug) { action ; } }
+#define DBG_log(x, args...) fprintf(stderr, x "\n" , ##args);
+#define RC_LOG_SERIOUS
+#define loglog(x, args...) fprintf(stderr, ##args);
+#define alloc_thing(thing, name) alloc_bytes(sizeof (thing), name)
+void * alloc_bytes(size_t size, const char *name) {
+ void *p=malloc(size);
+ if (p == NULL)
+ fprintf(stderr, "unable to malloc %lu bytes for %s",
+ (unsigned long) size, name);
+ memset(p, '\0', size);
+ return p;
+}
+#define pfreeany(ptr) free(ptr)
+#endif /* NO_PLUTO */
+
+/*
+ * sadb/ESP aa attrib converters
+ */
+int
+alg_info_esp_aa2sadb(int auth)
+{
+ int sadb_aalg = 0;
+
+ switch(auth) {
+ case AUTH_ALGORITHM_HMAC_MD5:
+ case AUTH_ALGORITHM_HMAC_SHA1:
+ sadb_aalg = auth + 1;
+ break;
+ case AUTH_ALGORITHM_HMAC_SHA2_256:
+ case AUTH_ALGORITHM_HMAC_SHA2_384:
+ case AUTH_ALGORITHM_HMAC_SHA2_512:
+ case AUTH_ALGORITHM_HMAC_RIPEMD:
+ sadb_aalg = auth;
+ break;
+ default:
+ /* loose ... */
+ sadb_aalg = auth;
+ }
+ return sadb_aalg;
+}
+
+int /* __attribute__ ((unused)) */
+alg_info_esp_sadb2aa(int sadb_aalg)
+{
+ int auth = 0;
+
+ switch(sadb_aalg) {
+ case SADB_AALG_MD5_HMAC:
+ case SADB_AALG_SHA1_HMAC:
+ auth = sadb_aalg - 1;
+ break;
+ /* since they are the same ... :) */
+ case AUTH_ALGORITHM_HMAC_SHA2_256:
+ case AUTH_ALGORITHM_HMAC_SHA2_384:
+ case AUTH_ALGORITHM_HMAC_SHA2_512:
+ case AUTH_ALGORITHM_HMAC_RIPEMD:
+ auth = sadb_aalg;
+ break;
+ default:
+ /* loose ... */
+ auth = sadb_aalg;
+ }
+ return auth;
+}
+
+/*
+ * Search enum_name array with in prefixed uppercase
+ */
+static int
+enum_search_prefix (enum_names *ed, const char *prefix, const char *str, int strlen)
+{
+ char buf[64];
+ char *ptr;
+ int ret;
+ int len = sizeof(buf) - 1; /* reserve space for final \0 */
+
+ for (ptr = buf; *prefix; *ptr++ = *prefix++, len--);
+ while (strlen-- && len-- && *str) *ptr++ = toupper(*str++);
+ *ptr = 0;
+
+ DBG(DBG_CRYPT,
+ DBG_log("enum_search_prefix () calling enum_search(%p, \"%s\")"
+ , ed, buf)
+ )
+ ret = enum_search(ed, buf);
+ return ret;
+}
+
+/*
+ * Search enum_name array with in prefixed and postfixed uppercase
+ */
+static int
+enum_search_ppfix (enum_names *ed, const char *prefix, const char *postfix, const char *str, int strlen)
+{
+ char buf[64];
+ char *ptr;
+ int ret;
+ int len = sizeof(buf) - 1; /* reserve space for final \0 */
+
+ for (ptr = buf; *prefix; *ptr++ = *prefix++, len--);
+ while (strlen-- && len-- && *str) *ptr++ = toupper(*str++);
+ while (len-- && *postfix) *ptr++ = *postfix++;
+ *ptr = 0;
+
+ DBG(DBG_CRYPT,
+ DBG_log("enum_search_ppfixi () calling enum_search(%p, \"%s\")"
+ , ed, buf)
+ )
+ ret = enum_search(ed, buf);
+ return ret;
+}
+
+/*
+ * Search esp_transformid_names for a match, eg:
+ * "3des" <=> "ESP_3DES"
+ */
+#define ESP_MAGIC_ID 0x00ffff01
+
+static int
+ealg_getbyname_esp(const char *const str, int len)
+{
+ if (!str || !*str)
+ return -1;
+
+ /* leave special case for eg: "id248" string */
+ if (strcmp("id", str) == 0)
+ return ESP_MAGIC_ID;
+
+ return enum_search_prefix(&esp_transformid_names, "ESP_", str, len);
+}
+
+/*
+ * Search auth_alg_names for a match, eg:
+ * "md5" <=> "AUTH_ALGORITHM_HMAC_MD5"
+ */
+static int
+aalg_getbyname_esp(const char *const str, int len)
+{
+ int ret;
+ unsigned num;
+
+ if (!str || !*str)
+ return -1;
+
+ /* interpret 'SHA' as 'SHA1' */
+ if (strncasecmp("SHA", str, len) == 0)
+ return enum_search(&auth_alg_names, "AUTH_ALGORITHM_HMAC_SHA1");
+
+ ret = enum_search_prefix(&auth_alg_names,"AUTH_ALGORITHM_HMAC_", str ,len);
+ if (ret >= 0)
+ return ret;
+
+ ret = enum_search_prefix(&auth_alg_names,"AUTH_ALGORITHM_", str, len);
+ if (ret >= 0)
+ return ret;
+
+ sscanf(str, "id%d%n", &ret, &num);
+ return (ret >= 0 && num != strlen(str))? -1 : ret;
+}
+
+static int
+modp_getbyname_esp(const char *const str, int len)
+{
+ int ret;
+
+ if (!str || !*str)
+ return -1;
+
+ ret = enum_search_prefix(&oakley_group_names,"OAKLEY_GROUP_", str, len);
+ if (ret >= 0)
+ return ret;
+
+ ret = enum_search_ppfix(&oakley_group_names, "OAKLEY_GROUP_", " (extension)", str, len);
+ return ret;
+}
+
+void
+alg_info_free(struct alg_info *alg_info)
+{
+ pfreeany(alg_info);
+}
+
+/*
+ * Raw add routine: only checks for no duplicates
+ */
+static void
+__alg_info_esp_add (struct alg_info_esp *alg_info, int ealg_id, unsigned ek_bits, int aalg_id, unsigned ak_bits)
+{
+ struct esp_info *esp_info=alg_info->esp;
+ unsigned cnt = alg_info->alg_info_cnt, i;
+
+ /* check for overflows */
+ passert(cnt < elemsof(alg_info->esp));
+
+ /* dont add duplicates */
+ for (i = 0; i < cnt; i++)
+ {
+ if (esp_info[i].esp_ealg_id == ealg_id
+ && (!ek_bits || esp_info[i].esp_ealg_keylen == ek_bits)
+ && esp_info[i].esp_aalg_id == aalg_id
+ && (!ak_bits || esp_info[i].esp_aalg_keylen == ak_bits))
+ return;
+ }
+
+ esp_info[cnt].esp_ealg_id = ealg_id;
+ esp_info[cnt].esp_ealg_keylen = ek_bits;
+ esp_info[cnt].esp_aalg_id = aalg_id;
+ esp_info[cnt].esp_aalg_keylen = ak_bits;
+
+ /* sadb values */
+ esp_info[cnt].encryptalg = ealg_id;
+ esp_info[cnt].authalg = alg_info_esp_aa2sadb(aalg_id);
+ alg_info->alg_info_cnt++;
+
+ DBG(DBG_CRYPT,
+ DBG_log("__alg_info_esp_add() ealg=%d aalg=%d cnt=%d"
+ , ealg_id, aalg_id, alg_info->alg_info_cnt)
+ )
+}
+
+/*
+ * Add ESP alg info _with_ logic (policy):
+ */
+static void
+alg_info_esp_add (struct alg_info *alg_info, int ealg_id, int ek_bits, int aalg_id, int ak_bits)
+{
+ /* Policy: default to 3DES */
+ if (ealg_id == 0)
+ ealg_id = ESP_3DES;
+
+ if (ealg_id > 0)
+ {
+#ifndef NO_PLUTO
+ if (aalg_id > 0)
+#else
+ /* Allow no auth for manual conns (from spi.c) */
+ if (aalg_id >= 0)
+#endif
+ __alg_info_esp_add((struct alg_info_esp *)alg_info,
+ ealg_id, ek_bits,
+ aalg_id, ak_bits);
+ else
+ {
+ /* Policy: default to MD5 and SHA1 */
+ __alg_info_esp_add((struct alg_info_esp *)alg_info,
+ ealg_id, ek_bits,
+ AUTH_ALGORITHM_HMAC_MD5, ak_bits);
+ __alg_info_esp_add((struct alg_info_esp *)alg_info,
+ ealg_id, ek_bits,
+ AUTH_ALGORITHM_HMAC_SHA1, ak_bits);
+ }
+ }
+}
+
+#ifndef NO_PLUTO
+/**************************************
+ *
+ * IKE alg
+ *
+ *************************************/
+/*
+ * Search oakley_enc_names for a match, eg:
+ * "3des_cbc" <=> "OAKLEY_3DES_CBC"
+ */
+static int
+ealg_getbyname_ike(const char *const str, int len)
+{
+ int ret;
+
+ if (!str || !*str)
+ return -1;
+
+ ret = enum_search_prefix(&oakley_enc_names,"OAKLEY_", str, len);
+ if (ret >= 0)
+ return ret;
+
+ ret = enum_search_ppfix(&oakley_enc_names, "OAKLEY_", "_CBC", str, len);
+ return ret;
+}
+
+/*
+ * Search oakley_hash_names for a match, eg:
+ * "md5" <=> "OAKLEY_MD5"
+ */
+static int
+aalg_getbyname_ike(const char *const str, int len)
+{
+ int ret;
+ unsigned num;
+
+ if (!str || !*str)
+ return -1;
+
+ /* interpret 'SHA1' as 'SHA' */
+ if (strncasecmp("SHA1", str, len) == 0)
+ return enum_search(&oakley_hash_names, "OAKLEY_SHA");
+
+ ret = enum_search_prefix(&oakley_hash_names,"OAKLEY_", str, len);
+ if (ret >= 0)
+ return ret;
+
+ sscanf(str, "id%d%n", &ret, &num);
+ return (ret >=0 && num != strlen(str))? -1 : ret;
+}
+
+/*
+ * Search oakley_group_names for a match, eg:
+ * "modp1024" <=> "OAKLEY_GROUP_MODP1024"
+ */
+static int
+modp_getbyname_ike(const char *const str, int len)
+{
+ int ret;
+
+ if (!str || !*str)
+ return -1;
+
+ ret = enum_search_prefix(&oakley_group_names,"OAKLEY_GROUP_", str, len);
+ if (ret >= 0)
+ return ret;
+
+ ret = enum_search_ppfix(&oakley_group_names, "OAKLEY_GROUP_", " (extension)", str, len);
+ return ret;
+}
+
+static void
+__alg_info_ike_add (struct alg_info_ike *alg_info, int ealg_id, unsigned ek_bits, int aalg_id, unsigned ak_bits, int modp_id)
+{
+ struct ike_info *ike_info = alg_info->ike;
+ unsigned cnt = alg_info->alg_info_cnt;
+ unsigned i;
+
+ /* check for overflows */
+ passert(cnt < elemsof(alg_info->ike));
+
+ /* dont add duplicates */
+ for (i = 0;i < cnt; i++)
+ {
+ if (ike_info[i].ike_ealg == ealg_id
+ && (!ek_bits || ike_info[i].ike_eklen == ek_bits)
+ && ike_info[i].ike_halg == aalg_id
+ && (!ak_bits || ike_info[i].ike_hklen == ak_bits)
+ && ike_info[i].ike_modp==modp_id)
+ return;
+ }
+
+ ike_info[cnt].ike_ealg = ealg_id;
+ ike_info[cnt].ike_eklen = ek_bits;
+ ike_info[cnt].ike_halg = aalg_id;
+ ike_info[cnt].ike_hklen = ak_bits;
+ ike_info[cnt].ike_modp = modp_id;
+ alg_info->alg_info_cnt++;
+
+ DBG(DBG_CRYPT,
+ DBG_log("__alg_info_ike_add() ealg=%d aalg=%d modp_id=%d, cnt=%d"
+ , ealg_id, aalg_id, modp_id
+ , alg_info->alg_info_cnt)
+ )
+}
+
+/*
+ * Proposals will be built by looping over default_ike_groups array and
+ * merging alg_info (ike_info) contents
+ */
+
+static int default_ike_groups[] = {
+ OAKLEY_GROUP_MODP1536,
+ OAKLEY_GROUP_MODP1024
+};
+
+/*
+ * Add IKE alg info _with_ logic (policy):
+ */
+static void
+alg_info_ike_add (struct alg_info *alg_info, int ealg_id, int ek_bits, int aalg_id, int ak_bits, int modp_id)
+{
+ int i = 0;
+ int n_groups = elemsof(default_ike_groups);
+
+ /* if specified modp_id avoid loop over default_ike_groups */
+ if (modp_id)
+ {
+ n_groups=0;
+ goto in_loop;
+ }
+
+ for (; n_groups--; i++)
+ {
+ modp_id = default_ike_groups[i];
+in_loop:
+ /* Policy: default to 3DES */
+ if (ealg_id == 0)
+ ealg_id = OAKLEY_3DES_CBC;
+
+ if (ealg_id > 0)
+ {
+ if (aalg_id > 0)
+ __alg_info_ike_add((struct alg_info_ike *)alg_info,
+ ealg_id, ek_bits,
+ aalg_id, ak_bits,
+ modp_id);
+ else
+ {
+ /* Policy: default to MD5 and SHA */
+ __alg_info_ike_add((struct alg_info_ike *)alg_info,
+ ealg_id, ek_bits,
+ OAKLEY_MD5, ak_bits,
+ modp_id);
+ __alg_info_ike_add((struct alg_info_ike *)alg_info,
+ ealg_id, ek_bits,
+ OAKLEY_SHA, ak_bits,
+ modp_id);
+ }
+ }
+ }
+}
+#endif /* NO_PLUTO */
+
+/*
+ * Creates a new alg_info by parsing passed string
+ */
+enum parser_state_esp {
+ ST_INI,
+ ST_EA, /* encrypt algo */
+ ST_EA_END,
+ ST_EK, /* enc. key length */
+ ST_EK_END,
+ ST_AA, /* auth algo */
+ ST_AA_END,
+ ST_AK, /* auth. key length */
+ ST_AK_END,
+ ST_MODP, /* modp spec */
+ ST_FLAG_STRICT,
+ ST_END,
+ ST_EOF,
+ ST_ERR
+};
+
+static const char *parser_state_esp_names[] = {
+ "ST_INI",
+ "ST_EA",
+ "ST_EA_END",
+ "ST_EK",
+ "ST_EK_END",
+ "ST_AA",
+ "ST_AA_END",
+ "ST_AK",
+ "ST_AK_END",
+ "ST_MOPD",
+ "ST_FLAG_STRICT",
+ "ST_END",
+ "ST_EOF",
+ "ST_ERR"
+};
+
+static const char*
+parser_state_name_esp(enum parser_state_esp state)
+{
+ return parser_state_esp_names[state];
+}
+
+/* XXX:jjo to implement different parser for ESP and IKE */
+struct parser_context {
+ unsigned state, old_state;
+ unsigned protoid;
+ char ealg_buf[16];
+ char aalg_buf[16];
+ char modp_buf[16];
+ int (*ealg_getbyname)(const char *const str, int len);
+ int (*aalg_getbyname)(const char *const str, int len);
+ int (*modp_getbyname)(const char *const str, int len);
+ char *ealg_str;
+ char *aalg_str;
+ char *modp_str;
+ int eklen;
+ int aklen;
+ int ch;
+ const char *err;
+};
+
+static inline void
+parser_set_state(struct parser_context *p_ctx, enum parser_state_esp state)
+{
+ if (state != p_ctx->state)
+ {
+ p_ctx->old_state = p_ctx->state;
+ p_ctx->state = state;
+ }
+}
+
+static int
+parser_machine(struct parser_context *p_ctx)
+{
+ int ch = p_ctx->ch;
+
+ /* special 'absolute' cases */
+ p_ctx->err = "No error.";
+
+ /* chars that end algo strings */
+ switch (ch){
+ case 0: /* end-of-string */
+ case '!': /* flag as strict algo list */
+ case ',': /* algo string separator */
+ switch (p_ctx->state) {
+ case ST_EA:
+ case ST_EK:
+ case ST_AA:
+ case ST_AK:
+ case ST_MODP:
+ case ST_FLAG_STRICT:
+ {
+ enum parser_state_esp next_state = 0;
+
+ switch (ch) {
+ case 0:
+ next_state = ST_EOF;
+ break;
+ case ',':
+ next_state = ST_END;
+ break;
+ case '!':
+ next_state = ST_FLAG_STRICT;
+ break;
+ }
+ /* ch? parser_set_state(p_ctx, ST_END) : parser_set_state(p_ctx, ST_EOF) ; */
+ parser_set_state(p_ctx, next_state);
+ goto out;
+ }
+ default:
+ p_ctx->err = "String ended with invalid char";
+ goto err;
+ }
+ }
+re_eval:
+ switch (p_ctx->state) {
+ case ST_INI:
+ if (isspace(ch))
+ break;
+ if (isalnum(ch))
+ {
+ *(p_ctx->ealg_str++) = ch;
+ parser_set_state(p_ctx, ST_EA);
+ break;
+ }
+ p_ctx->err = "No alphanum. char initially found";
+ goto err;
+ case ST_EA:
+ if (isalpha(ch) || ch == '_')
+ {
+ *(p_ctx->ealg_str++) = ch;
+ break;
+ }
+ if (isdigit(ch))
+ {
+ /* bravely switch to enc keylen */
+ *(p_ctx->ealg_str) = 0;
+ parser_set_state(p_ctx, ST_EK);
+ goto re_eval;
+ }
+ if (ch == '-')
+ {
+ *(p_ctx->ealg_str) = 0;
+ parser_set_state(p_ctx, ST_EA_END);
+ break;
+ }
+ p_ctx->err = "No valid char found after enc alg string";
+ goto err;
+ case ST_EA_END:
+ if (isdigit(ch))
+ {
+ /* bravely switch to enc keylen */
+ parser_set_state(p_ctx, ST_EK);
+ goto re_eval;
+ }
+ if (isalpha(ch))
+ {
+ parser_set_state(p_ctx, ST_AA);
+ goto re_eval;
+ }
+ p_ctx->err = "No alphanum char found after enc alg separator";
+ goto err;
+ case ST_EK:
+ if (ch == '-')
+ {
+ parser_set_state(p_ctx, ST_EK_END);
+ break;
+ }
+ if (isdigit(ch))
+ {
+ p_ctx->eklen = p_ctx->eklen*10 + ch - '0';
+ break;
+ }
+ p_ctx->err = "Non digit or valid separator found while reading enc keylen";
+ goto err;
+ case ST_EK_END:
+ if (isalpha(ch))
+ {
+ parser_set_state(p_ctx, ST_AA);
+ goto re_eval;
+ }
+ p_ctx->err = "Non alpha char found after enc keylen end separator";
+ goto err;
+ case ST_AA:
+ if (ch == '-')
+ {
+ *(p_ctx->aalg_str++) = 0;
+ parser_set_state(p_ctx, ST_AA_END);
+ break;
+ }
+ if (isalnum(ch) || ch == '_')
+ {
+ *(p_ctx->aalg_str++) = ch;
+ break;
+ }
+ p_ctx->err = "Non alphanum or valid separator found in auth string";
+ goto err;
+ case ST_AA_END:
+ if (isdigit(ch))
+ {
+ parser_set_state(p_ctx, ST_AK);
+ goto re_eval;
+ }
+ /* Only allow modpXXXX string if we have a modp_getbyname method */
+ if ((p_ctx->modp_getbyname) && isalpha(ch))
+ {
+ parser_set_state(p_ctx, ST_MODP);
+ goto re_eval;
+ }
+ p_ctx->err = "Non initial digit found for auth keylen";
+ goto err;
+ case ST_AK:
+ if (ch=='-')
+ {
+ parser_set_state(p_ctx, ST_AK_END);
+ break;
+ }
+ if (isdigit(ch))
+ {
+ p_ctx->aklen = p_ctx->aklen*10 + ch - '0';
+ break;
+ }
+ p_ctx->err = "Non digit found for auth keylen";
+ goto err;
+ case ST_AK_END:
+ /* Only allow modpXXXX string if we have a modp_getbyname method */
+ if ((p_ctx->modp_getbyname) && isalpha(ch))
+ {
+ parser_set_state(p_ctx, ST_MODP);
+ goto re_eval;
+ }
+ p_ctx->err = "Non alpha char found after auth keylen";
+ goto err;
+ case ST_MODP:
+ if (isalnum(ch))
+ {
+ *(p_ctx->modp_str++) = ch;
+ break;
+ }
+ p_ctx->err = "Non alphanum char found after in modp string";
+ goto err;
+ case ST_FLAG_STRICT:
+ if (ch == 0)
+ parser_set_state(p_ctx, ST_END);
+ p_ctx->err = "Flags character(s) must be at end of whole string";
+ goto err;
+
+ /* XXX */
+ case ST_END:
+ case ST_EOF:
+ case ST_ERR:
+ break;
+ /* XXX */
+ }
+out:
+ return p_ctx->state;
+err:
+ parser_set_state(p_ctx, ST_ERR);
+ return ST_ERR;
+}
+
+/*
+ * Must be called for each "new" char, with new
+ * character in ctx.ch
+ */
+static void
+parser_init(struct parser_context *p_ctx, unsigned protoid)
+{
+ memset(p_ctx, 0, sizeof (*p_ctx));
+ p_ctx->protoid = protoid; /* XXX: jjo */
+ p_ctx->protoid = PROTO_IPSEC_ESP;
+ p_ctx->ealg_str = p_ctx->ealg_buf;
+ p_ctx->aalg_str = p_ctx->aalg_buf;
+ p_ctx->modp_str = p_ctx->modp_buf;
+ p_ctx->state = ST_INI;
+
+ switch (protoid) {
+#ifndef NO_PLUTO
+ case PROTO_ISAKMP:
+ p_ctx->ealg_getbyname = ealg_getbyname_ike;
+ p_ctx->aalg_getbyname = aalg_getbyname_ike;
+ p_ctx->modp_getbyname = modp_getbyname_ike;
+ break;
+#endif
+ case PROTO_IPSEC_ESP:
+ p_ctx->ealg_getbyname = ealg_getbyname_esp;
+ p_ctx->aalg_getbyname = aalg_getbyname_esp;
+ break;
+ }
+}
+
+static int
+parser_alg_info_add(struct parser_context *p_ctx, struct alg_info *alg_info)
+{
+ int ealg_id = 0;
+ int aalg_id = 0;
+ int modp_id = 0;
+#ifndef NO_PLUTO
+ const struct oakley_group_desc *gd;
+#endif
+
+ if (*p_ctx->ealg_buf)
+ {
+ ealg_id = p_ctx->ealg_getbyname(p_ctx->ealg_buf, strlen(p_ctx->ealg_buf));
+ if (ealg_id == ESP_MAGIC_ID)
+ {
+ ealg_id = p_ctx->eklen;
+ p_ctx->eklen = 0;
+ }
+ if (ealg_id < 0)
+ {
+ p_ctx->err = "enc_alg not found";
+ return -1;
+ }
+ DBG(DBG_CRYPT,
+ DBG_log("parser_alg_info_add() ealg_getbyname(\"%s\")=%d"
+ , p_ctx->ealg_buf
+ , ealg_id)
+ )
+ }
+ if (*p_ctx->aalg_buf)
+ {
+ aalg_id = p_ctx->aalg_getbyname(p_ctx->aalg_buf, strlen(p_ctx->aalg_buf));
+ if (aalg_id < 0)
+ {
+ p_ctx->err = "hash_alg not found";
+ return -1;
+ }
+ DBG(DBG_CRYPT,
+ DBG_log("parser_alg_info_add() aalg_getbyname(\"%s\")=%d"
+ , p_ctx->aalg_buf
+ , aalg_id)
+ )
+ }
+ if (p_ctx->modp_getbyname && *p_ctx->modp_buf)
+ {
+ modp_id = p_ctx->modp_getbyname(p_ctx->modp_buf, strlen(p_ctx->modp_buf));
+ if (modp_id < 0)
+ {
+ p_ctx->err = "modp group not found";
+ return -1;
+ }
+ DBG(DBG_CRYPT,
+ DBG_log("parser_alg_info_add() modp_getbyname(\"%s\")=%d"
+ , p_ctx->modp_buf
+ , modp_id)
+ )
+ }
+ switch (alg_info->alg_info_protoid) {
+ case PROTO_IPSEC_ESP:
+ alg_info_esp_add(alg_info,
+ ealg_id, p_ctx->eklen,
+ aalg_id, p_ctx->aklen);
+ break;
+#ifndef NO_PLUTO
+ case PROTO_ISAKMP:
+ if (modp_id && !(gd = lookup_group(modp_id)))
+ {
+ p_ctx->err = "found modp group id, but not supported";
+ return -1;
+ }
+ alg_info_ike_add(alg_info,
+ ealg_id, p_ctx->eklen,
+ aalg_id, p_ctx->aklen,
+ modp_id);
+ break;
+#endif
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+static int
+alg_info_parse_str (struct alg_info *alg_info, const char *alg_str, const char **err_p)
+{
+ struct parser_context ctx;
+ int ret;
+ const char *ptr;
+ static char err_buf[256];
+
+ *err_buf = 0;
+ parser_init(&ctx, alg_info->alg_info_protoid);
+ if (err_p)
+ *err_p = NULL;
+
+ /* use default if nul esp string */
+ if (!*alg_str)
+ {
+ switch (alg_info->alg_info_protoid) {
+#ifndef NO_PLUTO
+ case PROTO_ISAKMP:
+ alg_info_ike_add(alg_info, 0, 0, 0, 0, 0);
+ return 0;
+#endif
+ case PROTO_IPSEC_ESP:
+ alg_info_esp_add(alg_info, 0, 0, 0, 0);
+ return 0;
+ default:
+ /* IMPOSSIBLE */
+ passert(alg_info->alg_info_protoid);
+ }
+ }
+
+ for (ret = 0, ptr = alg_str; ret < ST_EOF;)
+ {
+ ctx.ch = *ptr++;
+ ret = parser_machine(&ctx);
+
+ switch (ret) {
+ case ST_FLAG_STRICT:
+ alg_info->alg_info_flags |= ALG_INFO_F_STRICT;
+ break;
+ case ST_END:
+ case ST_EOF:
+ DBG(DBG_CRYPT,
+ DBG_log("alg_info_parse_str() ealg_buf=%s aalg_buf=%s"
+ "eklen=%d aklen=%d",
+ ctx.ealg_buf, ctx.aalg_buf,
+ ctx.eklen, ctx.aklen)
+ )
+ if (parser_alg_info_add(&ctx, alg_info) < 0)
+ {
+ snprintf(err_buf, sizeof(err_buf),
+ "%s, enc_alg=\"%s\", auth_alg=\"%s\", modp=\"%s\"",
+ ctx.err,
+ ctx.ealg_buf,
+ ctx.aalg_buf,
+ ctx.modp_buf);
+ goto err;
+ }
+ /* zero out for next run (ST_END) */
+ parser_init(&ctx, alg_info->alg_info_protoid);
+ break;
+ case ST_ERR:
+ snprintf(err_buf, sizeof(err_buf),
+ "%s, just after \"%.*s\" (old_state=%s)",
+ ctx.err,
+ (int)(ptr-alg_str-1), alg_str ,
+ parser_state_name_esp(ctx.old_state));
+ goto err;
+ default:
+ if (!ctx.ch)
+ break;
+ }
+ }
+ return 0;
+err:
+ if (err_p)
+ *err_p=err_buf;
+ return -1;
+}
+
+struct alg_info_esp *
+alg_info_esp_create_from_str (const char *alg_str, const char **err_p)
+{
+ struct alg_info_esp *alg_info_esp;
+ char esp_buf[256];
+ static char err_buf[256];
+ char *pfs_name;
+ int ret = 0;
+ /*
+ * alg_info storage should be sized dynamically
+ * but this may require 2passes to know
+ * transform count in advance.
+ */
+ alg_info_esp = alloc_thing (struct alg_info_esp, "alg_info_esp");
+ if (!alg_info_esp)
+ goto out;
+
+ pfs_name=index (alg_str, ';');
+ if (pfs_name)
+ {
+ memcpy(esp_buf, alg_str, pfs_name-alg_str);
+ esp_buf[pfs_name-alg_str] = 0;
+ alg_str = esp_buf;
+ pfs_name++;
+
+ /* if pfs strings AND first char is not '0' */
+ if (*pfs_name && pfs_name[0] != '0')
+ {
+ ret = modp_getbyname_esp(pfs_name, strlen(pfs_name));
+ if (ret < 0)
+ {
+ /* Bomb if pfsgroup not found */
+ DBG(DBG_CRYPT,
+ DBG_log("alg_info_esp_create_from_str(): pfsgroup \"%s\" not found"
+ , pfs_name)
+ )
+ if (*err_p)
+ {
+ snprintf(err_buf, sizeof(err_buf),
+ "pfsgroup \"%s\" not found",
+ pfs_name);
+
+ *err_p = err_buf;
+ }
+ goto out;
+ }
+ alg_info_esp->esp_pfsgroup = ret;
+ }
+ }
+ else
+ alg_info_esp->esp_pfsgroup = 0;
+
+ alg_info_esp->alg_info_protoid = PROTO_IPSEC_ESP;
+ ret = alg_info_parse_str((struct alg_info *)alg_info_esp, alg_str, err_p) ;
+out:
+ if (ret < 0)
+ {
+ pfreeany(alg_info_esp);
+ alg_info_esp = NULL;
+ }
+ return alg_info_esp;
+}
+
+#ifndef NO_PLUTO
+struct alg_info_ike *
+alg_info_ike_create_from_str (const char *alg_str, const char **err_p)
+{
+ struct alg_info_ike *alg_info_ike;
+ /*
+ * alg_info storage should be sized dynamically
+ * but this may require 2passes to know
+ * transform count in advance.
+ */
+ alg_info_ike = alloc_thing (struct alg_info_ike, "alg_info_ike");
+ alg_info_ike->alg_info_protoid = PROTO_ISAKMP;
+
+ if (alg_info_parse_str((struct alg_info *)alg_info_ike,
+ alg_str, err_p) < 0)
+ {
+ pfreeany(alg_info_ike);
+ return NULL;
+ }
+ return alg_info_ike;
+}
+#endif
+
+/*
+ * alg_info struct can be shared by
+ * several connections instances,
+ * handle free() with ref_cnts
+ */
+void
+alg_info_addref(struct alg_info *alg_info)
+{
+ if (alg_info != NULL)
+ {
+ alg_info->ref_cnt++;
+ DBG(DBG_CRYPT,
+ DBG_log("alg_info_addref() alg_info->ref_cnt=%d"
+ , alg_info->ref_cnt)
+ )
+ }
+}
+
+void
+alg_info_delref(struct alg_info **alg_info_p)
+{
+ struct alg_info *alg_info = *alg_info_p;
+
+ if (alg_info != NULL)
+ {
+ passert(alg_info->ref_cnt != 0);
+ alg_info->ref_cnt--;
+ DBG(DBG_CRYPT,
+ DBG_log("alg_info_delref() alg_info->ref_cnt=%d"
+ , alg_info->ref_cnt)
+ )
+ if (alg_info->ref_cnt == 0)
+ {
+ DBG(DBG_CRYPT,
+ DBG_log("alg_info_delref() freeing alg_info")
+ )
+ alg_info_free(alg_info);
+ }
+ *alg_info_p = NULL;
+ }
+}
+
+/* snprint already parsed transform list (alg_info) */
+int
+alg_info_snprint(char *buf, int buflen, struct alg_info *alg_info)
+{
+ char *ptr = buf;
+ int np = 0;
+ struct esp_info *esp_info;
+#ifndef NO_PLUTO
+ struct ike_info *ike_info;
+#endif
+ int cnt;
+
+ switch (alg_info->alg_info_protoid) {
+ case PROTO_IPSEC_ESP:
+ {
+ struct alg_info_esp *alg_info_esp = (struct alg_info_esp *)alg_info;
+
+ ALG_INFO_ESP_FOREACH(alg_info_esp, esp_info, cnt)
+ {
+ np = snprintf(ptr, buflen, "%d_%03d-%d, "
+ , esp_info->esp_ealg_id
+ , (int)esp_info->esp_ealg_keylen
+ , esp_info->esp_aalg_id);
+ ptr += np;
+ buflen -= np;
+ if (buflen < 0)
+ goto out;
+ }
+ if (alg_info_esp->esp_pfsgroup)
+ {
+ np = snprintf(ptr, buflen, "; pfsgroup=%d; "
+ , alg_info_esp->esp_pfsgroup);
+ ptr += np;
+ buflen -= np;
+ if (buflen < 0)
+ goto out;
+ }
+ break;
+ }
+#ifndef NO_PLUTO
+ case PROTO_ISAKMP:
+ ALG_INFO_IKE_FOREACH((struct alg_info_ike *)alg_info, ike_info, cnt)
+ {
+ np = snprintf(ptr, buflen, "%d_%03d-%d-%d, "
+ , ike_info->ike_ealg
+ , (int)ike_info->ike_eklen
+ , ike_info->ike_halg
+ , ike_info->ike_modp);
+ ptr += np;
+ buflen -= np;
+ if (buflen < 0)
+ goto out;
+ }
+ break;
+#endif
+ default:
+ np = snprintf(buf, buflen, "INVALID protoid=%d\n"
+ , alg_info->alg_info_protoid);
+ ptr += np;
+ buflen -= np;
+ goto out;
+ }
+
+ np = snprintf(ptr, buflen, "%s"
+ , alg_info->alg_info_flags & ALG_INFO_F_STRICT?
+ "strict":"");
+ ptr += np;
+ buflen -= np;
+out:
+ if (buflen < 0)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "buffer space exhausted in alg_info_snprint_ike(), buflen=%d"
+ , buflen);
+ }
+
+ return ptr - buf;
+}
+
+#ifndef NO_PLUTO
+int
+alg_info_snprint_esp(char *buf, int buflen, struct alg_info_esp *alg_info)
+{
+ char *ptr = buf;
+
+ int cnt = alg_info->alg_info_cnt;
+ struct esp_info *esp_info = alg_info->esp;
+
+ while (cnt--)
+ {
+ if (kernel_alg_esp_enc_ok(esp_info->esp_ealg_id, 0, NULL)
+ && kernel_alg_esp_auth_ok(esp_info->esp_aalg_id, NULL))
+ {
+ u_int eklen = (esp_info->esp_ealg_keylen)
+ ? esp_info->esp_ealg_keylen
+ : kernel_alg_esp_enc_keylen(esp_info->esp_ealg_id)
+ * BITS_PER_BYTE;
+
+ u_int aklen = esp_info->esp_aalg_keylen
+ ? esp_info->esp_aalg_keylen
+ : kernel_alg_esp_auth_keylen(esp_info->esp_aalg_id)
+ * BITS_PER_BYTE;
+
+ int ret = snprintf(ptr, buflen, "%d_%03d-%d_%03d, ",
+ esp_info->esp_ealg_id, eklen,
+ esp_info->esp_aalg_id, aklen);
+ ptr += ret;
+ buflen -= ret;
+ if (buflen < 0)
+ break;
+ }
+ esp_info++;
+ }
+ return ptr - buf;
+}
+
+int
+alg_info_snprint_ike(char *buf, int buflen, struct alg_info_ike *alg_info)
+{
+ char *ptr = buf;
+
+ int cnt = alg_info->alg_info_cnt;
+ struct ike_info *ike_info = alg_info->ike;
+
+ while (cnt--)
+ {
+ struct encrypt_desc *enc_desc = ike_alg_get_encrypter(ike_info->ike_ealg);
+ struct hash_desc *hash_desc = ike_alg_get_hasher(ike_info->ike_halg);
+
+ if (enc_desc != NULL && hash_desc != NULL
+ && lookup_group(ike_info->ike_modp))
+ {
+
+ u_int eklen = (ike_info->ike_eklen)
+ ? ike_info->ike_eklen
+ : enc_desc->keydeflen;
+
+ u_int aklen = (ike_info->ike_hklen)
+ ? ike_info->ike_hklen
+ : hash_desc->hash_digest_size * BITS_PER_BYTE;
+
+ int ret = snprintf(ptr, buflen, "%d_%03d-%d_%03d-%d, ",
+ ike_info->ike_ealg, eklen,
+ ike_info->ike_halg, aklen,
+ ike_info->ike_modp);
+ ptr += ret;
+ buflen -= ret;
+ if (buflen < 0)
+ break;
+ }
+ ike_info++;
+ }
+ return ptr - buf;
+}
+#endif /* NO_PLUTO */
diff --git a/src/pluto/alg_info.h b/src/pluto/alg_info.h
new file mode 100644
index 000000000..cd2011dcc
--- /dev/null
+++ b/src/pluto/alg_info.h
@@ -0,0 +1,85 @@
+/* Algorithm info parsing and creation functions
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: alg_info.h,v 1.4 2004/09/29 22:39:44 as Exp $
+ */
+
+#ifndef ALG_INFO_H
+#define ALG_INFO_H
+
+struct esp_info {
+ u_int8_t transid; /* ESP transform */
+ u_int16_t auth; /* AUTH */
+ size_t enckeylen; /* keylength for ESP transform */
+ size_t authkeylen; /* keylength for AUTH */
+ u_int8_t encryptalg; /* normally encryptalg=transid */
+ u_int8_t authalg; /* normally authalg=auth+1 */
+};
+
+struct ike_info {
+ u_int16_t ike_ealg; /* high 16 bit nums for reserved */
+ u_int8_t ike_halg;
+ size_t ike_eklen;
+ size_t ike_hklen;
+ u_int16_t ike_modp;
+};
+
+#define ALG_INFO_COMMON \
+ int alg_info_cnt; \
+ int ref_cnt; \
+ unsigned alg_info_flags; \
+ unsigned alg_info_protoid
+
+struct alg_info {
+ ALG_INFO_COMMON;
+};
+
+struct alg_info_esp {
+ ALG_INFO_COMMON;
+ struct esp_info esp[64];
+ int esp_pfsgroup;
+};
+
+struct alg_info_ike {
+ ALG_INFO_COMMON;
+ struct ike_info ike[64];
+};
+#define esp_ealg_id transid
+#define esp_aalg_id auth
+#define esp_ealg_keylen enckeylen /* bits */
+#define esp_aalg_keylen authkeylen /* bits */
+
+/* alg_info_flags bits */
+#define ALG_INFO_F_STRICT 0x01
+
+extern int alg_info_esp_aa2sadb(int auth);
+extern int alg_info_esp_sadb2aa(int sadb_aalg);
+extern void alg_info_free(struct alg_info *alg_info);
+extern void alg_info_addref(struct alg_info *alg_info);
+extern void alg_info_delref(struct alg_info **alg_info);
+extern struct alg_info_esp* alg_info_esp_create_from_str(const char *alg_str
+ , const char **err_p);
+extern struct alg_info_ike* alg_info_ike_create_from_str(const char *alg_str
+ , const char **err_p);
+extern int alg_info_parse(const char *str);
+extern int alg_info_snprint(char *buf, int buflen
+ , struct alg_info *alg_info);
+extern int alg_info_snprint_esp(char *buf, int buflen
+ , struct alg_info_esp *alg_info);
+extern int alg_info_snprint_ike(char *buf, int buflen
+ , struct alg_info_ike *alg_info);
+#define ALG_INFO_ESP_FOREACH(ai, ai_esp, i) \
+ for (i=(ai)->alg_info_cnt,ai_esp=(ai)->esp; i--; ai_esp++)
+#define ALG_INFO_IKE_FOREACH(ai, ai_ike, i) \
+ for (i=(ai)->alg_info_cnt,ai_ike=(ai)->ike; i--; ai_ike++)
+#endif /* ALG_INFO_H */
diff --git a/src/pluto/asn1.c b/src/pluto/asn1.c
new file mode 100644
index 000000000..0663bc490
--- /dev/null
+++ b/src/pluto/asn1.c
@@ -0,0 +1,770 @@
+/* Simple ASN.1 parser
+ * Copyright (C) 2000-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.
+ *
+ * RCSID $Id: asn1.c,v 1.16 2006/01/04 21:00:43 as Exp $
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "mp_defs.h"
+#include "asn1.h"
+#include "oid.h"
+#include "log.h"
+
+/* 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 = strchunk(ASN1_INTEGER_0_str);
+const chunk_t ASN1_INTEGER_1 = strchunk(ASN1_INTEGER_1_str);
+const chunk_t ASN1_INTEGER_2 = strchunk(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 = strchunk(ASN1_md5_id_str);
+const chunk_t ASN1_sha1_id = strchunk(ASN1_sha1_id_str);
+const chunk_t ASN1_rsaEncryption_id = strchunk(ASN1_rsaEncryption_id_str);
+const chunk_t ASN1_md5WithRSA_id = strchunk(ASN1_md5WithRSA_id_str);
+const chunk_t ASN1_sha1WithRSA_id = strchunk(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 empty_chunk;
+ }
+}
+
+/* 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)
+ {
+ DBG(DBG_PARSING,
+ DBG_log("number of length octets is larger than ASN.1 object")
+ )
+ return ASN1_INVALID_LENGTH;
+ }
+
+ if (n > sizeof(len))
+ {
+ DBG(DBG_PARSING,
+ DBG_log("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;
+}
+
+/*
+ * 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 = alloc_bytes(object->len, "asn1 object");
+
+ /* 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 */
+ chunkcpy(pos, length);
+
+ 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);
+ chunkcpy(pos, content);
+
+ 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':
+ mv_chunk(&pos, ch);
+ break;
+ case 'c':
+ default:
+ chunkcpy(pos, ch);
+ }
+ }
+ 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 */
+ size_t size = 1 + bits / BITS_PER_BYTE; /* size in bytes */
+ chunk_t n = mpz_to_n(value, size);
+
+ return asn1_wrap(ASN1_INTEGER, "m", n);
+}
+
+/*
+ * 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;
+}
+
+/*
+ * 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;
+}
+
+/*
+ * 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);
+}
+
+
+/*
+ * Initializes the internal context of the ASN.1 parser
+ */
+void
+asn1_init(asn1_ctx_t *ctx, chunk_t blob, u_int level0,
+ bool implicit, u_int cond)
+{
+ ctx->blobs[0] = blob;
+ ctx->level0 = level0;
+ ctx->implicit = implicit;
+ ctx->cond = cond;
+ 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, u_int cond)
+{
+ int oid;
+
+ switch (type)
+ {
+ case ASN1_OID:
+ oid = known_oid(object);
+ if (oid != OID_UNKNOWN)
+ {
+ DBG(DBG_PARSING,
+ DBG_log(" '%s'",oid_names[oid].name);
+ )
+ return;
+ }
+ break;
+ case ASN1_UTF8STRING:
+ case ASN1_IA5STRING:
+ case ASN1_PRINTABLESTRING:
+ case ASN1_T61STRING:
+ case ASN1_VISIBLESTRING:
+ DBG(DBG_PARSING,
+ DBG_log(" '%.*s'", (int)object.len, object.ptr);
+ )
+ return;
+ case ASN1_UTCTIME:
+ case ASN1_GENERALIZEDTIME:
+ DBG(DBG_PARSING,
+ time_t time = asn1totime(&object, type);
+ DBG_log(" '%s'", timetoa(&time, TRUE));
+ )
+ return;
+ default:
+ break;
+ }
+ DBG(cond,
+ DBG_dump_chunk("", 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 = empty_chunk;
+
+ 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 */
+ DBG(DBG_PARSING,
+ DBG_log("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)
+ {
+ DBG(DBG_PARSING,
+ DBG_log("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)
+ {
+ DBG(DBG_PARSING,
+ DBG_log("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)
+ {
+ DBG(DBG_PARSING,
+ DBG_log("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))
+ {
+ DBG(DBG_PARSING,
+ DBG_log("L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x",
+ *level, obj.name, obj.type, *start_ptr);
+ DBG_dump("", start_ptr, (u_int)(blob->ptr - start_ptr));
+ )
+ return FALSE;
+ }
+
+ DBG(DBG_PARSING,
+ DBG_log("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);
+ DBG(ctx->cond,
+ DBG_dump_chunk("", *object);
+ )
+ }
+ else if (obj.flags & ASN1_BODY)
+ {
+ *object = *blob1;
+ debug_asn1_simple_object(*object, obj.type, ctx->cond);
+ }
+ 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)
+ {
+ DBG(DBG_PARSING,
+ DBG_log("L%d - %s: ASN.1 object smaller than 2 octets",
+ level, name);
+ )
+ return FALSE;
+ }
+
+ if (*object->ptr != type)
+ {
+ DBG(DBG_PARSING,
+ DBG_log("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)
+ {
+ DBG(DBG_PARSING,
+ DBG_log("L%d - %s: length of ASN.1 object invalid or too large",
+ level, name);
+ )
+ return FALSE;
+ }
+
+ DBG(DBG_PARSING,
+ DBG_log("L%d - %s:", level, name);
+ )
+ debug_asn1_simple_object(*object, type, DBG_RAW);
+ 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, DBG_RAW);
+
+ 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)
+ {
+ DBG(DBG_PARSING,
+ DBG_log(" file content is not binary ASN.1");
+ )
+ return FALSE;
+ }
+ len = asn1_length(&blob);
+ if (len != blob.len)
+ {
+ DBG(DBG_PARSING,
+ DBG_log(" file size does not match ASN.1 coded length");
+ )
+ return FALSE;
+ }
+ return TRUE;
+}
diff --git a/src/pluto/asn1.h b/src/pluto/asn1.h
new file mode 100644
index 000000000..2a3fb3e9e
--- /dev/null
+++ b/src/pluto/asn1.h
@@ -0,0 +1,141 @@
+/* Simple ASN.1 parser
+ * Copyright (C) 2000-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.
+ *
+ * RCSID $Id: asn1.h,v 1.14 2005/12/06 22:50:10 as Exp $
+ */
+
+#ifndef _ASN1_H
+#define _ASN1_H
+
+#include <stdarg.h>
+#include <gmp.h>
+
+#include "defs.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 cond;
+ 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;
+
+extern chunk_t asn1_algorithmIdentifier(int oid);
+extern int known_oid(chunk_t object);
+extern u_int asn1_length(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 bool is_printablestring(chunk_t str);
+extern time_t asn1totime(const chunk_t *utctime, asn1_t type);
+extern chunk_t timetoasn1(const time_t *time, asn1_t type);
+extern void asn1_init(asn1_ctx_t *ctx, chunk_t blob
+ , u_int level0, bool implicit, u_int cond);
+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);
+
+#endif /* _ASN1_H */
+
diff --git a/src/pluto/ca.c b/src/pluto/ca.c
new file mode 100644
index 000000000..d1be22e2f
--- /dev/null
+++ b/src/pluto/ca.c
@@ -0,0 +1,694 @@
+/* Certification Authority (CA) support for IKE authentication
+ * Copyright (C) 2002-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.
+ *
+ * RCSID $Id: ca.c,v 1.10 2005/12/25 12:29:55 as Exp $
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <time.h>
+#include <sys/types.h>
+
+#include <freeswan.h>
+#include <ipsec_policy.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "x509.h"
+#include "ca.h"
+#include "certs.h"
+#include "whack.h"
+#include "fetch.h"
+
+/* chained list of X.509 authority certificates (ca, aa, and ocsp) */
+
+static x509cert_t *x509authcerts = NULL;
+
+const ca_info_t empty_ca_info = {
+ NULL , /* next */
+ NULL , /* name */
+ UNDEFINED_TIME,
+ { NULL, 0 } , /* authName */
+ { NULL, 0 } , /* authKeyID */
+ { NULL, 0 } , /* authKey SerialNumber */
+ NULL , /* ldaphost */
+ NULL , /* ldapbase */
+ NULL , /* ocspori */
+ NULL , /* crluri */
+ FALSE /* strictcrlpolicy */
+};
+
+/* chained list of X.509 certification authority information records */
+
+static ca_info_t *ca_infos = NULL;
+
+/*
+ * Checks if CA a is trusted by CA b
+ */
+bool
+trusted_ca(chunk_t a, chunk_t b, int *pathlen)
+{
+ bool match = FALSE;
+
+ /* no CA b specified -> any CA a is accepted */
+ if (b.ptr == NULL)
+ {
+ *pathlen = (a.ptr == NULL)? 0 : MAX_CA_PATH_LEN;
+ return TRUE;
+ }
+
+ /* no CA a specified -> trust cannot be established */
+ if (a.ptr == NULL)
+ {
+ *pathlen = MAX_CA_PATH_LEN;
+ return FALSE;
+ }
+
+ *pathlen = 0;
+
+ /* CA a equals CA b -> we have a match */
+ if (same_dn(a, b))
+ return TRUE;
+
+ /* CA a might be a subordinate CA of b */
+ lock_authcert_list("trusted_ca");
+
+ while ((*pathlen)++ < MAX_CA_PATH_LEN)
+ {
+ x509cert_t *cacert = get_authcert(a, empty_chunk, empty_chunk, AUTH_CA);
+
+ /* cacert not found or self-signed root cacert-> exit */
+ if (cacert == NULL || same_dn(cacert->issuer, a))
+ break;
+
+ /* does the issuer of CA a match CA b? */
+ match = same_dn(cacert->issuer, b);
+
+ /* we have a match and exit the loop */
+ if (match)
+ break;
+
+ /* go one level up in the CA chain */
+ a = cacert->issuer;
+ }
+
+ unlock_authcert_list("trusted_ca");
+ return match;
+}
+
+/*
+ * does our CA match one of the requested CAs?
+ */
+bool
+match_requested_ca(generalName_t *requested_ca, chunk_t our_ca, int *our_pathlen)
+{
+ /* if no ca is requested than any ca will match */
+ if (requested_ca == NULL)
+ {
+ *our_pathlen = 0;
+ return TRUE;
+ }
+
+ *our_pathlen = MAX_CA_PATH_LEN + 1;
+
+ while (requested_ca != NULL)
+ {
+ int pathlen;
+
+ if (trusted_ca(our_ca, requested_ca->name, &pathlen)
+ && pathlen < *our_pathlen)
+ *our_pathlen = pathlen;
+ requested_ca = requested_ca->next;
+ }
+
+ return *our_pathlen <= MAX_CA_PATH_LEN;
+}
+
+/*
+ * free the first authority certificate in the chain
+ */
+static void
+free_first_authcert(void)
+{
+ x509cert_t *first = x509authcerts;
+ x509authcerts = first->next;
+ free_x509cert(first);
+}
+
+/*
+ * free all CA certificates
+ */
+void
+free_authcerts(void)
+{
+ lock_authcert_list("free_authcerts");
+
+ while (x509authcerts != NULL)
+ free_first_authcert();
+
+ unlock_authcert_list("free_authcerts");
+}
+
+/*
+ * get a X.509 authority certificate with a given subject or keyid
+ */
+x509cert_t*
+get_authcert(chunk_t subject, chunk_t serial, chunk_t keyid, u_char auth_flags)
+{
+ x509cert_t *cert = x509authcerts;
+ x509cert_t *prev_cert = NULL;
+
+ while (cert != NULL)
+ {
+ if (cert->authority_flags & auth_flags
+ && ((keyid.ptr != NULL) ? same_keyid(keyid, cert->subjectKeyID)
+ : (same_dn(subject, cert->subject)
+ && same_serial(serial, cert->serialNumber))))
+ {
+ if (cert != x509authcerts)
+ {
+ /* bring the certificate up front */
+ prev_cert->next = cert->next;
+ cert->next = x509authcerts;
+ x509authcerts = cert;
+ }
+ return cert;
+ }
+ prev_cert = cert;
+ cert = cert->next;
+ }
+ return NULL;
+}
+
+/*
+ * add an authority certificate to the chained list
+ */
+bool
+add_authcert(x509cert_t *cert, u_char auth_flags)
+{
+ x509cert_t *old_cert;
+
+ /* set authority flags */
+ cert->authority_flags |= auth_flags;
+
+ lock_authcert_list("add_authcert");
+
+ old_cert = get_authcert(cert->subject, cert->serialNumber
+ , cert->subjectKeyID, auth_flags);
+
+ if (old_cert != NULL)
+ {
+ if (same_x509cert(cert, old_cert))
+ {
+ /* cert is already present, just add additional authority flags */
+ old_cert->authority_flags |= cert->authority_flags;
+ DBG(DBG_CONTROL | DBG_PARSING ,
+ DBG_log(" authcert is already present and identical")
+ )
+ unlock_authcert_list("add_authcert");
+
+ free_x509cert(cert);
+ return FALSE;
+ }
+ else
+ {
+ /* cert is already present but will be replaced by new cert */
+ free_first_authcert();
+ DBG(DBG_CONTROL | DBG_PARSING ,
+ DBG_log(" existing authcert deleted")
+ )
+ }
+ }
+
+ /* add new authcert to chained list */
+ cert->next = x509authcerts;
+ x509authcerts = cert;
+ share_x509cert(cert); /* set count to one */
+ DBG(DBG_CONTROL | DBG_PARSING,
+ DBG_log(" authcert inserted")
+ )
+ unlock_authcert_list("add_authcert");
+ return TRUE;
+}
+
+/*
+ * Loads authority certificates
+ */
+void
+load_authcerts(const char *type, const char *path, u_char auth_flags)
+{
+ struct dirent **filelist;
+ u_char buf[BUF_LEN];
+ u_char *save_dir;
+ int n;
+
+ /* change directory to specified path */
+ save_dir = getcwd(buf, BUF_LEN);
+
+ if (chdir(path))
+ {
+ plog("Could not change to directory '%s'", path);
+ }
+ else
+ {
+ plog("Changing to directory '%s'", path);
+ n = scandir(path, &filelist, file_select, alphasort);
+
+ if (n < 0)
+ plog(" scandir() error");
+ else
+ {
+ while (n--)
+ {
+ cert_t cert;
+
+ if (load_cert(filelist[n]->d_name, type, &cert))
+ add_authcert(cert.u.x509, auth_flags);
+
+ free(filelist[n]);
+ }
+ free(filelist);
+ }
+ }
+ /* restore directory path */
+ chdir(save_dir);
+}
+
+/*
+ * list all X.509 authcerts with given auth flags in a chained list
+ */
+void
+list_authcerts(const char *caption, u_char auth_flags, bool utc)
+{
+ lock_authcert_list("list_authcerts");
+ list_x509cert_chain(caption, x509authcerts, auth_flags, utc);
+ unlock_authcert_list("list_authcerts");
+}
+
+/*
+ * get a cacert with a given subject or keyid from an alternative list
+ */
+static const x509cert_t*
+get_alt_cacert(chunk_t subject, chunk_t serial, chunk_t keyid
+ , const x509cert_t *cert)
+{
+ while (cert != NULL)
+ {
+ if ((keyid.ptr != NULL) ? same_keyid(keyid, cert->subjectKeyID)
+ : (same_dn(subject, cert->subject)
+ && same_serial(serial, cert->serialNumber)))
+ {
+ return cert;
+ }
+ cert = cert->next;
+ }
+ return NULL;
+}
+
+/* establish trust into a candidate authcert by going up the trust chain.
+ * validity and revocation status are not checked.
+ */
+bool
+trust_authcert_candidate(const x509cert_t *cert, const x509cert_t *alt_chain)
+{
+ int pathlen;
+
+ lock_authcert_list("trust_authcert_candidate");
+
+ for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++)
+ {
+ const x509cert_t *authcert = NULL;
+ u_char buf[BUF_LEN];
+
+ DBG(DBG_CONTROL,
+ dntoa(buf, BUF_LEN, cert->subject);
+ DBG_log("subject: '%s'",buf);
+ dntoa(buf, BUF_LEN, cert->issuer);
+ DBG_log("issuer: '%s'",buf);
+ if (cert->authKeyID.ptr != NULL)
+ {
+ datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':'
+ , buf, BUF_LEN);
+ DBG_log("authkey: %s", buf);
+ }
+ )
+
+ /* search in alternative chain first */
+ authcert = get_alt_cacert(cert->issuer, cert->authKeySerialNumber
+ , cert->authKeyID, alt_chain);
+
+ if (authcert != NULL)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("issuer cacert found in alternative chain")
+ )
+ }
+ else
+ {
+ /* search in trusted chain */
+ authcert = get_authcert(cert->issuer, cert->authKeySerialNumber
+ , cert->authKeyID, AUTH_CA);
+
+ if (authcert != NULL)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("issuer cacert found")
+ )
+ }
+ else
+ {
+ plog("issuer cacert not found");
+ unlock_authcert_list("trust_authcert_candidate");
+ return FALSE;
+ }
+ }
+
+ if (!check_signature(cert->tbsCertificate, cert->signature
+ , cert->algorithm, cert->algorithm, authcert))
+ {
+ plog("certificate signature is invalid");
+ unlock_authcert_list("trust_authcert_candidate");
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("certificate signature is valid")
+ )
+
+ /* check if cert is a self-signed root ca */
+ if (pathlen > 0 && same_dn(cert->issuer, cert->subject))
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("reached self-signed root ca")
+ )
+ unlock_authcert_list("trust_authcert_candidate");
+ return TRUE;
+ }
+
+ /* go up one step in the trust chain */
+ cert = authcert;
+ }
+ plog("maximum ca path length of %d levels exceeded", MAX_CA_PATH_LEN);
+ unlock_authcert_list("trust_authcert_candidate");
+ return FALSE;
+}
+
+/*
+ * get a CA info record with a given authName or authKeyID
+ */
+ca_info_t*
+get_ca_info(chunk_t authname, chunk_t serial, chunk_t keyid)
+{
+ ca_info_t *ca= ca_infos;
+
+ while (ca!= NULL)
+ {
+ if ((keyid.ptr != NULL) ? same_keyid(keyid, ca->authKeyID)
+ : (same_dn(authname, ca->authName)
+ && same_serial(serial, ca->authKeySerialNumber)))
+ {
+ return ca;
+ }
+ ca = ca->next;
+ }
+ return NULL;
+}
+
+
+/*
+ * free the dynamic memory used by a ca_info record
+ */
+static void
+free_ca_info(ca_info_t* ca_info)
+{
+ if (ca_info == NULL)
+ return;
+
+ pfreeany(ca_info->name);
+ pfreeany(ca_info->ldaphost);
+ pfreeany(ca_info->ldapbase);
+ pfreeany(ca_info->ocspuri);
+
+ freeanychunk(ca_info->authName);
+ freeanychunk(ca_info->authKeyID);
+ freeanychunk(ca_info->authKeySerialNumber);
+
+ free_generalNames(ca_info->crluri, TRUE);
+
+ pfree(ca_info);
+}
+
+/*
+ * free all CA certificates
+ */
+void
+free_ca_infos(void)
+{
+ while (ca_infos != NULL)
+ {
+ ca_info_t *ca = ca_infos;
+
+ ca_infos = ca_infos->next;
+ free_ca_info(ca);
+ }
+}
+
+/*
+ * find a CA information record by name and optionally delete it
+ */
+bool
+find_ca_info_by_name(const char *name, bool delete)
+{
+ ca_info_t **ca_p = &ca_infos;
+ ca_info_t *ca = *ca_p;
+
+ while (ca != NULL)
+ {
+ /* is there already an entry? */
+ if (streq(name, ca->name))
+ {
+ if (delete)
+ {
+ lock_ca_info_list("find_ca_info_by_name");
+ *ca_p = ca->next;
+ free_ca_info(ca);
+ plog("deleting ca description \"%s\"", name);
+ unlock_ca_info_list("find_ca_info_by_name");
+ }
+ return TRUE;
+ }
+ ca_p = &ca->next;
+ ca = *ca_p;
+ }
+ return FALSE;
+}
+
+
+ /*
+ * adds a CA description to a chained list
+ */
+void
+add_ca_info(const whack_message_t *msg)
+{
+ smartcard_t *sc = NULL;
+ cert_t cert;
+ bool valid_cert = FALSE;
+ bool cached_cert = FALSE;
+
+ if (find_ca_info_by_name(msg->name, FALSE))
+ {
+ loglog(RC_DUPNAME, "attempt to redefine ca record \"%s\"", msg->name);
+ return;
+ }
+
+ if (scx_on_smartcard(msg->cacert))
+ {
+ /* load CA cert from smartcard */
+ valid_cert = scx_load_cert(msg->cacert, &sc, &cert, &cached_cert);
+ }
+ else
+ {
+ /* load CA cert from file */
+ valid_cert = load_ca_cert(msg->cacert, &cert);
+ }
+
+ if (valid_cert)
+ {
+ char buf[BUF_LEN];
+ x509cert_t *cacert = cert.u.x509;
+ ca_info_t *ca = NULL;
+
+ /* does the authname already exist? */
+ ca = get_ca_info(cacert->subject, cacert->serialNumber
+ , cacert->subjectKeyID);
+
+ if (ca != NULL)
+ {
+ /* ca_info is already present */
+ loglog(RC_DUPNAME, " duplicate ca information in record \"%s\" found,"
+ "ignoring \"%s\"", ca->name, msg->name);
+ free_x509cert(cacert);
+ return;
+ }
+
+ plog("added ca description \"%s\"", msg->name);
+
+ /* create and initialize new ca_info record */
+ ca = alloc_thing(ca_info_t, "ca info");
+ *ca = empty_ca_info;
+
+ /* name */
+ ca->name = clone_str(msg->name, "ca name");
+
+ /* authName */
+ clonetochunk(ca->authName, cacert->subject.ptr
+ , cacert->subject.len, "authName");
+ dntoa(buf, BUF_LEN, ca->authName);
+ DBG(DBG_CONTROL,
+ DBG_log("authname: '%s'", buf)
+ )
+
+ /* authSerialNumber */
+ clonetochunk(ca->authKeySerialNumber, cacert->serialNumber.ptr
+ , cacert->serialNumber.len, "authKeySerialNumber");
+
+ /* authKeyID */
+ if (cacert->subjectKeyID.ptr != NULL)
+ {
+ clonetochunk(ca->authKeyID, cacert->subjectKeyID.ptr
+ , cacert->subjectKeyID.len, "authKeyID");
+ datatot(cacert->subjectKeyID.ptr, cacert->subjectKeyID.len, ':'
+ , buf, BUF_LEN);
+ DBG(DBG_CONTROL | DBG_PARSING ,
+ DBG_log("authkey: %s", buf)
+ )
+ }
+
+ /* ldaphost */
+ ca->ldaphost = clone_str(msg->ldaphost, "ldaphost");
+
+ /* ldapbase */
+ ca->ldapbase = clone_str(msg->ldapbase, "ldapbase");
+
+ /* ocspuri */
+ if (msg->ocspuri != NULL)
+ {
+ if (strncasecmp(msg->ocspuri, "http", 4) == 0)
+ ca->ocspuri = clone_str(msg->ocspuri, "ocspuri");
+ else
+ plog(" ignoring ocspuri with unkown protocol");
+ }
+
+ /* crluri2*/
+ if (msg->crluri2 != NULL)
+ {
+ generalName_t gn =
+ { NULL, GN_URI, {msg->crluri2, strlen(msg->crluri2)} };
+
+ add_distribution_points(&gn, &ca->crluri);
+ }
+
+ /* crluri */
+ if (msg->crluri != NULL)
+ {
+ generalName_t gn =
+ { NULL, GN_URI, {msg->crluri, strlen(msg->crluri)} };
+
+ add_distribution_points(&gn, &ca->crluri);
+ }
+
+ /* strictrlpolicy */
+ ca->strictcrlpolicy = msg->whack_strict;
+
+ /* insert ca_info record into the chained list */
+ lock_ca_info_list("add_ca_info");
+
+ ca->next = ca_infos;
+ ca_infos = ca;
+ ca->installed = time(NULL);
+
+ unlock_ca_info_list("add_ca_info");
+
+ /* add cacert to list of authcerts */
+ if (!cached_cert)
+ {
+ if (add_authcert(cacert, AUTH_CA) && sc != NULL)
+ {
+ if (sc->last_cert.type == CERT_X509_SIGNATURE)
+ sc->last_cert.u.x509->count--;
+ sc->last_cert = cert;
+ share_cert(sc->last_cert);
+ }
+ }
+ if (sc != NULL)
+ time(&sc->last_load);
+ }
+}
+
+/*
+ * list all ca_info records in the chained list
+ */
+void
+list_ca_infos(bool utc)
+{
+ ca_info_t *ca = ca_infos;
+
+ if (ca != NULL)
+ {
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of X.509 CA Information Records:");
+ whack_log(RC_COMMENT, " ");
+ }
+
+ while (ca != NULL)
+ {
+ u_char buf[BUF_LEN];
+
+ /* strictpolicy per CA not supported yet
+ *
+ whack_log(RC_COMMENT, "%s, \"%s\", strictcrlpolicy: %s"
+ , timetoa(&ca->installed, utc), ca->name
+ , ca->strictcrlpolicy? "yes":"no");
+ */
+ whack_log(RC_COMMENT, "%s, \"%s\"", timetoa(&ca->installed, utc), ca->name);
+ dntoa(buf, BUF_LEN, ca->authName);
+ whack_log(RC_COMMENT, " authname: '%s'", buf);
+ if (ca->ldaphost != NULL)
+ whack_log(RC_COMMENT, " ldaphost: '%s'", ca->ldaphost);
+ if (ca->ldapbase != NULL)
+ whack_log(RC_COMMENT, " ldapbase: '%s'", ca->ldapbase);
+ if (ca->ocspuri != NULL)
+ whack_log(RC_COMMENT, " ocspuri: '%s'", ca->ocspuri);
+
+ list_distribution_points(ca->crluri);
+
+ if (ca->authKeyID.ptr != NULL)
+ {
+ datatot(ca->authKeyID.ptr, ca->authKeyID.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " authkey: %s", buf);
+ }
+ if (ca->authKeySerialNumber.ptr != NULL)
+ {
+ datatot(ca->authKeySerialNumber.ptr, ca->authKeySerialNumber.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " aserial: %s", buf);
+ }
+ ca = ca->next;
+ }
+}
+
+
diff --git a/src/pluto/ca.h b/src/pluto/ca.h
new file mode 100644
index 000000000..8d4602dc6
--- /dev/null
+++ b/src/pluto/ca.h
@@ -0,0 +1,70 @@
+/* Certification Authority (CA) support for IKE authentication
+ * Copyright (C) 2002-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.
+ *
+ * RCSID $Id: ca.h,v 1.5 2005/12/25 12:28:40 as Exp $
+ */
+
+#ifndef _CA_H
+#define _CA_H
+
+#include "x509.h"
+#include "whack.h"
+
+#define MAX_CA_PATH_LEN 7
+
+/* authority flags */
+
+#define AUTH_NONE 0x00 /* no authorities */
+#define AUTH_CA 0x01 /* certification authority */
+#define AUTH_AA 0x02 /* authorization authority */
+#define AUTH_OCSP 0x04 /* ocsp signing authority */
+
+/* CA info structures */
+
+typedef struct ca_info ca_info_t;
+
+struct ca_info {
+ ca_info_t *next;
+ char *name;
+ time_t installed;
+ chunk_t authName;
+ chunk_t authKeyID;
+ chunk_t authKeySerialNumber;
+ char *ldaphost;
+ char *ldapbase;
+ char *ocspuri;
+ generalName_t *crluri;
+ bool strictcrlpolicy;
+};
+
+extern bool trusted_ca(chunk_t a, chunk_t b, int *pathlen);
+extern bool match_requested_ca(generalName_t *requested_ca
+ , chunk_t our_ca, int *our_pathlen);
+extern x509cert_t* get_authcert(chunk_t subject, chunk_t serial, chunk_t keyid
+ , u_char auth_flags);
+extern void load_authcerts(const char *type, const char *path
+ , u_char auth_flags);
+extern bool add_authcert(x509cert_t *cert, u_char auth_flags);
+extern void free_authcerts(void);
+extern void list_authcerts(const char *caption, u_char auth_flags, bool utc);
+extern bool trust_authcert_candidate(const x509cert_t *cert
+ , const x509cert_t *alt_chain);
+extern ca_info_t* get_ca_info(chunk_t name, chunk_t serial, chunk_t keyid);
+extern bool find_ca_info_by_name(const char *name, bool delete);
+extern void add_ca_info(const whack_message_t *msg);
+extern void delete_ca_info(const char *name);
+extern void free_ca_infos(void);
+extern void list_ca_infos(bool utc);
+
+#endif /* _CA_H */
+
diff --git a/src/pluto/certs.c b/src/pluto/certs.c
new file mode 100644
index 000000000..779646a98
--- /dev/null
+++ b/src/pluto/certs.c
@@ -0,0 +1,287 @@
+/* Certificate support for IKE authentication
+ * Copyright (C) 2002-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.
+ *
+ * RCSID $Id: certs.c,v 1.8 2005/11/06 22:55:41 as Exp $
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <freeswan.h>
+#include <ipsec_policy.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "asn1.h"
+#include "id.h"
+#include "x509.h"
+#include "pgp.h"
+#include "pem.h"
+#include "certs.h"
+#include "pkcs1.h"
+
+/*
+ * used for initializatin of certs
+ */
+const cert_t empty_cert = {CERT_NONE, {NULL}};
+
+/*
+ * extracts the certificate to be sent to the peer
+ */
+chunk_t
+get_mycert(cert_t cert)
+{
+ switch (cert.type)
+ {
+ case CERT_PGP:
+ return cert.u.pgp->certificate;
+ case CERT_X509_SIGNATURE:
+ return cert.u.x509->certificate;
+ default:
+ return empty_chunk;
+ }
+}
+
+/* load a coded key or certificate file with autodetection
+ * of binary DER or base64 PEM ASN.1 formats and armored PGP format
+ */
+bool
+load_coded_file(const char *filename, prompt_pass_t *pass, const char *type
+, chunk_t *blob, bool *pgp)
+{
+ err_t ugh = NULL;
+
+ FILE *fd = fopen(filename, "r");
+
+ if (fd)
+ {
+ int bytes;
+ fseek(fd, 0, SEEK_END );
+ blob->len = ftell(fd);
+ rewind(fd);
+ blob->ptr = alloc_bytes(blob->len, type);
+ bytes = fread(blob->ptr, 1, blob->len, fd);
+ fclose(fd);
+ plog(" loaded %s file '%s' (%d bytes)", type, filename, bytes);
+
+ *pgp = FALSE;
+
+ /* try DER format */
+ if (is_asn1(*blob))
+ {
+ DBG(DBG_PARSING,
+ DBG_log(" file coded in DER format");
+ )
+ return TRUE;
+ }
+
+ /* try PEM format */
+ ugh = pemtobin(blob, pass, filename, pgp);
+
+ if (ugh == NULL)
+ {
+ if (*pgp)
+ {
+ DBG(DBG_PARSING,
+ DBG_log(" file coded in armored PGP format");
+ )
+ return TRUE;
+ }
+ if (is_asn1(*blob))
+ {
+ DBG(DBG_PARSING,
+ DBG_log(" file coded in PEM format");
+ )
+ return TRUE;
+ }
+ ugh = "file coded in unknown format, discarded";
+ }
+
+ /* a conversion error has occured */
+ plog(" %s", ugh);
+ pfree(blob->ptr);
+ *blob = empty_chunk;
+ }
+ else
+ {
+ plog(" could not open %s file '%s'", type, filename);
+ }
+ return FALSE;
+}
+
+/*
+ * Loads a PKCS#1 or PGP private RSA key file
+ */
+err_t
+load_rsa_private_key(const char* filename, prompt_pass_t *pass
+, RSA_private_key_t *key)
+{
+ err_t ugh = NULL;
+ bool pgp = FALSE;
+ chunk_t blob = empty_chunk;
+
+ const char *path = concatenate_paths(PRIVATE_KEY_PATH, filename);
+
+ if (load_coded_file(path, pass, "private key", &blob, &pgp))
+ {
+ if (pgp)
+ {
+ if (!parse_pgp(blob, NULL, key))
+ ugh = "syntax error in PGP private key file";
+ }
+ else
+ {
+ if (!pkcs1_parse_private_key(blob, key))
+ ugh = "syntax error in PKCS#1 private key file";
+ }
+ pfree(blob.ptr);
+ }
+ else
+ ugh = "error loading RSA private key file";
+
+ return ugh;
+}
+/*
+ * Loads a X.509 or OpenPGP certificate
+ */
+bool
+load_cert(const char *filename, const char *label, cert_t *cert)
+{
+ bool pgp = FALSE;
+ chunk_t blob = empty_chunk;
+
+ /* initialize cert struct */
+ cert->type = CERT_NONE;
+ cert->u.x509 = NULL;
+
+ if (load_coded_file(filename, NULL, label, &blob, &pgp))
+ {
+ if (pgp)
+ {
+ pgpcert_t *pgpcert = alloc_thing(pgpcert_t, "pgpcert");
+ *pgpcert = empty_pgpcert;
+ if (parse_pgp(blob, pgpcert, NULL))
+ {
+ cert->type = CERT_PGP;
+ cert->u.pgp = pgpcert;
+ return TRUE;
+ }
+ else
+ {
+ plog(" error in OpenPGP certificate");
+ free_pgpcert(pgpcert);
+ return FALSE;
+ }
+ }
+ else
+ {
+ x509cert_t *x509cert = alloc_thing(x509cert_t, "x509cert");
+ *x509cert = empty_x509cert;
+ if (parse_x509cert(blob, 0, x509cert))
+ {
+ cert->type = CERT_X509_SIGNATURE;
+ cert->u.x509 = x509cert;
+ return TRUE;
+ }
+ else
+ {
+ plog(" error in X.509 certificate");
+ free_x509cert(x509cert);
+ return FALSE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * Loads a host certificate
+ */
+bool
+load_host_cert(const char *filename, cert_t *cert)
+{
+ const char *path = concatenate_paths(HOST_CERT_PATH, filename);
+
+ return load_cert(path, "host cert", cert);
+}
+
+/*
+ * Loads a CA certificate
+ */
+bool
+load_ca_cert(const char *filename, cert_t *cert)
+{
+ const char *path = concatenate_paths(CA_CERT_PATH, filename);
+
+ return load_cert(path, "CA cert", cert);
+}
+
+/*
+ * establish equality of two certificates
+ */
+bool
+same_cert(const cert_t *a, const cert_t *b)
+{
+ return a->type == b->type && a->u.x509 == b->u.x509;
+}
+
+/* for each link pointing to the certif icate
+ " increase the count by one
+ */
+void
+share_cert(cert_t cert)
+{
+ switch (cert.type)
+ {
+ case CERT_PGP:
+ share_pgpcert(cert.u.pgp);
+ break;
+ case CERT_X509_SIGNATURE:
+ share_x509cert(cert.u.x509);
+ break;
+ default:
+ break;
+ }
+}
+
+/* release of a certificate decreases the count by one
+ " the certificate is freed when the counter reaches zero
+ */
+void
+release_cert(cert_t cert)
+{
+ switch (cert.type)
+ {
+ case CERT_PGP:
+ release_pgpcert(cert.u.pgp);
+ break;
+ case CERT_X509_SIGNATURE:
+ release_x509cert(cert.u.x509);
+ break;
+ default:
+ break;
+ }
+}
+
+/*
+ * list all X.509 and OpenPGP end certificates
+ */
+void
+list_certs(bool utc)
+{
+ list_x509_end_certs(utc);
+ list_pgp_end_certs(utc);
+}
+
diff --git a/src/pluto/certs.h b/src/pluto/certs.h
new file mode 100644
index 000000000..ca5acd35a
--- /dev/null
+++ b/src/pluto/certs.h
@@ -0,0 +1,80 @@
+/* Certificate support for IKE authentication
+ * Copyright (C) 2002-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.
+ *
+ * RCSID $Id: certs.h,v 1.7 2005/11/06 22:55:41 as Exp $
+ */
+
+#ifndef _CERTS_H
+#define _CERTS_H
+
+#include "pkcs1.h"
+#include "x509.h"
+#include "pgp.h"
+
+/* path definitions for private keys, end certs,
+ * cacerts, attribute certs and crls
+ */
+#define PRIVATE_KEY_PATH IPSEC_CONFDIR "/ipsec.d/private"
+#define HOST_CERT_PATH IPSEC_CONFDIR "/ipsec.d/certs"
+#define CA_CERT_PATH IPSEC_CONFDIR "/ipsec.d/cacerts"
+#define A_CERT_PATH IPSEC_CONFDIR "/ipsec.d/acerts"
+#define AA_CERT_PATH IPSEC_CONFDIR "/ipsec.d/aacerts"
+#define OCSP_CERT_PATH IPSEC_CONFDIR "/ipsec.d/ocspcerts"
+#define CRL_PATH IPSEC_CONFDIR "/ipsec.d/crls"
+#define REQ_PATH IPSEC_CONFDIR "/ipsec.d/reqs"
+
+/* advance warning of imminent expiry of
+ * cacerts, public keys, and crls
+ */
+#define CA_CERT_WARNING_INTERVAL 30 /* days */
+#define OCSP_CERT_WARNING_INTERVAL 30 /* days */
+#define PUBKEY_WARNING_INTERVAL 7 /* days */
+#define CRL_WARNING_INTERVAL 7 /* days */
+#define ACERT_WARNING_INTERVAL 1 /* day */
+
+/* certificate access structure
+ * currently X.509 and OpenPGP certificates are supported
+ */
+typedef struct {
+ u_char type;
+ union {
+ x509cert_t *x509;
+ pgpcert_t *pgp;
+ } u;
+} cert_t;
+
+/* used for initialization */
+extern const cert_t empty_cert;
+
+/* do not send certificate requests
+ * flag set in plutomain.c and used in ipsec_doi.c
+ */
+extern bool no_cr_send;
+
+extern err_t load_rsa_private_key(const char* filename, prompt_pass_t *pass
+ , RSA_private_key_t *key);
+extern chunk_t get_mycert(cert_t cert);
+extern bool load_coded_file(const char *filename, prompt_pass_t *pass
+ , const char *type, chunk_t *blob, bool *pgp);
+extern bool load_cert(const char *filename, const char *label
+ , cert_t *cert);
+extern bool load_host_cert(const char *filename, cert_t *cert);
+extern bool load_ca_cert(const char *filename, cert_t *cert);
+extern bool same_cert(const cert_t *a, const cert_t *b);
+extern void share_cert(cert_t cert);
+extern void release_cert(cert_t cert);
+extern void list_certs(bool utc);
+
+#endif /* _CERTS_H */
+
+
diff --git a/src/pluto/connections.c b/src/pluto/connections.c
new file mode 100644
index 000000000..0d02b979c
--- /dev/null
+++ b/src/pluto/connections.c
@@ -0,0 +1,4406 @@
+/* information about connections between hosts and clients
+ * Copyright (C) 1998-2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: connections.c,v 1.43 2006/04/29 18:16:02 as Exp $
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */
+#include <sys/queue.h>
+
+#include <freeswan.h>
+#include <ipsec_policy.h>
+#include "kameipsec.h"
+
+#include "constants.h"
+#include "defs.h"
+#include "id.h"
+#include "x509.h"
+#include "ca.h"
+#include "crl.h"
+#include "pgp.h"
+#include "certs.h"
+#include "ac.h"
+#include "smartcard.h"
+#include "fetch.h"
+#include "connections.h"
+#include "foodgroups.h"
+#include "demux.h"
+#include "state.h"
+#include "timer.h"
+#include "ipsec_doi.h" /* needs demux.h and state.h */
+#include "server.h"
+#include "kernel.h"
+#include "log.h"
+#include "keys.h"
+#include "adns.h" /* needs <resolv.h> */
+#include "dnskey.h" /* needs keys.h and adns.h */
+#include "whack.h"
+#include "alg_info.h"
+#include "ike_alg.h"
+#include "nat_traversal.h"
+#include "virtual.h"
+
+static void flush_pending_by_connection(struct connection *c); /* forward */
+
+static struct connection *connections = NULL;
+
+/* struct host_pair: a nexus of information about a pair of hosts.
+ * A host is an IP address, UDP port pair. This is a debatable choice:
+ * - should port be considered (no choice of port in standard)?
+ * - should ID be considered (hard because not always known)?
+ * - should IP address matter on our end (we don't know our end)?
+ * Only oriented connections are registered.
+ * Unoriented connections are kept on the unoriented_connections
+ * linked list (using hp_next). For them, host_pair is NULL.
+ */
+
+struct host_pair {
+ struct {
+ ip_address addr;
+ u_int16_t port; /* host order */
+ } me, him;
+ bool initial_connection_sent;
+ struct connection *connections; /* connections with this pair */
+ struct pending *pending; /* awaiting Keying Channel */
+ struct host_pair *next;
+};
+
+static struct host_pair *host_pairs = NULL;
+
+static struct connection *unoriented_connections = NULL;
+
+/* check to see that Ids of peers match */
+bool
+same_peer_ids(const struct connection *c, const struct connection *d
+, const struct id *his_id)
+{
+ return same_id(&c->spd.this.id, &d->spd.this.id)
+ && same_id(his_id == NULL? &c->spd.that.id : his_id, &d->spd.that.id);
+}
+
+static struct host_pair *
+find_host_pair(const ip_address *myaddr, u_int16_t myport
+, const ip_address *hisaddr, u_int16_t hisport)
+{
+ struct host_pair *p, *prev;
+
+ /* default hisaddr to an appropriate any */
+ if (hisaddr == NULL)
+ hisaddr = aftoinfo(addrtypeof(myaddr))->any;
+
+ if (nat_traversal_enabled)
+ {
+ /**
+ * port is not relevant in host_pair. with nat_traversal we
+ * always use pluto_port (500)
+ */
+ myport = pluto_port;
+ hisport = pluto_port;
+ }
+
+ for (prev = NULL, p = host_pairs; p != NULL; prev = p, p = p->next)
+ {
+ if (sameaddr(&p->me.addr, myaddr) && p->me.port == myport
+ && sameaddr(&p->him.addr, hisaddr) && p->him.port == hisport)
+ {
+ if (prev != NULL)
+ {
+ prev->next = p->next; /* remove p from list */
+ p->next = host_pairs; /* and stick it on front */
+ host_pairs = p;
+ }
+ break;
+ }
+ }
+ return p;
+}
+
+/* find head of list of connections with this pair of hosts */
+static struct connection *
+find_host_pair_connections(const ip_address *myaddr, u_int16_t myport
+, const ip_address *hisaddr, u_int16_t hisport)
+{
+ struct host_pair *hp = find_host_pair(myaddr, myport, hisaddr, hisport);
+
+ if (nat_traversal_enabled && hp && hisaddr)
+ {
+ struct connection *c;
+
+ for (c = hp->connections; c != NULL; c = c->hp_next)
+ {
+ if (c->spd.this.host_port == myport && c->spd.that.host_port == hisport)
+ return c;
+ }
+ return NULL;
+ }
+ return hp == NULL? NULL : hp->connections;
+}
+
+static void
+connect_to_host_pair(struct connection *c)
+{
+ if (oriented(*c))
+ {
+ struct host_pair *hp = find_host_pair(&c->spd.this.host_addr, c->spd.this.host_port
+ , &c->spd.that.host_addr, c->spd.that.host_port);
+
+ if (hp == NULL)
+ {
+ /* no suitable host_pair -- build one */
+ hp = alloc_thing(struct host_pair, "host_pair");
+ hp->me.addr = c->spd.this.host_addr;
+ hp->him.addr = c->spd.that.host_addr;
+ hp->me.port = nat_traversal_enabled ? pluto_port : c->spd.this.host_port;
+ hp->him.port = nat_traversal_enabled ? pluto_port : c->spd.that.host_port;
+ hp->initial_connection_sent = FALSE;
+ hp->connections = NULL;
+ hp->pending = NULL;
+ hp->next = host_pairs;
+ host_pairs = hp;
+ }
+ c->host_pair = hp;
+ c->hp_next = hp->connections;
+ hp->connections = c;
+ }
+ else
+ {
+ /* since this connection isn't oriented, we place it
+ * in the unoriented_connections list instead.
+ */
+ c->host_pair = NULL;
+ c->hp_next = unoriented_connections;
+ unoriented_connections = c;
+ }
+}
+
+/* find a connection by name.
+ * If strict, don't accept a CK_INSTANCE.
+ * Move the winner (if any) to the front.
+ * If none is found, and strict, a diagnostic is logged to whack.
+ */
+struct connection *
+con_by_name(const char *nm, bool strict)
+{
+ struct connection *p, *prev;
+
+ for (prev = NULL, p = connections; ; prev = p, p = p->ac_next)
+ {
+ if (p == NULL)
+ {
+ if (strict)
+ whack_log(RC_UNKNOWN_NAME
+ , "no connection named \"%s\"", nm);
+ break;
+ }
+ if (streq(p->name, nm)
+ && (!strict || p->kind != CK_INSTANCE))
+ {
+ if (prev != NULL)
+ {
+ prev->ac_next = p->ac_next; /* remove p from list */
+ p->ac_next = connections; /* and stick it on front */
+ connections = p;
+ }
+ break;
+ }
+ }
+ return p;
+}
+
+void
+release_connection(struct connection *c, bool relations)
+{
+ if (c->kind == CK_INSTANCE)
+ {
+ /* This does everything we need.
+ * Note that we will be called recursively by delete_connection,
+ * but kind will be CK_GOING_AWAY.
+ */
+ delete_connection(c, relations);
+ }
+ else
+ {
+ flush_pending_by_connection(c);
+ delete_states_by_connection(c, relations);
+ unroute_connection(c);
+ }
+}
+
+/* Delete a connection */
+
+#define list_rm(etype, enext, e, ehead) { \
+ etype **ep; \
+ for (ep = &(ehead); *ep != (e); ep = &(*ep)->enext) \
+ passert(*ep != NULL); /* we must not come up empty-handed */ \
+ *ep = (e)->enext; \
+ }
+
+
+void
+delete_connection(struct connection *c, bool relations)
+{
+ struct connection *old_cur_connection
+ = cur_connection == c? NULL : cur_connection;
+#ifdef DEBUG
+ lset_t old_cur_debugging = cur_debugging;
+#endif
+
+ set_cur_connection(c);
+
+ /* Must be careful to avoid circularity:
+ * we mark c as going away so it won't get deleted recursively.
+ */
+ passert(c->kind != CK_GOING_AWAY);
+ if (c->kind == CK_INSTANCE)
+ {
+ plog("deleting connection \"%s\" instance with peer %s {isakmp=#%lu/ipsec=#%lu}"
+ , c->name
+ , ip_str(&c->spd.that.host_addr)
+ , c->newest_isakmp_sa, c->newest_ipsec_sa);
+ c->kind = CK_GOING_AWAY;
+ }
+ else
+ {
+ plog("deleting connection");
+ }
+ release_connection(c, relations); /* won't delete c */
+
+ if (c->kind == CK_GROUP)
+ delete_group(c);
+
+ /* free up any logging resources */
+ perpeer_logfree(c);
+
+ /* find and delete c from connections list */
+ list_rm(struct connection, ac_next, c, connections);
+ cur_connection = old_cur_connection;
+
+ /* find and delete c from the host pair list */
+ if (c->host_pair == NULL)
+ {
+ if (c->ikev1)
+ list_rm(struct connection, hp_next, c, unoriented_connections);
+ }
+ else
+ {
+ struct host_pair *hp = c->host_pair;
+
+ list_rm(struct connection, hp_next, c, hp->connections);
+ c->host_pair = NULL; /* redundant, but safe */
+
+ /* if there are no more connections with this host_pair
+ * and we haven't even made an initial contact, let's delete
+ * this guy in case we were created by an attempted DOS attack.
+ */
+ if (hp->connections == NULL
+ && !hp->initial_connection_sent)
+ {
+ passert(hp->pending == NULL); /* ??? must deal with this! */
+ list_rm(struct host_pair, next, hp, host_pairs);
+ pfree(hp);
+ }
+ }
+
+ if (c->kind != CK_GOING_AWAY)
+ pfreeany(c->spd.that.virt);
+
+#ifdef DEBUG
+ cur_debugging = old_cur_debugging;
+#endif
+ pfreeany(c->name);
+ free_id_content(&c->spd.this.id);
+ pfreeany(c->spd.this.updown);
+ freeanychunk(c->spd.this.ca);
+ free_ietfAttrList(c->spd.this.groups);
+ free_id_content(&c->spd.that.id);
+ pfreeany(c->spd.that.updown);
+ freeanychunk(c->spd.that.ca);
+ free_ietfAttrList(c->spd.that.groups);
+ free_generalNames(c->requested_ca, TRUE);
+ gw_delref(&c->gw_info);
+
+ lock_certs_and_keys("delete_connection");
+ release_cert(c->spd.this.cert);
+ scx_release(c->spd.this.sc);
+ release_cert(c->spd.that.cert);
+ scx_release(c->spd.that.sc);
+ unlock_certs_and_keys("delete_connection");
+
+ alg_info_delref((struct alg_info **)&c->alg_info_esp);
+ alg_info_delref((struct alg_info **)&c->alg_info_ike);
+
+ pfree(c);
+}
+
+/* Delete connections with the specified name */
+void
+delete_connections_by_name(const char *name, bool strict)
+{
+ struct connection *c = con_by_name(name, strict);
+
+ for (; c != NULL; c = con_by_name(name, FALSE))
+ delete_connection(c, FALSE);
+}
+
+void
+delete_every_connection(void)
+{
+ while (connections != NULL)
+ delete_connection(connections, TRUE);
+}
+
+void
+release_dead_interfaces(void)
+{
+ struct host_pair *hp;
+
+ for (hp = host_pairs; hp != NULL; hp = hp->next)
+ {
+ struct connection **pp
+ , *p;
+
+ for (pp = &hp->connections; (p = *pp) != NULL; )
+ {
+ if (p->interface->change == IFN_DELETE)
+ {
+ /* this connection's interface is going away */
+ enum connection_kind k = p->kind;
+
+ release_connection(p, TRUE);
+
+ if (k <= CK_PERMANENT)
+ {
+ /* The connection should have survived release:
+ * move it to the unoriented_connections list.
+ */
+ passert(p == *pp);
+
+ p->interface = NULL;
+
+ *pp = p->hp_next; /* advance *pp */
+ p->host_pair = NULL;
+ p->hp_next = unoriented_connections;
+ unoriented_connections = p;
+ }
+ else
+ {
+ /* The connection should have vanished,
+ * but the previous connection remains.
+ */
+ passert(p != *pp);
+ }
+ }
+ else
+ {
+ pp = &p->hp_next; /* advance pp */
+ }
+ }
+ }
+}
+
+/* adjust orientations of connections to reflect newly added interfaces */
+void
+check_orientations(void)
+{
+ /* try to orient all the unoriented connections */
+ {
+ struct connection *c = unoriented_connections;
+
+ unoriented_connections = NULL;
+
+ while (c != NULL)
+ {
+ struct connection *nxt = c->hp_next;
+
+ (void)orient(c);
+ connect_to_host_pair(c);
+ c = nxt;
+ }
+ }
+
+ /* Check that no oriented connection has become double-oriented.
+ * In other words, the far side must not match one of our new interfaces.
+ */
+ {
+ struct iface *i;
+
+ for (i = interfaces; i != NULL; i = i->next)
+ {
+ if (i->change == IFN_ADD)
+ {
+ struct host_pair *hp;
+
+ for (hp = host_pairs; hp != NULL; hp = hp->next)
+ {
+ if (sameaddr(&hp->him.addr, &i->addr)
+ && (!no_klips || hp->him.port == pluto_port))
+ {
+ /* bad news: the whole chain of connections
+ * hanging off this host pair has both sides
+ * matching an interface.
+ * We'll get rid of them, using orient and
+ * connect_to_host_pair. But we'll be lazy
+ * and not ditch the host_pair itself (the
+ * cost of leaving it is slight and cannot
+ * be induced by a foe).
+ */
+ struct connection *c = hp->connections;
+
+ hp->connections = NULL;
+ while (c != NULL)
+ {
+ struct connection *nxt = c->hp_next;
+
+ c->interface = NULL;
+ (void)orient(c);
+ connect_to_host_pair(c);
+ c = nxt;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static err_t
+default_end(struct end *e, ip_address *dflt_nexthop)
+{
+ err_t ugh = NULL;
+ const struct af_info *afi = aftoinfo(addrtypeof(&e->host_addr));
+
+ if (afi == NULL)
+ return "unknown address family in default_end";
+
+ /* default ID to IP (but only if not NO_IP -- WildCard) */
+ if (e->id.kind == ID_NONE && !isanyaddr(&e->host_addr))
+ {
+ e->id.kind = afi->id_addr;
+ e->id.ip_addr = e->host_addr;
+ e->has_id_wildcards = FALSE;
+ }
+
+ /* default nexthop to other side */
+ if (isanyaddr(&e->host_nexthop))
+ e->host_nexthop = *dflt_nexthop;
+
+ /* default client to subnet containing only self
+ * XXX This may mean that the client's address family doesn't match
+ * tunnel_addr_family.
+ */
+ if (!e->has_client)
+ ugh = addrtosubnet(&e->host_addr, &e->client);
+
+ return ugh;
+}
+
+/* Format the topology of a connection end, leaving out defaults.
+ * Largest left end looks like: client === host : port [ host_id ] --- hop
+ * Note: if that==NULL, skip nexthop
+ * Returns strlen of formated result (length excludes NUL at end).
+ */
+size_t
+format_end(char *buf
+, size_t buf_len
+, const struct end *this
+, const struct end *that
+, bool is_left
+, lset_t policy)
+{
+ char client[SUBNETTOT_BUF];
+ const char *client_sep = "";
+ char protoport[sizeof(":255/65535")];
+ const char *host = NULL;
+ char host_space[ADDRTOT_BUF];
+ char host_port[sizeof(":65535")];
+ char host_id[BUF_LEN + 2];
+ char hop[ADDRTOT_BUF];
+ const char *hop_sep = "";
+ const char *open_brackets = "";
+ const char *close_brackets = "";
+
+ if (isanyaddr(&this->host_addr))
+ {
+ switch (policy & (POLICY_GROUP | POLICY_OPPO))
+ {
+ case POLICY_GROUP:
+ host = "%group";
+ break;
+ case POLICY_OPPO:
+ host = "%opportunistic";
+ break;
+ case POLICY_GROUP | POLICY_OPPO:
+ host = "%opportunisticgroup";
+ break;
+ default:
+ host = "%any";
+ break;
+ }
+ }
+
+ client[0] = '\0';
+
+ if (is_virtual_end(this) && isanyaddr(&this->host_addr))
+ {
+ host = "%virtual";
+ }
+
+ /* [client===] */
+ if (this->has_client)
+ {
+ ip_address client_net, client_mask;
+
+ networkof(&this->client, &client_net);
+ maskof(&this->client, &client_mask);
+ client_sep = "===";
+
+ /* {client_subnet_wildcard} */
+ if (this->has_client_wildcard)
+ {
+ open_brackets = "{";
+ close_brackets = "}";
+ }
+
+ if (isanyaddr(&client_net) && isanyaddr(&client_mask)
+ && (policy & (POLICY_GROUP | POLICY_OPPO)))
+ client_sep = ""; /* boring case */
+ else if (subnetisnone(&this->client))
+ strcpy(client, "?");
+ else
+ subnettot(&this->client, 0, client, sizeof(client));
+ }
+ else if (this->modecfg && isanyaddr(&this->host_srcip))
+ {
+ /* we are mode config client */
+ client_sep = "===";
+ strcpy(client, "%modecfg");
+ }
+
+ /* host */
+ if (host == NULL)
+ {
+ addrtot(&this->host_addr, 0, host_space, sizeof(host_space));
+ host = host_space;
+ }
+
+ host_port[0] = '\0';
+ if (this->host_port != IKE_UDP_PORT)
+ snprintf(host_port, sizeof(host_port), ":%u"
+ , this->host_port);
+
+ /* payload portocol and port */
+ protoport[0] = '\0';
+ if (this->has_port_wildcard)
+ snprintf(protoport, sizeof(protoport), ":%u/%%any", this->protocol);
+ else if (this->port || this->protocol)
+ snprintf(protoport, sizeof(protoport), ":%u/%u", this->protocol
+ , this->port);
+
+ /* id, if different from host */
+ host_id[0] = '\0';
+ if (this->id.kind == ID_MYID)
+ {
+ strcpy(host_id, "[%myid]");
+ }
+ else if (!(this->id.kind == ID_NONE
+ || (id_is_ipaddr(&this->id) && sameaddr(&this->id.ip_addr, &this->host_addr))))
+ {
+ int len = idtoa(&this->id, host_id+1, sizeof(host_id)-2);
+
+ host_id[0] = '[';
+ strcpy(&host_id[len < 0? (ptrdiff_t)sizeof(host_id)-2 : 1 + len], "]");
+ }
+
+ /* [---hop] */
+ hop[0] = '\0';
+ hop_sep = "";
+ if (that != NULL && !sameaddr(&this->host_nexthop, &that->host_addr))
+ {
+ addrtot(&this->host_nexthop, 0, hop, sizeof(hop));
+ hop_sep = "---";
+ }
+
+ if (is_left)
+ snprintf(buf, buf_len, "%s%s%s%s%s%s%s%s%s%s"
+ , open_brackets, client, close_brackets
+ , client_sep, host, host_port, host_id
+ , protoport, hop_sep, hop);
+ else
+ snprintf(buf, buf_len, "%s%s%s%s%s%s%s%s%s%s"
+ , hop, hop_sep, host, host_port, host_id
+ , protoport, client_sep
+ , open_brackets, client, close_brackets);
+ return strlen(buf);
+}
+
+/* format topology of a connection.
+ * Two symmetric ends separated by ...
+ */
+#define CONNECTION_BUF (2 * (END_BUF - 1) + 4)
+
+static size_t
+format_connection(char *buf, size_t buf_len
+ , const struct connection *c
+ , struct spd_route *sr)
+{
+ size_t w = format_end(buf, buf_len, &sr->this, &sr->that, TRUE, LEMPTY);
+
+ w += snprintf(buf + w, buf_len - w, "...");
+ return w + format_end(buf + w, buf_len - w, &sr->that, &sr->this, FALSE, c->policy);
+}
+
+static void
+unshare_connection_strings(struct connection *c)
+{
+ c->name = clone_str(c->name, "connection name");
+
+ unshare_id_content(&c->spd.this.id);
+ c->spd.this.updown = clone_str(c->spd.this.updown, "updown");
+ scx_share(c->spd.this.sc);
+ share_cert(c->spd.this.cert);
+ if (c->spd.this.ca.ptr != NULL)
+ clonetochunk(c->spd.this.ca, c->spd.this.ca.ptr, c->spd.this.ca.len, "ca string");
+
+ unshare_id_content(&c->spd.that.id);
+ c->spd.that.updown = clone_str(c->spd.that.updown, "updown");
+ scx_share(c->spd.that.sc);
+ share_cert(c->spd.that.cert);
+ if (c->spd.that.ca.ptr != NULL)
+ clonetochunk(c->spd.that.ca, c->spd.that.ca.ptr, c->spd.that.ca.len, "ca string");
+
+ /* increment references to algo's */
+ alg_info_addref((struct alg_info *)c->alg_info_esp);
+ alg_info_addref((struct alg_info *)c->alg_info_ike);
+}
+
+static void
+load_end_certificate(const char *filename, struct end *dst)
+{
+ time_t valid_until;
+ cert_t cert;
+ bool valid_cert = FALSE;
+ bool cached_cert = FALSE;
+
+ /* initialize end certificate */
+ dst->cert.type = CERT_NONE;
+ dst->cert.u.x509 = NULL;
+
+ /* initialize smartcard info record */
+ dst->sc = NULL;
+
+ if (filename != NULL)
+ {
+ if (scx_on_smartcard(filename))
+ {
+ /* load cert from smartcard */
+ valid_cert = scx_load_cert(filename, &dst->sc, &cert, &cached_cert);
+ }
+ else
+ {
+ /* load cert from file */
+ valid_cert = load_host_cert(filename, &cert);
+ }
+ }
+
+ if (valid_cert)
+ {
+ err_t ugh = NULL;
+
+ switch (cert.type)
+ {
+ case CERT_PGP:
+ select_pgpcert_id(cert.u.pgp, &dst->id);
+
+ if (cached_cert)
+ dst->cert = cert;
+ else
+ {
+ valid_until = cert.u.pgp->until;
+ add_pgp_public_key(cert.u.pgp, cert.u.pgp->until, DAL_LOCAL);
+ dst->cert.type = cert.type;
+ dst->cert.u.pgp = add_pgpcert(cert.u.pgp);
+ }
+ break;
+ case CERT_X509_SIGNATURE:
+ select_x509cert_id(cert.u.x509, &dst->id);
+
+ if (cached_cert)
+ dst->cert = cert;
+ else
+ {
+ /* check validity of cert */
+ valid_until = cert.u.x509->notAfter;
+ ugh = check_validity(cert.u.x509, &valid_until);
+ if (ugh != NULL)
+ {
+ plog(" %s", ugh);
+ free_x509cert(cert.u.x509);
+ break;
+ }
+
+ DBG(DBG_CONTROL,
+ DBG_log("certificate is valid")
+ )
+ add_x509_public_key(cert.u.x509, valid_until, DAL_LOCAL);
+ dst->cert.type = cert.type;
+ dst->cert.u.x509 = add_x509cert(cert.u.x509);
+ }
+ /* if no CA is defined, use issuer as default */
+ if (dst->ca.ptr == NULL)
+ dst->ca = dst->cert.u.x509->issuer;
+ break;
+ default:
+ break;
+ }
+
+ /* cache the certificate that was last retrieved from the smartcard */
+ if (dst->sc != NULL)
+ {
+ if (!same_cert(&dst->sc->last_cert, &dst->cert))
+ {
+ lock_certs_and_keys("load_end_certificates");
+ release_cert(dst->sc->last_cert);
+ dst->sc->last_cert = dst->cert;
+ share_cert(dst->cert);
+ unlock_certs_and_keys("load_end_certificates");
+ }
+ time(&dst->sc->last_load);
+ }
+ }
+}
+
+static bool
+extract_end(struct end *dst, const whack_end_t *src, const char *which)
+{
+ bool same_ca = FALSE;
+
+ /* decode id, if any */
+ if (src->id == NULL)
+ {
+ dst->id.kind = ID_NONE;
+ }
+ else
+ {
+ err_t ugh = atoid(src->id, &dst->id, TRUE);
+
+ if (ugh != NULL)
+ {
+ loglog(RC_BADID, "bad %s --id: %s (ignored)", which, ugh);
+ dst->id = empty_id; /* ignore bad one */
+ }
+ }
+
+ dst->ca = empty_chunk;
+
+ /* decode CA distinguished name, if any */
+ if (src->ca != NULL)
+ {
+ if streq(src->ca, "%same")
+ same_ca = TRUE;
+ else if (!streq(src->ca, "%any"))
+ {
+ err_t ugh;
+
+ dst->ca.ptr = temporary_cyclic_buffer();
+ ugh = atodn(src->ca, &dst->ca);
+ if (ugh != NULL)
+ {
+ plog("bad CA string '%s': %s (ignored)", src->ca, ugh);
+ dst->ca = empty_chunk;
+ }
+ }
+ }
+
+ /* load local end certificate and extract ID, if any */
+ load_end_certificate(src->cert, dst);
+
+ /* does id has wildcards? */
+ dst->has_id_wildcards = id_count_wildcards(&dst->id) > 0;
+
+ /* decode group attributes, if any */
+ decode_groups(src->groups, &dst->groups);
+
+ /* the rest is simple copying of corresponding fields */
+ dst->host_addr = src->host_addr;
+ dst->host_nexthop = src->host_nexthop;
+ dst->host_srcip = src->host_srcip;
+ dst->has_natip = src->has_natip;
+ dst->client = src->client;
+ dst->protocol = src->protocol;
+ dst->port = src->port;
+ dst->has_port_wildcard = src->has_port_wildcard;
+ dst->key_from_DNS_on_demand = src->key_from_DNS_on_demand;
+ dst->has_client = src->has_client;
+ dst->has_client_wildcard = src->has_client_wildcard;
+ dst->modecfg = src->modecfg;
+ dst->hostaccess = src->hostaccess;
+ dst->sendcert = src->sendcert;
+ dst->updown = src->updown;
+ dst->host_port = src->host_port;
+
+ /* if host sourceip is defined but no client is present
+ * behind the host then set client to sourceip/32
+ */
+ if (addrbytesptr(&dst->host_srcip, NULL)
+ && !isanyaddr(&dst->host_srcip)
+ && !dst->has_natip
+ && !dst->has_client)
+ {
+ err_t ugh = addrtosubnet(&dst->host_srcip, &dst->client);
+
+ if (ugh != NULL)
+ plog("could not assign host sourceip to client subnet");
+ else
+ dst->has_client = TRUE;
+ }
+ return same_ca;
+}
+
+static bool
+check_connection_end(const whack_end_t *this, const whack_end_t *that
+, const whack_message_t *wm)
+{
+ if (wm->addr_family != addrtypeof(&this->host_addr)
+ || wm->addr_family != addrtypeof(&this->host_nexthop)
+ || (this->has_client? wm->tunnel_addr_family : wm->addr_family)
+ != subnettypeof(&this->client)
+ || subnettypeof(&this->client) != subnettypeof(&that->client))
+ {
+ /* this should have been diagnosed by whack, so we need not be clear
+ * !!! overloaded use of RC_CLASH
+ */
+ loglog(RC_CLASH, "address family inconsistency in connection");
+ return FALSE;
+ }
+
+ if (isanyaddr(&that->host_addr))
+ {
+ /* other side is wildcard: we must check if other conditions met */
+ if (isanyaddr(&this->host_addr))
+ {
+ loglog(RC_ORIENT, "connection must specify host IP address for our side");
+ return FALSE;
+ }
+ }
+
+ if (this->virt && (!isanyaddr(&this->host_addr) || this->has_client))
+ {
+ loglog(RC_CLASH,
+ "virtual IP must only be used with %%any and without client");
+ return FALSE;
+ }
+
+ return TRUE; /* happy */
+}
+
+struct connection *
+find_connection_by_reqid(uint32_t reqid)
+{
+ struct connection *c;
+
+ reqid &= ~3;
+ for (c = connections; c != NULL; c = c->ac_next)
+ {
+ if (c->spd.reqid == reqid)
+ return c;
+ }
+
+ return NULL;
+}
+
+static uint32_t
+gen_reqid(void)
+{
+ uint32_t start;
+ static uint32_t reqid = IPSEC_MANUAL_REQID_MAX & ~3;
+
+ start = reqid;
+ do {
+ reqid += 4;
+ if (reqid == 0)
+ reqid = (IPSEC_MANUAL_REQID_MAX & ~3) + 4;
+ if (!find_connection_by_reqid(reqid))
+ return reqid;
+ } while (reqid != start);
+
+ exit_log("unable to allocate reqid");
+}
+
+void
+add_connection(const whack_message_t *wm)
+{
+ if (con_by_name(wm->name, FALSE) != NULL)
+ {
+ loglog(RC_DUPNAME, "attempt to redefine connection \"%s\"", wm->name);
+ }
+ else if (wm->right.protocol != wm->left.protocol)
+ {
+ /* this should haven been diagnosed by whack
+ * !!! overloaded use of RC_CLASH
+ */
+ loglog(RC_CLASH, "the protocol must be the same for leftport and rightport");
+ }
+ else if (check_connection_end(&wm->right, &wm->left, wm)
+ && check_connection_end(&wm->left, &wm->right, wm))
+ {
+ bool same_rightca, same_leftca;
+ struct connection *c = alloc_thing(struct connection, "struct connection");
+
+ c->name = wm->name;
+ c->ikev1 = wm->ikev1;
+ c->policy = wm->policy;
+
+ if ((c->policy & POLICY_COMPRESS) && !can_do_IPcomp)
+ loglog(RC_COMMENT
+ , "ignoring --compress in \"%s\" because KLIPS is not configured to do IPCOMP"
+ , c->name);
+
+ if (wm->esp)
+ {
+ const char *ugh;
+
+ DBG(DBG_CONTROL,
+ DBG_log("from whack: got --esp=%s", wm->esp ? wm->esp: "NULL")
+ )
+ c->alg_info_esp= alg_info_esp_create_from_str(wm->esp? wm->esp : "", &ugh);
+
+ DBG(DBG_CRYPT|DBG_CONTROL,
+ static char buf[256]="<NULL>";
+
+ if (c->alg_info_esp)
+ alg_info_snprint(buf, sizeof(buf)
+ ,(struct alg_info *)c->alg_info_esp);
+ DBG_log("esp string values: %s", buf);
+ )
+ if (c->alg_info_esp)
+ {
+ if (c->alg_info_esp->alg_info_cnt==0)
+ loglog(RC_LOG_SERIOUS
+ , "got 0 transforms for esp=\"%s\"", wm->esp);
+ }
+ else
+ {
+ loglog(RC_LOG_SERIOUS
+ , "esp string error: %s", ugh? ugh : "Unknown");
+ }
+ }
+
+ if (wm->ike)
+ {
+ const char *ugh;
+
+ DBG(DBG_CONTROL,
+ DBG_log("from whack: got --ike=%s", wm->ike ? wm->ike: "NULL")
+ )
+ c->alg_info_ike= alg_info_ike_create_from_str(wm->ike? wm->ike : "", &ugh);
+
+ DBG(DBG_CRYPT|DBG_CONTROL,
+ static char buf[256]="<NULL>";
+
+ if (c->alg_info_ike)
+ alg_info_snprint(buf, sizeof(buf)
+ , (struct alg_info *)c->alg_info_ike);
+ DBG_log("ike string values: %s", buf);
+ )
+ if (c->alg_info_ike)
+ {
+ if (c->alg_info_ike->alg_info_cnt==0)
+ loglog(RC_LOG_SERIOUS
+ , "got 0 transforms for ike=\"%s\"", wm->ike);
+ }
+ else
+ {
+ loglog(RC_LOG_SERIOUS
+ , "ike string error: %s", ugh? ugh : "Unknown");
+ }
+ }
+
+ c->sa_ike_life_seconds = wm->sa_ike_life_seconds;
+ c->sa_ipsec_life_seconds = wm->sa_ipsec_life_seconds;
+ c->sa_rekey_margin = wm->sa_rekey_margin;
+ c->sa_rekey_fuzz = wm->sa_rekey_fuzz;
+ c->sa_keying_tries = wm->sa_keying_tries;
+
+ /* RFC 3706 DPD */
+ c->dpd_delay = wm->dpd_delay;
+ c->dpd_timeout = wm->dpd_timeout;
+ c->dpd_action = wm->dpd_action;
+
+ c->addr_family = wm->addr_family;
+ c->tunnel_addr_family = wm->tunnel_addr_family;
+
+ c->requested_ca = NULL;
+
+ same_leftca = extract_end(&c->spd.this, &wm->left, "left");
+ same_rightca = extract_end(&c->spd.that, &wm->right, "right");
+
+ if (same_rightca)
+ c->spd.that.ca = c->spd.this.ca;
+ else if (same_leftca)
+ c->spd.this.ca = c->spd.that.ca;
+
+ default_end(&c->spd.this, &c->spd.that.host_addr);
+ default_end(&c->spd.that, &c->spd.this.host_addr);
+
+ /* force any wildcard host IP address, any wildcard subnet
+ * or any wildcard ID to that end
+ */
+ if (isanyaddr(&c->spd.this.host_addr) || c->spd.this.has_client_wildcard
+ || c->spd.this.has_port_wildcard || c->spd.this.has_id_wildcards)
+ {
+ struct end t = c->spd.this;
+
+ c->spd.this = c->spd.that;
+ c->spd.that = t;
+ }
+
+ c->spd.next = NULL;
+ c->spd.reqid = gen_reqid();
+
+ /* set internal fields */
+ c->instance_serial = 0;
+ c->ac_next = connections;
+ connections = c;
+ c->interface = NULL;
+ c->spd.routing = RT_UNROUTED;
+ c->newest_isakmp_sa = SOS_NOBODY;
+ c->newest_ipsec_sa = SOS_NOBODY;
+ c->spd.eroute_owner = SOS_NOBODY;
+
+ if (c->policy & POLICY_GROUP)
+ {
+ c->kind = CK_GROUP;
+ add_group(c);
+ }
+ else if ((isanyaddr(&c->spd.that.host_addr) && !NEVER_NEGOTIATE(c->policy))
+ || c->spd.that.has_client_wildcard || c->spd.that.has_port_wildcard
+ || c->spd.that.has_id_wildcards)
+ {
+ /* Opportunistic or Road Warrior or wildcard client subnet
+ * or wildcard ID */
+ c->kind = CK_TEMPLATE;
+ }
+ else
+ {
+ c->kind = CK_PERMANENT;
+ }
+ set_policy_prio(c); /* must be after kind is set */
+
+#ifdef DEBUG
+ c->extra_debugging = wm->debugging;
+#endif
+
+ c->gw_info = NULL;
+
+ passert(!(wm->left.virt && wm->right.virt));
+ if (wm->left.virt || wm->right.virt)
+ {
+ passert(isanyaddr(&c->spd.that.host_addr));
+ c->spd.that.virt = create_virtual(c,
+ wm->left.virt ? wm->left.virt : wm->right.virt);
+ if (c->spd.that.virt)
+ c->spd.that.has_client = TRUE;
+ }
+
+ unshare_connection_strings(c);
+ (void)orient(c);
+
+ if (c->ikev1)
+ connect_to_host_pair(c);
+
+ /* log all about this connection */
+ plog("added connection description \"%s\"", c->name);
+ DBG(DBG_CONTROL,
+ char topo[CONNECTION_BUF];
+
+ (void) format_connection(topo, sizeof(topo), c, &c->spd);
+
+ DBG_log("%s", topo);
+
+ /* Make sure that address families can be correctly inferred
+ * from printed ends.
+ */
+ passert(c->addr_family == addrtypeof(&c->spd.this.host_addr)
+ && c->addr_family == addrtypeof(&c->spd.this.host_nexthop)
+ && (c->spd.this.has_client? c->tunnel_addr_family : c->addr_family)
+ == subnettypeof(&c->spd.this.client)
+
+ && c->addr_family == addrtypeof(&c->spd.that.host_addr)
+ && c->addr_family == addrtypeof(&c->spd.that.host_nexthop)
+ && (c->spd.that.has_client? c->tunnel_addr_family : c->addr_family)
+ == subnettypeof(&c->spd.that.client));
+
+ DBG_log("ike_life: %lus; ipsec_life: %lus; rekey_margin: %lus;"
+ " rekey_fuzz: %lu%%; keyingtries: %lu; policy: %s"
+ , (unsigned long) c->sa_ike_life_seconds
+ , (unsigned long) c->sa_ipsec_life_seconds
+ , (unsigned long) c->sa_rekey_margin
+ , (unsigned long) c->sa_rekey_fuzz
+ , (unsigned long) c->sa_keying_tries
+ , prettypolicy(c->policy));
+ );
+ }
+}
+
+/* Derive a template connection from a group connection and target.
+ * Similar to instantiate(). Happens at whack --listen.
+ * Returns name of new connection. May be NULL.
+ * Caller is responsible for pfreeing.
+ */
+char *
+add_group_instance(struct connection *group, const ip_subnet *target)
+{
+ char namebuf[100]
+ , targetbuf[SUBNETTOT_BUF];
+ struct connection *t;
+ char *name = NULL;
+
+ passert(group->kind == CK_GROUP);
+ passert(oriented(*group));
+
+ /* manufacture a unique name for this template */
+ subnettot(target, 0, targetbuf, sizeof(targetbuf));
+ snprintf(namebuf, sizeof(namebuf), "%s#%s", group->name, targetbuf);
+
+ if (con_by_name(namebuf, FALSE) != NULL)
+ {
+ loglog(RC_DUPNAME, "group name + target yields duplicate name \"%s\""
+ , namebuf);
+ }
+ else
+ {
+ t = clone_thing(*group, "group instance");
+ t->name = namebuf;
+ unshare_connection_strings(t);
+ name = clone_str(t->name, "group instance name");
+ t->spd.that.client = *target;
+ t->policy &= ~(POLICY_GROUP | POLICY_GROUTED);
+ t->kind = isanyaddr(&t->spd.that.host_addr) && !NEVER_NEGOTIATE(t->policy)
+ ? CK_TEMPLATE : CK_INSTANCE;
+
+ /* reset log file info */
+ t->log_file_name = NULL;
+ t->log_file = NULL;
+ t->log_file_err = FALSE;
+
+ t->spd.reqid = gen_reqid();
+
+ if (t->spd.that.virt)
+ {
+ DBG_log("virtual_ip not supported in group instance");
+ t->spd.that.virt = NULL;
+ }
+
+ /* add to connections list */
+ t->ac_next = connections;
+ connections = t;
+
+ /* same host_pair as parent: stick after parent on list */
+ group->hp_next = t;
+
+ /* route if group is routed */
+ if (group->policy & POLICY_GROUTED)
+ {
+ if (!trap_connection(t))
+ whack_log(RC_ROUTE, "could not route");
+ }
+ }
+ return name;
+}
+
+/* an old target has disappeared for a group: delete instance */
+void
+remove_group_instance(const struct connection *group USED_BY_DEBUG
+, const char *name)
+{
+ passert(group->kind == CK_GROUP);
+ passert(oriented(*group));
+
+ delete_connections_by_name(name, FALSE);
+}
+
+/* Common part of instantiating a Road Warrior or Opportunistic connection.
+ * his_id can be used to carry over an ID discovered in Phase 1.
+ * It must not disagree with the one in c, but if that is unspecified,
+ * the new connection will use his_id.
+ * If his_id is NULL, and c.that.id is uninstantiated (ID_NONE), the
+ * new connection will continue to have an uninstantiated that.id.
+ * Note: instantiation does not affect port numbers.
+ *
+ * Note that instantiate can only deal with a single SPD/eroute.
+ */
+static struct connection *
+instantiate(struct connection *c, const ip_address *him
+, u_int16_t his_port
+, const struct id *his_id)
+{
+ struct connection *d;
+ int wildcards;
+
+ passert(c->kind == CK_TEMPLATE);
+ passert(c->spd.next == NULL);
+
+ c->instance_serial++;
+ d = clone_thing(*c, "temporary connection");
+ if (his_id != NULL)
+ {
+ passert(match_id(his_id, &d->spd.that.id, &wildcards));
+ d->spd.that.id = *his_id;
+ d->spd.that.has_id_wildcards = FALSE;
+ }
+ unshare_connection_strings(d);
+ unshare_ietfAttrList(&d->spd.this.groups);
+ unshare_ietfAttrList(&d->spd.that.groups);
+ d->kind = CK_INSTANCE;
+
+ passert(oriented(*d));
+ d->spd.that.host_addr = *him;
+ setportof(htons(c->spd.that.port), &d->spd.that.host_addr);
+
+ if (his_port) d->spd.that.host_port = his_port;
+
+ default_end(&d->spd.that, &d->spd.this.host_addr);
+
+ /* We cannot guess what our next_hop should be, but if it was
+ * explicitly specified as 0.0.0.0, we set it to be him.
+ * (whack will not allow nexthop to be elided in RW case.)
+ */
+ default_end(&d->spd.this, &d->spd.that.host_addr);
+ d->spd.next = NULL;
+ d->spd.reqid = gen_reqid();
+
+ /* set internal fields */
+ d->ac_next = connections;
+ connections = d;
+ d->spd.routing = RT_UNROUTED;
+ d->newest_isakmp_sa = SOS_NOBODY;
+ d->newest_ipsec_sa = SOS_NOBODY;
+ d->spd.eroute_owner = SOS_NOBODY;
+
+ /* reset log file info */
+ d->log_file_name = NULL;
+ d->log_file = NULL;
+ d->log_file_err = FALSE;
+
+ connect_to_host_pair(d);
+
+ return d;
+}
+
+struct connection *
+rw_instantiate(struct connection *c, const ip_address *him, u_int16_t his_port
+, const ip_subnet *his_net, const struct id *his_id)
+{
+ struct connection *d = instantiate(c, him, his_port, his_id);
+
+ if (d && his_net && is_virtual_connection(c))
+ {
+ d->spd.that.client = *his_net;
+ d->spd.that.virt = NULL;
+ if (subnetishost(his_net) && addrinsubnet(him, his_net))
+ d->spd.that.has_client = FALSE;
+ }
+
+ if (d->policy & POLICY_OPPO)
+ {
+ /* This must be before we know the client addresses.
+ * Fill in one that is impossible. This prevents anyone else from
+ * trying to use this connection to get to a particular client
+ */
+ d->spd.that.client = *aftoinfo(subnettypeof(&d->spd.that.client))->none;
+ }
+ DBG(DBG_CONTROL
+ , DBG_log("instantiated \"%s\" for %s" , d->name, ip_str(him)));
+ return d;
+}
+
+struct connection *
+oppo_instantiate(struct connection *c
+, const ip_address *him
+, const struct id *his_id
+, struct gw_info *gw
+, const ip_address *our_client USED_BY_DEBUG
+, const ip_address *peer_client)
+{
+ struct connection *d = instantiate(c, him, 0, his_id);
+
+ passert(d->spd.next == NULL);
+
+ /* fill in our client side */
+ if (d->spd.this.has_client)
+ {
+ /* there was a client in the abstract connection
+ * so we demand that the required client is within that subnet.
+ */
+ passert(addrinsubnet(our_client, &d->spd.this.client));
+ happy(addrtosubnet(our_client, &d->spd.this.client));
+ /* opportunistic connections do not use port selectors */
+ setportof(0, &d->spd.this.client.addr);
+ }
+ else
+ {
+ /* there was no client in the abstract connection
+ * so we demand that the required client be the host
+ */
+ passert(sameaddr(our_client, &d->spd.this.host_addr));
+ }
+
+ /* fill in peer's client side.
+ * If the client is the peer, excise the client from the connection.
+ */
+ passert((d->policy & POLICY_OPPO)
+ && addrinsubnet(peer_client, &d->spd.that.client));
+ happy(addrtosubnet(peer_client, &d->spd.that.client));
+ /* opportunistic connections do not use port selectors */
+ setportof(0, &d->spd.that.client.addr);
+
+ if (sameaddr(peer_client, &d->spd.that.host_addr))
+ d->spd.that.has_client = FALSE;
+
+ passert(d->gw_info == NULL);
+ gw_addref(gw);
+ d->gw_info = gw;
+
+ /* Adjust routing if something is eclipsing c.
+ * It must be a %hold for us (hard to passert this).
+ * If there was another instance eclipsing, we'd be using it.
+ */
+ if (c->spd.routing == RT_ROUTED_ECLIPSED)
+ d->spd.routing = RT_ROUTED_PROSPECTIVE;
+
+ /* Remember if the template is routed:
+ * if so, this instance applies for initiation
+ * even if it is created for responding.
+ */
+ if (routed(c->spd.routing))
+ d->instance_initiation_ok = TRUE;
+
+ DBG(DBG_CONTROL,
+ char topo[CONNECTION_BUF];
+
+ (void) format_connection(topo, sizeof(topo), d, &d->spd);
+ DBG_log("instantiated \"%s\": %s", d->name, topo);
+ );
+ return d;
+}
+
+/* priority formatting */
+void
+fmt_policy_prio(policy_prio_t pp, char buf[POLICY_PRIO_BUF])
+{
+ if (pp == BOTTOM_PRIO)
+ snprintf(buf, POLICY_PRIO_BUF, "0");
+ else
+ snprintf(buf, POLICY_PRIO_BUF, "%lu,%lu"
+ , pp>>16, (pp & ~(~(policy_prio_t)0 << 16)) >> 8);
+}
+
+/* Format any information needed to identify an instance of a connection.
+ * Fills any needed information into buf which MUST be big enough.
+ * Road Warrior: peer's IP address
+ * Opportunistic: [" " myclient "==="] " ..." peer ["===" hisclient] '\0'
+ */
+static size_t
+fmt_client(const ip_subnet *client, const ip_address *gw, const char *prefix, char buf[ADDRTOT_BUF])
+{
+ if (subnetisaddr(client, gw))
+ {
+ buf[0] = '\0'; /* compact denotation for "self" */
+ }
+ else
+ {
+ char *ap;
+
+ strcpy(buf, prefix);
+ ap = buf + strlen(prefix);
+ if (subnetisnone(client))
+ strcpy(ap, "?"); /* unknown */
+ else
+ subnettot(client, 0, ap, SUBNETTOT_BUF);
+ }
+ return strlen(buf);
+}
+
+void
+fmt_conn_instance(const struct connection *c, char buf[CONN_INST_BUF])
+{
+ char *p = buf;
+
+ *p = '\0';
+
+ if (c->kind == CK_INSTANCE)
+ {
+ if (c->instance_serial != 0)
+ {
+ snprintf(p, CONN_INST_BUF, "[%lu]", c->instance_serial);
+ p += strlen(p);
+ }
+
+ if (c->policy & POLICY_OPPO)
+ {
+ size_t w = fmt_client(&c->spd.this.client, &c->spd.this.host_addr, " ", p);
+
+ p += w;
+
+ strcpy(p, w == 0? " ..." : "=== ...");
+ p += strlen(p);
+
+ addrtot(&c->spd.that.host_addr, 0, p, ADDRTOT_BUF);
+ p += strlen(p);
+
+ (void) fmt_client(&c->spd.that.client, &c->spd.that.host_addr, "===", p);
+ }
+ else
+ {
+ *p++ = ' ';
+ addrtot(&c->spd.that.host_addr, 0, p, ADDRTOT_BUF);
+#
+ if (c->spd.that.host_port != pluto_port)
+ {
+ p += strlen(p);
+ sprintf(p, ":%d", c->spd.that.host_port);
+ }
+ }
+ }
+}
+
+/* Find an existing connection for a trapped outbound packet.
+ * This is attempted before we bother with gateway discovery.
+ * + this connection is routed or instance_of_routed_template
+ * (i.e. approved for on-demand)
+ * + this subnet contains our_client (or we are our_client)
+ * + that subnet contains peer_client (or peer is peer_client)
+ * + don't care about Phase 1 IDs (we don't know)
+ * Note: result may still need to be instantiated.
+ * The winner has the highest policy priority.
+ *
+ * If there are several with that priority, we give preference to
+ * the first one that is an instance.
+ *
+ * See also build_outgoing_opportunistic_connection.
+ */
+struct connection *
+find_connection_for_clients(struct spd_route **srp,
+ const ip_address *our_client,
+ const ip_address *peer_client,
+ int transport_proto)
+{
+ struct connection *c = connections, *best = NULL;
+ policy_prio_t best_prio = BOTTOM_PRIO;
+ struct spd_route *sr;
+ struct spd_route *best_sr = NULL;
+ int our_port = ntohs(portof(our_client));
+ int peer_port = ntohs(portof(peer_client));
+
+ passert(!isanyaddr(our_client) && !isanyaddr(peer_client));
+#ifdef DEBUG
+ if (DBGP(DBG_CONTROL))
+ {
+ char ocb[ADDRTOT_BUF], pcb[ADDRTOT_BUF];
+
+ addrtot(our_client, 0, ocb, sizeof(ocb));
+ addrtot(peer_client, 0, pcb, sizeof(pcb));
+ DBG_log("find_connection: "
+ "looking for policy for connection: %s:%d/%d -> %s:%d/%d"
+ , ocb, transport_proto, our_port, pcb, transport_proto, peer_port);
+ }
+#endif /* DEBUG */
+
+ for (c = connections; c != NULL; c = c->ac_next)
+ {
+ if (c->kind == CK_GROUP)
+ continue;
+
+ for (sr = &c->spd; best!=c && sr; sr = sr->next)
+ {
+ if ((routed(sr->routing) || c->instance_initiation_ok)
+ && addrinsubnet(our_client, &sr->this.client)
+ && addrinsubnet(peer_client, &sr->that.client)
+ && addrinsubnet(peer_client, &sr->that.client)
+ && (!sr->this.protocol || transport_proto == sr->this.protocol)
+ && (!sr->this.port || our_port == sr->this.port)
+ && (!sr->that.port || peer_port == sr->that.port))
+ {
+ char cib[CONN_INST_BUF];
+ char cib2[CONN_INST_BUF];
+
+ policy_prio_t prio = 8 * (c->prio + (c->kind == CK_INSTANCE))
+ + 2 * (sr->this.port == our_port)
+ + 2 * (sr->that.port == peer_port)
+ + (sr->this.protocol == transport_proto);
+
+#ifdef DEBUG
+ if (DBGP(DBG_CONTROL|DBG_CONTROLMORE))
+ {
+ char c_ocb[SUBNETTOT_BUF], c_pcb[SUBNETTOT_BUF];
+
+ subnettot(&c->spd.this.client, 0, c_ocb, sizeof(c_ocb));
+ subnettot(&c->spd.that.client, 0, c_pcb, sizeof(c_pcb));
+ DBG_log("find_connection: conn \"%s\"%s has compatible peers: %s->%s [pri: %ld]"
+ , c->name
+ , (fmt_conn_instance(c, cib), cib)
+ , c_ocb, c_pcb, prio);
+ }
+#endif /* DEBUG */
+
+ if (best == NULL)
+ {
+ best = c;
+ best_sr = sr;
+ best_prio = prio;
+ }
+
+ DBG(DBG_CONTROLMORE,
+ DBG_log("find_connection: "
+ "comparing best \"%s\"%s [pri:%ld]{%p} (child %s) to \"%s\"%s [pri:%ld]{%p} (child %s)"
+ , best->name
+ , (fmt_conn_instance(best, cib), cib)
+ , best_prio
+ , best
+ , (best->policy_next ? best->policy_next->name : "none")
+ , c->name
+ , (fmt_conn_instance(c, cib2), cib2)
+ , prio
+ , c
+ , (c->policy_next ? c->policy_next->name : "none")));
+
+ if (prio > best_prio)
+ {
+ best = c;
+ best_sr = sr;
+ best_prio = prio;
+ }
+ }
+ }
+ }
+
+ if (best!= NULL && NEVER_NEGOTIATE(best->policy))
+ best = NULL;
+
+ if (srp != NULL && best != NULL)
+ *srp = best_sr;
+
+#ifdef DEBUG
+ if (DBGP(DBG_CONTROL))
+ {
+ if (best)
+ {
+ char cib[CONN_INST_BUF];
+ DBG_log("find_connection: concluding with \"%s\"%s [pri:%ld]{%p} kind=%s"
+ , best->name
+ , (fmt_conn_instance(best, cib), cib)
+ , best_prio
+ , best
+ , enum_name(&connection_kind_names, best->kind));
+ } else {
+ DBG_log("find_connection: concluding with empty");
+ }
+ }
+#endif /* DEBUG */
+
+ return best;
+}
+
+/* Find and instantiate a connection for an outgoing Opportunistic connection.
+ * We've already discovered its gateway.
+ * We look for a the connection such that:
+ * + this is one of our interfaces
+ * + this subnet contains our_client (or we are our_client)
+ * (we will specialize the client). We prefer the smallest such subnet.
+ * + that subnet contains peer_clent (we will specialize the client).
+ * We prefer the smallest such subnet.
+ * + is opportunistic
+ * + that peer is NO_IP
+ * + don't care about Phase 1 IDs (probably should be default)
+ * We could look for a connection that already had the desired peer
+ * (rather than NO_IP) specified, but it doesn't seem worth the
+ * bother.
+ *
+ * We look for the routed policy applying to the narrowest subnets.
+ * We only succeed if we find such a policy AND it is satisfactory.
+ *
+ * The body of the inner loop is a lot like that in
+ * find_connection_for_clients. In this case, we know the gateways
+ * that we need to instantiate an opportunistic connection.
+ */
+struct connection *
+build_outgoing_opportunistic_connection(struct gw_info *gw
+ ,const ip_address *our_client
+ ,const ip_address *peer_client)
+{
+ struct iface *p;
+ struct connection *best = NULL;
+ struct spd_route *sr, *bestsr;
+ char ocb[ADDRTOT_BUF], pcb[ADDRTOT_BUF];
+
+ addrtot(our_client, 0, ocb, sizeof(ocb));
+ addrtot(peer_client, 0, pcb, sizeof(pcb));
+
+ passert(!isanyaddr(our_client) && !isanyaddr(peer_client));
+
+ /* We don't know his ID yet, so gw id must be an ipaddr */
+ passert(gw->key != NULL);
+ passert(id_is_ipaddr(&gw->gw_id));
+
+ /* for each of our addresses... */
+ for (p = interfaces; p != NULL; p = p->next)
+ {
+ /* go through those connections with our address and NO_IP as hosts
+ * We cannot know what port the peer would use, so we assume
+ * that it is pluto_port (makes debugging easier).
+ */
+ struct connection *c = find_host_pair_connections(&p->addr
+ , pluto_port, (ip_address *)NULL, pluto_port);
+
+ for (; c != NULL; c = c->hp_next)
+ {
+ DBG(DBG_OPPO,
+ DBG_log("checking %s", c->name));
+ if (c->kind == CK_GROUP)
+ {
+ continue;
+ }
+
+ for (sr = &c->spd; best!=c && sr; sr = sr->next)
+ {
+ if (routed(sr->routing)
+ && addrinsubnet(our_client, &sr->this.client)
+ && addrinsubnet(peer_client, &sr->that.client))
+ {
+ if (best == NULL)
+ {
+ best = c;
+ break;
+ }
+
+ DBG(DBG_OPPO,
+ DBG_log("comparing best %s to %s"
+ , best->name, c->name));
+
+ for (bestsr = &best->spd; best!=c && bestsr; bestsr=bestsr->next)
+ {
+ if (!subnetinsubnet(&bestsr->this.client, &sr->this.client)
+ || (samesubnet(&bestsr->this.client, &sr->this.client)
+ && !subnetinsubnet(&bestsr->that.client
+ , &sr->that.client)))
+ {
+ best = c;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (best == NULL
+ || NEVER_NEGOTIATE(best->policy)
+ || (best->policy & POLICY_OPPO) == LEMPTY
+ || best->kind != CK_TEMPLATE)
+ return NULL;
+ else
+ return oppo_instantiate(best, &gw->gw_id.ip_addr, NULL, gw
+ , our_client, peer_client);
+}
+
+bool
+orient(struct connection *c)
+{
+ struct spd_route *sr;
+
+ if (!oriented(*c))
+ {
+ struct iface *p;
+
+ for (sr = &c->spd; sr; sr = sr->next)
+ {
+ /* Note: this loop does not stop when it finds a match:
+ * it continues checking to catch any ambiguity.
+ */
+ for (p = interfaces; p != NULL; p = p->next)
+ {
+ if (p->ike_float)
+ continue;
+
+ for (;;)
+ {
+ /* check if this interface matches this end */
+ if (sameaddr(&sr->this.host_addr, &p->addr)
+ && (!no_klips || sr->this.host_port == pluto_port))
+ {
+ if (oriented(*c))
+ {
+ if (c->interface == p)
+ loglog(RC_LOG_SERIOUS
+ , "both sides of \"%s\" are our interface %s!"
+ , c->name, p->rname);
+ else
+ loglog(RC_LOG_SERIOUS, "two interfaces match \"%s\" (%s, %s)"
+ , c->name, c->interface->rname, p->rname);
+ c->interface = NULL; /* withdraw orientation */
+ return FALSE;
+ }
+ c->interface = p;
+ }
+
+ /* done with this interface if it doesn't match that end */
+ if (!(sameaddr(&sr->that.host_addr, &p->addr)
+ && (!no_klips || sr->that.host_port == pluto_port)))
+ break;
+
+ /* swap ends and try again.
+ * It is a little tricky to see that this loop will stop.
+ * Only continue if the far side matches.
+ * If both sides match, there is an error-out.
+ */
+ {
+ struct end t = sr->this;
+
+ sr->this = sr->that;
+ sr->that = t;
+ }
+ }
+ }
+ }
+ }
+ return oriented(*c);
+}
+
+void
+initiate_connection(const char *name, int whackfd)
+{
+ struct connection *c = con_by_name(name, TRUE);
+
+ if (c != NULL && c->ikev1)
+ {
+ set_cur_connection(c);
+ if (!oriented(*c))
+ {
+ loglog(RC_ORIENT, "we have no ipsecN interface for either end of this connection");
+ }
+ else if (NEVER_NEGOTIATE(c->policy))
+ {
+ loglog(RC_INITSHUNT
+ , "cannot initiate an authby=never connection");
+ }
+ else if (c->kind != CK_PERMANENT)
+ {
+ if (isanyaddr(&c->spd.that.host_addr))
+ loglog(RC_NOPEERIP, "cannot initiate connection without knowing peer IP address");
+ else
+ loglog(RC_WILDCARD, "cannot initiate connection with ID wildcards");
+ }
+ else
+ {
+ /* We will only request an IPsec SA if policy isn't empty
+ * (ignoring Main Mode items).
+ * This is a fudge, but not yet important.
+ * If we are to proceed asynchronously, whackfd will be NULL_FD.
+ */
+ c->policy |= POLICY_UP;
+ /* do we have to prompt for a PIN code? */
+ if (c->spd.this.sc != NULL && !c->spd.this.sc->valid && whackfd != NULL_FD)
+ scx_get_pin(c->spd.this.sc, whackfd);
+
+ if (c->spd.this.sc != NULL && !c->spd.this.sc->valid)
+ {
+ loglog(RC_NOVALIDPIN, "cannot initiate connection without valid PIN");
+ }
+ else
+ {
+ ipsecdoi_initiate(whackfd, c, c->policy, 1, SOS_NOBODY);
+ whackfd = NULL_FD; /* protect from close */
+ }
+ }
+ reset_cur_connection();
+ }
+ close_any(whackfd);
+}
+
+/* (Possibly) Opportunistic Initiation:
+ * Knowing clients (single IP addresses), try to build an tunnel.
+ * This may involve discovering a gateway and instantiating an
+ * Opportunistic connection. Called when a packet is caught by
+ * a %trap, or when whack --oppohere --oppothere is used.
+ * It may turn out that an existing or non-opporunistic connnection
+ * can handle the traffic.
+ *
+ * Most of the code will be restarted if an ADNS request is made
+ * to discover the gateway. The only difference between the first
+ * and second entry is whether gateways_from_dns is NULL or not.
+ * initiate_opportunistic: initial entrypoint
+ * continue_oppo: where we pickup when ADNS result arrives
+ * initiate_opportunistic_body: main body shared by above routines
+ * cannot_oppo: a helper function to log a diagnostic
+ * This structure repeats a lot of code when the ADNS result arrives.
+ * This seems like a waste, but anything learned the first time through
+ * may no longer be true!
+ *
+ * After the first IKE message is sent, the regular state machinery
+ * carries negotiation forward.
+ */
+
+enum find_oppo_step {
+ fos_start,
+ fos_myid_ip_txt,
+ fos_myid_hostname_txt,
+ fos_myid_ip_key,
+ fos_myid_hostname_key,
+ fos_our_client,
+ fos_our_txt,
+#ifdef USE_KEYRR
+ fos_our_key,
+#endif /* USE_KEYRR */
+ fos_his_client,
+ fos_done
+};
+
+#ifdef DEBUG
+static const char *const oppo_step_name[] = {
+ "fos_start",
+ "fos_myid_ip_txt",
+ "fos_myid_hostname_txt",
+ "fos_myid_ip_key",
+ "fos_myid_hostname_key",
+ "fos_our_client",
+ "fos_our_txt",
+#ifdef USE_KEYRR
+ "fos_our_key",
+#endif /* USE_KEYRR */
+ "fos_his_client",
+ "fos_done"
+};
+#endif /* DEBUG */
+
+struct find_oppo_bundle {
+ enum find_oppo_step step;
+ err_t want;
+ bool failure_ok; /* if true, continue_oppo should not die on DNS failure */
+ ip_address our_client; /* not pointer! */
+ ip_address peer_client;
+ int transport_proto;
+ bool held;
+ policy_prio_t policy_prio;
+ ipsec_spi_t failure_shunt; /* in host order! 0 for delete. */
+ int whackfd;
+};
+
+struct find_oppo_continuation {
+ struct adns_continuation ac; /* common prefix */
+ struct find_oppo_bundle b;
+};
+
+static void
+cannot_oppo(struct connection *c
+ , struct find_oppo_bundle *b
+ , err_t ugh)
+{
+ char pcb[ADDRTOT_BUF];
+ char ocb[ADDRTOT_BUF];
+
+ addrtot(&b->peer_client, 0, pcb, sizeof(pcb));
+ addrtot(&b->our_client, 0, ocb, sizeof(ocb));
+
+ DBG(DBG_DNS | DBG_OPPO, DBG_log("Can't Opportunistically initiate for %s to %s: %s"
+ , ocb, pcb, ugh));
+
+ whack_log(RC_OPPOFAILURE
+ , "Can't Opportunistically initiate for %s to %s: %s"
+ , ocb, pcb, ugh);
+
+ if (c != NULL && c->policy_next != NULL)
+ {
+ /* there is some policy that comes afterwards */
+ struct spd_route *shunt_spd;
+ struct connection *nc = c->policy_next;
+ struct state *st;
+
+ passert(c->kind == CK_TEMPLATE);
+ passert(c->policy_next->kind == CK_PERMANENT);
+
+ DBG(DBG_OPPO, DBG_log("OE failed for %s to %s, but %s overrides shunt"
+ , ocb, pcb, c->policy_next->name));
+
+ /*
+ * okay, here we need add to the "next" policy, which is ought
+ * to be an instance.
+ * We will add another entry to the spd_route list for the specific
+ * situation that we have.
+ */
+
+ shunt_spd = clone_thing(nc->spd, "shunt eroute policy");
+
+ shunt_spd->next = nc->spd.next;
+ nc->spd.next = shunt_spd;
+
+ happy(addrtosubnet(&b->peer_client, &shunt_spd->that.client));
+
+ if (sameaddr(&b->peer_client, &shunt_spd->that.host_addr))
+ shunt_spd->that.has_client = FALSE;
+
+ /*
+ * override the tunnel destination with the one from the secondaried
+ * policy
+ */
+ shunt_spd->that.host_addr = nc->spd.that.host_addr;
+
+ /* now, lookup the state, and poke it up.
+ */
+
+ st = state_with_serialno(nc->newest_ipsec_sa);
+
+ /* XXX what to do if the IPSEC SA has died? */
+ passert(st != NULL);
+
+ /* link the new connection instance to the state's list of
+ * connections
+ */
+
+ DBG(DBG_OPPO, DBG_log("installing state: %ld for %s to %s"
+ , nc->newest_ipsec_sa
+ , ocb, pcb));
+
+#ifdef DEBUG
+ if (DBGP(DBG_OPPO | DBG_CONTROLMORE))
+ {
+ char state_buf[LOG_WIDTH];
+ char state_buf2[LOG_WIDTH];
+ time_t n = now();
+
+ fmt_state(FALSE, st, n
+ , state_buf, sizeof(state_buf)
+ , state_buf2, sizeof(state_buf2));
+ DBG_log("cannot_oppo, failure SA1: %s", state_buf);
+ DBG_log("cannot_oppo, failure SA2: %s", state_buf2);
+ }
+#endif /* DEBUG */
+
+ if (!route_and_eroute(c, shunt_spd, st))
+ {
+ whack_log(RC_OPPOFAILURE
+ , "failed to instantiate shunt policy %s for %s to %s"
+ , c->name
+ , ocb, pcb);
+ }
+ return;
+ }
+
+#ifdef KLIPS
+ if (b->held)
+ {
+ /* Replace HOLD with b->failure_shunt.
+ * If no b->failure_shunt specified, use SPI_PASS -- THIS MAY CHANGE.
+ */
+ if (b->failure_shunt == 0)
+ {
+ DBG(DBG_OPPO, DBG_log("no explicit failure shunt for %s to %s; installing %%pass"
+ , ocb, pcb));
+ }
+
+ (void) replace_bare_shunt(&b->our_client, &b->peer_client
+ , b->policy_prio
+ , b->failure_shunt
+ , b->failure_shunt != 0
+ , b->transport_proto
+ , ugh);
+ }
+#endif
+}
+
+static void initiate_opportunistic_body(struct find_oppo_bundle *b
+ , struct adns_continuation *ac, err_t ac_ugh); /* forward */
+
+void
+initiate_opportunistic(const ip_address *our_client
+, const ip_address *peer_client
+, int transport_proto
+, bool held
+, int whackfd)
+{
+ struct find_oppo_bundle b;
+
+ b.want = (whackfd == NULL_FD ? "whack" : "acquire");
+ b.failure_ok = FALSE;
+ b.our_client = *our_client;
+ b.peer_client = *peer_client;
+ b.transport_proto = transport_proto;
+ b.held = held;
+ b.policy_prio = BOTTOM_PRIO;
+ b.failure_shunt = 0;
+ b.whackfd = whackfd;
+ b.step = fos_start;
+ initiate_opportunistic_body(&b, NULL, NULL);
+}
+
+static void
+continue_oppo(struct adns_continuation *acr, err_t ugh)
+{
+ struct find_oppo_continuation *cr = (void *)acr; /* inherit, damn you! */
+ struct connection *c;
+ bool was_held = cr->b.held;
+ int whackfd = cr->b.whackfd;
+
+ /* note: cr->id has no resources; cr->sgw_id is id_none:
+ * neither need freeing.
+ */
+ whack_log_fd = whackfd;
+
+#ifdef KLIPS
+ /* Discover and record whether %hold has gone away.
+ * This could have happened while we were awaiting DNS.
+ * We must check BEFORE any call to cannot_oppo.
+ */
+ if (was_held)
+ cr->b.held = has_bare_hold(&cr->b.our_client, &cr->b.peer_client
+ , cr->b.transport_proto);
+#endif
+
+#ifdef DEBUG
+ /* if we're going to ignore the error, at least note it in debugging log */
+ if (cr->b.failure_ok && ugh != NULL)
+ {
+ DBG(DBG_CONTROL | DBG_DNS,
+ {
+ char ocb[ADDRTOT_BUF];
+ char pcb[ADDRTOT_BUF];
+
+ addrtot(&cr->b.our_client, 0, ocb, sizeof(ocb));
+ addrtot(&cr->b.peer_client, 0, pcb, sizeof(pcb));
+ DBG_log("continuing from failed DNS lookup for %s, %s to %s: %s"
+ , cr->b.want, ocb, pcb, ugh);
+ });
+ }
+#endif
+
+ if (!cr->b.failure_ok && ugh != NULL)
+ {
+ c = find_connection_for_clients(NULL, &cr->b.our_client, &cr->b.peer_client
+ , cr->b.transport_proto);
+ cannot_oppo(c, &cr->b
+ , builddiag("%s: %s", cr->b.want, ugh));
+ }
+ else if (was_held && !cr->b.held)
+ {
+ /* was_held indicates we were started due to a %trap firing
+ * (as opposed to a "whack --oppohere --oppothere").
+ * Since the %hold has gone, we can assume that somebody else
+ * has beaten us to the punch. We can go home. But lets log it.
+ */
+ char ocb[ADDRTOT_BUF];
+ char pcb[ADDRTOT_BUF];
+
+ addrtot(&cr->b.our_client, 0, ocb, sizeof(ocb));
+ addrtot(&cr->b.peer_client, 0, pcb, sizeof(pcb));
+
+ loglog(RC_COMMENT
+ , "%%hold otherwise handled during DNS lookup for Opportunistic Initiation for %s to %s"
+ , ocb, pcb);
+ }
+ else
+ {
+ initiate_opportunistic_body(&cr->b, &cr->ac, ugh);
+ whackfd = NULL_FD; /* was handed off */
+ }
+
+ whack_log_fd = NULL_FD;
+ close_any(whackfd);
+}
+
+#ifdef USE_KEYRR
+static err_t
+check_key_recs(enum myid_state try_state
+, const struct connection *c
+, struct adns_continuation *ac)
+{
+ /* Check if KEY lookup yielded good results.
+ * Looking up based on our ID. Used if
+ * client is ourself, or if TXT had no public key.
+ * Note: if c is different this time, there is
+ * a chance that we did the wrong query.
+ * If so, treat as a kind of failure.
+ */
+ enum myid_state old_myid_state = myid_state;
+ const struct RSA_private_key *our_RSA_pri;
+ err_t ugh = NULL;
+
+ myid_state = try_state;
+
+ if (old_myid_state != myid_state
+ && old_myid_state == MYID_SPECIFIED)
+ {
+ ugh = "%myid was specified while we were guessing";
+ }
+ else if ((our_RSA_pri = get_RSA_private_key(c)) == NULL)
+ {
+ ugh = "we don't know our own RSA key";
+ }
+ else if (!same_id(&ac->id, &c->spd.this.id))
+ {
+ ugh = "our ID changed underfoot";
+ }
+ else
+ {
+ /* Similar to code in RSA_check_signature
+ * for checking the other side.
+ */
+ pubkey_list_t *kr;
+
+ ugh = "no KEY RR found for us";
+ for (kr = ac->keys_from_dns; kr != NULL; kr = kr->next)
+ {
+ ugh = "all our KEY RRs have the wrong public key";
+ if (kr->key->alg == PUBKEY_ALG_RSA
+ && same_RSA_public_key(&our_RSA_pri->pub, &kr->key->u.rsa))
+ {
+ ugh = NULL; /* good! */
+ break;
+ }
+ }
+ }
+ if (ugh != NULL)
+ myid_state = old_myid_state;
+ return ugh;
+}
+#endif /* USE_KEYRR */
+
+static err_t
+check_txt_recs(enum myid_state try_state
+, const struct connection *c
+, struct adns_continuation *ac)
+{
+ /* Check if TXT lookup yielded good results.
+ * Looking up based on our ID. Used if
+ * client is ourself, or if TXT had no public key.
+ * Note: if c is different this time, there is
+ * a chance that we did the wrong query.
+ * If so, treat as a kind of failure.
+ */
+ enum myid_state old_myid_state = myid_state;
+ const struct RSA_private_key *our_RSA_pri;
+ err_t ugh = NULL;
+
+ myid_state = try_state;
+
+ if (old_myid_state != myid_state
+ && old_myid_state == MYID_SPECIFIED)
+ {
+ ugh = "%myid was specified while we were guessing";
+ }
+ else if ((our_RSA_pri = get_RSA_private_key(c)) == NULL)
+ {
+ ugh = "we don't know our own RSA key";
+ }
+ else if (!same_id(&ac->id, &c->spd.this.id))
+ {
+ ugh = "our ID changed underfoot";
+ }
+ else
+ {
+ /* Similar to code in RSA_check_signature
+ * for checking the other side.
+ */
+ struct gw_info *gwp;
+
+ ugh = "no TXT RR found for us";
+ for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next)
+ {
+ ugh = "all our TXT RRs have the wrong public key";
+ if (gwp->key->alg == PUBKEY_ALG_RSA
+ && same_RSA_public_key(&our_RSA_pri->pub, &gwp->key->u.rsa))
+ {
+ ugh = NULL; /* good! */
+ break;
+ }
+ }
+ }
+ if (ugh != NULL)
+ myid_state = old_myid_state;
+ return ugh;
+}
+
+
+/* note: gateways_from_dns must be NULL iff this is the first call */
+static void
+initiate_opportunistic_body(struct find_oppo_bundle *b
+, struct adns_continuation *ac
+, err_t ac_ugh)
+{
+ struct connection *c;
+ struct spd_route *sr;
+
+ /* What connection shall we use?
+ * First try for one that explicitly handles the clients.
+ */
+ DBG(DBG_CONTROL,
+ {
+ char ours[ADDRTOT_BUF];
+ char his[ADDRTOT_BUF];
+ int ourport;
+ int hisport;
+
+ addrtot(&b->our_client, 0, ours, sizeof(ours));
+ addrtot(&b->peer_client, 0, his, sizeof(his));
+ ourport = ntohs(portof(&b->our_client));
+ hisport = ntohs(portof(&b->peer_client));
+ DBG_log("initiate on demand from %s:%d to %s:%d proto=%d state: %s because: %s"
+ , ours, ourport, his, hisport, b->transport_proto
+ , oppo_step_name[b->step], b->want);
+ });
+ if (isanyaddr(&b->our_client) || isanyaddr(&b->peer_client))
+ {
+ cannot_oppo(NULL, b, "impossible IP address");
+ }
+ else if ((c = find_connection_for_clients(&sr
+ , &b->our_client
+ , &b->peer_client
+ , b->transport_proto)) == NULL)
+ {
+ /* No connection explicitly handles the clients and there
+ * are no Opportunistic connections -- whine and give up.
+ * The failure policy cannot be gotten from a connection; we pick %pass.
+ */
+ cannot_oppo(NULL, b, "no routed Opportunistic template covers this pair");
+ }
+ else if (c->kind != CK_TEMPLATE)
+ {
+ /* We've found a connection that can serve.
+ * Do we have to initiate it?
+ * Not if there is currently an IPSEC SA.
+ * But if there is an IPSEC SA, then KLIPS would not
+ * have generated the acquire. So we assume that there isn't one.
+ * This may be redundant if a non-opportunistic
+ * negotiation is already being attempted.
+ */
+
+ /* If we are to proceed asynchronously, b->whackfd will be NULL_FD. */
+
+ if(c->kind == CK_INSTANCE)
+ {
+ char cib[CONN_INST_BUF];
+ /* there is already an instance being negotiated, no nothing */
+ DBG(DBG_CONTROL, DBG_log("found existing instance \"%s\"%s, rekeying it"
+ , c->name
+ , (fmt_conn_instance(c, cib), cib)));
+ /* XXX-mcr - return; */
+ }
+
+ /* otherwise, there is some kind of static conn that can handle
+ * this connection, so we initiate it */
+
+#ifdef KLIPS
+ if (b->held)
+ {
+ /* what should we do on failure? */
+ (void) assign_hold(c, sr, b->transport_proto, &b->our_client, &b->peer_client);
+ }
+#endif
+ ipsecdoi_initiate(b->whackfd, c, c->policy, 1, SOS_NOBODY);
+ b->whackfd = NULL_FD; /* protect from close */
+ }
+ else
+ {
+ /* We are handling an opportunistic situation.
+ * This involves several DNS lookup steps that require suspension.
+ * Note: many facts might change while we're suspended.
+ * Here be dragons.
+ *
+ * The first chunk of code handles the result of the previous
+ * DNS query (if any). It also selects the kind of the next step.
+ * The second chunk initiates the next DNS query (if any).
+ */
+ enum find_oppo_step next_step;
+ err_t ugh = ac_ugh;
+ char mycredentialstr[BUF_LEN];
+ char cib[CONN_INST_BUF];
+
+ DBG(DBG_CONTROL, DBG_log("creating new instance from \"%s\"%s"
+ , c->name
+ , (fmt_conn_instance(c, cib), cib)));
+
+
+ idtoa(&sr->this.id, mycredentialstr, sizeof(mycredentialstr));
+
+ passert(c->policy & POLICY_OPPO); /* can't initiate Road Warrior connections */
+
+ /* handle any DNS answer; select next step */
+
+ switch (b->step)
+ {
+ case fos_start:
+ /* just starting out: select first query step */
+ next_step = fos_myid_ip_txt;
+ break;
+
+ case fos_myid_ip_txt: /* TXT for our default IP address as %myid */
+ ugh = check_txt_recs(MYID_IP, c, ac);
+ if (ugh != NULL)
+ {
+ /* cannot use our IP as OE identitiy for initiation */
+ DBG(DBG_OPPO, DBG_log("can not use our IP (%s:TXT) as identity: %s"
+ , myid_str[MYID_IP]
+ , ugh));
+ if (!logged_myid_ip_txt_warning)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "can not use our IP (%s:TXT) as identity: %s"
+ , myid_str[MYID_IP]
+ , ugh);
+ logged_myid_ip_txt_warning = TRUE;
+ }
+
+ next_step = fos_myid_hostname_txt;
+ ugh = NULL; /* failure can be recovered from */
+ }
+ else
+ {
+ /* we can use our IP as OE identity for initiation */
+ if (!logged_myid_ip_txt_warning)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "using our IP (%s:TXT) as identity!"
+ , myid_str[MYID_IP]);
+ logged_myid_ip_txt_warning = TRUE;
+ }
+
+ next_step = fos_our_client;
+ }
+ break;
+
+ case fos_myid_hostname_txt: /* TXT for our hostname as %myid */
+ ugh = check_txt_recs(MYID_HOSTNAME, c, ac);
+ if (ugh != NULL)
+ {
+ /* cannot use our hostname as OE identitiy for initiation */
+ DBG(DBG_OPPO, DBG_log("can not use our hostname (%s:TXT) as identity: %s"
+ , myid_str[MYID_HOSTNAME]
+ , ugh));
+ if (!logged_myid_fqdn_txt_warning)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "can not use our hostname (%s:TXT) as identity: %s"
+ , myid_str[MYID_HOSTNAME]
+ , ugh);
+ logged_myid_fqdn_txt_warning = TRUE;
+ }
+#ifdef USE_KEYRR
+ next_step = fos_myid_ip_key;
+ ugh = NULL; /* failure can be recovered from */
+#endif
+ }
+ else
+ {
+ /* we can use our hostname as OE identity for initiation */
+ if (!logged_myid_fqdn_txt_warning)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "using our hostname (%s:TXT) as identity!"
+ , myid_str[MYID_HOSTNAME]);
+ logged_myid_fqdn_txt_warning = TRUE;
+ }
+ next_step = fos_our_client;
+ }
+ break;
+
+#ifdef USE_KEYRR
+ case fos_myid_ip_key: /* KEY for our default IP address as %myid */
+ ugh = check_key_recs(MYID_IP, c, ac);
+ if (ugh != NULL)
+ {
+ /* cannot use our IP as OE identitiy for initiation */
+ DBG(DBG_OPPO, DBG_log("can not use our IP (%s:KEY) as identity: %s"
+ , myid_str[MYID_IP]
+ , ugh));
+ if (!logged_myid_ip_key_warning)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "can not use our IP (%s:KEY) as identity: %s"
+ , myid_str[MYID_IP]
+ , ugh);
+ logged_myid_ip_key_warning = TRUE;
+ }
+
+ next_step = fos_myid_hostname_key;
+ ugh = NULL; /* failure can be recovered from */
+ }
+ else
+ {
+ /* we can use our IP as OE identity for initiation */
+ if (!logged_myid_ip_key_warning)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "using our IP (%s:KEY) as identity!"
+ , myid_str[MYID_IP]);
+ logged_myid_ip_key_warning = TRUE;
+ }
+ next_step = fos_our_client;
+ }
+ break;
+
+ case fos_myid_hostname_key: /* KEY for our hostname as %myid */
+ ugh = check_key_recs(MYID_HOSTNAME, c, ac);
+ if (ugh != NULL)
+ {
+ /* cannot use our IP as OE identitiy for initiation */
+ DBG(DBG_OPPO, DBG_log("can not use our hostname (%s:KEY) as identity: %s"
+ , myid_str[MYID_HOSTNAME]
+ , ugh));
+ if (!logged_myid_fqdn_key_warning)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "can not use our hostname (%s:KEY) as identity: %s"
+ , myid_str[MYID_HOSTNAME]
+ , ugh);
+ logged_myid_fqdn_key_warning = TRUE;
+ }
+
+ next_step = fos_myid_hostname_key;
+ ugh = NULL; /* failure can be recovered from */
+ }
+ else
+ {
+ /* we can use our IP as OE identity for initiation */
+ if (!logged_myid_fqdn_key_warning)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "using our hostname (%s:KEY) as identity!"
+ , myid_str[MYID_HOSTNAME]);
+ logged_myid_fqdn_key_warning = TRUE;
+ }
+ next_step = fos_our_client;
+ }
+ break;
+#endif
+
+ case fos_our_client: /* TXT for our client */
+ {
+ /* Our client is not us: we must check the TXT records.
+ * Note: if c is different this time, there is
+ * a chance that we did the wrong query.
+ * If so, treat as a kind of failure.
+ */
+ const struct RSA_private_key *our_RSA_pri = get_RSA_private_key(c);
+
+ next_step = fos_his_client; /* normal situation */
+
+ passert(sr != NULL);
+
+ if (our_RSA_pri == NULL)
+ {
+ ugh = "we don't know our own RSA key";
+ }
+ else if (sameaddr(&sr->this.host_addr, &b->our_client))
+ {
+ /* this wasn't true when we started -- bail */
+ ugh = "our IP address changed underfoot";
+ }
+ else if (!same_id(&ac->sgw_id, &sr->this.id))
+ {
+ /* this wasn't true when we started -- bail */
+ ugh = "our ID changed underfoot";
+ }
+ else
+ {
+ /* Similar to code in quick_inI1_outR1_tail
+ * for checking the other side.
+ */
+ struct gw_info *gwp;
+
+ ugh = "no TXT RR for our client delegates us";
+ for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next)
+ {
+ passert(same_id(&gwp->gw_id, &sr->this.id));
+
+ ugh = "TXT RR for our client has wrong key";
+ /* If there is a key from the TXT record,
+ * we count it as a win if we match the key.
+ * If there was no key, we have a tentative win:
+ * we need to check our KEY record to be sure.
+ */
+ if (!gwp->gw_key_present)
+ {
+ /* Success, but the TXT had no key
+ * so we must check our our own KEY records.
+ */
+ next_step = fos_our_txt;
+ ugh = NULL; /* good! */
+ break;
+ }
+ if (same_RSA_public_key(&our_RSA_pri->pub, &gwp->key->u.rsa))
+ {
+ ugh = NULL; /* good! */
+ break;
+ }
+ }
+ }
+ }
+ break;
+
+ case fos_our_txt: /* TXT for us */
+ {
+ /* Check if TXT lookup yielded good results.
+ * Looking up based on our ID. Used if
+ * client is ourself, or if TXT had no public key.
+ * Note: if c is different this time, there is
+ * a chance that we did the wrong query.
+ * If so, treat as a kind of failure.
+ */
+ const struct RSA_private_key *our_RSA_pri = get_RSA_private_key(c);
+
+ next_step = fos_his_client; /* unless we decide to look for KEY RR */
+
+ if (our_RSA_pri == NULL)
+ {
+ ugh = "we don't know our own RSA key";
+ }
+ else if (!same_id(&ac->id, &c->spd.this.id))
+ {
+ ugh = "our ID changed underfoot";
+ }
+ else
+ {
+ /* Similar to code in RSA_check_signature
+ * for checking the other side.
+ */
+ struct gw_info *gwp;
+
+ ugh = "no TXT RR for us";
+ for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next)
+ {
+ passert(same_id(&gwp->gw_id, &sr->this.id));
+
+ ugh = "TXT RR for us has wrong key";
+ if (gwp->gw_key_present
+ && same_RSA_public_key(&our_RSA_pri->pub, &gwp->key->u.rsa))
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("initiate on demand found TXT with right public key at: %s"
+ , mycredentialstr));
+ ugh = NULL;
+ break;
+ }
+ }
+#ifdef USE_KEYRR
+ if (ugh != NULL)
+ {
+ /* if no TXT with right key, try KEY */
+ DBG(DBG_CONTROL,
+ DBG_log("will try for KEY RR since initiate on demand found %s: %s"
+ , ugh, mycredentialstr));
+ next_step = fos_our_key;
+ ugh = NULL;
+ }
+#endif
+ }
+ }
+ break;
+
+#ifdef USE_KEYRR
+ case fos_our_key: /* KEY for us */
+ {
+ /* Check if KEY lookup yielded good results.
+ * Looking up based on our ID. Used if
+ * client is ourself, or if TXT had no public key.
+ * Note: if c is different this time, there is
+ * a chance that we did the wrong query.
+ * If so, treat as a kind of failure.
+ */
+ const struct RSA_private_key *our_RSA_pri = get_RSA_private_key(c);
+
+ next_step = fos_his_client; /* always */
+
+ if (our_RSA_pri == NULL)
+ {
+ ugh = "we don't know our own RSA key";
+ }
+ else if (!same_id(&ac->id, &c->spd.this.id))
+ {
+ ugh = "our ID changed underfoot";
+ }
+ else
+ {
+ /* Similar to code in RSA_check_signature
+ * for checking the other side.
+ */
+ pubkey_list_t *kr;
+
+ ugh = "no KEY RR found for us (and no good TXT RR)";
+ for (kr = ac->keys_from_dns; kr != NULL; kr = kr->next)
+ {
+ ugh = "all our KEY RRs have the wrong public key (and no good TXT RR)";
+ if (kr->key->alg == PUBKEY_ALG_RSA
+ && same_RSA_public_key(&our_RSA_pri->pub, &kr->key->u.rsa))
+ {
+ /* do this only once a day */
+ if (!logged_txt_warning)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "found KEY RR but not TXT RR for %s. See http://www.freeswan.org/err/txt-change.html."
+ , mycredentialstr);
+ logged_txt_warning = TRUE;
+ }
+ ugh = NULL; /* good! */
+ break;
+ }
+ }
+ }
+ }
+ break;
+#endif /* USE_KEYRR */
+
+ case fos_his_client: /* TXT for his client */
+ {
+ /* We've finished last DNS queries: TXT for his client.
+ * Using the information, try to instantiate a connection
+ * and start negotiating.
+ * We now know the peer. The chosing of "c" ignored this,
+ * so we will disregard its current value.
+ * !!! We need to randomize the entry in gw that we choose.
+ */
+ next_step = fos_done; /* no more queries */
+
+ c = build_outgoing_opportunistic_connection(ac->gateways_from_dns
+ , &b->our_client
+ , &b->peer_client);
+
+ if (c == NULL)
+ {
+ /* We cannot seem to instantiate a suitable connection:
+ * complain clearly.
+ */
+ char ocb[ADDRTOT_BUF]
+ , pcb[ADDRTOT_BUF]
+ , pb[ADDRTOT_BUF];
+
+ addrtot(&b->our_client, 0, ocb, sizeof(ocb));
+ addrtot(&b->peer_client, 0, pcb, sizeof(pcb));
+ passert(id_is_ipaddr(&ac->gateways_from_dns->gw_id));
+ addrtot(&ac->gateways_from_dns->gw_id.ip_addr, 0, pb, sizeof(pb));
+ loglog(RC_OPPOFAILURE
+ , "no suitable connection for opportunism"
+ " between %s and %s with %s as peer"
+ , ocb, pcb, pb);
+
+#ifdef KLIPS
+ if (b->held)
+ {
+ /* Replace HOLD with PASS.
+ * The type of replacement *ought* to be
+ * specified by policy.
+ */
+ (void) replace_bare_shunt(&b->our_client, &b->peer_client
+ , BOTTOM_PRIO
+ , SPI_PASS /* fail into PASS */
+ , TRUE, b->transport_proto
+ , "no suitable connection");
+ }
+#endif
+ }
+ else
+ {
+ /* If we are to proceed asynchronously, b->whackfd will be NULL_FD. */
+ passert(c->kind == CK_INSTANCE);
+ passert(c->gw_info != NULL);
+ passert(HAS_IPSEC_POLICY(c->policy));
+ passert(LHAS(LELEM(RT_UNROUTED) | LELEM(RT_ROUTED_PROSPECTIVE), c->spd.routing));
+#ifdef KLIPS
+ if (b->held)
+ {
+ /* what should we do on failure? */
+ (void) assign_hold(c, &c->spd
+ , b->transport_proto
+ , &b->our_client, &b->peer_client);
+ }
+#endif
+ c->gw_info->key->last_tried_time = now();
+ ipsecdoi_initiate(b->whackfd, c, c->policy, 1, SOS_NOBODY);
+ b->whackfd = NULL_FD; /* protect from close */
+ }
+ }
+ break;
+
+ default:
+ bad_case(b->step);
+ }
+
+ /* the second chunk: initiate the next DNS query (if any) */
+ DBG(DBG_CONTROL,
+ {
+ char ours[ADDRTOT_BUF];
+ char his[ADDRTOT_BUF];
+
+ addrtot(&b->our_client, 0, ours, sizeof(ours));
+ addrtot(&b->peer_client, 0, his, sizeof(his));
+ DBG_log("initiate on demand from %s to %s new state: %s with ugh: %s"
+ , ours, his, oppo_step_name[b->step], ugh ? ugh : "ok");
+ });
+
+ if (ugh != NULL)
+ {
+ b->policy_prio = c->prio;
+ b->failure_shunt = shunt_policy_spi(c, FALSE);
+ cannot_oppo(c, b, ugh);
+ }
+ else if (next_step == fos_done)
+ {
+ /* nothing to do */
+ }
+ else
+ {
+ /* set up the next query */
+ struct find_oppo_continuation *cr = alloc_thing(struct find_oppo_continuation
+ , "opportunistic continuation");
+ struct id id;
+
+ b->policy_prio = c->prio;
+ b->failure_shunt = shunt_policy_spi(c, FALSE);
+ cr->b = *b; /* copy; start hand off of whackfd */
+ cr->b.failure_ok = FALSE;
+ cr->b.step = next_step;
+
+ for (sr = &c->spd
+ ; sr!=NULL && !sameaddr(&sr->this.host_addr, &b->our_client)
+ ; sr = sr->next)
+ ;
+
+ if (sr == NULL)
+ sr = &c->spd;
+
+ /* If a %hold shunt has replaced the eroute for this template,
+ * record this fact.
+ */
+ if (b->held
+ && sr->routing == RT_ROUTED_PROSPECTIVE && eclipsable(sr))
+ {
+ sr->routing = RT_ROUTED_ECLIPSED;
+ eclipse_count++;
+ }
+
+ /* Switch to issue next query.
+ * A case may turn out to be unnecessary. If so, it falls
+ * through to the next case.
+ * Figuring out what %myid can stand for must be done before
+ * our client credentials are looked up: we must know what
+ * the client credentials may use to identify us.
+ * On the other hand, our own credentials should be looked
+ * up after our clients in case our credentials are not
+ * needed at all.
+ * XXX this is a wasted effort if we don't have credentials
+ * BUT they are not needed.
+ */
+ switch (next_step)
+ {
+ case fos_myid_ip_txt:
+ if (c->spd.this.id.kind == ID_MYID
+ && myid_state != MYID_SPECIFIED)
+ {
+ cr->b.failure_ok = TRUE;
+ cr->b.want = b->want = "TXT record for IP address as %myid";
+ ugh = start_adns_query(&myids[MYID_IP]
+ , &myids[MYID_IP]
+ , T_TXT
+ , continue_oppo
+ , &cr->ac);
+ break;
+ }
+ cr->b.step = fos_myid_hostname_txt;
+ /* fall through */
+
+ case fos_myid_hostname_txt:
+ if (c->spd.this.id.kind == ID_MYID
+ && myid_state != MYID_SPECIFIED)
+ {
+#ifdef USE_KEYRR
+ cr->b.failure_ok = TRUE;
+#else
+ cr->b.failure_ok = FALSE;
+#endif
+ cr->b.want = b->want = "TXT record for hostname as %myid";
+ ugh = start_adns_query(&myids[MYID_HOSTNAME]
+ , &myids[MYID_HOSTNAME]
+ , T_TXT
+ , continue_oppo
+ , &cr->ac);
+ break;
+ }
+
+#ifdef USE_KEYRR
+ cr->b.step = fos_myid_ip_key;
+ /* fall through */
+
+ case fos_myid_ip_key:
+ if (c->spd.this.id.kind == ID_MYID
+ && myid_state != MYID_SPECIFIED)
+ {
+ cr->b.failure_ok = TRUE;
+ cr->b.want = b->want = "KEY record for IP address as %myid (no good TXT)";
+ ugh = start_adns_query(&myids[MYID_IP]
+ , (const struct id *) NULL /* security gateway meaningless */
+ , T_KEY
+ , continue_oppo
+ , &cr->ac);
+ break;
+ }
+ cr->b.step = fos_myid_hostname_key;
+ /* fall through */
+
+ case fos_myid_hostname_key:
+ if (c->spd.this.id.kind == ID_MYID
+ && myid_state != MYID_SPECIFIED)
+ {
+ cr->b.failure_ok = FALSE; /* last attempt! */
+ cr->b.want = b->want = "KEY record for hostname as %myid (no good TXT)";
+ ugh = start_adns_query(&myids[MYID_HOSTNAME]
+ , (const struct id *) NULL /* security gateway meaningless */
+ , T_KEY
+ , continue_oppo
+ , &cr->ac);
+ break;
+ }
+#endif
+ cr->b.step = fos_our_client;
+ /* fall through */
+
+ case fos_our_client: /* TXT for our client */
+ if (!sameaddr(&c->spd.this.host_addr, &b->our_client))
+ {
+ /* Check that at least one TXT(reverse(b->our_client)) is workable.
+ * Note: {unshare|free}_id_content not needed for id: ephemeral.
+ */
+ cr->b.want = b->want = "our client's TXT record";
+ iptoid(&b->our_client, &id);
+ ugh = start_adns_query(&id
+ , &c->spd.this.id /* we are the security gateway */
+ , T_TXT
+ , continue_oppo
+ , &cr->ac);
+ break;
+ }
+ cr->b.step = fos_our_txt;
+ /* fall through */
+
+ case fos_our_txt: /* TXT for us */
+ cr->b.failure_ok = b->failure_ok = TRUE;
+ cr->b.want = b->want = "our TXT record";
+ ugh = start_adns_query(&sr->this.id
+ , &sr->this.id /* we are the security gateway XXX - maybe ignore? mcr */
+ , T_TXT
+ , continue_oppo
+ , &cr->ac);
+ break;
+
+#ifdef USE_KEYRR
+ case fos_our_key: /* KEY for us */
+ cr->b.want = b->want = "our KEY record";
+ cr->b.failure_ok = b->failure_ok = FALSE;
+ ugh = start_adns_query(&sr->this.id
+ , (const struct id *) NULL /* security gateway meaningless */
+ , T_KEY
+ , continue_oppo
+ , &cr->ac);
+ break;
+#endif /* USE_KEYRR */
+
+ case fos_his_client: /* TXT for his client */
+ /* note: {unshare|free}_id_content not needed for id: ephemeral */
+ cr->b.want = b->want = "target's TXT record";
+ cr->b.failure_ok = b->failure_ok = FALSE;
+ iptoid(&b->peer_client, &id);
+ ugh = start_adns_query(&id
+ , (const struct id *) NULL /* security gateway unconstrained */
+ , T_TXT
+ , continue_oppo
+ , &cr->ac);
+ break;
+
+ default:
+ bad_case(next_step);
+ }
+
+ if (ugh == NULL)
+ b->whackfd = NULL_FD; /* complete hand-off */
+ else
+ cannot_oppo(c, b, ugh);
+ }
+ }
+ close_any(b->whackfd);
+}
+
+void
+terminate_connection(const char *nm)
+{
+ /* Loop because more than one may match (master and instances)
+ * But at least one is required (enforced by con_by_name).
+ */
+ struct connection *c = con_by_name(nm, TRUE);
+
+ if (c == NULL || !c->ikev1)
+ return;
+
+ do
+ {
+ struct connection *n = c->ac_next; /* grab this before c might disappear */
+
+ if (streq(c->name, nm)
+ && c->kind >= CK_PERMANENT
+ && !NEVER_NEGOTIATE(c->policy))
+ {
+ set_cur_connection(c);
+ plog("terminating SAs using this connection");
+ c->policy &= ~POLICY_UP;
+ flush_pending_by_connection(c);
+ delete_states_by_connection(c, FALSE);
+ reset_cur_connection();
+ }
+ c = n;
+ } while (c != NULL);
+}
+
+/* check nexthop safety
+ * Our nexthop must not be within a routed client subnet, and vice versa.
+ * Note: we don't think this is true. We think that KLIPS will
+ * not process a packet output by an eroute.
+ */
+#ifdef NEVER
+//bool
+//check_nexthop(const struct connection *c)
+//{
+// struct connection *d;
+//
+// if (addrinsubnet(&c->spd.this.host_nexthop, &c->spd.that.client))
+// {
+// loglog(RC_LOG_SERIOUS, "cannot perform routing for connection \"%s\""
+// " because nexthop is within peer's client network",
+// c->name);
+// return FALSE;
+// }
+//
+// for (d = connections; d != NULL; d = d->next)
+// {
+// if (d->routing != RT_UNROUTED)
+// {
+// if (addrinsubnet(&c->spd.this.host_nexthop, &d->spd.that.client))
+// {
+// loglog(RC_LOG_SERIOUS, "cannot do routing for connection \"%s\"
+// " because nexthop is contained in"
+// " existing routing for connection \"%s\"",
+// c->name, d->name);
+// return FALSE;
+// }
+// if (addrinsubnet(&d->spd.this.host_nexthop, &c->spd.that.client))
+// {
+// loglog(RC_LOG_SERIOUS, "cannot do routing for connection \"%s\"
+// " because it contains nexthop of"
+// " existing routing for connection \"%s\"",
+// c->name, d->name);
+// return FALSE;
+// }
+// }
+// }
+// return TRUE;
+//}
+#endif /* NEVER */
+
+/* an ISAKMP SA has been established.
+ * Note the serial number, and release any connections with
+ * the same peer ID but different peer IP address.
+ */
+bool uniqueIDs = FALSE; /* --uniqueids? */
+
+void
+ISAKMP_SA_established(struct connection *c, so_serial_t serial)
+{
+ c->newest_isakmp_sa = serial;
+
+ /* the connection is now oriented so that we are able to determine
+ * whether we are a mode config server with a virtual IP to send.
+ */
+ if (!isanyaddr(&c->spd.that.host_srcip) && !c->spd.that.has_natip)
+ c->spd.that.modecfg = TRUE;
+
+ if (uniqueIDs)
+ {
+ /* for all connections: if the same Phase 1 IDs are used
+ * for a different IP address, unorient that connection.
+ */
+ struct connection *d;
+
+ for (d = connections; d != NULL; )
+ {
+ struct connection *next = d->ac_next; /* might move underneath us */
+
+ if (d->kind >= CK_PERMANENT
+ && same_id(&c->spd.this.id, &d->spd.this.id)
+ && same_id(&c->spd.that.id, &d->spd.that.id)
+ && (!sameaddr(&c->spd.that.host_addr, &d->spd.that.host_addr) ||
+ (c->spd.that.host_port != d->spd.that.host_port)))
+ {
+ release_connection(d, FALSE);
+ }
+ d = next;
+ }
+ }
+}
+
+/* Find the connection to connection c's peer's client with the
+ * largest value of .routing. All other things being equal,
+ * preference is given to c. If none is routed, return NULL.
+ *
+ * If erop is non-null, set *erop to a connection sharing both
+ * our client subnet and peer's client subnet with the largest value
+ * of .routing. If none is erouted, set *erop to NULL.
+ *
+ * The return value is used to find other connections sharing a route.
+ * *erop is used to find other connections sharing an eroute.
+ */
+struct connection *
+route_owner(struct connection *c
+ , struct spd_route **srp
+ , struct connection **erop
+ , struct spd_route **esrp)
+{
+ struct connection *d
+ , *best_ro = c
+ , *best_ero = c;
+ struct spd_route *srd, *src;
+ struct spd_route *best_sr, *best_esr;
+ enum routing_t best_routing, best_erouting;
+
+ passert(oriented(*c));
+ best_sr = NULL;
+ best_esr = NULL;
+ best_routing = c->spd.routing;
+ best_erouting = best_routing;
+
+ for (d = connections; d != NULL; d = d->ac_next)
+ {
+ for (srd = &d->spd; srd; srd = srd->next)
+ {
+ if (srd->routing == RT_UNROUTED)
+ continue;
+
+ for (src = &c->spd; src; src=src->next)
+ {
+ if (!samesubnet(&src->that.client, &srd->that.client))
+ continue;
+ if (src->that.protocol != srd->that.protocol)
+ continue;
+ if (src->that.port != srd->that.port)
+ continue;
+ passert(oriented(*d));
+ if (srd->routing > best_routing)
+ {
+ best_ro = d;
+ best_sr = srd;
+ best_routing = srd->routing;
+ }
+
+ if (!samesubnet(&src->this.client, &srd->this.client))
+ continue;
+ if (src->this.protocol != srd->this.protocol)
+ continue;
+ if (src->this.port != srd->this.port)
+ continue;
+ if (srd->routing > best_erouting)
+ {
+ best_ero = d;
+ best_esr = srd;
+ best_erouting = srd->routing;
+ }
+ }
+ }
+ }
+
+ DBG(DBG_CONTROL,
+ {
+ char cib[CONN_INST_BUF];
+ err_t m = builddiag("route owner of \"%s\"%s %s:"
+ , c->name
+ , (fmt_conn_instance(c, cib), cib)
+ , enum_name(&routing_story, c->spd.routing));
+
+ if (!routed(best_ro->spd.routing))
+ m = builddiag("%s NULL", m);
+ else if (best_ro == c)
+ m = builddiag("%s self", m);
+ else
+ m = builddiag("%s \"%s\"%s %s", m
+ , best_ro->name
+ , (fmt_conn_instance(best_ro, cib), cib)
+ , enum_name(&routing_story, best_ro->spd.routing));
+
+ if (erop != NULL)
+ {
+ m = builddiag("%s; eroute owner:", m);
+ if (!erouted(best_ero->spd.routing))
+ m = builddiag("%s NULL", m);
+ else if (best_ero == c)
+ m = builddiag("%s self", m);
+ else
+ m = builddiag("%s \"%s\"%s %s", m
+ , best_ero->name
+ , (fmt_conn_instance(best_ero, cib), cib)
+ , enum_name(&routing_story, best_ero->spd.routing));
+ }
+
+ DBG_log("%s", m);
+ });
+
+ if (erop != NULL)
+ *erop = erouted(best_erouting)? best_ero : NULL;
+
+ if (srp != NULL )
+ {
+ *srp = best_sr;
+ if (esrp != NULL )
+ *esrp = best_esr;
+ }
+
+ return routed(best_routing)? best_ro : NULL;
+}
+
+/* Find a connection that owns the shunt eroute between subnets.
+ * There ought to be only one.
+ * This might get to be a bottleneck -- try hashing if it does.
+ */
+struct connection *
+shunt_owner(const ip_subnet *ours, const ip_subnet *his)
+{
+ struct connection *c;
+ struct spd_route *sr;
+
+ for (c = connections; c != NULL; c = c->ac_next)
+ {
+ for (sr = &c->spd; sr; sr = sr->next)
+ {
+ if (shunt_erouted(sr->routing)
+ && samesubnet(ours, &sr->this.client)
+ && samesubnet(his, &sr->that.client))
+ return c;
+ }
+ }
+ return NULL;
+}
+
+/* Find some connection with this pair of hosts.
+ * We don't know enough to chose amongst those available.
+ * ??? no longer usefully different from find_host_pair_connections
+ */
+struct connection *
+find_host_connection(const ip_address *me, u_int16_t my_port
+, const ip_address *him, u_int16_t his_port, lset_t policy)
+{
+ struct connection *c = find_host_pair_connections(me, my_port, him, his_port);
+
+ if (policy != LEMPTY)
+ {
+ lset_t auth_requested = policy & POLICY_ID_AUTH_MASK;
+
+ /* if we have requirements for the policy,
+ * choose the first matching connection.
+ */
+ while (c != NULL)
+ {
+ if (c->policy & auth_requested)
+ {
+ break;
+ }
+ c = c->hp_next;
+ }
+ }
+ return c;
+}
+
+/* given an up-until-now satisfactory connection, find the best connection
+ * now that we just got the Phase 1 Id Payload from the peer.
+ *
+ * Comments in the code describe the (tricky!) matching criteria.
+ * Although this routine could handle the initiator case,
+ * it isn't currently called in this case.
+ * If it were, it could "upgrade" an Opportunistic Connection
+ * to a Road Warrior Connection if a suitable Peer ID were found.
+ *
+ * In RFC 2409 "The Internet Key Exchange (IKE)",
+ * in 5.1 "IKE Phase 1 Authenticated With Signatures", describing Main
+ * Mode:
+ *
+ * Initiator Responder
+ * ----------- -----------
+ * HDR, SA -->
+ * <-- HDR, SA
+ * HDR, KE, Ni -->
+ * <-- HDR, KE, Nr
+ * HDR*, IDii, [ CERT, ] SIG_I -->
+ * <-- HDR*, IDir, [ CERT, ] SIG_R
+ *
+ * In 5.4 "Phase 1 Authenticated With a Pre-Shared Key":
+ *
+ * HDR, SA -->
+ * <-- HDR, SA
+ * HDR, KE, Ni -->
+ * <-- HDR, KE, Nr
+ * HDR*, IDii, HASH_I -->
+ * <-- HDR*, IDir, HASH_R
+ *
+ * refine_host_connection could be called in two case:
+ *
+ * - the Responder receives the IDii payload:
+ * + [PSK] after using PSK to decode this message
+ * + before sending its IDir payload
+ * + before using its ID in HASH_R computation
+ * + [DSig] before using its private key to sign SIG_R
+ * + before using the Initiator's ID in HASH_I calculation
+ * + [DSig] before using the Initiator's public key to check SIG_I
+ *
+ * - the Initiator receives the IDir payload:
+ * + [PSK] after using PSK to encode previous message and decode this message
+ * + after sending its IDii payload
+ * + after using its ID in HASH_I computation
+ * + [DSig] after using its private key to sign SIG_I
+ * + before using the Responder's ID to compute HASH_R
+ * + [DSig] before using Responder's public key to check SIG_R
+ *
+ * refine_host_connection can choose a different connection, as long as
+ * nothing already used is changed.
+ *
+ * In the Initiator case, the particular connection might have been
+ * specified by whatever provoked Pluto to initiate. For example:
+ * whack --initiate connection-name
+ * The advantages of switching connections when we're the Initiator seem
+ * less important than the disadvantages, so after FreeS/WAN 1.9, we
+ * don't do this.
+ */
+struct connection *
+refine_host_connection(const struct state *st, const struct id *peer_id
+, chunk_t peer_ca)
+{
+ struct connection *c = st->st_connection;
+ u_int16_t auth = st->st_oakley.auth;
+ struct connection *d;
+ struct connection *best_found = NULL;
+ lset_t auth_policy;
+ const chunk_t *psk = NULL;
+ bool wcpip; /* wildcard Peer IP? */
+
+ int wildcards, our_pathlen, peer_pathlen;
+ int best_wildcards = MAX_WILDCARDS;
+ int best_our_pathlen = MAX_CA_PATH_LEN;
+ int best_peer_pathlen = MAX_CA_PATH_LEN;
+
+ if (same_id(&c->spd.that.id, peer_id)
+ && trusted_ca(peer_ca, c->spd.that.ca, &peer_pathlen)
+ && peer_pathlen == 0
+ && match_requested_ca(c->requested_ca, c->spd.this.ca, &our_pathlen)
+ && our_pathlen == 0)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("current connection is a full match"
+ " -- no need to look further");
+ )
+ return c;
+ }
+
+ switch (auth)
+ {
+ case OAKLEY_PRESHARED_KEY:
+ auth_policy = POLICY_PSK;
+ psk = get_preshared_secret(c);
+ /* It should be virtually impossible to fail to find PSK:
+ * we just used it to decode the current message!
+ */
+ if (psk == NULL)
+ return NULL; /* cannot determine PSK! */
+ break;
+ case XAUTHInitPreShared:
+ case XAUTHRespPreShared:
+ auth_policy = POLICY_XAUTH_PSK;
+ psk = get_preshared_secret(c);
+ if (psk == NULL)
+ return NULL; /* cannot determine PSK! */
+ break;
+ case OAKLEY_RSA_SIG:
+ auth_policy = POLICY_RSASIG;
+ break;
+ case XAUTHInitRSA:
+ case XAUTHRespRSA:
+ auth_policy = POLICY_XAUTH_RSASIG;
+ break;
+ default:
+ bad_case(auth);
+ }
+
+ /* The current connection won't do: search for one that will.
+ * First search for one with the same pair of hosts.
+ * If that fails, search for a suitable Road Warrior or Opportunistic
+ * connection (i.e. wildcard peer IP).
+ * We need to match:
+ * - peer_id (slightly complicated by instantiation)
+ * - if PSK auth, the key must not change (we used it to decode message)
+ * - policy-as-used must be acceptable to new connection
+ */
+ d = c->host_pair->connections;
+ for (wcpip = FALSE; ; wcpip = TRUE)
+ {
+ for (; d != NULL; d = d->hp_next)
+ {
+ const char *match_name[] = {"no", "ok"};
+
+ bool matching_id = match_id(peer_id
+ , &d->spd.that.id, &wildcards);
+ bool matching_auth = (d->policy & auth_policy) != LEMPTY;
+
+ bool matching_trust = trusted_ca(peer_ca
+ , d->spd.that.ca, &peer_pathlen);
+ bool matching_request = match_requested_ca(c->requested_ca
+ , d->spd.this.ca, &our_pathlen);
+ bool match = matching_id && matching_auth &&
+ matching_trust && matching_request;
+
+ DBG(DBG_CONTROLMORE,
+ DBG_log("%s: %s match (id: %s, auth: %s, trust: %s, request: %s)"
+ , d->name
+ , match ? "full":" no"
+ , match_name[matching_id]
+ , match_name[matching_auth]
+ , match_name[matching_trust]
+ , match_name[matching_request])
+ )
+
+ /* do we have a match? */
+ if (!match)
+ continue;
+
+ /* ignore group connections */
+ if (d->policy & POLICY_GROUP)
+ continue;
+
+ if (c->spd.that.host_port != d->spd.that.host_port
+ && d->kind == CK_INSTANCE)
+ {
+ continue;
+ }
+
+ switch (auth)
+ {
+ case OAKLEY_PRESHARED_KEY:
+ case XAUTHInitPreShared:
+ case XAUTHRespPreShared:
+ /* secret must match the one we already used */
+ {
+ const chunk_t *dpsk = get_preshared_secret(d);
+
+ if (dpsk == NULL)
+ continue; /* no secret */
+
+ if (psk != dpsk)
+ if (psk->len != dpsk->len
+ || memcmp(psk->ptr, dpsk->ptr, psk->len) != 0)
+ continue; /* different secret */
+ }
+ break;
+
+ case OAKLEY_RSA_SIG:
+ case XAUTHInitRSA:
+ case XAUTHRespRSA:
+ /*
+ * We must at least be able to find our private key
+ .*/
+ if (d->spd.this.sc == NULL /* no smartcard */
+ && get_RSA_private_key(d) == NULL) /* no private key */
+ continue;
+ break;
+
+ default:
+ bad_case(auth);
+ }
+
+ /* d has passed all the tests.
+ * We'll go with it if the Peer ID was an exact match.
+ */
+ if (match && wildcards == 0 && peer_pathlen == 0 && our_pathlen == 0)
+ return d;
+
+ /* We'll remember it as best_found in case an exact
+ * match doesn't come along.
+ */
+ if (best_found == NULL || wildcards < best_wildcards
+ || ((wildcards == best_wildcards && peer_pathlen < best_peer_pathlen)
+ || (peer_pathlen == best_peer_pathlen && our_pathlen < best_our_pathlen)))
+ {
+ best_found = d;
+ best_wildcards = wildcards;
+ best_peer_pathlen = peer_pathlen;
+ best_our_pathlen = our_pathlen;
+ }
+ }
+ if (wcpip)
+ return best_found; /* been around twice already */
+
+ /* Starting second time around.
+ * We're willing to settle for a connection that needs Peer IP
+ * instantiated: Road Warrior or Opportunistic.
+ * Look on list of connections for host pair with wildcard Peer IP
+ */
+ d = find_host_pair_connections(&c->spd.this.host_addr, c->spd.this.host_port
+ , (ip_address *)NULL, c->spd.that.host_port);
+ }
+}
+
+/**
+ * With virtual addressing, we must not allow someone to use an already
+ * used (by another id) addr/net.
+ */
+static bool
+is_virtual_net_used(const ip_subnet *peer_net, const struct id *peer_id)
+{
+ struct connection *d;
+
+ for (d = connections; d != NULL; d = d->ac_next)
+ {
+ switch (d->kind)
+ {
+ case CK_PERMANENT:
+ case CK_INSTANCE:
+ if ((subnetinsubnet(peer_net,&d->spd.that.client) ||
+ subnetinsubnet(&d->spd.that.client,peer_net))
+ && !same_id(&d->spd.that.id, peer_id))
+ {
+ char buf[BUF_LEN];
+ char client[SUBNETTOT_BUF];
+
+ subnettot(peer_net, 0, client, sizeof(client));
+ idtoa(&d->spd.that.id, buf, sizeof(buf));
+ plog("Virtual IP %s is already used by '%s'", client, buf);
+ idtoa(peer_id, buf, sizeof(buf));
+ plog("Your ID is '%s'", buf);
+ return TRUE; /* already used by another one */
+ }
+ break;
+ case CK_GOING_AWAY:
+ default:
+ break;
+ }
+ }
+ return FALSE; /* you can safely use it */
+}
+
+/* find_client_connection: given a connection suitable for ISAKMP
+ * (i.e. the hosts match), find a one suitable for IPSEC
+ * (i.e. with matching clients).
+ *
+ * If we don't find an exact match (not even our current connection),
+ * we try for one that still needs instantiation. Try Road Warrior
+ * abstract connections and the Opportunistic abstract connections.
+ * This requires inverse instantiation: abstraction.
+ *
+ * After failing to find an exact match, we abstract the peer
+ * to be NO_IP (the wildcard value). This enables matches with
+ * Road Warrior and Opportunistic abstract connections.
+ *
+ * After failing that search, we also abstract the Phase 1 peer ID
+ * if possible. If the peer's ID was the peer's IP address, we make
+ * it NO_ID; instantiation will make it the peer's IP address again.
+ *
+ * If searching for a Road Warrior abstract connection fails,
+ * and conditions are suitable, we search for the best Opportunistic
+ * abstract connection.
+ *
+ * Note: in the end, both Phase 1 IDs must be preserved, after any
+ * instantiation. They are the IDs that have been authenticated.
+ */
+
+#define PATH_WEIGHT 1
+#define WILD_WEIGHT (MAX_CA_PATH_LEN+1)
+#define PRIO_WEIGHT (MAX_WILDCARDS+1)*WILD_WEIGHT
+
+/* fc_try: a helper function for find_client_connection */
+static struct connection *
+fc_try(const struct connection *c
+, struct host_pair *hp
+, const struct id *peer_id
+, const ip_subnet *our_net
+, const ip_subnet *peer_net
+, const u_int8_t our_protocol
+, const u_int16_t our_port
+, const u_int8_t peer_protocol
+, const u_int16_t peer_port
+, chunk_t peer_ca
+, const ietfAttrList_t *peer_list)
+{
+ struct connection *d;
+ struct connection *best = NULL;
+ policy_prio_t best_prio = BOTTOM_PRIO;
+ int wildcards, pathlen;
+
+ const bool peer_net_is_host = subnetisaddr(peer_net, &c->spd.that.host_addr);
+
+ for (d = hp->connections; d != NULL; d = d->hp_next)
+ {
+ struct spd_route *sr;
+
+ if (d->policy & POLICY_GROUP)
+ continue;
+
+ if (!(same_id(&c->spd.this.id, &d->spd.this.id)
+ && match_id(&c->spd.that.id, &d->spd.that.id, &wildcards)
+ && trusted_ca(peer_ca, d->spd.that.ca, &pathlen)
+ && group_membership(peer_list, d->name, d->spd.that.groups)))
+ continue;
+
+ /* compare protocol and ports */
+ if (d->spd.this.protocol != our_protocol
+ || d->spd.this.port != our_port
+ || d->spd.that.protocol != peer_protocol
+ || (d->spd.that.port != peer_port && !d->spd.that.has_port_wildcard))
+ continue;
+
+ /* non-Opportunistic case:
+ * our_client must match.
+ *
+ * So must peer_client, but the testing is complicated
+ * by the fact that the peer might be a wildcard
+ * and if so, the default value of that.client
+ * won't match the default peer_net. The appropriate test:
+ *
+ * If d has a peer client, it must match peer_net.
+ * If d has no peer client, peer_net must just have peer itself.
+ */
+
+ for (sr = &d->spd; best != d && sr != NULL; sr = sr->next)
+ {
+ policy_prio_t prio;
+#ifdef DEBUG
+ if (DBGP(DBG_CONTROLMORE))
+ {
+ char s1[SUBNETTOT_BUF],d1[SUBNETTOT_BUF];
+ char s3[SUBNETTOT_BUF],d3[SUBNETTOT_BUF];
+
+ subnettot(our_net, 0, s1, sizeof(s1));
+ subnettot(peer_net, 0, d1, sizeof(d1));
+ subnettot(&sr->this.client, 0, s3, sizeof(s3));
+ subnettot(&sr->that.client, 0, d3, sizeof(d3));
+ DBG_log(" fc_try trying "
+ "%s:%s:%d/%d -> %s:%d/%d vs %s:%s:%d/%d -> %s:%d/%d"
+ , c->name, s1, c->spd.this.protocol, c->spd.this.port
+ , d1, c->spd.that.protocol, c->spd.that.port
+ , d->name, s3, sr->this.protocol, sr->this.port
+ , d3, sr->that.protocol, sr->that.port);
+ }
+#endif /* DEBUG */
+
+ if (!samesubnet(&sr->this.client, our_net))
+ continue;
+
+ if (sr->that.has_client)
+ {
+ if (sr->that.has_client_wildcard)
+ {
+ if (!subnetinsubnet(peer_net, &sr->that.client))
+ continue;
+ }
+ else
+ {
+ if (!samesubnet(&sr->that.client, peer_net) && !is_virtual_connection(d))
+ continue;
+ if (is_virtual_connection(d)
+ && (!is_virtual_net_allowed(d, peer_net, &c->spd.that.host_addr)
+ || is_virtual_net_used(peer_net, peer_id?peer_id:&c->spd.that.id)))
+ continue;
+ }
+ }
+ else
+ {
+ if (!peer_net_is_host)
+ continue;
+ }
+
+ /* We've run the gauntlet -- success:
+ * We've got an exact match of subnets.
+ * The connection is feasible, but we continue looking for the best.
+ * The highest priority wins, implementing eroute-like rule.
+ * - a routed connection is preferrred
+ * - given that, the smallest number of ID wildcards are preferred
+ * - given that, the shortest CA pathlength is preferred
+ */
+ prio = PRIO_WEIGHT * routed(sr->routing)
+ + WILD_WEIGHT * (MAX_WILDCARDS - wildcards)
+ + PATH_WEIGHT * (MAX_CA_PATH_LEN - pathlen)
+ + 1;
+ if (prio > best_prio)
+ {
+ best = d;
+ best_prio = prio;
+ }
+ }
+ }
+
+ if (best != NULL && NEVER_NEGOTIATE(best->policy))
+ best = NULL;
+
+ DBG(DBG_CONTROLMORE,
+ DBG_log(" fc_try concluding with %s [%ld]"
+ , (best ? best->name : "none"), best_prio)
+ )
+ return best;
+}
+
+static struct connection *
+fc_try_oppo(const struct connection *c
+, struct host_pair *hp
+, const ip_subnet *our_net
+, const ip_subnet *peer_net
+, const u_int8_t our_protocol
+, const u_int16_t our_port
+, const u_int8_t peer_protocol
+, const u_int16_t peer_port
+, chunk_t peer_ca
+, const ietfAttrList_t *peer_list)
+{
+ struct connection *d;
+ struct connection *best = NULL;
+ policy_prio_t best_prio = BOTTOM_PRIO;
+ int wildcards, pathlen;
+
+ for (d = hp->connections; d != NULL; d = d->hp_next)
+ {
+ struct spd_route *sr;
+ policy_prio_t prio;
+
+ if (d->policy & POLICY_GROUP)
+ continue;
+
+ if (!(same_id(&c->spd.this.id, &d->spd.this.id)
+ && match_id(&c->spd.that.id, &d->spd.that.id, &wildcards)
+ && trusted_ca(peer_ca, d->spd.that.ca, &pathlen)
+ && group_membership(peer_list, d->name, d->spd.that.groups)))
+ continue;
+
+ /* compare protocol and ports */
+ if (d->spd.this.protocol != our_protocol
+ || d->spd.this.port != our_port
+ || d->spd.that.protocol != peer_protocol
+ || (d->spd.that.port != peer_port && !d->spd.that.has_port_wildcard))
+ continue;
+
+ /* Opportunistic case:
+ * our_net must be inside d->spd.this.client
+ * and peer_net must be inside d->spd.that.client
+ * Note: this host_pair chain also has shunt
+ * eroute conns (clear, drop), but they won't
+ * be marked as opportunistic.
+ */
+ for (sr = &d->spd; sr != NULL; sr = sr->next)
+ {
+#ifdef DEBUG
+ if (DBGP(DBG_CONTROLMORE))
+ {
+ char s1[SUBNETTOT_BUF],d1[SUBNETTOT_BUF];
+ char s3[SUBNETTOT_BUF],d3[SUBNETTOT_BUF];
+
+ subnettot(our_net, 0, s1, sizeof(s1));
+ subnettot(peer_net, 0, d1, sizeof(d1));
+ subnettot(&sr->this.client, 0, s3, sizeof(s3));
+ subnettot(&sr->that.client, 0, d3, sizeof(d3));
+ DBG_log(" fc_try_oppo trying %s:%s -> %s vs %s:%s -> %s"
+ , c->name, s1, d1, d->name, s3, d3);
+ }
+#endif /* DEBUG */
+
+ if (!subnetinsubnet(our_net, &sr->this.client)
+ || !subnetinsubnet(peer_net, &sr->that.client))
+ continue;
+
+ /* The connection is feasible, but we continue looking for the best.
+ * The highest priority wins, implementing eroute-like rule.
+ * - our smallest client subnet is preferred (longest mask)
+ * - given that, his smallest client subnet is preferred
+ * - given that, a routed connection is preferrred
+ * - given that, the smallest number of ID wildcards are preferred
+ * - given that, the shortest CA pathlength is preferred
+ */
+ prio = PRIO_WEIGHT * (d->prio + routed(sr->routing))
+ + WILD_WEIGHT * (MAX_WILDCARDS - wildcards)
+ + PATH_WEIGHT * (MAX_CA_PATH_LEN - pathlen);
+ if (prio > best_prio)
+ {
+ best = d;
+ best_prio = prio;
+ }
+ }
+ }
+
+ /* if the best wasn't opportunistic, we fail: it must be a shunt */
+ if (best != NULL
+ && (NEVER_NEGOTIATE(best->policy)
+ || (best->policy & POLICY_OPPO) == LEMPTY))
+ {
+ best = NULL;
+ }
+
+ DBG(DBG_CONTROLMORE,
+ DBG_log(" fc_try_oppo concluding with %s [%ld]"
+ , (best ? best->name : "none"), best_prio)
+ )
+ return best;
+
+}
+
+/*
+ * get the peer's CA and group attributes
+ */
+chunk_t
+get_peer_ca_and_groups(struct connection *c, const ietfAttrList_t **peer_list)
+{
+ struct state *p1st = find_phase1_state(c, ISAKMP_SA_ESTABLISHED_STATES);
+
+ *peer_list = NULL;
+
+ if (p1st != NULL
+ && p1st->st_peer_pubkey != NULL
+ && p1st->st_peer_pubkey->issuer.ptr != NULL)
+ {
+ x509acert_t *ac = get_x509acert(p1st->st_peer_pubkey->issuer
+ , p1st->st_peer_pubkey->serial);;
+
+ if (ac != NULL && verify_x509acert(ac, strict_crl_policy))
+ *peer_list = ac->groups;
+ else
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("no valid attribute cert found")
+ )
+ }
+ return p1st->st_peer_pubkey->issuer;
+ }
+ return empty_chunk;
+}
+
+struct connection *
+find_client_connection(struct connection *c
+, const ip_subnet *our_net, const ip_subnet *peer_net
+, const u_int8_t our_protocol, const u_int16_t our_port
+, const u_int8_t peer_protocol, const u_int16_t peer_port)
+{
+ struct connection *d;
+ struct spd_route *sr;
+
+ const ietfAttrList_t *peer_list = NULL;
+ chunk_t peer_ca = get_peer_ca_and_groups(c, &peer_list);
+
+#ifdef DEBUG
+ if (DBGP(DBG_CONTROLMORE))
+ {
+ char s1[SUBNETTOT_BUF],d1[SUBNETTOT_BUF];
+
+ subnettot(our_net, 0, s1, sizeof(s1));
+ subnettot(peer_net, 0, d1, sizeof(d1));
+
+ DBG_log("find_client_connection starting with %s"
+ , (c ? c->name : "(none)"));
+ DBG_log(" looking for %s:%d/%d -> %s:%d/%d"
+ , s1, our_protocol, our_port
+ , d1, peer_protocol, peer_port);
+ }
+#endif /* DEBUG */
+
+ /* give priority to current connection
+ * but even greater priority to a routed concrete connection
+ */
+ {
+ struct connection *unrouted = NULL;
+ int srnum = -1;
+
+ for (sr = &c->spd; unrouted == NULL && sr != NULL; sr = sr->next)
+ {
+ srnum++;
+
+#ifdef DEBUG
+ if (DBGP(DBG_CONTROLMORE))
+ {
+ char s2[SUBNETTOT_BUF],d2[SUBNETTOT_BUF];
+
+ subnettot(&sr->this.client, 0, s2, sizeof(s2));
+ subnettot(&sr->that.client, 0, d2, sizeof(d2));
+ DBG_log(" concrete checking against sr#%d %s -> %s"
+ , srnum, s2, d2);
+ }
+#endif /* DEBUG */
+
+ if (samesubnet(&sr->this.client, our_net)
+ && samesubnet(&sr->that.client, peer_net)
+ && sr->this.protocol == our_protocol
+ && sr->this.port == our_port
+ && sr->that.protocol == peer_protocol
+ && sr->that.port == peer_port
+ && group_membership(peer_list, c->name, sr->that.groups))
+ {
+ passert(oriented(*c));
+ if (routed(sr->routing))
+ return c;
+
+ unrouted = c;
+ }
+ }
+
+ /* exact match? */
+ d = fc_try(c, c->host_pair, NULL, our_net, peer_net
+ , our_protocol, our_port, peer_protocol, peer_port
+ , peer_ca, peer_list);
+
+ DBG(DBG_CONTROLMORE,
+ DBG_log(" fc_try %s gives %s"
+ , c->name
+ , (d ? d->name : "none"))
+ )
+
+ if (d == NULL)
+ d = unrouted;
+ }
+
+ if (d == NULL)
+ {
+ /* look for an abstract connection to match */
+ struct spd_route *sr;
+ struct host_pair *hp = NULL;
+
+ for (sr = &c->spd; hp==NULL && sr != NULL; sr = sr->next)
+ {
+ hp = find_host_pair(&sr->this.host_addr
+ , sr->this.host_port
+ , NULL
+ , sr->that.host_port);
+#ifdef DEBUG
+ if (DBGP(DBG_CONTROLMORE))
+ {
+ char s2[SUBNETTOT_BUF],d2[SUBNETTOT_BUF];
+
+ subnettot(&sr->this.client, 0, s2, sizeof(s2));
+ subnettot(&sr->that.client, 0, d2, sizeof(d2));
+
+ DBG_log(" checking hostpair %s -> %s is %s"
+ , s2, d2
+ , (hp ? "found" : "not found"));
+ }
+#endif /* DEBUG */
+ }
+
+ if (hp != NULL)
+ {
+ /* RW match with actual peer_id or abstract peer_id? */
+ d = fc_try(c, hp, NULL, our_net, peer_net
+ , our_protocol, our_port, peer_protocol, peer_port
+ , peer_ca, peer_list);
+
+ if (d == NULL
+ && subnetishost(our_net)
+ && subnetishost(peer_net))
+ {
+ /* Opportunistic match?
+ * Always use abstract peer_id.
+ * Note that later instantiation will result in the same peer_id.
+ */
+ d = fc_try_oppo(c, hp, our_net, peer_net
+ , our_protocol, our_port, peer_protocol, peer_port
+ , peer_ca, peer_list);
+ }
+ }
+ }
+
+ DBG(DBG_CONTROLMORE,
+ DBG_log(" concluding with d = %s"
+ , (d ? d->name : "none"))
+ )
+ return d;
+}
+
+int
+connection_compare(const struct connection *ca
+, const struct connection *cb)
+{
+ int ret;
+
+ /* DBG_log("comparing %s to %s", ca->name, cb->name); */
+
+ ret = strcasecmp(ca->name, cb->name);
+ if (ret != 0)
+ return ret;
+
+ ret = ca->kind - cb->kind; /* note: enum connection_kind behaves like int */
+ if (ret != 0)
+ return ret;
+
+ /* same name, and same type */
+ switch (ca->kind)
+ {
+ case CK_INSTANCE:
+ return ca->instance_serial < cb->instance_serial ? -1
+ : ca->instance_serial > cb->instance_serial ? 1
+ : 0;
+
+ default:
+ return ca->prio < cb->prio ? -1
+ : ca->prio > cb->prio ? 1
+ : 0;
+ }
+}
+
+static int
+connection_compare_qsort(const void *a, const void *b)
+{
+ return connection_compare(*(const struct connection *const *)a
+ , *(const struct connection *const *)b);
+}
+
+void
+show_connections_status(bool all, const char *name)
+{
+ struct connection *c;
+ int count, i;
+ struct connection **array;
+
+ /* make an array of connections, and sort it */
+ count = 0;
+ for (c = connections; c != NULL; c = c->ac_next)
+ {
+ if (c->ikev1 && (name == NULL || streq(c->name, name)))
+ count++;
+ }
+ array = alloc_bytes(sizeof(struct connection *)*count, "connection array");
+
+ count=0;
+ for (c = connections; c != NULL; c = c->ac_next)
+ {
+ if (c->ikev1 && (name == NULL || streq(c->name, name)))
+ array[count++]=c;
+ }
+
+ /* sort it! */
+ qsort(array, count, sizeof(struct connection *), connection_compare_qsort);
+
+ for (i = 0; i < count; i++)
+ {
+ const char *ifn;
+ char instance[1 + 10 + 1];
+ char prio[POLICY_PRIO_BUF];
+
+ c = array[i];
+
+ ifn = oriented(*c)? c->interface->rname : "";
+
+ instance[0] = '\0';
+ if (c->kind == CK_INSTANCE && c->instance_serial != 0)
+ snprintf(instance, sizeof(instance), "[%lu]", c->instance_serial);
+
+ /* show topology */
+ {
+ char topo[CONNECTION_BUF];
+ struct spd_route *sr = &c->spd;
+ int num=0;
+
+ while (sr != NULL)
+ {
+ (void) format_connection(topo, sizeof(topo), c, sr);
+ whack_log(RC_COMMENT, "\"%s\"%s: %s; %s; eroute owner: #%lu"
+ , c->name, instance, topo
+ , enum_name(&routing_story, sr->routing)
+ , sr->eroute_owner);
+ sr = sr->next;
+ num++;
+ }
+ }
+
+ if (all)
+ {
+ /* show CAs if defined */
+ if (c->spd.this.ca.ptr != NULL || c->spd.that.ca.ptr != NULL)
+ {
+ char this_ca[BUF_LEN], that_ca[BUF_LEN];
+
+ dntoa_or_null(this_ca, BUF_LEN, c->spd.this.ca, "%any");
+ dntoa_or_null(that_ca, BUF_LEN, c->spd.that.ca, "%any");
+
+ whack_log(RC_COMMENT
+ , "\"%s\"%s: CAs: '%s'...'%s'"
+ , c->name
+ , instance
+ , this_ca
+ , that_ca);
+ }
+
+ /* show group attributes if defined */
+ if (c->spd.that.groups != NULL)
+ {
+ char buf[BUF_LEN];
+
+ format_groups(c->spd.that.groups, buf, BUF_LEN);
+ whack_log(RC_COMMENT
+ , "\"%s\"%s: groups: %s"
+ , c->name
+ , instance
+ , buf);
+ }
+
+ whack_log(RC_COMMENT
+ , "\"%s\"%s: ike_life: %lus; ipsec_life: %lus;"
+ " rekey_margin: %lus; rekey_fuzz: %lu%%; keyingtries: %lu"
+ , c->name
+ , instance
+ , (unsigned long) c->sa_ike_life_seconds
+ , (unsigned long) c->sa_ipsec_life_seconds
+ , (unsigned long) c->sa_rekey_margin
+ , (unsigned long) c->sa_rekey_fuzz
+ , (unsigned long) c->sa_keying_tries);
+
+ /* show DPD parameters if defined */
+
+ if (c->dpd_action != DPD_ACTION_NONE)
+ whack_log(RC_COMMENT
+ , "\"%s\"%s: dpd_action: %s;"
+ " dpd_delay: %lus; dpd_timeout: %lus;"
+ , c->name
+ , instance
+ , enum_show(&dpd_action_names, c->dpd_action)
+ , (unsigned long) c->dpd_delay
+ , (unsigned long) c->dpd_timeout);
+
+ if (c->policy_next)
+ {
+ whack_log(RC_COMMENT
+ , "\"%s\"%s: policy_next: %s"
+ , c->name, instance, c->policy_next->name);
+ }
+
+ /* Note: we display key_from_DNS_on_demand as if policy [lr]KOD */
+ fmt_policy_prio(c->prio, prio);
+ whack_log(RC_COMMENT
+ , "\"%s\"%s: policy: %s%s%s; prio: %s; interface: %s; "
+ , c->name
+ , instance
+ , prettypolicy(c->policy)
+ , c->spd.this.key_from_DNS_on_demand? "+lKOD" : ""
+ , c->spd.that.key_from_DNS_on_demand? "+rKOD" : ""
+ , prio
+ , ifn);
+ }
+
+ whack_log(RC_COMMENT
+ , "\"%s\"%s: newest ISAKMP SA: #%ld; newest IPsec SA: #%ld; "
+ , c->name
+ , instance
+ , c->newest_isakmp_sa
+ , c->newest_ipsec_sa);
+
+ if (all)
+ {
+ ike_alg_show_connection(c, instance);
+ kernel_alg_show_connection(c, instance);
+ }
+ }
+ if (count > 0)
+ whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */
+
+ pfree(array);
+}
+
+/* struct pending, the structure representing Quick Mode
+ * negotiations delayed until a Keying Channel has been negotiated.
+ * Essentially, a pending call to quick_outI1.
+ */
+
+struct pending {
+ int whack_sock;
+ struct state *isakmp_sa;
+ struct connection *connection;
+ lset_t policy;
+ unsigned long try;
+ so_serial_t replacing;
+
+ struct pending *next;
+};
+
+/* queue a Quick Mode negotiation pending completion of a suitable Main Mode */
+void
+add_pending(int whack_sock
+, struct state *isakmp_sa
+, struct connection *c
+, lset_t policy
+, unsigned long try
+, so_serial_t replacing)
+{
+ bool already_queued = FALSE;
+ struct pending *p = c->host_pair->pending;
+
+ while (p != NULL)
+ {
+ if (streq(c->name, p->connection->name))
+ {
+ already_queued = TRUE;
+ break;
+ }
+ p = p->next;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("Queuing pending Quick Mode with %s \"%s\"%s"
+ , ip_str(&c->spd.that.host_addr)
+ , c->name
+ , already_queued? " already done" : "")
+ )
+ if (already_queued)
+ return;
+
+ p = alloc_thing(struct pending, "struct pending");
+ p->whack_sock = whack_sock;
+ p->isakmp_sa = isakmp_sa;
+ p->connection = c;
+ p->policy = policy;
+ p->try = try;
+ p->replacing = replacing;
+ p->next = c->host_pair->pending;
+ c->host_pair->pending = p;
+}
+
+/* Release all the whacks awaiting the completion of this state.
+ * This is accomplished by closing all the whack socket file descriptors.
+ * We go to a lot of trouble to tell each whack, but to not tell it twice.
+ */
+void
+release_pending_whacks(struct state *st, err_t story)
+{
+ struct pending *p;
+ struct stat stst;
+
+ if (st->st_whack_sock == NULL_FD || fstat(st->st_whack_sock, &stst) != 0)
+ zero(&stst); /* resulting st_dev/st_ino ought to be distinct */
+
+ release_whack(st);
+
+ for (p = st->st_connection->host_pair->pending; p != NULL; p = p->next)
+ {
+ if (p->isakmp_sa == st && p->whack_sock != NULL_FD)
+ {
+ struct stat pst;
+
+ if (fstat(p->whack_sock, &pst) == 0
+ && (stst.st_dev != pst.st_dev || stst.st_ino != pst.st_ino))
+ {
+ passert(whack_log_fd == NULL_FD);
+ whack_log_fd = p->whack_sock;
+ whack_log(RC_COMMENT
+ , "%s for ISAKMP SA, but releasing whack for pending IPSEC SA"
+ , story);
+ whack_log_fd = NULL_FD;
+ }
+ close(p->whack_sock);
+ p->whack_sock = NULL_FD;
+ }
+ }
+}
+
+static void
+delete_pending(struct pending **pp)
+{
+ struct pending *p = *pp;
+
+ *pp = p->next;
+ if (p->connection != NULL)
+ connection_discard(p->connection);
+ close_any(p->whack_sock);
+ pfree(p);
+}
+
+void
+unpend(struct state *st)
+{
+ struct pending **pp
+ , *p;
+
+ for (pp = &st->st_connection->host_pair->pending; (p = *pp) != NULL; )
+ {
+ if (p->isakmp_sa == st)
+ {
+ DBG(DBG_CONTROL, DBG_log("unqueuing pending Quick Mode with %s \"%s\""
+ , ip_str(&p->connection->spd.that.host_addr)
+ , p->connection->name));
+ (void) quick_outI1(p->whack_sock, st, p->connection, p->policy
+ , p->try, p->replacing);
+ p->whack_sock = NULL_FD; /* ownership transferred */
+ p->connection = NULL; /* ownership transferred */
+ delete_pending(pp);
+ }
+ else
+ {
+ pp = &p->next;
+ }
+ }
+}
+
+/* a Main Mode negotiation has been replaced; update any pending */
+void
+update_pending(struct state *os, struct state *ns)
+{
+ struct pending *p;
+
+ for (p = os->st_connection->host_pair->pending; p != NULL; p = p->next)
+ {
+ if (p->isakmp_sa == os)
+ p->isakmp_sa = ns;
+ if (p->connection->spd.this.host_port != ns->st_connection->spd.this.host_port)
+ {
+ p->connection->spd.this.host_port = ns->st_connection->spd.this.host_port;
+ p->connection->spd.that.host_port = ns->st_connection->spd.that.host_port;
+ }
+ }
+}
+
+/* a Main Mode negotiation has failed; discard any pending */
+void
+flush_pending_by_state(struct state *st)
+{
+ struct host_pair *hp = st->st_connection->host_pair;
+
+ if (hp != NULL)
+ {
+ struct pending **pp
+ , *p;
+
+ for (pp = &hp->pending; (p = *pp) != NULL; )
+ {
+ if (p->isakmp_sa == st)
+ delete_pending(pp);
+ else
+ pp = &p->next;
+ }
+ }
+}
+
+/* a connection has been deleted; discard any related pending */
+static void
+flush_pending_by_connection(struct connection *c)
+{
+ if (c->host_pair != NULL)
+ {
+ struct pending **pp
+ , *p;
+
+ for (pp = &c->host_pair->pending; (p = *pp) != NULL; )
+ {
+ if (p->connection == c)
+ {
+ p->connection = NULL; /* prevent delete_pending from releasing */
+ delete_pending(pp);
+ }
+ else
+ {
+ pp = &p->next;
+ }
+ }
+ }
+}
+
+void
+show_pending_phase2(const struct host_pair *hp, const struct state *st)
+{
+ const struct pending *p;
+
+ for (p = hp->pending; p != NULL; p = p->next)
+ {
+ if (p->isakmp_sa == st)
+ {
+ /* connection-name state-number [replacing state-number] */
+ char cip[CONN_INST_BUF];
+
+ fmt_conn_instance(p->connection, cip);
+ whack_log(RC_COMMENT, "#%lu: pending Phase 2 for \"%s\"%s replacing #%lu"
+ , p->isakmp_sa->st_serialno
+ , p->connection->name
+ , cip
+ , p->replacing);
+ }
+ }
+}
+
+/* Delete a connection if it is an instance and it is no longer in use.
+ * We must be careful to avoid circularity:
+ * we don't touch it if it is CK_GOING_AWAY.
+ */
+void
+connection_discard(struct connection *c)
+{
+ if (c->kind == CK_INSTANCE)
+ {
+ /* see if it is being used by a pending */
+ struct pending *p;
+
+ for (p = c->host_pair->pending; p != NULL; p = p->next)
+ if (p->connection == c)
+ return; /* in use, so we're done */
+
+ if (!states_use_connection(c))
+ delete_connection(c, FALSE);
+ }
+}
+
+
+/* A template connection's eroute can be eclipsed by
+ * either a %hold or an eroute for an instance iff
+ * the template is a /32 -> /32. This requires some special casing.
+ */
+
+long eclipse_count = 0;
+
+struct connection *
+eclipsed(struct connection *c, struct spd_route **esrp)
+{
+ struct connection *ue;
+ struct spd_route *sr1 = &c->spd;
+
+ ue = NULL;
+
+ while (sr1 != NULL && ue != NULL)
+ {
+ for (ue = connections; ue != NULL; ue = ue->ac_next)
+ {
+ struct spd_route *srue = &ue->spd;
+
+ while (srue != NULL
+ && srue->routing == RT_ROUTED_ECLIPSED
+ && !(samesubnet(&sr1->this.client, &srue->this.client)
+ && samesubnet(&sr1->that.client, &srue->that.client)))
+ {
+ srue = srue->next;
+ }
+ if (srue != NULL && srue->routing==RT_ROUTED_ECLIPSED)
+ {
+ *esrp = srue;
+ break;
+ }
+ }
+ }
+ return ue;
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset:4
+ * c-style: pluto
+ * End:
+ */
diff --git a/src/pluto/connections.h b/src/pluto/connections.h
new file mode 100644
index 000000000..df3af9dd4
--- /dev/null
+++ b/src/pluto/connections.h
@@ -0,0 +1,367 @@
+/* information about connections between hosts and clients
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: connections.h,v 1.18 2006/04/22 21:59:20 as Exp $
+ */
+
+#ifndef _CONNECTIONS_H
+#define _CONNECTIONS_H
+
+#include <sys/queue.h>
+
+#include "id.h"
+#include "certs.h"
+#include "ac.h"
+#include "smartcard.h"
+#include "whack.h"
+
+/* There are two kinds of connections:
+ * - ISAKMP connections, between hosts (for IKE communication)
+ * - IPsec connections, between clients (for secure IP communication)
+ *
+ * An ISAKMP connection looks like:
+ * host<--->host
+ *
+ * An IPsec connection looks like:
+ * client-subnet<-->host<->nexthop<--->nexthop<->host<-->client-subnet
+ *
+ * For the connection to be relevant to this instance of Pluto,
+ * exactly one of the hosts must be a public interface of our machine
+ * known to this instance.
+ *
+ * The client subnet might simply be the host -- this is a
+ * representation of "host mode".
+ *
+ * Each nexthop defaults to the neighbouring host's IP address.
+ * The nexthop is a property of the pair of hosts, not each
+ * individually. It is only needed for IPsec because of the
+ * way IPsec is mixed into the kernel routing logic. Furthermore,
+ * only this end's nexthop is actually used. Eventually, nexthop
+ * will be unnecessary.
+ *
+ * Other information represented:
+ * - each connection has a name: a chunk of uninterpreted text
+ * that is unique for each connection.
+ * - security requirements (currently just the "policy" flags from
+ * the whack command to initiate the connection, but eventually
+ * much more. Different for ISAKMP and IPsec connections.
+ * - rekeying parameters:
+ * + time an SA may live
+ * + time before SA death that a rekeying should be attempted
+ * (only by the initiator)
+ * + number of times to attempt rekeying
+ * - With the current KLIPS, we must route packets for a client
+ * subnet through the ipsec interface (ipsec0). Only one
+ * gateway can get traffic for a specific (client) subnet.
+ * Furthermore, if the routing isn't in place, packets will
+ * be sent in the clear.
+ * "routing" indicates whether the routing has been done for
+ * this connection. Note that several connections may claim
+ * the same routing, as long as they agree about where the
+ * packets are to be sent.
+ * - With the current KLIPS, only one outbound IPsec SA bundle can be
+ * used for a particular client. This is due to a limitation
+ * of using only routing for selection. So only one IPsec state (SA)
+ * may "own" the eroute. "eroute_owner" is the serial number of
+ * this state, SOS_NOBODY if there is none. "routing" indicates
+ * what kind of erouting has been done for this connection, if any.
+ *
+ * Details on routing is in constants.h
+ *
+ * Operations on Connections:
+ *
+ * - add a new connection (with all details) [whack command]
+ * - delete a connection (by name) [whack command]
+ * - initiate a connection (by name) [whack command]
+ * - find a connection (by IP addresses of hosts)
+ * [response to peer request; finding ISAKMP connection for IPsec connection]
+ *
+ * Some connections are templates, missing the address of the peer
+ * (represented by INADDR_ANY). These are always arranged so that the
+ * missing end is "that" (there can only be one missing end). These can
+ * be instantiated (turned into real connections) by Pluto in one of two
+ * different ways: Road Warrior Instantiation or Opportunistic
+ * Instantiation. A template connection is marked for Opportunistic
+ * Instantiation by specifying the peer client as 0.0.0.0/32 (or the IPV6
+ * equivalent). Otherwise, it is suitable for Road Warrior Instantiation.
+ *
+ * Instantiation creates a new temporary connection, with the missing
+ * details filled in. The resulting template lasts only as long as there
+ * is a state that uses it.
+ */
+
+/* connection policy priority: how important this policy is
+ * - used to implement eroute-like precedence (augmented by a small
+ * bonus for a routed connection).
+ * - a whole number
+ * - larger is more important
+ * - three subcomponents. In order of decreasing significance:
+ * + length of source subnet mask (8 bits)
+ * + length of destination subnet mask (8 bits)
+ * + bias (8 bit)
+ * - a bias of 1 is added to allow prio BOTTOM_PRIO to be less than all
+ * normal priorities
+ * - other bias values are created on the fly to give mild preference
+ * to certaion conditions (eg. routedness)
+ * - priority is inherited -- an instance of a policy has the same priority
+ * as the original policy, even though its subnets might be smaller.
+ * - display format: n,m
+ */
+typedef unsigned long policy_prio_t;
+#define BOTTOM_PRIO ((policy_prio_t)0) /* smaller than any real prio */
+#define set_policy_prio(c) { (c)->prio = \
+ ((policy_prio_t)(c)->spd.this.client.maskbits << 16) \
+ | ((policy_prio_t)(c)->spd.that.client.maskbits << 8) \
+ | (policy_prio_t)1; }
+#define POLICY_PRIO_BUF (3+1+3+1)
+extern void fmt_policy_prio(policy_prio_t pp, char buf[POLICY_PRIO_BUF]);
+
+struct virtual_t;
+
+struct end {
+ struct id id;
+ ip_address
+ host_addr,
+ host_nexthop,
+ host_srcip;
+ ip_subnet client;
+
+ bool key_from_DNS_on_demand;
+ bool has_client;
+ bool has_client_wildcard;
+ bool has_port_wildcard;
+ bool has_id_wildcards;
+ bool has_natip;
+ char *updown;
+ u_int16_t host_port; /* host order */
+ u_int16_t port; /* host order */
+ u_int8_t protocol;
+ cert_t cert; /* end certificate */
+ chunk_t ca; /* CA distinguished name */
+ struct ietfAttrList *groups;/* access control groups */
+ smartcard_t *sc; /* smartcard reader and key info */
+ struct virtual_t *virt;
+ bool modecfg; /* this end: request local address from server */
+ /* that end: give local addresses to clients */
+ bool hostaccess; /* allow access to host via iptables INPUT/OUTPUT */
+ /* rules if client behind host is a subnet */
+ certpolicy_t sendcert; /* whether or not to send the certificate */
+};
+
+struct spd_route {
+ struct spd_route *next;
+ struct end this;
+ struct end that;
+ so_serial_t eroute_owner;
+ enum routing_t routing; /* level of routing in place */
+ uint32_t reqid;
+};
+
+struct connection {
+ char *name;
+ bool ikev1;
+
+ lset_t policy;
+ time_t sa_ike_life_seconds;
+ time_t sa_ipsec_life_seconds;
+ time_t sa_rekey_margin;
+ unsigned long sa_rekey_fuzz;
+ unsigned long sa_keying_tries;
+
+ /* RFC 3706 DPD */
+ time_t dpd_delay;
+ time_t dpd_timeout;
+ dpd_action_t dpd_action;
+
+ char *log_file_name; /* name of log file */
+ FILE *log_file; /* possibly open FILE */
+ CIRCLEQ_ENTRY(connection) log_link; /* linked list of open conns */
+ bool log_file_err; /* only bitch once */
+
+ struct spd_route spd;
+
+ /* internal fields: */
+
+ unsigned long instance_serial;
+ policy_prio_t prio;
+ bool instance_initiation_ok; /* this is an instance of a policy that mandates initiate */
+ enum connection_kind kind;
+ const struct iface *interface; /* filled in iff oriented */
+
+ so_serial_t /* state object serial number */
+ newest_isakmp_sa,
+ newest_ipsec_sa;
+
+
+#ifdef DEBUG
+ lset_t extra_debugging;
+#endif
+
+ /* note: if the client is the gateway, the following must be equal */
+ sa_family_t addr_family; /* between gateways */
+ sa_family_t tunnel_addr_family; /* between clients */
+
+ struct connection *policy_next; /* if multiple policies,
+ next one to apply */
+
+ struct gw_info *gw_info;
+ struct alg_info_esp *alg_info_esp;
+ struct alg_info_ike *alg_info_ike;
+
+ struct host_pair *host_pair;
+ struct connection *hp_next; /* host pair list link */
+
+ struct connection *ac_next; /* all connections list link */
+
+ generalName_t *requested_ca; /* collected certificate requests */
+ bool got_certrequest;
+};
+
+#define oriented(c) ((c).interface != NULL)
+extern bool orient(struct connection *c);
+
+extern bool same_peer_ids(const struct connection *c
+ , const struct connection *d, const struct id *his_id);
+
+/* Format the topology of a connection end, leaving out defaults.
+ * Largest left end looks like: client === host : port [ host_id ] --- hop
+ * Note: if that==NULL, skip nexthop
+ */
+#define END_BUF (SUBNETTOT_BUF + ADDRTOT_BUF + IDTOA_BUF + ADDRTOT_BUF + 10)
+extern size_t format_end(char *buf, size_t buf_len
+ , const struct end *this, const struct end *that
+ , bool is_left, lset_t policy);
+
+extern void add_connection(const whack_message_t *wm);
+extern void initiate_connection(const char *name, int whackfd);
+extern void initiate_opportunistic(const ip_address *our_client
+ , const ip_address *peer_client, int transport_proto, bool held, int whackfd);
+extern void terminate_connection(const char *nm);
+extern void release_connection(struct connection *c, bool relations);
+extern void delete_connection(struct connection *c, bool relations);
+extern void delete_connections_by_name(const char *name, bool strict);
+extern void delete_every_connection(void);
+extern char *add_group_instance(struct connection *group, const ip_subnet *target);
+extern void remove_group_instance(const struct connection *group, const char *name);
+extern void release_dead_interfaces(void);
+extern void check_orientations(void);
+extern struct connection *route_owner(struct connection *c
+ , struct spd_route **srp
+ , struct connection **erop
+ , struct spd_route **esrp);
+extern struct connection *shunt_owner(const ip_subnet *ours
+ , const ip_subnet *his);
+
+extern bool uniqueIDs; /* --uniqueids? */
+extern void ISAKMP_SA_established(struct connection *c, so_serial_t serial);
+
+#define his_id_was_instantiated(c) ((c)->kind == CK_INSTANCE \
+ && (id_is_ipaddr(&(c)->spd.that.id)? \
+ sameaddr(&(c)->spd.that.id.ip_addr, &(c)->spd.that.host_addr) : TRUE))
+
+struct state; /* forward declaration of tag (defined in state.h) */
+extern struct connection
+ *con_by_name(const char *nm, bool strict),
+ *find_host_connection(const ip_address *me, u_int16_t my_port
+ , const ip_address *him, u_int16_t his_port, lset_t policy),
+ *refine_host_connection(const struct state *st, const struct id *id
+ , chunk_t peer_ca),
+ *find_client_connection(struct connection *c
+ , const ip_subnet *our_net
+ , const ip_subnet *peer_net
+ , const u_int8_t our_protocol
+ , const u_int16_t out_port
+ , const u_int8_t peer_protocol
+ , const u_int16_t peer_port),
+ *find_connection_by_reqid(uint32_t reqid);
+
+extern struct connection *
+find_connection_for_clients(struct spd_route **srp
+ , const ip_address *our_client
+ , const ip_address *peer_client
+ , int transport_proto);
+
+extern chunk_t get_peer_ca_and_groups(struct connection *c
+ , const ietfAttrList_t **peer_list);
+
+/* instantiating routines
+ * Note: connection_discard() is in state.h because all its work
+ * is looking through state objects.
+ */
+struct gw_info; /* forward declaration of tag (defined in dnskey.h) */
+struct alg_info; /* forward declaration of tag (defined in alg_info.h) */
+extern struct connection *rw_instantiate(struct connection *c
+ , const ip_address *him
+ , u_int16_t his_port
+ , const ip_subnet *his_net
+ , const struct id *his_id);
+
+extern struct connection *oppo_instantiate(struct connection *c
+ , const ip_address *him
+ , const struct id *his_id
+ , struct gw_info *gw
+ , const ip_address *our_client
+ , const ip_address *peer_client);
+
+extern struct connection
+ *build_outgoing_opportunistic_connection(struct gw_info *gw
+ , const ip_address *our_client
+ , const ip_address *peer_client);
+
+/* worst case: "[" serial "] " myclient "=== ..." peer "===" hisclient '\0' */
+#define CONN_INST_BUF \
+ (2 + 10 + 1 + SUBNETTOT_BUF + 7 + ADDRTOT_BUF + 3 + SUBNETTOT_BUF + 1)
+
+extern void fmt_conn_instance(const struct connection *c
+ , char buf[CONN_INST_BUF]);
+
+/* operations on "pending", the structure representing Quick Mode
+ * negotiations delayed until a Keying Channel has been negotiated.
+ */
+
+struct pending; /* forward declaration (opaque outside connections.c) */
+
+extern void add_pending(int whack_sock
+ , struct state *isakmp_sa
+ , struct connection *c
+ , lset_t policy
+ , unsigned long try
+ , so_serial_t replacing);
+
+extern void release_pending_whacks(struct state *st, err_t story);
+extern void unpend(struct state *st);
+extern void update_pending(struct state *os, struct state *ns);
+extern void flush_pending_by_state(struct state *st);
+extern void show_pending_phase2(const struct host_pair *hp, const struct state *st);
+
+extern void connection_discard(struct connection *c);
+
+/* A template connection's eroute can be eclipsed by
+ * either a %hold or an eroute for an instance iff
+ * the template is a /32 -> /32. This requires some special casing.
+ */
+#define eclipsable(sr) (subnetishost(&(sr)->this.client) && subnetishost(&(sr)->that.client))
+extern long eclipse_count;
+extern struct connection *eclipsed(struct connection *c, struct spd_route **);
+
+
+/* print connection status */
+
+extern void show_connections_status(bool all, const char *name);
+extern int connection_compare(const struct connection *ca
+ , const struct connection *cb);
+extern void update_host_pair(const char *why, struct connection *c
+ , const ip_address *myaddr, u_int16_t myport
+ , const ip_address *hisaddr, u_int16_t hisport);
+
+#endif /* _CONNECTIONS_H */
diff --git a/src/pluto/constants.c b/src/pluto/constants.c
new file mode 100644
index 000000000..e7d7216ee
--- /dev/null
+++ b/src/pluto/constants.c
@@ -0,0 +1,1353 @@
+/* tables of names for values defined in constants.h
+ * Copyright (C) 1998-2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: constants.c,v 1.21 2006/03/27 07:38:59 as Exp $
+ */
+
+/*
+ * Note that the array sizes are all specified; this is to enable range
+ * checking by code that only includes constants.h.
+ */
+
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+#include <netinet/in.h>
+
+#include <freeswan.h>
+#include <ipsec_policy.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "packet.h"
+
+/* string naming compile-time options that have interop implications */
+
+const char compile_time_interop_options[] = ""
+#ifdef THREADS
+ " THREADS"
+#endif
+#ifdef LIBCURL
+ " LIBCURL"
+#endif
+#ifdef LIBLDAP
+ " LIBLDAP"
+#endif
+#ifdef SMARTCARD
+ " SMARTCARD"
+#endif
+#ifdef VENDORID
+ " VENDORID"
+#endif
+#ifdef CISCO_QUIRKS
+ " CISCO_QUIRKS"
+#endif
+#ifdef USE_KEYRR
+ " KEYRR"
+#endif
+ ;
+
+/* version */
+
+static const char *const version_name[] = {
+ "ISAKMP Version 1.0",
+};
+
+enum_names version_names =
+ { ISAKMP_MAJOR_VERSION<<ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION,
+ ISAKMP_MAJOR_VERSION<<ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION,
+ version_name, NULL };
+
+/* RFC 2459 CRL reason codes */
+
+static const char *const crl_reason_name[] = {
+ "unspecified",
+ "key compromise",
+ "ca compromise",
+ "affiliation changed",
+ "superseded",
+ "cessation of operation",
+ "certificate hold",
+ "reason #7",
+ "remove from crl"
+ };
+
+enum_names crl_reason_names =
+ { REASON_UNSPECIFIED, REASON_REMOVE_FROM_CRL, crl_reason_name, NULL};
+
+/* RFC 3706 Dead Peer Detection */
+
+static const char *const dpd_action_name[] = {
+ "none",
+ "clear",
+ "hold",
+ "restart"
+ };
+
+enum_names dpd_action_names =
+ { DPD_ACTION_NONE, DPD_ACTION_RESTART, dpd_action_name, NULL};
+
+/* Timer events */
+
+static const char *const timer_event_name[] = {
+ "EVENT_NULL",
+ "EVENT_REINIT_SECRET",
+ "EVENT_SHUNT_SCAN",
+ "EVENT_SO_DISCARD",
+ "EVENT_RETRANSMIT",
+ "EVENT_SA_REPLACE",
+ "EVENT_SA_REPLACE_IF_USED",
+ "EVENT_SA_EXPIRE",
+ "EVENT_NAT_T_KEEPALIVE",
+ "EVENT_DPD",
+ "EVENT_DPD_TIMEOUT",
+ "EVENT_LOG_DAILY"
+ };
+
+enum_names timer_event_names =
+ { EVENT_NULL, EVENT_LOG_DAILY, timer_event_name, NULL };
+
+/* Domain of Interpretation */
+
+static const char *const doi_name[] = {
+ "ISAKMP_DOI_ISAKMP",
+ "ISAKMP_DOI_IPSEC",
+};
+
+enum_names doi_names = { ISAKMP_DOI_ISAKMP, ISAKMP_DOI_IPSEC, doi_name, NULL };
+
+/* debugging settings: a set of selections for reporting
+ * These would be more naturally situated in log.h,
+ * but they are shared with whack.
+ * It turns out that "debug-" is clutter in all contexts this is used,
+ * so we leave it off.
+ */
+#ifdef DEBUG
+const char *const debug_bit_names[] = {
+ "raw",
+ "crypt",
+ "parsing",
+ "emitting",
+ "control",
+ "lifecycle",
+ "klips",
+ "dns",
+ "natt",
+ "oppo",
+ "controlmore",
+
+ "private",
+
+ "impair-delay-adns-key-answer",
+ "impair-delay-adns-txt-answer",
+ "impair-bust-mi2",
+ "impair-bust-mr2",
+
+ NULL
+ };
+#endif
+
+/* State of exchanges */
+
+static const char *const state_name[] = {
+ "STATE_MAIN_R0",
+ "STATE_MAIN_I1",
+ "STATE_MAIN_R1",
+ "STATE_MAIN_I2",
+ "STATE_MAIN_R2",
+ "STATE_MAIN_I3",
+ "STATE_MAIN_R3",
+ "STATE_MAIN_I4",
+
+ "STATE_QUICK_R0",
+ "STATE_QUICK_I1",
+ "STATE_QUICK_R1",
+ "STATE_QUICK_I2",
+ "STATE_QUICK_R2",
+
+ "STATE_INFO",
+ "STATE_INFO_PROTECTED",
+
+ "STATE_XAUTH_I0",
+ "STATE_XAUTH_R1",
+ "STATE_XAUTH_I1",
+ "STATE_XAUTH_R2",
+ "STATE_XAUTH_I2",
+ "STATE_XAUTH_R3",
+
+ "STATE_MODE_CFG_R0",
+ "STATE_MODE_CFG_I1",
+ "STATE_MODE_CFG_R1",
+ "STATE_MODE_CFG_I2",
+
+ "STATE_MODE_CFG_I0",
+ "STATE_MODE_CFG_R3",
+ "STATE_MODE_CFG_I3",
+ "STATE_MODE_CFG_R4",
+
+ "STATE_IKE_ROOF"
+ };
+
+enum_names state_names =
+ { STATE_MAIN_R0, STATE_IKE_ROOF-1, state_name, NULL };
+
+/* story for state */
+
+const char *const state_story[] = {
+ "expecting MI1", /* STATE_MAIN_R0 */
+ "sent MI1, expecting MR1", /* STATE_MAIN_I1 */
+ "sent MR1, expecting MI2", /* STATE_MAIN_R1 */
+ "sent MI2, expecting MR2", /* STATE_MAIN_I2 */
+ "sent MR2, expecting MI3", /* STATE_MAIN_R2 */
+ "sent MI3, expecting MR3", /* STATE_MAIN_I3 */
+ "sent MR3, ISAKMP SA established", /* STATE_MAIN_R3 */
+ "ISAKMP SA established", /* STATE_MAIN_I4 */
+
+ "expecting QI1", /* STATE_QUICK_R0 */
+ "sent QI1, expecting QR1", /* STATE_QUICK_I1 */
+ "sent QR1, inbound IPsec SA installed, expecting QI2", /* STATE_QUICK_R1 */
+ "sent QI2, IPsec SA established", /* STATE_QUICK_I2 */
+ "IPsec SA established", /* STATE_QUICK_R2 */
+
+ "got Informational Message in clear", /* STATE_INFO */
+ "got encrypted Informational Message", /* STATE_INFO_PROTECTED */
+
+ "expecting XAUTH request", /* STATE_XAUTH_I0 */
+ "sent XAUTH request, expecting reply", /* STATE_XAUTH_R1 */
+ "sent XAUTH reply, expecting status", /* STATE_XAUTH_I1 */
+ "sent XAUTH status, expecting ack", /* STATE_XAUTH_R2 */
+ "sent XAUTH ack, established", /* STATE_XAUTH_I2 */
+ "received XAUTH ack, established", /* STATE_XAUTH_R3 */
+
+ "expecting ModeCfg request", /* STATE_MODE_CFG_R0 */
+ "sent ModeCfg request, expecting reply", /* STATE_MODE_CFG_I1 */
+ "sent ModeCfg reply, established", /* STATE_MODE_CFG_R1 */
+ "received ModeCfg reply, established", /* STATE_MODE_CFG_I2 */
+
+ "expecting ModeCfg set", /* STATE_MODE_CFG_I0 */
+ "sent ModeCfg set, expecting ack", /* STATE_MODE_CFG_R3 */
+ "sent ModeCfg ack, established", /* STATE_MODE_CFG_I3 */
+ "received ModeCfg ack, established", /* STATE_MODE_CFG_R4 */
+ };
+
+/* kind of struct connection */
+
+static const char *const connection_kind_name[] = {
+ "CK_GROUP", /* policy group: instantiates to template */
+ "CK_TEMPLATE", /* abstract connection, with wildcard */
+ "CK_PERMANENT", /* normal connection */
+ "CK_INSTANCE", /* instance of template, created for a particular attempt */
+ "CK_GOING_AWAY" /* instance being deleted -- don't delete again */
+};
+
+enum_names connection_kind_names =
+ { CK_GROUP, CK_GOING_AWAY, connection_kind_name, NULL };
+
+/* routing status names */
+
+static const char *const routing_story_strings[] = {
+ "unrouted", /* RT_UNROUTED: unrouted */
+ "unrouted HOLD", /* RT_UNROUTED_HOLD: unrouted, but HOLD shunt installed */
+ "eroute eclipsed", /* RT_ROUTED_ECLIPSED: RT_ROUTED_PROSPECTIVE except bare HOLD or instance has eroute */
+ "prospective erouted", /* RT_ROUTED_PROSPECTIVE: routed, and prospective shunt installed */
+ "erouted HOLD", /* RT_ROUTED_HOLD: routed, and HOLD shunt installed */
+ "fail erouted", /* RT_ROUTED_FAILURE: routed, and failure-context shunt eroute installed */
+ "erouted", /* RT_ROUTED_TUNNEL: routed, and erouted to an IPSEC SA group */
+ "keyed, unrouted", /* RT_UNROUTED_KEYED: was routed+keyed, but it got turned into an outer policy */
+ };
+
+enum_names routing_story =
+ { RT_UNROUTED, RT_ROUTED_TUNNEL, routing_story_strings, NULL};
+
+/* Payload types (RFC 2408 "ISAKMP" section 3.1) */
+
+const char *const payload_name[] = {
+ "ISAKMP_NEXT_NONE",
+ "ISAKMP_NEXT_SA",
+ "ISAKMP_NEXT_P",
+ "ISAKMP_NEXT_T",
+ "ISAKMP_NEXT_KE",
+ "ISAKMP_NEXT_ID",
+ "ISAKMP_NEXT_CERT",
+ "ISAKMP_NEXT_CR",
+ "ISAKMP_NEXT_HASH",
+ "ISAKMP_NEXT_SIG",
+ "ISAKMP_NEXT_NONCE",
+ "ISAKMP_NEXT_N",
+ "ISAKMP_NEXT_D",
+ "ISAKMP_NEXT_VID",
+ "ISAKMP_NEXT_MODECFG",
+ "ISAKMP_NEXT_15",
+ "ISAKMP_NEXT_16",
+ "ISAKMP_NEXT_17",
+ "ISAKMP_NEXT_18",
+ "ISAKMP_NEXT_19",
+ "ISAKMP_NEXT_NAT-D",
+ "ISAKMP_NEXT_NAT-OA",
+ NULL
+ };
+
+const char *const payload_name_nat_d[] = { "ISAKMP_NEXT_NAT-D",
+ "ISAKMP_NEXT_NAT-OA", NULL };
+
+static enum_names payload_names_nat_d =
+ { ISAKMP_NEXT_NATD_DRAFTS, ISAKMP_NEXT_NATOA_DRAFTS, payload_name_nat_d, NULL };
+
+enum_names payload_names =
+ { ISAKMP_NEXT_NONE, ISAKMP_NEXT_NATOA_RFC, payload_name, &payload_names_nat_d };
+
+/* Exchange types (note: two discontinuous ranges) */
+
+static const char *const exchange_name[] = {
+ "ISAKMP_XCHG_NONE",
+ "ISAKMP_XCHG_BASE",
+ "ISAKMP_XCHG_IDPROT",
+ "ISAKMP_XCHG_AO",
+ "ISAKMP_XCHG_AGGR",
+ "ISAKMP_XCHG_INFO",
+ "ISAKMP_XCHG_MODE_CFG",
+ };
+
+static const char *const exchange_name2[] = {
+ "ISAKMP_XCHG_QUICK",
+ "ISAKMP_XCHG_NGRP",
+ "ISAKMP_XCHG_ACK_INFO",
+ };
+
+static enum_names exchange_desc2 =
+ { ISAKMP_XCHG_QUICK, ISAKMP_XCHG_ACK_INFO, exchange_name2, NULL };
+
+enum_names exchange_names =
+ { ISAKMP_XCHG_NONE, ISAKMP_XCHG_MODE_CFG, exchange_name, &exchange_desc2 };
+
+/* Flag BITS */
+const char *const flag_bit_names[] = {
+ "ISAKMP_FLAG_ENCRYPTION",
+ "ISAKMP_FLAG_COMMIT",
+ NULL
+ };
+
+/* Situation BITS definition for IPsec DOI */
+
+const char *const sit_bit_names[] = {
+ "SIT_IDENTITY_ONLY",
+ "SIT_SECRECY",
+ "SIT_INTEGRITY",
+ NULL
+ };
+
+/* Protocol IDs (RFC 2407 "IPsec DOI" section 4.4.1) */
+
+static const char *const protocol_name[] = {
+ "PROTO_ISAKMP",
+ "PROTO_IPSEC_AH",
+ "PROTO_IPSEC_ESP",
+ "PROTO_IPCOMP",
+ };
+
+enum_names protocol_names =
+ { PROTO_ISAKMP, PROTO_IPCOMP, protocol_name, NULL };
+
+/* IPsec ISAKMP transform values */
+
+static const char *const isakmp_transform_name[] = {
+ "KEY_IKE",
+ };
+
+enum_names isakmp_transformid_names =
+ { KEY_IKE, KEY_IKE, isakmp_transform_name, NULL };
+
+/* IPsec AH transform values */
+
+static const char *const ah_transform_name[] = {
+ "AH_MD5",
+ "AH_SHA",
+ "AH_DES",
+ "AH_SHA2_256",
+ "AH_SHA2_384",
+ "AH_SHA2_512",
+ "AH_RIPEMD"
+ };
+
+enum_names ah_transformid_names =
+ { AH_MD5, AH_RIPEMD, ah_transform_name, NULL };
+
+/* IPsec ESP transform values */
+
+static const char *const esp_transform_name[] = {
+ "ESP_DES_IV64",
+ "ESP_DES",
+ "ESP_3DES",
+ "ESP_RC5",
+ "ESP_IDEA",
+ "ESP_CAST",
+ "ESP_BLOWFISH",
+ "ESP_3IDEA",
+ "ESP_DES_IV32",
+ "ESP_RC4",
+ "ESP_NULL",
+ "ESP_AES",
+ "ESP_AES-CTR",
+ "ESP_AES-CCM_8",
+ "ESP_AES-CCM_12",
+ "ESP_AES-CCM_16"
+ };
+
+/*
+ * ipsec drafts suggest "high" ESP ids values for testing,
+ * assign generic ESP_ID<num> if not officially defined
+ */
+static const char *const esp_transform_name_high[] = {
+ "ESP_SERPENT",
+ "ESP_TWOFISH"
+ };
+
+enum_names esp_transformid_names_high =
+ { ESP_SERPENT, ESP_TWOFISH, esp_transform_name_high, NULL };
+
+enum_names esp_transformid_names =
+ { ESP_DES_IV64, ESP_AES_CCM_16, esp_transform_name, &esp_transformid_names_high };
+
+/* IPCOMP transform values */
+
+static const char *const ipcomp_transform_name[] = {
+ "IPCOMP_OUI",
+ "IPCOMP_DEFLAT",
+ "IPCOMP_LZS",
+ "IPCOMP_LZJH",
+ };
+
+enum_names ipcomp_transformid_names =
+ { IPCOMP_OUI, IPCOMP_LZJH, ipcomp_transform_name, NULL };
+
+/* Identification type values */
+
+static const char *const ident_name[] = {
+ "ID_IPV4_ADDR",
+ "ID_FQDN",
+ "ID_USER_FQDN",
+ "ID_IPV4_ADDR_SUBNET",
+ "ID_IPV6_ADDR",
+ "ID_IPV6_ADDR_SUBNET",
+ "ID_IPV4_ADDR_RANGE",
+ "ID_IPV6_ADDR_RANGE",
+ "ID_DER_ASN1_DN",
+ "ID_DER_ASN1_GN",
+ "ID_KEY_ID",
+ };
+
+enum_names ident_names =
+ { ID_IPV4_ADDR, ID_KEY_ID, ident_name, NULL };
+
+/* Certificate type values */
+
+static const char *const cert_type_name[] = {
+ "CERT_NONE",
+ "CERT_PKCS7_WRAPPED_X509",
+ "CERT_PGP",
+ "CERT_DNS_SIGNED_KEY",
+ "CERT_X509_SIGNATURE",
+ "CERT_X509_KEY_EXCHANGE",
+ "CERT_KERBEROS_TOKENS",
+ "CERT_CRL",
+ "CERT_ARL",
+ "CERT_SPKI",
+ "CERT_X509_ATTRIBUTE",
+ };
+
+enum_names cert_type_names =
+ { CERT_NONE, CERT_X509_ATTRIBUTE, cert_type_name, NULL };
+
+/* Certificate policy names */
+
+static const char *const cert_policy_name[] = {
+ "ALWAYS_SEND",
+ "SEND_IF_ASKED",
+ "NEVER_SEND",
+ };
+
+enum_names cert_policy_names =
+ { CERT_ALWAYS_SEND, CERT_NEVER_SEND, cert_policy_name, NULL };
+
+/* Goal BITs for establishing an SA
+ * Note: we drop the POLICY_ prefix so that logs are more concise.
+ */
+
+const char *const sa_policy_bit_names[] = {
+ "PSK",
+ "RSASIG",
+ "ENCRYPT",
+ "AUTHENTICATE",
+ "COMPRESS",
+ "TUNNEL",
+ "PFS",
+ "DISABLEARRIVALCHECK",
+ "SHUNT0",
+ "SHUNT1",
+ "FAILSHUNT0",
+ "FAILSHUNT1",
+ "DONTREKEY",
+ "OPPORTUNISTIC",
+ "GROUP",
+ "GROUTED",
+ "UP",
+ "MODECFGPUSH",
+ "XAUTHPSK",
+ "XAUTHRSASIG",
+ "XAUTHSERVER",
+ "DONTREAUTH",
+ NULL
+ };
+
+const char *const policy_shunt_names[4] = {
+ "TRAP",
+ "PASS",
+ "DROP",
+ "REJECT",
+ };
+
+const char *const policy_fail_names[4] = {
+ "NONE",
+ "PASS",
+ "DROP",
+ "REJECT",
+ };
+
+/* Oakley transform attributes
+ * oakley_attr_bit_names does double duty: it is used for enum names
+ * and bit names.
+ */
+
+const char *const oakley_attr_bit_names[] = {
+ "OAKLEY_ENCRYPTION_ALGORITHM",
+ "OAKLEY_HASH_ALGORITHM",
+ "OAKLEY_AUTHENTICATION_METHOD",
+ "OAKLEY_GROUP_DESCRIPTION",
+ "OAKLEY_GROUP_TYPE",
+ "OAKLEY_GROUP_PRIME",
+ "OAKLEY_GROUP_GENERATOR_ONE",
+ "OAKLEY_GROUP_GENERATOR_TWO",
+ "OAKLEY_GROUP_CURVE_A",
+ "OAKLEY_GROUP_CURVE_B",
+ "OAKLEY_LIFE_TYPE",
+ "OAKLEY_LIFE_DURATION",
+ "OAKLEY_PRF",
+ "OAKLEY_KEY_LENGTH",
+ "OAKLEY_FIELD_SIZE",
+ "OAKLEY_GROUP_ORDER",
+ "OAKLEY_BLOCK_SIZE",
+ NULL
+ };
+
+static const char *const oakley_var_attr_name[] = {
+ "OAKLEY_GROUP_PRIME (variable length)",
+ "OAKLEY_GROUP_GENERATOR_ONE (variable length)",
+ "OAKLEY_GROUP_GENERATOR_TWO (variable length)",
+ "OAKLEY_GROUP_CURVE_A (variable length)",
+ "OAKLEY_GROUP_CURVE_B (variable length)",
+ NULL,
+ "OAKLEY_LIFE_DURATION (variable length)",
+ NULL,
+ NULL,
+ NULL,
+ "OAKLEY_GROUP_ORDER (variable length)",
+ };
+
+static enum_names oakley_attr_desc_tv = {
+ OAKLEY_ENCRYPTION_ALGORITHM + ISAKMP_ATTR_AF_TV,
+ OAKLEY_GROUP_ORDER + ISAKMP_ATTR_AF_TV, oakley_attr_bit_names, NULL };
+
+enum_names oakley_attr_names = {
+ OAKLEY_GROUP_PRIME, OAKLEY_GROUP_ORDER,
+ oakley_var_attr_name, &oakley_attr_desc_tv };
+
+/* for each Oakley attribute, which enum_names describes its values? */
+enum_names *oakley_attr_val_descs[] = {
+ NULL, /* (none) */
+ &oakley_enc_names, /* OAKLEY_ENCRYPTION_ALGORITHM */
+ &oakley_hash_names, /* OAKLEY_HASH_ALGORITHM */
+ &oakley_auth_names, /* OAKLEY_AUTHENTICATION_METHOD */
+ &oakley_group_names, /* OAKLEY_GROUP_DESCRIPTION */
+ &oakley_group_type_names,/* OAKLEY_GROUP_TYPE */
+ NULL, /* OAKLEY_GROUP_PRIME */
+ NULL, /* OAKLEY_GROUP_GENERATOR_ONE */
+ NULL, /* OAKLEY_GROUP_GENERATOR_TWO */
+ NULL, /* OAKLEY_GROUP_CURVE_A */
+ NULL, /* OAKLEY_GROUP_CURVE_B */
+ &oakley_lifetime_names, /* OAKLEY_LIFE_TYPE */
+ NULL, /* OAKLEY_LIFE_DURATION */
+ &oakley_prf_names, /* OAKLEY_PRF */
+ NULL, /* OAKLEY_KEY_LENGTH */
+ NULL, /* OAKLEY_FIELD_SIZE */
+ NULL, /* OAKLEY_GROUP_ORDER */
+ };
+
+/* IPsec DOI attributes (RFC 2407 "IPsec DOI" section 4.5) */
+
+static const char *const ipsec_attr_name[] = {
+ "SA_LIFE_TYPE",
+ "SA_LIFE_DURATION",
+ "GROUP_DESCRIPTION",
+ "ENCAPSULATION_MODE",
+ "AUTH_ALGORITHM",
+ "KEY_LENGTH",
+ "KEY_ROUNDS",
+ "COMPRESS_DICT_SIZE",
+ "COMPRESS_PRIVATE_ALG",
+ };
+
+static const char *const ipsec_var_attr_name[] = {
+ "SA_LIFE_DURATION (variable length)",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "COMPRESS_PRIVATE_ALG (variable length)",
+ };
+
+static enum_names ipsec_attr_desc_tv = {
+ SA_LIFE_TYPE + ISAKMP_ATTR_AF_TV,
+ COMPRESS_PRIVATE_ALG + ISAKMP_ATTR_AF_TV,
+ ipsec_attr_name, NULL };
+
+enum_names ipsec_attr_names = {
+ SA_LIFE_DURATION, COMPRESS_PRIVATE_ALG,
+ ipsec_var_attr_name, &ipsec_attr_desc_tv };
+
+/* for each IPsec attribute, which enum_names describes its values? */
+enum_names *ipsec_attr_val_descs[] = {
+ NULL, /* (none) */
+ &sa_lifetime_names, /* SA_LIFE_TYPE */
+ NULL, /* SA_LIFE_DURATION */
+ &oakley_group_names, /* GROUP_DESCRIPTION */
+ &enc_mode_names, /* ENCAPSULATION_MODE */
+ &auth_alg_names, /* AUTH_ALGORITHM */
+ NULL, /* KEY_LENGTH */
+ NULL, /* KEY_ROUNDS */
+ NULL, /* COMPRESS_DICT_SIZE */
+ NULL, /* COMPRESS_PRIVATE_ALG */
+ };
+
+/* SA Lifetime Type attribute */
+
+static const char *const sa_lifetime_name[] = {
+ "SA_LIFE_TYPE_SECONDS",
+ "SA_LIFE_TYPE_KBYTES",
+ };
+
+enum_names sa_lifetime_names =
+ { SA_LIFE_TYPE_SECONDS, SA_LIFE_TYPE_KBYTES, sa_lifetime_name, NULL };
+
+/* Encapsulation Mode attribute */
+
+static const char *const enc_mode_name[] = {
+ "ENCAPSULATION_MODE_TUNNEL",
+ "ENCAPSULATION_MODE_TRANSPORT",
+ "ENCAPSULATION_MODE_UDP_TUNNEL",
+ "ENCAPSULATION_MODE_UDP_TRANSPORT",
+ };
+
+static const char *const enc_udp_mode_name[] = {
+ "ENCAPSULATION_MODE_UDP_TUNNEL",
+ "ENCAPSULATION_MODE_UDP_TRANSPORT",
+ };
+
+static enum_names enc_udp_mode_names =
+ { ENCAPSULATION_MODE_UDP_TUNNEL_DRAFTS, ENCAPSULATION_MODE_UDP_TRANSPORT_DRAFTS, enc_udp_mode_name, NULL };
+
+enum_names enc_mode_names =
+ { ENCAPSULATION_MODE_TUNNEL, ENCAPSULATION_MODE_UDP_TRANSPORT_RFC, enc_mode_name, &enc_udp_mode_names };
+
+/* Auth Algorithm attribute */
+
+static const char *const auth_alg_name[] = {
+ "AUTH_ALGORITHM_HMAC_MD5",
+ "AUTH_ALGORITHM_HMAC_SHA1",
+ "AUTH_ALGORITHM_DES_MAC",
+ "AUTH_ALGORITHM_KPDK",
+ "AUTH_ALGORITHM_HMAC_SHA2_256",
+ "AUTH_ALGORITHM_HMAC_SHA2_384",
+ "AUTH_ALGORITHM_HMAC_SHA2_512",
+ "AUTH_ALGORITHM_HMAC_RIPEMD",
+ };
+
+static const char *const extended_auth_alg_name[] = {
+ "AUTH_ALGORITHM_NULL"
+ };
+
+enum_names extended_auth_alg_names =
+ { AUTH_ALGORITHM_NULL, AUTH_ALGORITHM_NULL, extended_auth_alg_name, NULL };
+
+enum_names auth_alg_names =
+ { AUTH_ALGORITHM_HMAC_MD5, AUTH_ALGORITHM_HMAC_RIPEMD, auth_alg_name
+ , &extended_auth_alg_names };
+
+/* From draft-beaulieu-ike-xauth */
+static const char *const xauth_type_name[] = {
+ "Generic",
+ "RADIUS-CHAP",
+ "OTP",
+ "S/KEY",
+};
+
+enum_names xauth_type_names =
+ { XAUTH_TYPE_GENERIC, XAUTH_TYPE_SKEY, xauth_type_name, NULL};
+
+/* From draft-beaulieu-ike-xauth */
+static const char *const xauth_attr_tv_name[] = {
+ "XAUTH_TYPE",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "XAUTH_STATUS",
+ };
+
+enum_names xauth_attr_tv_names = {
+ XAUTH_TYPE + ISAKMP_ATTR_AF_TV,
+ XAUTH_STATUS + ISAKMP_ATTR_AF_TV, xauth_attr_tv_name, NULL };
+
+static const char *const unity_attr_name[] = {
+ "UNITY_BANNER",
+ "UNITY_SAVE_PASSWD",
+ "UNITY_DEF_DOMAIN",
+ "UNITY_SPLITDNS_NAME",
+ "UNITY_SPLIT_INCLUDE",
+ "UNITY_NATT_PORT",
+ "UNITY_LOCAL_LAN",
+ "UNITY_PFS",
+ "UNITY_FW_TYPE",
+ "UNITY_BACKUP_SERVERS",
+ "UNITY_DDNS_HOSTNAME",
+};
+
+enum_names unity_attr_names =
+ { UNITY_BANNER , UNITY_DDNS_HOSTNAME, unity_attr_name , &xauth_attr_tv_names };
+
+
+static const char *const xauth_attr_name[] = {
+ "XAUTH_USER_NAME",
+ "XAUTH_USER_PASSWORD",
+ "XAUTH_PASSCODE",
+ "XAUTH_MESSAGE",
+ "XAUTH_CHALLENGE",
+ "XAUTH_DOMAIN",
+ "XAUTH_STATUS (wrong TLV syntax, should be TV)",
+ "XAUTH_NEXT_PIN",
+ "XAUTH_ANSWER",
+ };
+
+enum_names xauth_attr_names =
+ { XAUTH_USER_NAME , XAUTH_ANSWER, xauth_attr_name , &unity_attr_names };
+
+static const char *const modecfg_attr_name[] = {
+ "INTERNAL_IP4_ADDRESS",
+ "INTERNAL_IP4_NETMASK",
+ "INTERNAL_IP4_DNS",
+ "INTERNAL_IP4_NBNS",
+ "INTERNAL_ADDRESS_EXPIRY",
+ "INTERNAL_IP4_DHCP",
+ "APPLICATION_VERSION",
+ "INTERNAL_IP6_ADDRESS",
+ "INTERNAL_IP6_NETMASK",
+ "INTERNAL_IP6_DNS",
+ "INTERNAL_IP6_NBNS",
+ "INTERNAL_IP6_DHCP",
+ "INTERNAL_IP4_SUBNET",
+ "SUPPORTED_ATTRIBUTES",
+ "INTERNAL_IP6_SUBNET",
+ };
+
+enum_names modecfg_attr_names =
+ { INTERNAL_IP4_ADDRESS, INTERNAL_IP6_SUBNET, modecfg_attr_name , &xauth_attr_names };
+
+/* Oakley Lifetime Type attribute */
+
+static const char *const oakley_lifetime_name[] = {
+ "OAKLEY_LIFE_SECONDS",
+ "OAKLEY_LIFE_KILOBYTES",
+ };
+
+enum_names oakley_lifetime_names =
+ { OAKLEY_LIFE_SECONDS, OAKLEY_LIFE_KILOBYTES, oakley_lifetime_name, NULL };
+
+/* Oakley PRF attribute (none defined) */
+
+enum_names oakley_prf_names =
+ { 1, 0, NULL, NULL };
+
+/* Oakley Encryption Algorithm attribute */
+
+static const char *const oakley_enc_name[] = {
+ "OAKLEY_DES_CBC",
+ "OAKLEY_IDEA_CBC",
+ "OAKLEY_BLOWFISH_CBC",
+ "OAKLEY_RC5_R16_B64_CBC",
+ "OAKLEY_3DES_CBC",
+ "OAKLEY_CAST_CBC",
+ "OAKLEY_AES_CBC",
+ };
+
+#ifdef NO_EXTRA_IKE
+enum_names oakley_enc_names =
+ { OAKLEY_DES_CBC, OAKLEY_AES_CBC, oakley_enc_name, NULL };
+#else
+static const char *const oakley_enc_name_draft_aes_cbc_02[] = {
+ "OAKLEY_MARS_CBC" /* 65001 */,
+ "OAKLEY_RC6_CBC" /* 65002 */,
+ "OAKLEY_ID_65003" /* 65003 */,
+ "OAKLEY_SERPENT_CBC" /* 65004 */,
+ "OAKLEY_TWOFISH_CBC" /* 65005 */,
+};
+static const char *const oakley_enc_name_ssh[] = {
+ "OAKLEY_TWOFISH_CBC_SSH",
+};
+enum_names oakley_enc_names_ssh =
+ { OAKLEY_TWOFISH_CBC_SSH, OAKLEY_TWOFISH_CBC_SSH, oakley_enc_name_ssh
+ , NULL };
+
+enum_names oakley_enc_names_draft_aes_cbc_02 =
+ { OAKLEY_MARS_CBC, OAKLEY_TWOFISH_CBC, oakley_enc_name_draft_aes_cbc_02
+ , &oakley_enc_names_ssh };
+
+enum_names oakley_enc_names =
+ { OAKLEY_DES_CBC, OAKLEY_AES_CBC, oakley_enc_name
+ , &oakley_enc_names_draft_aes_cbc_02 };
+#endif
+
+/* Oakley Hash Algorithm attribute */
+
+static const char *const oakley_hash_name[] = {
+ "OAKLEY_MD5",
+ "OAKLEY_SHA",
+ "OAKLEY_TIGER",
+ "OAKLEY_SHA2_256",
+ "OAKLEY_SHA2_384",
+ "OAKLEY_SHA2_512",
+ };
+
+enum_names oakley_hash_names =
+ { OAKLEY_MD5, OAKLEY_SHA2_512, oakley_hash_name, NULL };
+
+/* Oakley Authentication Method attribute */
+
+static const char *const oakley_auth_name1[] = {
+ "OAKLEY_PRESHARED_KEY",
+ "OAKLEY_DSS_SIG",
+ "OAKLEY_RSA_SIG",
+ "OAKLEY_RSA_ENC",
+ "OAKLEY_RSA_ENC_REV",
+ "OAKLEY_ELGAMAL_ENC",
+ "OAKLEY_ELGAMAL_ENC_REV",
+ };
+
+static const char *const oakley_auth_name2[] = {
+ "HybridInitRSA",
+ "HybridRespRSA",
+ "HybridInitDSS",
+ "HybridRespDSS",
+ };
+
+static const char *const oakley_auth_name3[] = {
+ "XAUTHInitPreShared",
+ "XAUTHRespPreShared",
+ "XAUTHInitDSS",
+ "XAUTHRespDSS",
+ "XAUTHInitRSA",
+ "XAUTHRespRSA",
+ "XAUTHInitRSAEncryption",
+ "XAUTHRespRSAEncryption",
+ "XAUTHInitRSARevisedEncryption",
+ "XAUTHRespRSARevisedEncryption",
+ };
+
+static enum_names oakley_auth_names1 =
+ { OAKLEY_PRESHARED_KEY, OAKLEY_ELGAMAL_ENC_REV
+ , oakley_auth_name1, NULL };
+
+static enum_names oakley_auth_names2 =
+ { HybridInitRSA, HybridRespDSS
+ , oakley_auth_name2, &oakley_auth_names1 };
+
+enum_names oakley_auth_names =
+ { XAUTHInitPreShared, XAUTHRespRSARevisedEncryption
+ , oakley_auth_name3, &oakley_auth_names2 };
+
+/* Oakley Group Description attribute */
+
+static const char *const oakley_group_name[] = {
+ "OAKLEY_GROUP_MODP768",
+ "OAKLEY_GROUP_MODP1024",
+ "OAKLEY_GROUP_GP155",
+ "OAKLEY_GROUP_GP185",
+ "OAKLEY_GROUP_MODP1536",
+ };
+
+static const char *const oakley_group_name_rfc3526[] = {
+ "OAKLEY_GROUP_MODP2048",
+ "OAKLEY_GROUP_MODP3072",
+ "OAKLEY_GROUP_MODP4096",
+ "OAKLEY_GROUP_MODP6144",
+ "OAKLEY_GROUP_MODP8192"
+};
+enum_names oakley_group_names_rfc3526 =
+ { OAKLEY_GROUP_MODP2048, OAKLEY_GROUP_MODP8192,
+ oakley_group_name_rfc3526, NULL };
+
+enum_names oakley_group_names =
+ { OAKLEY_GROUP_MODP768, OAKLEY_GROUP_MODP1536,
+ oakley_group_name, &oakley_group_names_rfc3526 };
+
+/* Oakley Group Type attribute */
+
+static const char *const oakley_group_type_name[] = {
+ "OAKLEY_GROUP_TYPE_MODP",
+ "OAKLEY_GROUP_TYPE_ECP",
+ "OAKLEY_GROUP_TYPE_EC2N",
+ };
+
+enum_names oakley_group_type_names =
+ { OAKLEY_GROUP_TYPE_MODP, OAKLEY_GROUP_TYPE_EC2N, oakley_group_type_name, NULL };
+
+/* Notify messages -- error types */
+
+static const char *const notification_name[] = {
+ "INVALID_PAYLOAD_TYPE",
+ "DOI_NOT_SUPPORTED",
+ "SITUATION_NOT_SUPPORTED",
+ "INVALID_COOKIE",
+ "INVALID_MAJOR_VERSION",
+ "INVALID_MINOR_VERSION",
+ "INVALID_EXCHANGE_TYPE",
+ "INVALID_FLAGS",
+ "INVALID_MESSAGE_ID",
+ "INVALID_PROTOCOL_ID",
+ "INVALID_SPI",
+ "INVALID_TRANSFORM_ID",
+ "ATTRIBUTES_NOT_SUPPORTED",
+ "NO_PROPOSAL_CHOSEN",
+ "BAD_PROPOSAL_SYNTAX",
+ "PAYLOAD_MALFORMED",
+ "INVALID_KEY_INFORMATION",
+ "INVALID_ID_INFORMATION",
+ "INVALID_CERT_ENCODING",
+ "INVALID_CERTIFICATE",
+ "CERT_TYPE_UNSUPPORTED",
+ "INVALID_CERT_AUTHORITY",
+ "INVALID_HASH_INFORMATION",
+ "AUTHENTICATION_FAILED",
+ "INVALID_SIGNATURE",
+ "ADDRESS_NOTIFICATION",
+ "NOTIFY_SA_LIFETIME",
+ "CERTIFICATE_UNAVAILABLE",
+ "UNSUPPORTED_EXCHANGE_TYPE",
+ "UNEQUAL_PAYLOAD_LENGTHS",
+ };
+
+static const char *const notification_status_name[] = {
+ "CONNECTED",
+ };
+
+static const char *const ipsec_notification_name[] = {
+ "IPSEC_RESPONDER_LIFETIME",
+ "IPSEC_REPLAY_STATUS",
+ "IPSEC_INITIAL_CONTACT",
+ };
+
+static const char *const notification_dpd_name[] = {
+ "R_U_THERE",
+ "R_U_THERE_ACK",
+};
+
+enum_names notification_dpd_names =
+ { R_U_THERE, R_U_THERE_ACK,
+ notification_dpd_name, NULL };
+
+enum_names ipsec_notification_names =
+ { IPSEC_RESPONDER_LIFETIME, IPSEC_INITIAL_CONTACT,
+ ipsec_notification_name, &notification_dpd_names };
+
+enum_names notification_status_names =
+ { CONNECTED, CONNECTED,
+ notification_status_name, &ipsec_notification_names };
+
+enum_names notification_names =
+ { INVALID_PAYLOAD_TYPE, UNEQUAL_PAYLOAD_LENGTHS,
+ notification_name, &notification_status_names };
+
+/* MODECFG
+ * From draft-dukes-ike-mode-cfg
+ */
+const char *const attr_msg_type_name[] = {
+ "ISAKMP_CFG_RESERVED",
+ "ISAKMP_CFG_REQUEST",
+ "ISAKMP_CFG_REPLY",
+ "ISAKMP_CFG_SET",
+ "ISAKMP_CFG_ACK",
+ NULL
+ };
+
+enum_names attr_msg_type_names =
+ { 0 , ISAKMP_CFG_ACK, attr_msg_type_name , NULL };
+
+/* socket address family info */
+
+static const char *const af_inet_name[] = {
+ "AF_INET",
+ };
+
+static const char *const af_inet6_name[] = {
+ "AF_INET6",
+ };
+
+static enum_names af_names6 = { AF_INET6, AF_INET6, af_inet6_name, NULL };
+
+enum_names af_names = { AF_INET, AF_INET, af_inet_name, &af_names6 };
+
+static ip_address ipv4_any, ipv6_any;
+static ip_subnet ipv4_wildcard, ipv6_wildcard;
+static ip_subnet ipv4_all, ipv6_all;
+
+const struct af_info af_inet4_info = {
+ AF_INET,
+ "AF_INET",
+ sizeof(struct in_addr),
+ sizeof(struct sockaddr_in),
+ 32,
+ ID_IPV4_ADDR, ID_IPV4_ADDR_SUBNET, ID_IPV4_ADDR_RANGE,
+ &ipv4_any, &ipv4_wildcard, &ipv4_all,
+ };
+
+const struct af_info af_inet6_info = {
+ AF_INET6,
+ "AF_INET6",
+ sizeof(struct in6_addr),
+ sizeof(struct sockaddr_in6),
+ 128,
+ ID_IPV6_ADDR, ID_IPV6_ADDR_SUBNET, ID_IPV6_ADDR_RANGE,
+ &ipv6_any, &ipv6_wildcard, &ipv6_all,
+ };
+
+const struct af_info *
+aftoinfo(int af)
+{
+ switch (af)
+ {
+ case AF_INET:
+ return &af_inet4_info;
+ case AF_INET6:
+ return &af_inet6_info;
+ default:
+ return NULL;
+ }
+}
+
+bool
+subnetisnone(const ip_subnet *sn)
+{
+ ip_address base;
+
+ networkof(sn, &base);
+ return isanyaddr(&base) && subnetishost(sn);
+}
+
+/* BIND enumerated types */
+
+#include <arpa/nameser.h>
+
+static const char *const rr_type_name[] = {
+ "T_A", /* 1 host address */
+ "T_NS", /* 2 authoritative server */
+ "T_MD", /* 3 mail destination */
+ "T_MF", /* 4 mail forwarder */
+ "T_CNAME", /* 5 canonical name */
+ "T_SOA", /* 6 start of authority zone */
+ "T_MB", /* 7 mailbox domain name */
+ "T_MG", /* 8 mail group member */
+ "T_MR", /* 9 mail rename name */
+ "T_NULL", /* 10 null resource record */
+ "T_WKS", /* 11 well known service */
+ "T_PTR", /* 12 domain name pointer */
+ "T_HINFO", /* 13 host information */
+ "T_MINFO", /* 14 mailbox information */
+ "T_MX", /* 15 mail routing information */
+ "T_TXT", /* 16 text strings */
+ "T_RP", /* 17 responsible person */
+ "T_AFSDB", /* 18 AFS cell database */
+ "T_X25", /* 19 X_25 calling address */
+ "T_ISDN", /* 20 ISDN calling address */
+ "T_RT", /* 21 router */
+ "T_NSAP", /* 22 NSAP address */
+ "T_NSAP_PTR", /* 23 reverse NSAP lookup (deprecated) */
+ "T_SIG", /* 24 security signature */
+ "T_KEY", /* 25 security key */
+ "T_PX", /* 26 X.400 mail mapping */
+ "T_GPOS", /* 27 geographical position (withdrawn) */
+ "T_AAAA", /* 28 IP6 Address */
+ "T_LOC", /* 29 Location Information */
+ "T_NXT", /* 30 Next Valid Name in Zone */
+ "T_EID", /* 31 Endpoint identifier */
+ "T_NIMLOC", /* 32 Nimrod locator */
+ "T_SRV", /* 33 Server selection */
+ "T_ATMA", /* 34 ATM Address */
+ "T_NAPTR", /* 35 Naming Authority PoinTeR */
+ NULL
+ };
+
+enum_names rr_type_names = { T_A, T_NAPTR, rr_type_name, NULL };
+
+/* Query type values which do not appear in resource records */
+static const char *const rr_qtype_name[] = {
+ "T_IXFR", /* 251 incremental zone transfer */
+ "T_AXFR", /* 252 transfer zone of authority */
+ "T_MAILB", /* 253 transfer mailbox records */
+ "T_MAILA", /* 254 transfer mail agent records */
+ "T_ANY", /* 255 wildcard match */
+ NULL
+ };
+
+enum_names rr_qtype_names = { T_IXFR, T_ANY, rr_qtype_name, &rr_type_names };
+
+static const char *const rr_class_name[] = {
+ "C_IN", /* 1 the arpa internet */
+ NULL
+ };
+
+enum_names rr_class_names = { C_IN, C_IN, rr_class_name, NULL };
+
+/*
+ * NAT-Traversal defines for nat_traveral type from nat_traversal.h
+ *
+ */
+const char *const natt_type_bitnames[] = {
+ "draft-ietf-ipsec-nat-t-ike-00/01", /* 0 */
+ "draft-ietf-ipsec-nat-t-ike-02/03",
+ "RFC 3947",
+ "3", /* 3 */
+ "4", "5", "6", "7",
+ "8", "9", "10", "11",
+ "12", "13", "14", "15",
+ "16", "17", "18", "19",
+ "20", "21", "22", "23",
+ "24", "25", "26", "27",
+ "28", "29",
+ "nat is behind me",
+ "nat is behind peer"
+};
+
+/* look up enum names in an enum_names */
+
+const char *
+enum_name(enum_names *ed, unsigned long val)
+{
+ enum_names *p;
+
+ for (p = ed; p != NULL; p = p->en_next_range)
+ {
+ if (p->en_first <= val && val <= p->en_last)
+ return p->en_names[val - p->en_first];
+ }
+ return NULL;
+}
+
+/* find or construct a string to describe an enum value
+ * Result may be in STATIC buffer!
+ */
+const char *
+enum_show(enum_names *ed, unsigned long val)
+{
+ const char *p = enum_name(ed, val);
+
+ if (p == NULL)
+ {
+ static char buf[12]; /* only one! I hope that it is big enough */
+
+ snprintf(buf, sizeof(buf), "%lu??", val);
+ p = buf;
+ }
+ return p;
+}
+
+
+static char bitnamesbuf[200]; /* only one! I hope that it is big enough! */
+
+int
+enum_search(enum_names *ed, const char *str)
+{
+ enum_names *p;
+ const char *ptr;
+ unsigned en;
+
+ for (p = ed; p != NULL; p = p->en_next_range)
+ for (en = p->en_first; en <= p->en_last ;en++)
+ {
+ ptr = p->en_names[en - p->en_first];
+ if (ptr == 0) continue;
+ /* if (strncmp(ptr, str, strlen(ptr))==0) */
+ if (strcmp(ptr, str) == 0)
+ return en;
+ }
+ return -1;
+}
+
+/* construct a string to name the bits on in a set
+ * Result may be in STATIC buffer!
+ * Note: prettypolicy depends on internal details.
+ */
+const char *
+bitnamesof(const char *const table[], lset_t val)
+{
+ char *p = bitnamesbuf;
+ lset_t bit;
+ const char *const *tp;
+
+ if (val == 0)
+ return "none";
+
+ for (tp = table, bit = 01; val != 0; bit <<= 1)
+ {
+ if (val & bit)
+ {
+ const char *n = *tp;
+ size_t nl;
+
+ if (n == NULL || *n == '\0')
+ {
+ /* no name for this bit, so use hex */
+ static char flagbuf[sizeof("0x80000000")];
+
+ snprintf(flagbuf, sizeof(flagbuf), "0x%llx", bit);
+ n = flagbuf;
+ }
+
+ nl = strlen(n);
+
+ if (p != bitnamesbuf && p < bitnamesbuf+sizeof(bitnamesbuf) - 1)
+ *p++ = '+';
+
+ if (bitnamesbuf+sizeof(bitnamesbuf) - p > (ptrdiff_t)nl)
+ {
+ strcpy(p, n);
+ p += nl;
+ }
+ val -= bit;
+ }
+ if (*tp != NULL)
+ tp++; /* move on, but not past end */
+ }
+ *p = '\0';
+ return bitnamesbuf;
+}
+
+/* print a policy: like bitnamesof, but it also does the non-bitfields.
+ * Suppress the shunt and fail fields if 0.
+ */
+const char *
+prettypolicy(lset_t policy)
+{
+ const char *bn = bitnamesof(sa_policy_bit_names
+ , policy & ~(POLICY_SHUNT_MASK | POLICY_FAIL_MASK));
+ size_t len;
+ lset_t shunt = (policy & POLICY_SHUNT_MASK) >> POLICY_SHUNT_SHIFT;
+ lset_t fail = (policy & POLICY_FAIL_MASK) >> POLICY_FAIL_SHIFT;
+
+ if (bn != bitnamesbuf)
+ bitnamesbuf[0] = '\0';
+ len = strlen(bitnamesbuf);
+ if (shunt != 0)
+ {
+ snprintf(bitnamesbuf + len, sizeof(bitnamesbuf) - len, "+%s"
+ , policy_shunt_names[shunt]);
+ len += strlen(bitnamesbuf + len);
+ }
+ if (fail != 0)
+ {
+ snprintf(bitnamesbuf + len, sizeof(bitnamesbuf) - len, "+failure%s"
+ , policy_fail_names[fail]);
+ len += strlen(bitnamesbuf + len);
+ }
+ if (NEVER_NEGOTIATE(policy))
+ {
+ snprintf(bitnamesbuf + len, sizeof(bitnamesbuf) - len, "+NEVER_NEGOTIATE");
+ len += strlen(bitnamesbuf + len);
+ }
+ return bitnamesbuf;
+}
+
+/* test a set by seeing if all bits have names */
+
+bool
+testset(const char *const table[], lset_t val)
+{
+ lset_t bit;
+ const char *const *tp;
+
+ for (tp = table, bit = 01; val != 0; bit <<= 1, tp++)
+ {
+ const char *n = *tp;
+
+ if (n == NULL || ((val & bit) && *n == '\0'))
+ return FALSE;
+ val &= ~bit;
+ }
+ return TRUE;
+}
+
+
+const char sparse_end[] = "end of sparse names";
+
+/* look up enum names in a sparse_names */
+const char *sparse_name(sparse_names sd, unsigned long val)
+{
+ const struct sparse_name *p;
+
+ for (p = sd; p->name != sparse_end; p++)
+ if (p->val == val)
+ return p->name;
+ return NULL;
+}
+
+/* find or construct a string to describe an sparse value
+ * Result may be in STATIC buffer!
+ */
+const char *
+sparse_val_show(sparse_names sd, unsigned long val)
+{
+ const char *p = sparse_name(sd, val);
+
+ if (p == NULL)
+ {
+ static char buf[12]; /* only one! I hope that it is big enough */
+
+ snprintf(buf, sizeof(buf), "%lu??", val);
+ p = buf;
+ }
+ return p;
+}
+
+void init_constants(void)
+{
+ happy(anyaddr(AF_INET, &ipv4_any));
+ happy(anyaddr(AF_INET6, &ipv6_any));
+
+ happy(addrtosubnet(&ipv4_any, &ipv4_wildcard));
+ happy(addrtosubnet(&ipv6_any, &ipv6_wildcard));
+
+ happy(initsubnet(&ipv4_any, 0, '0', &ipv4_all));
+ happy(initsubnet(&ipv6_any, 0, '0', &ipv6_all));
+}
diff --git a/src/pluto/constants.h b/src/pluto/constants.h
new file mode 100644
index 000000000..3ab10be61
--- /dev/null
+++ b/src/pluto/constants.h
@@ -0,0 +1,1269 @@
+
+/* manifest constants
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: constants.h,v 1.20 2006/02/28 19:13:33 as Exp $
+ */
+
+#ifndef _CONSTANTS_H
+#define _CONSTANTS_H
+
+extern const char compile_time_interop_options[];
+
+extern void init_constants(void);
+
+/*
+ * NOTE:For debugging purposes, constants.c has tables to map numbers back to names.
+ * Any changes here should be reflected there.
+ */
+
+#define elemsof(array) (sizeof(array) / sizeof(*(array))) /* number of elements in an array */
+
+/* Many routines return only success or failure, but wish to describe
+ * the failure in a message. We use the convention that they return
+ * a NULL on success and a pointer to constant string on failure.
+ * The fact that the string is a constant is limiting, but it
+ * avoids storage management issues: the recipient is allowed to assume
+ * that the string will live "long enough" (usually forever).
+ * <freeswan.h> defines err_t for this return type.
+ */
+
+typedef int bool;
+#define FALSE 0
+#define TRUE 1
+
+#define NULL_FD (-1) /* NULL file descriptor */
+#define dup_any(fd) ((fd) == NULL_FD? NULL_FD : dup(fd))
+#define close_any(fd) { if ((fd) != NULL_FD) { close(fd); (fd) = NULL_FD; } }
+
+#define BITS_PER_BYTE 8
+
+#define streq(a, b) (strcmp((a), (b)) == 0) /* clearer shorthand */
+#define strcaseeq(a, b) (strcasecmp((a), (b)) == 0) /* clearer shorthand */
+
+/* set type with room for at least 64 elements for ALG opts (was 32 in stock FS) */
+
+typedef unsigned long long lset_t;
+#define LEMPTY 0ULL
+#define LELEM(opt) (1ULL << (opt))
+#define LRANGE(lwb, upb) LRANGES(LELEM(lwb), LELEM(upb))
+#define LRANGES(first, last) (last - first + last)
+#define LHAS(set, elem) ((LELEM(elem) & (set)) != LEMPTY)
+#define LIN(subset, set) (((subset) & (set)) == (subset))
+#define LDISJOINT(a, b) (((a) & (b)) == LEMPTY)
+
+/* Control and lock pathnames */
+#ifndef IPSEC_PIDDIR
+# define IPSEC_PIDDIR "/var/run"
+#endif
+#ifndef DEFAULT_CTLBASE
+# define DEFAULT_CTLBASE IPSEC_PIDDIR "/pluto"
+#endif
+
+#define CTL_SUFFIX ".ctl" /* for UNIX domain socket pathname */
+#define LOCK_SUFFIX ".pid" /* for pluto's lock */
+#define INFO_SUFFIX ".info" /* for UNIX domain socket for apps */
+
+/* Routines to check and display values.
+ *
+ * An enum_names describes an enumeration.
+ * enum_name() returns the name of an enum value, or NULL if invalid.
+ * enum_show() is like enum_name, except it formats a numeric representation
+ * for any invalid value (in a static area!)
+ *
+ * bitnames() formats a display of a set of named bits (in a static area)
+ */
+
+struct enum_names {
+ unsigned long en_first; /* first value in range */
+ unsigned long en_last; /* last value in range (inclusive) */
+ const char *const *en_names;
+ const struct enum_names *en_next_range; /* descriptor of next range */
+};
+
+typedef const struct enum_names enum_names;
+
+extern const char *enum_name(enum_names *ed, unsigned long val);
+extern const char *enum_show(enum_names *ed, unsigned long val);
+extern int enum_search(enum_names *ed, const char *string);
+
+extern bool testset(const char *const table[], lset_t val);
+extern const char *bitnamesof(const char *const table[], lset_t val);
+
+/* sparse_names is much like enum_names, except values are
+ * not known to be contiguous or ordered.
+ * The array of names is ended with one with the name sparse_end
+ * (this avoids having to reserve a value to signify the end).
+ * Often appropriate for enums defined by others.
+ */
+struct sparse_name {
+ unsigned long val;
+ const char *const name;
+};
+typedef const struct sparse_name sparse_names[];
+
+extern const char *sparse_name(sparse_names sd, unsigned long val);
+extern const char *sparse_val_show(sparse_names sd, unsigned long val);
+extern const char sparse_end[];
+
+#define FULL_INET_ADDRESS_SIZE 6
+
+/* Group parameters from draft-ietf-ike-01.txt section 6 */
+
+#define MODP_GENERATOR "2"
+
+#define MODP768_MODULUS \
+ "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 " \
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD " \
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245 " \
+ "E485B576 625E7EC6 F44C42E9 A63A3620 FFFFFFFF FFFFFFFF"
+
+#define MODP1024_MODULUS \
+ "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 " \
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD " \
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245 " \
+ "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED " \
+ "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE65381 " \
+ "FFFFFFFF FFFFFFFF"
+
+#define MODP1536_MODULUS \
+ "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 " \
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD " \
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245 " \
+ "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED " \
+ "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D " \
+ "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F " \
+ "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D " \
+ "670C354E 4ABC9804 F1746C08 CA237327 FFFFFFFF FFFFFFFF "
+
+/* draft-ietf-ipsec-ike-modp-groups-03.txt */
+#define MODP2048_MODULUS \
+ "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \
+ "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \
+ "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" \
+ "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" \
+ "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \
+ "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" \
+ "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" \
+ "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" \
+ "15728E5A 8AACAA68 FFFFFFFF FFFFFFFF"
+
+#define MODP3072_MODULUS \
+ "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \
+ "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \
+ "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" \
+ "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" \
+ "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \
+ "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" \
+ "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" \
+ "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" \
+ "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" \
+ "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" \
+ "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" \
+ "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" \
+ "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" \
+ "43DB5BFC E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF"
+
+#define MODP4096_MODULUS \
+ "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \
+ "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \
+ "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" \
+ "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" \
+ "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \
+ "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" \
+ "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" \
+ "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" \
+ "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" \
+ "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" \
+ "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" \
+ "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" \
+ "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" \
+ "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" \
+ "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" \
+ "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" \
+ "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" \
+ "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" \
+ "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34063199" \
+ "FFFFFFFF FFFFFFFF"
+
+/* copy&pasted from rfc3526: */
+#define MODP6144_MODULUS \
+ "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 29024E08" \
+ "8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD EF9519B3 CD3A431B" \
+ "302B0A6D F25F1437 4FE1356D 6D51C245 E485B576 625E7EC6 F44C42E9" \
+ "A637ED6B 0BFF5CB6 F406B7ED EE386BFB 5A899FA5 AE9F2411 7C4B1FE6" \
+ "49286651 ECE45B3D C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8" \
+ "FD24CF5F 83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \
+ "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B E39E772C" \
+ "180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9 DE2BCBF6 95581718" \
+ "3995497C EA956AE5 15D22618 98FA0510 15728E5A 8AAAC42D AD33170D" \
+ "04507A33 A85521AB DF1CBA64 ECFB8504 58DBEF0A 8AEA7157 5D060C7D" \
+ "B3970F85 A6E1E4C7 ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226" \
+ "1AD2EE6B F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" \
+ "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31 43DB5BFC" \
+ "E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7 88719A10 BDBA5B26" \
+ "99C32718 6AF4E23C 1A946834 B6150BDA 2583E9CA 2AD44CE8 DBBBC2DB" \
+ "04DE8EF9 2E8EFC14 1FBECAA6 287C5947 4E6BC05D 99B2964F A090C3A2" \
+ "233BA186 515BE7ED 1F612970 CEE2D7AF B81BDD76 2170481C D0069127" \
+ "D5B05AA9 93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" \
+ "36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD F8FF9406" \
+ "AD9E530E E5DB382F 413001AE B06A53ED 9027D831 179727B0 865A8918" \
+ "DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B DB7F1447 E6CC254B 33205151" \
+ "2BD7AF42 6FB8F401 378CD2BF 5983CA01 C64B92EC F032EA15 D1721D03" \
+ "F482D7CE 6E74FEF6 D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F" \
+ "BEC7E8F3 23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" \
+ "CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328 06A1D58B" \
+ "B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C DA56C9EC 2EF29632" \
+ "387FE8D7 6E3C0468 043E8F66 3F4860EE 12BF2D5B 0B7474D6 E694F91E" \
+ "6DCC4024 FFFFFFFF FFFFFFFF"
+
+/* copy&pasted from rfc3526: */
+#define MODP8192_MODULUS \
+ "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \
+ "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \
+ "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" \
+ "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" \
+ "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \
+ "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" \
+ "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" \
+ "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" \
+ "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" \
+ "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" \
+ "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" \
+ "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" \
+ "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" \
+ "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" \
+ "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" \
+ "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" \
+ "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" \
+ "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" \
+ "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" \
+ "36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD" \
+ "F8FF9406 AD9E530E E5DB382F 413001AE B06A53ED 9027D831" \
+ "179727B0 865A8918 DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B" \
+ "DB7F1447 E6CC254B 33205151 2BD7AF42 6FB8F401 378CD2BF" \
+ "5983CA01 C64B92EC F032EA15 D1721D03 F482D7CE 6E74FEF6" \
+ "D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F BEC7E8F3" \
+ "23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" \
+ "CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328" \
+ "06A1D58B B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C" \
+ "DA56C9EC 2EF29632 387FE8D7 6E3C0468 043E8F66 3F4860EE" \
+ "12BF2D5B 0B7474D6 E694F91E 6DBE1159 74A3926F 12FEE5E4" \
+ "38777CB6 A932DF8C D8BEC4D0 73B931BA 3BC832B6 8D9DD300" \
+ "741FA7BF 8AFC47ED 2576F693 6BA42466 3AAB639C 5AE4F568" \
+ "3423B474 2BF1C978 238F16CB E39D652D E3FDB8BE FC848AD9" \
+ "22222E04 A4037C07 13EB57A8 1A23F0C7 3473FC64 6CEA306B" \
+ "4BCBC886 2F8385DD FA9D4B7F A2C087E8 79683303 ED5BDD3A" \
+ "062B3CF5 B3A278A6 6D2A13F8 3F44F82D DF310EE0 74AB6A36" \
+ "4597E899 A0255DC1 64F31CC5 0846851D F9AB4819 5DED7EA1" \
+ "B1D510BD 7EE74D73 FAF36BC3 1ECFA268 359046F4 EB879F92" \
+ "4009438B 481C6CD7 889A002E D5EE382B C9190DA6 FC026E47" \
+ "9558E447 5677E9AA 9E3050E2 765694DF C81F56E8 80B96E71" \
+ "60C980DD 98EDD3DF FFFFFFFF FFFFFFFF"
+#define LOCALSECRETSIZE (256 / BITS_PER_BYTE)
+
+/* limits on nonce sizes. See RFC2409 "The internet key exchange (IKE)" 5 */
+#define MINIMUM_NONCE_SIZE 8 /* bytes */
+#define DEFAULT_NONCE_SIZE 16 /* bytes */
+#define MAXIMUM_NONCE_SIZE 256 /* bytes */
+
+#define COOKIE_SIZE 8
+#define MAX_ISAKMP_SPI_SIZE 16
+
+#define MD2_DIGEST_SIZE (128 / BITS_PER_BYTE)
+#define MD5_DIGEST_SIZE (128 / BITS_PER_BYTE)
+#define SHA1_DIGEST_SIZE (160 / BITS_PER_BYTE)
+#define SHA2_256_DIGEST_SIZE (256 / BITS_PER_BYTE)
+#define SHA2_384_DIGEST_SIZE (384 / BITS_PER_BYTE)
+#define SHA2_512_DIGEST_SIZE (512 / BITS_PER_BYTE)
+
+#define MD5_BLOCK_SIZE (512 / BITS_PER_BYTE)
+#define SHA1_BLOCK_SIZE (512 / BITS_PER_BYTE)
+#define SHA2_256_BLOCK_SIZE (512 / BITS_PER_BYTE)
+#define SHA2_384_BLOCK_SIZE (1024 / BITS_PER_BYTE)
+#define SHA2_512_BLOCK_SIZE (1024 / BITS_PER_BYTE)
+
+#define DES_CBC_BLOCK_SIZE (64 / BITS_PER_BYTE)
+
+#define DSS_QBITS 160 /* bits in DSS's "q" (FIPS 186-1) */
+
+/* Maximum is required for SHA2_512 */
+#define MAX_DIGEST_LEN SHA2_512_DIGEST_SIZE
+#define MAX_HASH_BLOCK_SIZE SHA2_512_BLOCK_SIZE
+
+/* RFC 2404 "HMAC-SHA-1-96" section 3 */
+#define HMAC_SHA1_KEY_LEN SHA1_DIGEST_SIZE
+
+/* RFC 2403 "HMAC-MD5-96" section 3 */
+#define HMAC_MD5_KEY_LEN MD5_DIGEST_SIZE
+
+#define IKE_UDP_PORT 500
+
+/* RFC 2560 OCSP - certificate status */
+
+typedef enum {
+ CERT_GOOD = 0,
+ CERT_REVOKED = 1,
+ CERT_UNKNOWN = 2,
+ CERT_UNDEFINED = 3
+} cert_status_t;
+
+/* RFC 2459 CRL reason codes */
+
+extern enum_names crl_reason_names;
+
+typedef enum {
+ REASON_UNSPECIFIED = 0,
+ REASON_KEY_COMPROMISE = 1,
+ REASON_CA_COMPROMISE = 2,
+ REASON_AFFILIATION_CHANGED = 3,
+ REASON_SUPERSEDED = 4,
+ REASON_CESSATION_OF_OPERATON = 5,
+ REASON_CERTIFICATE_HOLD = 6,
+ REASON_REMOVE_FROM_CRL = 8
+} crl_reason_t;
+
+/* RFC 3706 Dead Peer Detection */
+
+extern enum_names dpd_action_names;
+
+typedef enum {
+ DPD_ACTION_NONE = 0,
+ DPD_ACTION_CLEAR = 1,
+ DPD_ACTION_HOLD = 2,
+ DPD_ACTION_RESTART = 3,
+ DPD_ACTION_UNKNOWN = 4
+} dpd_action_t;
+
+/* Timer events */
+
+extern enum_names timer_event_names;
+
+enum event_type {
+ EVENT_NULL, /* non-event */
+ EVENT_REINIT_SECRET, /* Refresh cookie secret */
+#ifdef KLIPS
+ EVENT_SHUNT_SCAN, /* scan shunt eroutes known to kernel */
+#endif
+ EVENT_SO_DISCARD, /* discard unfinished state object */
+ EVENT_RETRANSMIT, /* Retransmit packet */
+ EVENT_SA_REPLACE, /* SA replacement event */
+ EVENT_SA_REPLACE_IF_USED, /* SA replacement event */
+ EVENT_SA_EXPIRE, /* SA expiration event */
+ EVENT_NAT_T_KEEPALIVE, /* NAT Traversal Keepalive */
+ EVENT_DPD, /* dead peer detection */
+ EVENT_DPD_TIMEOUT, /* dead peer detection timeout */
+ EVENT_LOG_DAILY /* reset certain log events/stats */
+};
+
+#define EVENT_REINIT_SECRET_DELAY 3600 /* 1 hour */
+#define EVENT_RETRANSMIT_DELAY_0 10 /* 10 seconds */
+
+/* Misc. stuff */
+
+#define MAXIMUM_RETRANSMISSIONS 2
+#define MAXIMUM_RETRANSMISSIONS_INITIAL 20
+
+#define MAX_INPUT_UDP_SIZE 65536
+#define MAX_OUTPUT_UDP_SIZE 65536
+
+/* Version numbers */
+
+#define ISAKMP_MAJOR_VERSION 0x1
+#define ISAKMP_MINOR_VERSION 0x0
+
+extern enum_names version_names;
+
+/* Domain of Interpretation */
+
+extern enum_names doi_names;
+
+#define ISAKMP_DOI_ISAKMP 0
+#define ISAKMP_DOI_IPSEC 1
+
+/* IPsec DOI things */
+
+#define IPSEC_DOI_SITUATION_LENGTH 4
+#define IPSEC_DOI_LDI_LENGTH 4
+#define IPSEC_DOI_SPI_SIZE 4
+
+/* SPI value 0 is invalid and values 1-255 are reserved to IANA.
+ * ESP: RFC 2402 2.4; AH: RFC 2406 2.1
+ * IPComp RFC 2393 substitutes a CPI in the place of an SPI.
+ * see also draft-shacham-ippcp-rfc2393bis-05.txt.
+ * We (FreeS/WAN) reserve 0x100 to 0xFFF for manual keying, so
+ * Pluto won't generate these values.
+ */
+#define IPSEC_DOI_SPI_MIN 0x100
+#define IPSEC_DOI_SPI_OUR_MIN 0x1000
+
+/* debugging settings: a set of selections for reporting
+ * These would be more naturally situated in log.h,
+ * but they are shared with whack.
+ * IMPAIR_* actually change behaviour, usually badly,
+ * to aid in testing. Naturally, these are not included in ALL.
+ *
+ * NOTE: changes here must be done in concert with changes to DBGOPT_*
+ * in whack.c. A change to WHACK_MAGIC in whack.h will be required too.
+ */
+#ifdef DEBUG
+extern const char *const debug_bit_names[];
+#endif
+
+#define DBG_RAW LELEM(0) /* raw packet I/O */
+#define DBG_CRYPT LELEM(1) /* encryption/decryption of messages */
+#define DBG_PARSING LELEM(2) /* show decoding of messages */
+#define DBG_EMITTING LELEM(3) /* show encoding of messages */
+#define DBG_CONTROL LELEM(4) /* control flow within Pluto */
+#define DBG_LIFECYCLE LELEM(5) /* SA lifecycle */
+#define DBG_KLIPS LELEM(6) /* messages to KLIPS */
+#define DBG_DNS LELEM(7) /* DNS activity */
+#define DBG_NATT LELEM(8) /* NAT-T */
+#define DBG_OPPO LELEM(9) /* opportunism */
+#define DBG_CONTROLMORE LELEM(10) /* more detailed debugging */
+
+#define DBG_PRIVATE LELEM(11) /* private information: DANGER! */
+
+#define IMPAIR0 12 /* first bit for IMPAIR_* */
+
+#define IMPAIR_DELAY_ADNS_KEY_ANSWER LELEM(IMPAIR0+0) /* sleep before answering */
+#define IMPAIR_DELAY_ADNS_TXT_ANSWER LELEM(IMPAIR0+1) /* sleep before answering */
+#define IMPAIR_BUST_MI2 LELEM(IMPAIR0+2) /* make MI2 really large */
+#define IMPAIR_BUST_MR2 LELEM(IMPAIR0+3) /* make MI2 really large */
+
+#define DBG_NONE 0 /* no options on, including impairments */
+#define DBG_ALL LRANGES(DBG_RAW, DBG_CONTROLMORE) /* all logging options on EXCEPT DBG_PRIVATE */
+
+/* State of exchanges
+ *
+ * The name of the state describes the last message sent, not the
+ * message currently being input or output (except during retry).
+ * In effect, the state represents the last completed action.
+ *
+ * Messages are named [MQ][IR]n where
+ * - M stands for Main Mode (Phase 1);
+ * Q stands for Quick Mode (Phase 2)
+ * - I stands for Initiator;
+ * R stands for Responder
+ * - n, a digit, stands for the number of the message
+ *
+ * It would be more convenient if each state accepted a message
+ * and produced one. This is the case for states at the start
+ * or end of an exchange. To fix this, we pretend that there are
+ * MR0 and QR0 messages before the MI1 and QR1 messages. Similarly,
+ * we pretend that there are MR4 and QR2 messages.
+ *
+ * STATE_MAIN_R0 and STATE_QUICK_R0 are intermediate states (not
+ * retained between messages) representing the state that accepts the
+ * first message of an exchange has been read but not processed.
+ *
+ * state_microcode state_microcode_table in demux.c describes
+ * other important details.
+ */
+
+extern enum_names state_names;
+extern const char *const state_story[];
+
+enum state_kind {
+ STATE_UNDEFINED, /* 0 -- most likely accident */
+
+ /* Opportunism states: see "Opportunistic Encryption" 2.2 */
+
+ OPPO_ACQUIRE, /* got an ACQUIRE message for this pair */
+ OPPO_GW_DISCOVERED, /* got TXT specifying gateway */
+
+ /* IKE states */
+
+ STATE_MAIN_R0,
+ STATE_MAIN_I1,
+ STATE_MAIN_R1,
+ STATE_MAIN_I2,
+ STATE_MAIN_R2,
+ STATE_MAIN_I3,
+ STATE_MAIN_R3,
+ STATE_MAIN_I4,
+
+ STATE_QUICK_R0,
+ STATE_QUICK_I1,
+ STATE_QUICK_R1,
+ STATE_QUICK_I2,
+ STATE_QUICK_R2,
+
+ STATE_INFO,
+ STATE_INFO_PROTECTED,
+
+ /* XAUTH states */
+
+ STATE_XAUTH_I0, /* initiator state (client) */
+ STATE_XAUTH_R1, /* responder state (server) */
+ STATE_XAUTH_I1,
+ STATE_XAUTH_R2,
+ STATE_XAUTH_I2,
+ STATE_XAUTH_R3,
+
+ /* Mode Config pull states */
+
+ STATE_MODE_CFG_R0, /* responder state (server) */
+ STATE_MODE_CFG_I1, /* initiator state (client) */
+ STATE_MODE_CFG_R1,
+ STATE_MODE_CFG_I2,
+
+ /* Mode Config push states */
+
+ STATE_MODE_CFG_I0, /* initiator state (client) */
+ STATE_MODE_CFG_R3, /* responder state (server) */
+ STATE_MODE_CFG_I3,
+ STATE_MODE_CFG_R4,
+
+ STATE_IKE_ROOF
+};
+
+#define STATE_IKE_FLOOR STATE_MAIN_R0
+
+#define PHASE1_INITIATOR_STATES (LELEM(STATE_MAIN_I1) | LELEM(STATE_MAIN_I2) \
+ | LELEM(STATE_MAIN_I3) | LELEM(STATE_MAIN_I4))
+#define ISAKMP_SA_ESTABLISHED_STATES ( \
+ LELEM(STATE_MAIN_R3) | LELEM(STATE_MAIN_I4) \
+ | LELEM(STATE_XAUTH_R1) | LELEM(STATE_XAUTH_R2) | LELEM(STATE_XAUTH_R3) \
+ | LELEM(STATE_XAUTH_I1) | LELEM(STATE_XAUTH_I2) \
+ | LELEM(STATE_MODE_CFG_I1) | LELEM(STATE_MODE_CFG_R1) | LELEM(STATE_MODE_CFG_I2) \
+ | LELEM(STATE_MODE_CFG_R3) | LELEM(STATE_MODE_CFG_I3) | LELEM(STATE_MODE_CFG_R4))
+
+#define IS_PHASE1(s) ((STATE_MAIN_R0 <= (s) && (s) <= STATE_MAIN_I4) \
+ || (STATE_XAUTH_I0 <= (s) && (s) <= STATE_XAUTH_R3) \
+ || (STATE_MODE_CFG_R0 <= (s) && (s) <= STATE_MODE_CFG_R4))
+
+#define IS_QUICK(s) (STATE_QUICK_R0 <= (s) && (s) <= STATE_QUICK_R2)
+#define IS_ISAKMP_ENCRYPTED(s) (STATE_MAIN_I2 <= (s))
+
+#define IS_ISAKMP_SA_ESTABLISHED(s) ( \
+ (s) == STATE_MAIN_R3 \
+ || (s) == STATE_MAIN_I4 \
+ || (s) == STATE_XAUTH_I2 \
+ || (s) == STATE_XAUTH_R3 \
+ || (s) == STATE_MODE_CFG_R1 \
+ || (s) == STATE_MODE_CFG_I2 \
+ || (s) == STATE_MODE_CFG_I3 \
+ || (s) == STATE_MODE_CFG_R4)
+
+#define IS_IPSEC_SA_ESTABLISHED(s) ((s) == STATE_QUICK_I2 || (s) == STATE_QUICK_R2)
+#define IS_ONLY_INBOUND_IPSEC_SA_ESTABLISHED(s) ((s) == STATE_QUICK_R1)
+
+/* kind of struct connection
+ * Ordered (mostly) by concreteness. Order is exploited.
+ */
+
+extern enum_names connection_kind_names;
+
+enum connection_kind {
+ CK_GROUP, /* policy group: instantiates to template */
+ CK_TEMPLATE, /* abstract connection, with wildcard */
+ CK_PERMANENT, /* normal connection */
+ CK_INSTANCE, /* instance of template, created for a particular attempt */
+ CK_GOING_AWAY /* instance being deleted -- don't delete again */
+};
+
+
+/* routing status.
+ * Note: routing ignores source address, but erouting does not!
+ * Note: a connection can only be routed if it is NEVER_NEGOTIATE
+ * or HAS_IPSEC_POLICY.
+ */
+
+extern enum_names routing_story;
+
+/* note that this is assumed to be ordered! */
+enum routing_t {
+ RT_UNROUTED, /* unrouted */
+ RT_UNROUTED_HOLD, /* unrouted, but HOLD shunt installed */
+ RT_ROUTED_ECLIPSED, /* RT_ROUTED_PROSPECTIVE except bare HOLD or instance has eroute */
+ RT_ROUTED_PROSPECTIVE, /* routed, and prospective shunt installed */
+ RT_ROUTED_HOLD, /* routed, and HOLD shunt installed */
+ RT_ROUTED_FAILURE, /* routed, and failure-context shunt installed */
+ RT_ROUTED_TUNNEL, /* routed, and erouted to an IPSEC SA group */
+ RT_UNROUTED_KEYED /* keyed, but not routed, on purpose */
+};
+
+#define routed(rs) ((rs) > RT_UNROUTED_HOLD)
+#define erouted(rs) ((rs) != RT_UNROUTED)
+#define shunt_erouted(rs) (erouted(rs) && (rs) != RT_ROUTED_TUNNEL)
+
+/* Payload types
+ * RFC2408 Internet Security Association and Key Management Protocol (ISAKMP)
+ * section 3.1
+ *
+ * RESERVED 14-127
+ * Private USE 128-255
+ */
+
+extern enum_names payload_names;
+extern const char *const payload_name[];
+
+#define ISAKMP_NEXT_NONE 0 /* No other payload following */
+#define ISAKMP_NEXT_SA 1 /* Security Association */
+#define ISAKMP_NEXT_P 2 /* Proposal */
+#define ISAKMP_NEXT_T 3 /* Transform */
+#define ISAKMP_NEXT_KE 4 /* Key Exchange */
+#define ISAKMP_NEXT_ID 5 /* Identification */
+#define ISAKMP_NEXT_CERT 6 /* Certificate */
+#define ISAKMP_NEXT_CR 7 /* Certificate Request */
+#define ISAKMP_NEXT_HASH 8 /* Hash */
+#define ISAKMP_NEXT_SIG 9 /* Signature */
+#define ISAKMP_NEXT_NONCE 10 /* Nonce */
+#define ISAKMP_NEXT_N 11 /* Notification */
+#define ISAKMP_NEXT_D 12 /* Delete */
+#define ISAKMP_NEXT_VID 13 /* Vendor ID */
+#define ISAKMP_NEXT_ATTR 14 /* Mode config Attribute */
+
+#define ISAKMP_NEXT_NATD_RFC 20 /* NAT-Traversal: NAT-D (rfc) */
+#define ISAKMP_NEXT_NATOA_RFC 21 /* NAT-Traversal: NAT-OA (rfc) */
+#define ISAKMP_NEXT_ROOF 22 /* roof on payload types */
+
+#define ISAKMP_NEXT_NATD_DRAFTS 130 /* NAT-Traversal: NAT-D (drafts) */
+#define ISAKMP_NEXT_NATOA_DRAFTS 131 /* NAT-Traversal: NAT-OA (drafts) */
+
+/* These values are to be used within the Type field of an Attribute (14)
+ * ISAKMP payload.
+ */
+#define ISAKMP_CFG_REQUEST 1
+#define ISAKMP_CFG_REPLY 2
+#define ISAKMP_CFG_SET 3
+#define ISAKMP_CFG_ACK 4
+
+extern enum_names attr_msg_type_names;
+
+/* Mode Config attribute values */
+#define INTERNAL_IP4_ADDRESS 1
+#define INTERNAL_IP4_NETMASK 2
+#define INTERNAL_IP4_DNS 3
+#define INTERNAL_IP4_NBNS 4
+#define INTERNAL_ADDRESS_EXPIRY 5
+#define INTERNAL_IP4_DHCP 6
+#define APPLICATION_VERSION 7
+#define INTERNAL_IP6_ADDRESS 8
+#define INTERNAL_IP6_NETMASK 9
+#define INTERNAL_IP6_DNS 10
+#define INTERNAL_IP6_NBNS 11
+#define INTERNAL_IP6_DHCP 12
+#define INTERNAL_IP4_SUBNET 13
+#define SUPPORTED_ATTRIBUTES 14
+#define INTERNAL_IP6_SUBNET 15
+
+
+extern enum_names modecfg_attr_names;
+
+/* XAUTH attribute values */
+#define XAUTH_TYPE 16520
+#define XAUTH_USER_NAME 16521
+#define XAUTH_USER_PASSWORD 16522
+#define XAUTH_PASSCODE 16523
+#define XAUTH_MESSAGE 16524
+#define XAUTH_CHALLENGE 16525
+#define XAUTH_DOMAIN 16526
+#define XAUTH_STATUS 16527
+#define XAUTH_NEXT_PIN 16528
+#define XAUTH_ANSWER 16529
+
+#define XAUTH_BASE XAUTH_TYPE
+
+extern enum_names xauth_attr_names;
+
+/* ISAKMP mode config attributes specific to the Unity vendor Id */
+#define UNITY_BANNER 28672
+#define UNITY_SAVE_PASSWD 28673
+#define UNITY_DEF_DOMAIN 28674
+#define UNITY_SPLITDNS_NAME 28675
+#define UNITY_SPLIT_INCLUDE 28676
+#define UNITY_NATT_PORT 28677
+#define UNITY_LOCAL_LAN 28678
+#define UNITY_PFS 28679
+#define UNITY_FW_TYPE 28680
+#define UNITY_BACKUP_SERVERS 28681
+#define UNITY_DDNS_HOSTNAME 28682
+
+#define UNITY_BASE UNITY_BANNER
+
+extern enum_names unity_attr_names;
+
+/* XAUTH authentication types */
+#define XAUTH_TYPE_GENERIC 0
+#define XAUTH_TYPE_CHAP 1
+#define XAUTH_TYPE_OTP 2
+#define XAUTH_TYPE_SKEY 3
+
+/* Values for XAUTH_STATUS */
+#define XAUTH_STATUS_FAIL 0
+#define XAUTH_STATUS_OK 1
+
+extern enum_names xauth_type_names;
+
+/* Exchange types
+ * RFC2408 "Internet Security Association and Key Management Protocol (ISAKMP)"
+ * section 3.1
+ *
+ * ISAKMP Future Use 6 - 31
+ * DOI Specific Use 32 - 239
+ * Private Use 240 - 255
+ *
+ * Note: draft-ietf-ipsec-dhless-enc-mode-00.txt Appendix A
+ * defines "DHless RSA Encryption" as 6.
+ */
+
+extern enum_names exchange_names;
+
+#define ISAKMP_XCHG_NONE 0
+#define ISAKMP_XCHG_BASE 1
+#define ISAKMP_XCHG_IDPROT 2 /* ID Protection */
+#define ISAKMP_XCHG_AO 3 /* Authentication Only */
+#define ISAKMP_XCHG_AGGR 4 /* Aggressive */
+#define ISAKMP_XCHG_INFO 5 /* Informational */
+#define ISAKMP_XCHG_MODE_CFG 6 /* Mode Config */
+
+/* Extra exchange types, defined by Oakley
+ * RFC2409 "The Internet Key Exchange (IKE)", near end of Appendix A
+ */
+#define ISAKMP_XCHG_QUICK 32 /* Oakley Quick Mode */
+#define ISAKMP_XCHG_NGRP 33 /* Oakley New Group Mode */
+/* added in draft-ietf-ipsec-ike-01.txt, near end of Appendix A */
+#define ISAKMP_XCHG_ACK_INFO 34 /* Oakley Acknowledged Informational */
+
+/* Flag bits */
+
+extern const char *const flag_bit_names[];
+
+#define ISAKMP_FLAG_ENCRYPTION 0x1
+#define ISAKMP_FLAG_COMMIT 0x2
+
+/* Situation definition for IPsec DOI */
+
+extern const char *const sit_bit_names[];
+
+#define SIT_IDENTITY_ONLY 0x01
+#define SIT_SECRECY 0x02
+#define SIT_INTEGRITY 0x04
+
+/* Protocol IDs
+ * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.4.1
+ */
+
+extern enum_names protocol_names;
+
+#define PROTO_ISAKMP 1
+#define PROTO_IPSEC_AH 2
+#define PROTO_IPSEC_ESP 3
+#define PROTO_IPCOMP 4
+
+/* warning: trans_show uses enum_show, so same static buffer is used */
+#define trans_show(p, t) \
+ ((p)==PROTO_IPSEC_AH ? enum_show(&ah_transformid_names, (t)) \
+ : (p)==PROTO_IPSEC_ESP ? enum_show(&esp_transformid_names, (t)) \
+ : (p)==PROTO_IPCOMP ? enum_show(&ipcomp_transformid_names, (t)) \
+ : "??")
+
+/* many transform values are moved to freeswan/ipsec_policy.h */
+
+extern enum_names isakmp_transformid_names;
+
+#define KEY_IKE 1
+
+extern enum_names ah_transformid_names;
+extern enum_names esp_transformid_names;
+extern enum_names ipcomp_transformid_names;
+
+/* the following are from RFC 2393/draft-shacham-ippcp-rfc2393bis-05.txt 3.3 */
+typedef u_int16_t cpi_t;
+#define IPCOMP_CPI_SIZE 2
+#define IPCOMP_FIRST_NEGOTIATED 256
+#define IPCOMP_LAST_NEGOTIATED 61439
+
+/* Identification type values
+ * RFC 2407 The Internet IP security Domain of Interpretation for ISAKMP 4.6.2.1
+ */
+
+extern enum_names ident_names;
+extern enum_names cert_type_names;
+extern enum_names cert_policy_names;
+
+typedef enum certpolicy {
+ CERT_ALWAYS_SEND = 0, /* the default */
+ CERT_SEND_IF_ASKED = 1,
+ CERT_NEVER_SEND = 2,
+
+ CERT_YES_SEND = 3, /* synonym for CERT_ALWAYS_SEND */
+ CERT_NO_SEND = 4 /* synonym for CERT_NEVER_SEND */
+} certpolicy_t;
+
+/* Policies for establishing an SA
+ *
+ * These are used to specify attributes (eg. encryption) and techniques
+ * (eg PFS) for an SA.
+ * Note: certain CD_ definitions in whack.c parallel these -- keep them
+ * in sync!
+ */
+
+extern const char *const sa_policy_bit_names[];
+extern const char *prettypolicy(lset_t policy);
+
+/* ISAKMP auth techniques (none means never negotiate) */
+#define POLICY_PSK LELEM(0)
+#define POLICY_RSASIG LELEM(1)
+
+#define POLICY_ISAKMP_SHIFT 0 /* log2(POLICY_PSK) */
+#define POLICY_ID_AUTH_MASK (POLICY_PSK | POLICY_RSASIG | POLICY_XAUTH_PSK | POLICY_XAUTH_RSASIG)
+#define POLICY_ISAKMP_MASK POLICY_ID_AUTH_MASK /* all so far */
+
+/* Quick Mode (IPSEC) attributes */
+#define POLICY_ENCRYPT LELEM(2) /* must be first of IPSEC policies */
+#define POLICY_AUTHENTICATE LELEM(3) /* must be second */
+#define POLICY_COMPRESS LELEM(4) /* must be third */
+#define POLICY_TUNNEL LELEM(5)
+#define POLICY_PFS LELEM(6)
+#define POLICY_DISABLEARRIVALCHECK LELEM(7) /* supress tunnel egress address checking */
+
+#define POLICY_IPSEC_SHIFT 2 /* log2(POLICY_ENCRYPT) */
+#define POLICY_IPSEC_MASK LRANGES(POLICY_ENCRYPT, POLICY_DISABLEARRIVALCHECK)
+
+/* shunt attributes: what to do when routed without tunnel (2 bits) */
+#define POLICY_SHUNT_SHIFT 8 /* log2(POLICY_SHUNT_PASS) */
+#define POLICY_SHUNT_MASK (03ul << POLICY_SHUNT_SHIFT)
+
+#define POLICY_SHUNT_TRAP (0ul << POLICY_SHUNT_SHIFT) /* default: negotiate */
+#define POLICY_SHUNT_PASS (1ul << POLICY_SHUNT_SHIFT)
+#define POLICY_SHUNT_DROP (2ul << POLICY_SHUNT_SHIFT)
+#define POLICY_SHUNT_REJECT (3ul << POLICY_SHUNT_SHIFT)
+
+/* fail attributes: what to do with failed negotiation (2 bits) */
+
+#define POLICY_FAIL_SHIFT 10 /* log2(POLICY_FAIL_PASS) */
+#define POLICY_FAIL_MASK (03ul << POLICY_FAIL_SHIFT)
+
+#define POLICY_FAIL_NONE (0ul << POLICY_FAIL_SHIFT) /* default */
+#define POLICY_FAIL_PASS (1ul << POLICY_FAIL_SHIFT)
+#define POLICY_FAIL_DROP (2ul << POLICY_FAIL_SHIFT)
+#define POLICY_FAIL_REJECT (3ul << POLICY_FAIL_SHIFT)
+
+/* connection policy
+ * Other policies could vary per state object. These live in connection.
+ */
+#define POLICY_DONT_REKEY LELEM(12) /* don't rekey state either Phase */
+#define POLICY_OPPO LELEM(13) /* is this opportunistic? */
+#define POLICY_GROUP LELEM(14) /* is this a group template? */
+#define POLICY_GROUTED LELEM(15) /* do we want this group routed? */
+#define POLICY_UP LELEM(16) /* do we want this up? */
+#define POLICY_MODECFG_PUSH LELEM(17) /* is modecfg pushed by server? */
+#define POLICY_XAUTH_PSK LELEM(18) /* do we support XAUTH????PreShared? */
+#define POLICY_XAUTH_RSASIG LELEM(19) /* do we support XAUTH????RSA? */
+#define POLICY_XAUTH_SERVER LELEM(20) /* are we an XAUTH server? */
+#define POLICY_DONT_REAUTH LELEM(21) /* don't reauthenticate on rekeying, IKEv2 only */
+#define POLICY_BEET LELEM(22) /* bound end2end tunnel, IKEv2 */
+
+/* Any IPsec policy? If not, a connection description
+ * is only for ISAKMP SA, not IPSEC SA. (A pun, I admit.)
+ * Note: a connection can only be routed if it is NEVER_NEGOTIATE
+ * or HAS_IPSEC_POLICY.
+ */
+#define HAS_IPSEC_POLICY(p) (((p) & POLICY_IPSEC_MASK) != 0)
+
+/* Don't allow negotiation? */
+#define NEVER_NEGOTIATE(p) (LDISJOINT((p), POLICY_ID_AUTH_MASK))
+
+
+/* Oakley transform attributes
+ * draft-ietf-ipsec-ike-01.txt appendix A
+ */
+
+extern enum_names oakley_attr_names;
+extern const char *const oakley_attr_bit_names[];
+
+#define OAKLEY_ENCRYPTION_ALGORITHM 1
+#define OAKLEY_HASH_ALGORITHM 2
+#define OAKLEY_AUTHENTICATION_METHOD 3
+#define OAKLEY_GROUP_DESCRIPTION 4
+#define OAKLEY_GROUP_TYPE 5
+#define OAKLEY_GROUP_PRIME 6 /* B/V */
+#define OAKLEY_GROUP_GENERATOR_ONE 7 /* B/V */
+#define OAKLEY_GROUP_GENERATOR_TWO 8 /* B/V */
+#define OAKLEY_GROUP_CURVE_A 9 /* B/V */
+#define OAKLEY_GROUP_CURVE_B 10 /* B/V */
+#define OAKLEY_LIFE_TYPE 11
+#define OAKLEY_LIFE_DURATION 12 /* B/V */
+#define OAKLEY_PRF 13
+#define OAKLEY_KEY_LENGTH 14
+#define OAKLEY_FIELD_SIZE 15
+#define OAKLEY_GROUP_ORDER 16 /* B/V */
+#define OAKLEY_BLOCK_SIZE 17
+
+/* for each Oakley attribute, which enum_names describes its values? */
+extern enum_names *oakley_attr_val_descs[];
+
+/* IPsec DOI attributes
+ * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.5
+ */
+
+extern enum_names ipsec_attr_names;
+
+#define SA_LIFE_TYPE 1
+#define SA_LIFE_DURATION 2 /* B/V */
+#define GROUP_DESCRIPTION 3
+#define ENCAPSULATION_MODE 4
+#define AUTH_ALGORITHM 5
+#define KEY_LENGTH 6
+#define KEY_ROUNDS 7
+#define COMPRESS_DICT_SIZE 8
+#define COMPRESS_PRIVATE_ALG 9 /* B/V */
+
+/* for each IPsec attribute, which enum_names describes its values? */
+extern enum_names *ipsec_attr_val_descs[];
+
+/* SA Lifetime Type attribute
+ * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.5
+ * Default time specified in 4.5
+ *
+ * There are two defaults for IPSEC SA lifetime, SA_LIFE_DURATION_DEFAULT,
+ * and PLUTO_SA_LIFE_DURATION_DEFAULT.
+ * SA_LIFE_DURATION_DEFAULT is specified in RFC2407 "The Internet IP
+ * Security Domain of Interpretation for ISAKMP" 4.5. It applies when
+ * an ISAKMP negotiation does not explicitly specify a life duration.
+ * PLUTO_SA_LIFE_DURATION_DEFAULT is specified in pluto(8). It applies
+ * when a connection description does not specify --ipseclifetime.
+ * The value of SA_LIFE_DURATION_MAXIMUM is our local policy.
+ */
+
+extern enum_names sa_lifetime_names;
+
+#define SA_LIFE_TYPE_SECONDS 1
+#define SA_LIFE_TYPE_KBYTES 2
+
+#define SA_LIFE_DURATION_DEFAULT 28800 /* eight hours (RFC2407 4.5) */
+#define PLUTO_SA_LIFE_DURATION_DEFAULT 3600 /* one hour (pluto(8)) */
+#define SA_LIFE_DURATION_MAXIMUM 86400 /* one day */
+
+#define SA_REPLACEMENT_MARGIN_DEFAULT 540 /* (IPSEC & IKE) nine minutes */
+#define SA_REPLACEMENT_FUZZ_DEFAULT 100 /* (IPSEC & IKE) 100% of MARGIN */
+#define SA_REPLACEMENT_RETRIES_DEFAULT 3 /* (IPSEC & IKE) */
+
+#define SA_LIFE_DURATION_K_DEFAULT 0xFFFFFFFFlu
+
+/* Encapsulation Mode attribute */
+
+extern enum_names enc_mode_names;
+
+#define ENCAPSULATION_MODE_UNSPECIFIED 0 /* not legal -- used internally */
+#define ENCAPSULATION_MODE_TUNNEL 1
+#define ENCAPSULATION_MODE_TRANSPORT 2
+
+#define ENCAPSULATION_MODE_UDP_TUNNEL_RFC 3
+#define ENCAPSULATION_MODE_UDP_TRANSPORT_RFC 4
+
+#define ENCAPSULATION_MODE_UDP_TUNNEL_DRAFTS 61443
+#define ENCAPSULATION_MODE_UDP_TRANSPORT_DRAFTS 61444
+
+/* Auth Algorithm attribute */
+
+extern enum_names auth_alg_names, extended_auth_alg_names;
+
+#define AUTH_ALGORITHM_NONE 0 /* our private designation */
+#define AUTH_ALGORITHM_HMAC_MD5 1
+#define AUTH_ALGORITHM_HMAC_SHA1 2
+#define AUTH_ALGORITHM_DES_MAC 3
+#define AUTH_ALGORITHM_KPDK 4
+#define AUTH_ALGORITHM_HMAC_SHA2_256 5
+#define AUTH_ALGORITHM_HMAC_SHA2_384 6
+#define AUTH_ALGORITHM_HMAC_SHA2_512 7
+#define AUTH_ALGORITHM_HMAC_RIPEMD 8
+#define AUTH_ALGORITHM_NULL 251
+
+/* Oakley Lifetime Type attribute
+ * draft-ietf-ipsec-ike-01.txt appendix A
+ * As far as I can see, there is not specification for
+ * OAKLEY_ISAKMP_SA_LIFETIME_DEFAULT. This could lead to interop problems!
+ * For no particular reason, we chose three hours.
+ * The value of OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM is our local policy.
+ */
+extern enum_names oakley_lifetime_names;
+
+#define OAKLEY_LIFE_SECONDS 1
+#define OAKLEY_LIFE_KILOBYTES 2
+
+#define OAKLEY_ISAKMP_SA_LIFETIME_DEFAULT 10800 /* three hours */
+#define OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM 86400 /* one day */
+
+/* Oakley PRF attribute (none defined)
+ * draft-ietf-ipsec-ike-01.txt appendix A
+ */
+extern enum_names oakley_prf_names;
+
+/* HMAC (see rfc2104.txt) */
+
+#define HMAC_IPAD 0x36
+#define HMAC_OPAD 0x5C
+
+/* Oakley Encryption Algorithm attribute
+ * draft-ietf-ipsec-ike-01.txt appendix A
+ * and from http://www.isi.edu/in-notes/iana/assignments/ipsec-registry
+ */
+
+extern enum_names oakley_enc_names;
+
+#define OAKLEY_DES_CBC 1
+#define OAKLEY_IDEA_CBC 2
+#define OAKLEY_BLOWFISH_CBC 3
+#define OAKLEY_RC5_R16_B64_CBC 4
+#define OAKLEY_3DES_CBC 5
+#define OAKLEY_CAST_CBC 6
+#define OAKLEY_AES_CBC 7
+
+#define OAKLEY_MARS_CBC 65001
+#define OAKLEY_RC6_CBC 65002
+#define OAKLEY_ID_65003 65003
+#define OAKLEY_SERPENT_CBC 65004
+#define OAKLEY_TWOFISH_CBC 65005
+
+#define OAKLEY_TWOFISH_CBC_SSH 65289
+
+#define OAKLEY_ENCRYPT_MAX 65535 /* pretty useless :) */
+
+/* Oakley Hash Algorithm attribute
+ * draft-ietf-ipsec-ike-01.txt appendix A
+ * and from http://www.isi.edu/in-notes/iana/assignments/ipsec-registry
+ */
+
+extern enum_names oakley_hash_names;
+
+#define OAKLEY_MD5 1
+#define OAKLEY_SHA 2
+#define OAKLEY_TIGER 3
+#define OAKLEY_SHA2_256 4
+#define OAKLEY_SHA2_384 5
+#define OAKLEY_SHA2_512 6
+
+#define OAKLEY_HASH_MAX 7
+
+/* Oakley Authentication Method attribute
+ * draft-ietf-ipsec-ike-01.txt appendix A
+ * Goofy Hybrid extensions from draft-ietf-ipsec-isakmp-hybrid-auth-05.txt
+ * Goofy XAUTH extensions from draft-ietf-ipsec-isakmp-xauth-06.txt
+ */
+
+extern enum_names oakley_auth_names;
+
+#define OAKLEY_PRESHARED_KEY 1
+#define OAKLEY_DSS_SIG 2
+#define OAKLEY_RSA_SIG 3
+#define OAKLEY_RSA_ENC 4
+#define OAKLEY_RSA_ENC_REV 5
+#define OAKLEY_ELGAMAL_ENC 6
+#define OAKLEY_ELGAMAL_ENC_REV 7
+
+#define OAKLEY_AUTH_ROOF 8 /* roof on auth values THAT WE SUPPORT */
+
+#define HybridInitRSA 64221
+#define HybridRespRSA 64222
+#define HybridInitDSS 64223
+#define HybridRespDSS 64224
+
+#define XAUTHInitPreShared 65001
+#define XAUTHRespPreShared 65002
+#define XAUTHInitDSS 65003
+#define XAUTHRespDSS 65004
+#define XAUTHInitRSA 65005
+#define XAUTHRespRSA 65006
+#define XAUTHInitRSAEncryption 65007
+#define XAUTHRespRSAEncryption 65008
+#define XAUTHInitRSARevisedEncryption 65009
+#define XAUTHRespRSARevisedEncryption 65010
+
+/* Oakley Group Description attribute
+ * draft-ietf-ipsec-ike-01.txt appendix A
+ */
+extern enum_names oakley_group_names;
+
+#define OAKLEY_GROUP_MODP768 1
+#define OAKLEY_GROUP_MODP1024 2
+#define OAKLEY_GROUP_GP155 3
+#define OAKLEY_GROUP_GP185 4
+#define OAKLEY_GROUP_MODP1536 5
+
+#define OAKLEY_GROUP_MODP2048 14
+#define OAKLEY_GROUP_MODP3072 15
+#define OAKLEY_GROUP_MODP4096 16
+#define OAKLEY_GROUP_MODP6144 17
+#define OAKLEY_GROUP_MODP8192 18
+/* you must also touch: constants.c, crypto.c */
+
+/* Oakley Group Type attribute
+ * draft-ietf-ipsec-ike-01.txt appendix A
+ */
+extern enum_names oakley_group_type_names;
+
+#define OAKLEY_GROUP_TYPE_MODP 1
+#define OAKLEY_GROUP_TYPE_ECP 2
+#define OAKLEY_GROUP_TYPE_EC2N 3
+
+
+/* Notify messages -- error types
+ * See RFC2408 ISAKMP 3.14.1
+ */
+
+extern enum_names notification_names;
+extern enum_names ipsec_notification_names;
+
+typedef enum {
+ NOTHING_WRONG = 0, /* unofficial! */
+
+ INVALID_PAYLOAD_TYPE = 1,
+ DOI_NOT_SUPPORTED = 2,
+ SITUATION_NOT_SUPPORTED = 3,
+ INVALID_COOKIE = 4,
+ INVALID_MAJOR_VERSION = 5,
+ INVALID_MINOR_VERSION = 6,
+ INVALID_EXCHANGE_TYPE = 7,
+ INVALID_FLAGS = 8,
+ INVALID_MESSAGE_ID = 9,
+ INVALID_PROTOCOL_ID = 10,
+ INVALID_SPI = 11,
+ INVALID_TRANSFORM_ID = 12,
+ ATTRIBUTES_NOT_SUPPORTED = 13,
+ NO_PROPOSAL_CHOSEN = 14,
+ BAD_PROPOSAL_SYNTAX = 15,
+ PAYLOAD_MALFORMED = 16,
+ INVALID_KEY_INFORMATION = 17,
+ INVALID_ID_INFORMATION = 18,
+ INVALID_CERT_ENCODING = 19,
+ INVALID_CERTIFICATE = 20,
+ CERT_TYPE_UNSUPPORTED = 21,
+ INVALID_CERT_AUTHORITY = 22,
+ INVALID_HASH_INFORMATION = 23,
+ AUTHENTICATION_FAILED = 24,
+ INVALID_SIGNATURE = 25,
+ ADDRESS_NOTIFICATION = 26,
+ NOTIFY_SA_LIFETIME = 27,
+ CERTIFICATE_UNAVAILABLE = 28,
+ UNSUPPORTED_EXCHANGE_TYPE = 29,
+ UNEQUAL_PAYLOAD_LENGTHS = 30,
+
+ /* ISAKMP status type */
+ CONNECTED = 16384,
+
+ /* IPSEC DOI additions; status types (RFC2407 IPSEC DOI 4.6.3)
+ * These must be sent under the protection of an ISAKMP SA.
+ */
+ IPSEC_RESPONDER_LIFETIME = 24576,
+ IPSEC_REPLAY_STATUS = 24577,
+ IPSEC_INITIAL_CONTACT = 24578,
+
+ /* RFC 3706 DPD */
+ R_U_THERE = 36136,
+ R_U_THERE_ACK = 36137
+
+ } notification_t;
+
+
+/* Public key algorithm number
+ * Same numbering as used in DNSsec
+ * See RFC 2535 DNSsec 3.2 The KEY Algorithm Number Specification.
+ * Also found in BIND 8.2.2 include/isc/dst.h as DST algorithm codes.
+ */
+
+enum pubkey_alg
+{
+ PUBKEY_ALG_RSA = 1,
+ PUBKEY_ALG_DSA = 3,
+};
+
+/* Limits on size of RSA moduli.
+ * The upper bound matches that of DNSsec (see RFC 2537).
+ * The lower bound must be more than 11 octets for certain
+ * the encoding to work, but it must be much larger for any
+ * real security. For now, we require 512 bits.
+ */
+
+#define RSA_MIN_OCTETS_RFC 12
+
+#define RSA_MIN_OCTETS (512 / BITS_PER_BYTE)
+#define RSA_MIN_OCTETS_UGH "RSA modulus too small for security: less than 512 bits"
+
+#define RSA_MAX_OCTETS (8192 / BITS_PER_BYTE)
+#define RSA_MAX_OCTETS_UGH "RSA modulus too large: more than 8192 bits"
+
+/* Note: RFC 2537 encoding adds a few bytes. If you use a small
+ * modulus like 3, the overhead is only 2 bytes
+ */
+#define RSA_MAX_ENCODING_BYTES (RSA_MAX_OCTETS + 2)
+
+/* socket address family info */
+
+struct af_info
+{
+ int af;
+ const char *name;
+ size_t ia_sz;
+ size_t sa_sz;
+ int mask_cnt;
+ u_int8_t id_addr, id_subnet, id_range;
+ const ip_address *any;
+ const ip_subnet *none; /* 0.0.0.0/32 or IPv6 equivalent */
+ const ip_subnet *all; /* 0.0.0.0/0 or IPv6 equivalent */
+};
+
+extern const struct af_info
+ af_inet4_info,
+ af_inet6_info;
+
+extern const struct af_info *aftoinfo(int af);
+
+extern enum_names af_names;
+
+#define subnetisaddr(sn, a) (subnetishost(sn) && addrinsubnet((a), (sn)))
+extern bool subnetisnone(const ip_subnet *sn);
+
+/* BIND enumerated types */
+
+extern enum_names
+ rr_qtype_names,
+ rr_type_names,
+ rr_class_names;
+
+/* How authenticated is info that might have come from DNS?
+ * In order of increasing confidence.
+ */
+enum dns_auth_level {
+ DAL_UNSIGNED, /* AD in response, but no signature: no authentication */
+ DAL_NOTSEC, /* no AD in response: authentication impossible */
+ DAL_SIGNED, /* AD and signature in response: authentic */
+ DAL_LOCAL /* locally provided (pretty good) */
+};
+
+/*
+ * define a macro for use in error messages
+ */
+
+#ifdef USE_KEYRR
+#define RRNAME "TXT or KEY"
+#else
+#define RRNAME "TXT"
+#endif
+
+/* natt traversal types */
+extern const char *const natt_type_bitnames[];
+
+#endif /* _CONSTANTS_H */
diff --git a/src/pluto/cookie.c b/src/pluto/cookie.c
new file mode 100644
index 000000000..458120e46
--- /dev/null
+++ b/src/pluto/cookie.c
@@ -0,0 +1,67 @@
+/* cookie generation/verification routines.
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: cookie.c,v 1.2 2005/08/17 16:38:20 as Exp $
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "sha1.h"
+#include "rnd.h"
+#include "cookie.h"
+
+const u_char zero_cookie[COOKIE_SIZE]; /* guaranteed 0 */
+
+/* Generate a cookie.
+ * First argument is true if we're to create an Initiator cookie.
+ * Length SHOULD be a multiple of sizeof(u_int32_t).
+ */
+void
+get_cookie(bool initiator, u_int8_t *cookie, int length, const ip_address *addr)
+{
+ u_char buffer[SHA1_DIGEST_SIZE];
+ SHA1_CTX ctx;
+
+ do {
+ if (initiator)
+ {
+ get_rnd_bytes(cookie, length);
+ }
+ else /* Responder cookie */
+ {
+ /* This looks as good as any way */
+ size_t addr_length;
+ static u_int32_t counter = 0;
+ unsigned char addr_buff[
+ sizeof(union {struct in_addr A; struct in6_addr B;})];
+
+ addr_length = addrbytesof(addr, addr_buff, sizeof(addr_buff));
+ SHA1Init(&ctx);
+ SHA1Update(&ctx, addr_buff, addr_length);
+ SHA1Update(&ctx, secret_of_the_day, sizeof(secret_of_the_day));
+ counter++;
+ SHA1Update(&ctx, (const void *) &counter, sizeof(counter));
+ SHA1Final(buffer, &ctx);
+ memcpy(cookie, buffer, length);
+ }
+ } while (is_zero_cookie(cookie)); /* probably never loops */
+}
diff --git a/src/pluto/cookie.h b/src/pluto/cookie.h
new file mode 100644
index 000000000..f5b0e64d1
--- /dev/null
+++ b/src/pluto/cookie.h
@@ -0,0 +1,24 @@
+/* cookie generation/verification routines.
+ * Copyright (C) 1998-2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: cookie.h,v 1.1 2004/03/15 20:35:28 as Exp $
+ */
+
+#include <freeswan.h>
+
+extern const u_char zero_cookie[COOKIE_SIZE]; /* guaranteed 0 */
+
+extern void get_cookie(bool initiator, u_int8_t *cookie, int length
+ , const ip_address *addr);
+
+#define is_zero_cookie(cookie) all_zero((cookie), COOKIE_SIZE)
diff --git a/src/pluto/crl.c b/src/pluto/crl.c
new file mode 100644
index 000000000..05e8d1402
--- /dev/null
+++ b/src/pluto/crl.c
@@ -0,0 +1,763 @@
+/* Support of X.509 certificate revocation lists (CRLs)
+ * Copyright (C) 2000-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.
+ *
+ * RCSID $Id: crl.c,v 1.12 2005/12/06 22:49:57 as Exp $
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <time.h>
+#include <sys/types.h>
+
+#include <freeswan.h>
+#include <ipsec_policy.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "asn1.h"
+#include "oid.h"
+#include "x509.h"
+#include "crl.h"
+#include "ca.h"
+#include "certs.h"
+#include "keys.h"
+#include "whack.h"
+#include "fetch.h"
+#include "sha1.h"
+
+/* chained lists of X.509 crls */
+
+static x509crl_t *x509crls = NULL;
+
+/* ASN.1 definition of an X.509 certificate list */
+
+static const asn1Object_t crlObjects[] = {
+ { 0, "certificateList", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
+ { 1, "tbsCertList", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
+ { 2, "version", ASN1_INTEGER, ASN1_OPT |
+ ASN1_BODY }, /* 2 */
+ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 3 */
+ { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 4 */
+ { 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */
+ { 2, "thisUpdate", ASN1_EOC, ASN1_RAW }, /* 6 */
+ { 2, "nextUpdate", ASN1_EOC, ASN1_RAW }, /* 7 */
+ { 2, "revokedCertificates", ASN1_SEQUENCE, ASN1_OPT |
+ ASN1_LOOP }, /* 8 */
+ { 3, "certList", ASN1_SEQUENCE, ASN1_NONE }, /* 9 */
+ { 4, "userCertificate", ASN1_INTEGER, ASN1_BODY }, /* 10 */
+ { 4, "revocationDate", ASN1_EOC, ASN1_RAW }, /* 11 */
+ { 4, "crlEntryExtensions", ASN1_SEQUENCE, ASN1_OPT |
+ ASN1_LOOP }, /* 12 */
+ { 5, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */
+ { 6, "extnID", ASN1_OID, ASN1_BODY }, /* 14 */
+ { 6, "critical", ASN1_BOOLEAN, ASN1_DEF |
+ ASN1_BODY }, /* 15 */
+ { 6, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 16 */
+ { 4, "end opt or loop", ASN1_EOC, ASN1_END }, /* 17 */
+ { 2, "end opt or loop", ASN1_EOC, ASN1_END }, /* 18 */
+ { 2, "optional extensions", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 19 */
+ { 3, "crlExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 20 */
+ { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 21 */
+ { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 22 */
+ { 5, "critical", ASN1_BOOLEAN, ASN1_DEF |
+ ASN1_BODY }, /* 23 */
+ { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 24 */
+ { 3, "end loop", ASN1_EOC, ASN1_END }, /* 25 */
+ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 26 */
+ { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 27 */
+ { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY } /* 28 */
+ };
+
+#define CRL_OBJ_CERTIFICATE_LIST 0
+#define CRL_OBJ_TBS_CERT_LIST 1
+#define CRL_OBJ_VERSION 2
+#define CRL_OBJ_SIG_ALG 4
+#define CRL_OBJ_ISSUER 5
+#define CRL_OBJ_THIS_UPDATE 6
+#define CRL_OBJ_NEXT_UPDATE 7
+#define CRL_OBJ_USER_CERTIFICATE 10
+#define CRL_OBJ_REVOCATION_DATE 11
+#define CRL_OBJ_CRL_ENTRY_EXTN_ID 14
+#define CRL_OBJ_CRL_ENTRY_CRITICAL 15
+#define CRL_OBJ_CRL_ENTRY_EXTN_VALUE 16
+#define CRL_OBJ_EXTN_ID 22
+#define CRL_OBJ_CRITICAL 23
+#define CRL_OBJ_EXTN_VALUE 24
+#define CRL_OBJ_ALGORITHM 27
+#define CRL_OBJ_SIGNATURE 28
+#define CRL_OBJ_ROOF 29
+
+
+const x509crl_t empty_x509crl = {
+ NULL , /* *next */
+ UNDEFINED_TIME, /* installed */
+ NULL , /* distributionPoints */
+ { NULL, 0 } , /* certificateList */
+ { NULL, 0 } , /* tbsCertList */
+ 1 , /* version */
+ OID_UNKNOWN , /* sigAlg */
+ { NULL, 0 } , /* issuer */
+ UNDEFINED_TIME, /* thisUpdate */
+ UNDEFINED_TIME, /* nextUpdate */
+ NULL , /* revokedCertificates */
+ /* crlExtensions */
+ /* extension */
+ /* extnID */
+ /* critical */
+ /* extnValue */
+ { NULL, 0 } , /* authKeyID */
+ { NULL, 0 } , /* authKeySerialNumber */
+ OID_UNKNOWN , /* algorithm */
+ { NULL, 0 } /* signature */
+};
+
+/*
+ * get the X.509 CRL with a given issuer
+ */
+static x509crl_t*
+get_x509crl(chunk_t issuer, chunk_t serial, chunk_t keyid)
+{
+ x509crl_t *crl = x509crls;
+ x509crl_t *prev_crl = NULL;
+
+ while (crl != NULL)
+ {
+ if ((keyid.ptr != NULL && crl->authKeyID.ptr != NULL)
+ ? same_keyid(keyid, crl->authKeyID)
+ : (same_dn(crl->issuer, issuer) && same_serial(serial, crl->authKeySerialNumber)))
+ {
+ if (crl != x509crls)
+ {
+ /* bring the CRL up front */
+ prev_crl->next = crl->next;
+ crl->next = x509crls;
+ x509crls = crl;
+ }
+ return crl;
+ }
+ prev_crl = crl;
+ crl = crl->next;
+ }
+ return NULL;
+}
+
+/*
+ * free the dynamic memory used to store revoked certificates
+ */
+static void
+free_revoked_certs(revokedCert_t* revokedCerts)
+{
+ while (revokedCerts != NULL)
+ {
+ revokedCert_t * revokedCert = revokedCerts;
+ revokedCerts = revokedCert->next;
+ pfree(revokedCert);
+ }
+}
+
+/*
+ * free the dynamic memory used to store CRLs
+ */
+void
+free_crl(x509crl_t *crl)
+{
+ free_revoked_certs(crl->revokedCertificates);
+ free_generalNames(crl->distributionPoints, TRUE);
+ pfree(crl->certificateList.ptr);
+ pfree(crl);
+}
+
+static void
+free_first_crl(void)
+{
+ x509crl_t *crl = x509crls;
+
+ x509crls = crl->next;
+ free_crl(crl);
+}
+
+void
+free_crls(void)
+{
+ lock_crl_list("free_crls");
+
+ while (x509crls != NULL)
+ free_first_crl();
+
+ unlock_crl_list("free_crls");
+}
+
+/*
+ * Insert X.509 CRL into chained list
+ */
+bool
+insert_crl(chunk_t blob, chunk_t crl_uri, bool cache_crl)
+{
+ x509crl_t *crl = alloc_thing(x509crl_t, "x509crl");
+
+ *crl = empty_x509crl;
+
+ if (parse_x509crl(blob, 0, crl))
+ {
+ x509cert_t *issuer_cert;
+ x509crl_t *oldcrl;
+ bool valid_sig;
+ generalName_t *gn;
+
+ /* add distribution point */
+ gn = alloc_thing(generalName_t, "generalName");
+ gn->kind = GN_URI;
+ gn->name = crl_uri;
+ gn->next = crl->distributionPoints;
+ crl->distributionPoints = gn;
+
+ lock_authcert_list("insert_crl");
+ /* get the issuer cacert */
+ issuer_cert = get_authcert(crl->issuer, crl->authKeySerialNumber,
+ crl->authKeyID, AUTH_CA);
+ if (issuer_cert == NULL)
+ {
+ plog("crl issuer cacert not found");
+ free_crl(crl);
+ unlock_authcert_list("insert_crl");
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("crl issuer cacert found")
+ )
+
+ /* check the issuer's signature of the crl */
+ valid_sig = check_signature(crl->tbsCertList, crl->signature
+ , crl->algorithm, crl->algorithm, issuer_cert);
+ unlock_authcert_list("insert_crl");
+
+ if (!valid_sig)
+ {
+ free_crl(crl);
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("crl signature is valid")
+ )
+
+ lock_crl_list("insert_crl");
+ oldcrl = get_x509crl(crl->issuer, crl->authKeySerialNumber
+ , crl->authKeyID);
+
+ if (oldcrl != NULL)
+ {
+ if (crl->thisUpdate > oldcrl->thisUpdate)
+ {
+ /* keep any known CRL distribution points */
+ add_distribution_points(oldcrl->distributionPoints
+ , &crl->distributionPoints);
+
+ /* now delete the old CRL */
+ free_first_crl();
+ DBG(DBG_CONTROL,
+ DBG_log("thisUpdate is newer - existing crl deleted")
+ )
+ }
+ else
+ {
+ unlock_crl_list("insert_crls");
+ DBG(DBG_CONTROL,
+ DBG_log("thisUpdate is not newer - existing crl not replaced");
+ )
+ free_crl(crl);
+ return oldcrl->nextUpdate - time(NULL) > 2*crl_check_interval;
+ }
+ }
+
+ /* insert new CRL */
+ crl->next = x509crls;
+ x509crls = crl;
+
+ unlock_crl_list("insert_crl");
+
+ /* If crl caching is enabled then the crl is saved locally.
+ * Only http or ldap URIs are cached but not local file URIs.
+ * The issuer's subjectKeyID is used as a unique filename
+ */
+ if (cache_crl && strncasecmp(crl_uri.ptr, "file", 4) != 0)
+ {
+ char path[BUF_LEN];
+ char buf[BUF_LEN];
+ char digest_buf[SHA1_DIGEST_SIZE];
+ chunk_t subjectKeyID = { digest_buf, SHA1_DIGEST_SIZE };
+
+ if (issuer_cert->subjectKeyID.ptr == NULL)
+ compute_subjectKeyID(issuer_cert, subjectKeyID);
+ else
+ subjectKeyID = issuer_cert->subjectKeyID;
+
+ datatot(subjectKeyID.ptr, subjectKeyID.len, 16, buf, BUF_LEN);
+ snprintf(path, BUF_LEN, "%s/%s.crl", CRL_PATH, buf);
+ write_chunk(path, "crl", crl->certificateList, 0022, TRUE);
+ }
+
+ /* is the fetched crl valid? */
+ return crl->nextUpdate - time(NULL) > 2*crl_check_interval;
+ }
+ else
+ {
+ plog(" error in X.509 crl");
+ free_crl(crl);
+ return FALSE;
+ }
+}
+
+/*
+ * Loads CRLs
+ */
+void
+load_crls(void)
+{
+ struct dirent **filelist;
+ u_char buf[BUF_LEN];
+ u_char *save_dir;
+ int n;
+
+ /* change directory to specified path */
+ save_dir = getcwd(buf, BUF_LEN);
+ if (chdir(CRL_PATH))
+ {
+ plog("Could not change to directory '%s'", CRL_PATH);
+ }
+ else
+ {
+ plog("Changing to directory '%s'", CRL_PATH);
+ n = scandir(CRL_PATH, &filelist, file_select, alphasort);
+
+ if (n < 0)
+ plog(" scandir() error");
+ else
+ {
+ while (n--)
+ {
+ bool pgp = FALSE;
+ chunk_t blob = empty_chunk;
+ char *filename = filelist[n]->d_name;
+
+ if (load_coded_file(filename, NULL, "crl", &blob, &pgp))
+ {
+ chunk_t crl_uri;
+
+ crl_uri.len = 7 + sizeof(CRL_PATH) + strlen(filename);
+ crl_uri.ptr = alloc_bytes(crl_uri.len + 1, "crl uri");
+
+ /* build CRL file URI */
+ snprintf(crl_uri.ptr, crl_uri.len + 1, "file://%s/%s"
+ , CRL_PATH, filename);
+
+ insert_crl(blob, crl_uri, FALSE);
+ }
+ free(filelist[n]);
+ }
+ free(filelist);
+ }
+ }
+ /* restore directory path */
+ chdir(save_dir);
+}
+
+/*
+ * Parses a CRL revocation reason code
+ */
+static crl_reason_t
+parse_crl_reasonCode(chunk_t object)
+{
+ crl_reason_t reason = REASON_UNSPECIFIED;
+
+ if (*object.ptr == ASN1_ENUMERATED
+ && asn1_length(&object) == 1)
+ {
+ reason = *object.ptr;
+ }
+
+ DBG(DBG_PARSING,
+ DBG_log(" '%s'", enum_name(&crl_reason_names, reason))
+ )
+ return reason;
+}
+
+/*
+ * Parses an X.509 CRL
+ */
+bool
+parse_x509crl(chunk_t blob, u_int level0, x509crl_t *crl)
+{
+ u_char buf[BUF_LEN];
+ asn1_ctx_t ctx;
+ bool critical;
+ chunk_t extnID;
+ chunk_t userCertificate;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+
+ asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
+
+ while (objectID < CRL_OBJ_ROOF)
+ {
+ if (!extract_object(crlObjects, &objectID, &object, &level, &ctx))
+ return FALSE;
+
+ /* those objects which will parsed further need the next higher level */
+ level++;
+
+ switch (objectID) {
+ case CRL_OBJ_CERTIFICATE_LIST:
+ crl->certificateList = object;
+ break;
+ case CRL_OBJ_TBS_CERT_LIST:
+ crl->tbsCertList = object;
+ break;
+ case CRL_OBJ_VERSION:
+ crl->version = (object.len) ? (1+(u_int)*object.ptr) : 1;
+ DBG(DBG_PARSING,
+ DBG_log(" v%d", crl->version);
+ )
+ break;
+ case CRL_OBJ_SIG_ALG:
+ crl->sigAlg = parse_algorithmIdentifier(object, level, NULL);
+ break;
+ case CRL_OBJ_ISSUER:
+ crl->issuer = object;
+ DBG(DBG_PARSING,
+ dntoa(buf, BUF_LEN, object);
+ DBG_log(" '%s'",buf)
+ )
+ break;
+ case CRL_OBJ_THIS_UPDATE:
+ crl->thisUpdate = parse_time(object, level);
+ break;
+ case CRL_OBJ_NEXT_UPDATE:
+ crl->nextUpdate = parse_time(object, level);
+ break;
+ case CRL_OBJ_USER_CERTIFICATE:
+ userCertificate = object;
+ break;
+ case CRL_OBJ_REVOCATION_DATE:
+ {
+ /* put all the serial numbers and the revocation date in a chained list
+ with revocedCertificates pointing to the first revoked certificate */
+
+ revokedCert_t *revokedCert = alloc_thing(revokedCert_t, "revokedCert");
+ revokedCert->userCertificate = userCertificate;
+ revokedCert->revocationDate = parse_time(object, level);
+ revokedCert->revocationReason = REASON_UNSPECIFIED;
+ revokedCert->next = crl->revokedCertificates;
+ crl->revokedCertificates = revokedCert;
+ }
+ break;
+ case CRL_OBJ_CRL_ENTRY_EXTN_ID:
+ case CRL_OBJ_EXTN_ID:
+ extnID = object;
+ break;
+ case CRL_OBJ_CRL_ENTRY_CRITICAL:
+ case CRL_OBJ_CRITICAL:
+ critical = object.len && *object.ptr;
+ DBG(DBG_PARSING,
+ DBG_log(" %s",(critical)?"TRUE":"FALSE");
+ )
+ break;
+ case CRL_OBJ_CRL_ENTRY_EXTN_VALUE:
+ case CRL_OBJ_EXTN_VALUE:
+ {
+ u_int extn_oid = known_oid(extnID);
+
+ if (extn_oid == OID_CRL_REASON_CODE)
+ {
+ crl->revokedCertificates->revocationReason =
+ parse_crl_reasonCode(object);
+ }
+ else if (extn_oid == OID_AUTHORITY_KEY_ID)
+ {
+ parse_authorityKeyIdentifier(object, level
+ , &crl->authKeyID, &crl->authKeySerialNumber);
+ }
+ }
+ break;
+ case CRL_OBJ_ALGORITHM:
+ crl->algorithm = parse_algorithmIdentifier(object, level, NULL);
+ break;
+ case CRL_OBJ_SIGNATURE:
+ crl->signature = object;
+ break;
+ default:
+ break;
+ }
+ objectID++;
+ }
+ time(&crl->installed);
+ return TRUE;
+}
+
+/* Checks if the current certificate is revoked. It goes through the
+ * list of revoked certificates of the corresponding crl. Either the
+ * status CERT_GOOD or CERT_REVOKED is returned
+ */
+static cert_status_t
+check_revocation(const x509crl_t *crl, chunk_t serial
+, time_t *revocationDate, crl_reason_t * revocationReason)
+{
+ revokedCert_t *revokedCert = crl->revokedCertificates;
+
+ *revocationDate = UNDEFINED_TIME;
+ *revocationReason = REASON_UNSPECIFIED;
+
+ DBG(DBG_CONTROL,
+ DBG_dump_chunk("serial number:", serial)
+ )
+
+ while(revokedCert != NULL)
+ {
+ /* compare serial numbers */
+ if (revokedCert->userCertificate.len == serial.len &&
+ memcmp(revokedCert->userCertificate.ptr, serial.ptr, serial.len) == 0)
+ {
+ *revocationDate = revokedCert->revocationDate;
+ *revocationReason = revokedCert->revocationReason;
+ return CERT_REVOKED;
+ }
+ revokedCert = revokedCert->next;
+ }
+ return CERT_GOOD;
+}
+
+/*
+ * check if any crls are about to expire
+ */
+void
+check_crls(void)
+{
+ x509crl_t *crl;
+
+ lock_crl_list("check_crls");
+ crl = x509crls;
+
+ while (crl != NULL)
+ {
+ time_t time_left = crl->nextUpdate - time(NULL);
+ u_char buf[BUF_LEN];
+
+ DBG(DBG_CONTROL,
+ dntoa(buf, BUF_LEN, crl->issuer);
+ DBG_log("issuer: '%s'",buf);
+ if (crl->authKeyID.ptr != NULL)
+ {
+ datatot(crl->authKeyID.ptr, crl->authKeyID.len, ':'
+ , buf, BUF_LEN);
+ DBG_log("authkey: %s", buf);
+ }
+ DBG_log("%ld seconds left", time_left)
+ )
+ if (time_left < 2*crl_check_interval)
+ {
+ fetch_req_t *req = build_crl_fetch_request(crl->issuer
+ , crl->authKeySerialNumber
+ , crl->authKeyID, crl->distributionPoints);
+ add_crl_fetch_request(req);
+ }
+ crl = crl->next;
+ }
+ unlock_crl_list("check_crls");
+}
+
+/*
+ * verify if a cert hasn't been revoked by a crl
+ */
+cert_status_t
+verify_by_crl(const x509cert_t *cert, time_t *until, time_t *revocationDate
+, crl_reason_t *revocationReason)
+{
+ x509crl_t *crl;
+
+ ca_info_t *ca = get_ca_info(cert->issuer, cert->authKeySerialNumber
+ , cert->authKeyID);
+
+ generalName_t *crluri = (ca == NULL)? NULL : ca->crluri;
+
+ *revocationDate = UNDEFINED_TIME;
+ *revocationReason = REASON_UNSPECIFIED;
+
+ lock_crl_list("verify_by_crl");
+ crl = get_x509crl(cert->issuer, cert->authKeySerialNumber, cert->authKeyID);
+
+ if (crl == NULL)
+ {
+ unlock_crl_list("verify_by_crl");
+ plog("crl not found");
+
+ if (cert->crlDistributionPoints != NULL)
+ {
+ fetch_req_t *req = build_crl_fetch_request(cert->issuer
+ , cert->authKeySerialNumber
+ , cert->authKeyID, cert->crlDistributionPoints);
+ add_crl_fetch_request(req);
+ }
+
+ if (crluri != NULL)
+ {
+ fetch_req_t *req = build_crl_fetch_request(cert->issuer
+ , cert->authKeySerialNumber
+ , cert->authKeyID, crluri);
+ add_crl_fetch_request(req);
+ }
+
+ if (cert->crlDistributionPoints != 0 || crluri != NULL)
+ {
+ wake_fetch_thread("verify_by_crl");
+ return CERT_UNKNOWN;
+ }
+ else
+ return CERT_UNDEFINED;
+ }
+ else
+ {
+ x509cert_t *issuer_cert;
+ bool valid;
+
+ DBG(DBG_CONTROL,
+ DBG_log("crl found")
+ )
+
+ add_distribution_points(cert->crlDistributionPoints
+ , &crl->distributionPoints);
+
+ add_distribution_points(crluri
+ , &crl->distributionPoints);
+
+ lock_authcert_list("verify_by_crl");
+
+ issuer_cert = get_authcert(crl->issuer, crl->authKeySerialNumber
+ , crl->authKeyID, AUTH_CA);
+ valid = check_signature(crl->tbsCertList, crl->signature
+ , crl->algorithm, crl->algorithm, issuer_cert);
+
+ unlock_authcert_list("verify_by_crl");
+
+ if (valid)
+ {
+ cert_status_t status;
+
+ DBG(DBG_CONTROL,
+ DBG_log("crl signature is valid")
+ )
+ /* return the expiration date */
+ *until = crl->nextUpdate;
+
+ /* has the certificate been revoked? */
+ status = check_revocation(crl, cert->serialNumber, revocationDate
+ , revocationReason);
+
+ if (*until < time(NULL))
+ {
+ fetch_req_t *req;
+
+ plog("crl update is overdue since %s"
+ , timetoa(until, TRUE));
+
+ /* try to fetch a crl update */
+ req = build_crl_fetch_request(crl->issuer
+ , crl->authKeySerialNumber
+ , crl->authKeyID, crl->distributionPoints);
+ unlock_crl_list("verify_by_crl");
+
+ add_crl_fetch_request(req);
+ wake_fetch_thread("verify_by_crl");
+ }
+ else
+ {
+ unlock_crl_list("verify_by_crl");
+ DBG(DBG_CONTROL,
+ DBG_log("crl is valid")
+ )
+ }
+ return status;
+ }
+ else
+ {
+ unlock_crl_list("verify_by_crl");
+ plog("crl signature is invalid");
+ return CERT_UNKNOWN;
+ }
+ }
+}
+
+/*
+ * list all X.509 crls in the chained list
+ */
+void
+list_crls(bool utc, bool strict)
+{
+ x509crl_t *crl;
+
+ lock_crl_list("list_crls");
+ crl = x509crls;
+
+ if (crl != NULL)
+ {
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of X.509 CRLs:");
+ whack_log(RC_COMMENT, " ");
+ }
+
+ while (crl != NULL)
+ {
+ u_char buf[BUF_LEN];
+ u_int revoked = 0;
+ revokedCert_t *revokedCert = crl->revokedCertificates;
+
+ /* count number of revoked certificates in CRL */
+ while (revokedCert != NULL)
+ {
+ revoked++;
+ revokedCert = revokedCert->next;
+ }
+
+ whack_log(RC_COMMENT, "%s, revoked certs: %d",
+ timetoa(&crl->installed, utc), revoked);
+ dntoa(buf, BUF_LEN, crl->issuer);
+ whack_log(RC_COMMENT, " issuer: '%s'", buf);
+
+ list_distribution_points(crl->distributionPoints);
+
+ whack_log(RC_COMMENT, " updates: this %s",
+ timetoa(&crl->thisUpdate, utc));
+ whack_log(RC_COMMENT, " next %s %s",
+ timetoa(&crl->nextUpdate, utc),
+ check_expiry(crl->nextUpdate, CRL_WARNING_INTERVAL, strict));
+ if (crl->authKeyID.ptr != NULL)
+ {
+ datatot(crl->authKeyID.ptr, crl->authKeyID.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " authkey: %s", buf);
+ }
+ if (crl->authKeySerialNumber.ptr != NULL)
+ {
+ datatot(crl->authKeySerialNumber.ptr, crl->authKeySerialNumber.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " aserial: %s", buf);
+ }
+
+ crl = crl->next;
+ }
+ unlock_crl_list("list_crls");
+}
+
diff --git a/src/pluto/crl.h b/src/pluto/crl.h
new file mode 100644
index 000000000..9f985b6cd
--- /dev/null
+++ b/src/pluto/crl.h
@@ -0,0 +1,87 @@
+/* Support of X.509 certificate revocation lists (CRLs)
+ * Copyright (C) 2000-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.
+ *
+ * RCSID $Id: crl.h,v 1.4 2005/07/18 19:36:22 as Exp $
+ */
+
+#include "constants.h"
+
+/* access structure for a revoked serial number */
+
+typedef struct revokedCert revokedCert_t;
+
+struct revokedCert{
+ revokedCert_t *next;
+ chunk_t userCertificate;
+ time_t revocationDate;
+ crl_reason_t revocationReason;
+};
+
+/* storage structure for an X.509 CRL */
+
+typedef struct x509crl x509crl_t;
+
+struct x509crl {
+ x509crl_t *next;
+ time_t installed;
+ generalName_t *distributionPoints;
+ chunk_t certificateList;
+ chunk_t tbsCertList;
+ u_int version;
+ /* signature */
+ int sigAlg;
+ chunk_t issuer;
+ time_t thisUpdate;
+ time_t nextUpdate;
+ revokedCert_t *revokedCertificates;
+ /* v2 extensions */
+ /* crlExtensions */
+ /* extension */
+ /* extnID */
+ /* critical */
+ /* extnValue */
+ chunk_t authKeyID;
+ chunk_t authKeySerialNumber;
+
+ /* signatureAlgorithm */
+ int algorithm;
+ chunk_t signature;
+};
+
+/* apply a strict CRL policy
+ * flag set in plutomain.c and used in ipsec_doi.c and rcv_whack.c
+ */
+extern bool strict_crl_policy;
+
+/*
+ * cache the retrieved CRLs by storing them locally as a file
+ */
+extern bool cache_crls;
+
+/*
+ * check periodically for expired crls
+ */
+extern long crl_check_interval;
+
+/* used for initialization */
+extern const x509crl_t empty_x509crl;
+
+extern bool parse_x509crl(chunk_t blob, u_int level0, x509crl_t *crl);
+extern void load_crls(void);
+extern void check_crls(void);
+extern bool insert_crl(chunk_t blob, chunk_t crl_uri, bool cache_crl);
+extern cert_status_t verify_by_crl(const x509cert_t *cert, time_t *until
+ , time_t *revocationDate, crl_reason_t *revocationReason);
+extern void list_crls(bool utc, bool strict);
+extern void free_crls(void);
+extern void free_crl(x509crl_t *crl);
diff --git a/src/pluto/crypto.c b/src/pluto/crypto.c
new file mode 100644
index 000000000..f1b7c3f5f
--- /dev/null
+++ b/src/pluto/crypto.c
@@ -0,0 +1,627 @@
+/* crypto interfaces
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier
+ * Copyright (C) 2007 Andreas Steffen
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: crypto.c,v 1.5 2005/12/06 22:51:34 as Exp $
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#include <freeswan.h>
+#define HEADER_DES_LOCL_H /* stupid trick to force prototype decl in <des.h> */
+#include <libdes/des.h>
+
+#include <errno.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "state.h"
+#include "log.h"
+#include "md5.h"
+#include "sha1.h"
+#include "crypto.h" /* requires sha1.h and md5.h */
+#include "alg_info.h"
+#include "ike_alg.h"
+
+
+/* moduli and generator. */
+
+static MP_INT
+ modp1024_modulus,
+ modp1536_modulus,
+ modp2048_modulus,
+ modp3072_modulus,
+ modp4096_modulus,
+ modp6144_modulus,
+ modp8192_modulus;
+
+MP_INT groupgenerator; /* MODP group generator (2) */
+
+static void do_3des(u_int8_t *buf, size_t buf_len, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc);
+
+static struct encrypt_desc crypto_encryptor_3des =
+{
+ algo_type: IKE_ALG_ENCRYPT,
+ algo_id: OAKLEY_3DES_CBC,
+ algo_next: NULL,
+ enc_ctxsize: sizeof(des_key_schedule) * 3,
+ enc_blocksize: DES_CBC_BLOCK_SIZE,
+ keydeflen: DES_CBC_BLOCK_SIZE * 3 * BITS_PER_BYTE,
+ keyminlen: DES_CBC_BLOCK_SIZE * 3 * BITS_PER_BYTE,
+ keymaxlen: DES_CBC_BLOCK_SIZE * 3 * BITS_PER_BYTE,
+ do_crypt: do_3des,
+};
+
+/* MD5 hash test vectors
+ * from RFC 1321 "MD5 Message-Digest Algorithm"
+ * April 1992, R. Rivest, RSA Data Security
+ */
+
+static const u_char md5_test0_msg[] = {
+
+};
+
+static const u_char md5_test0_msg_digest[] = {
+ 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04,
+ 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e
+};
+
+static const u_char md5_test1_msg[] = {
+ 0x61
+};
+
+static const u_char md5_test1_msg_digest[] = {
+ 0x0c, 0xc1, 0x75, 0xb9, 0xc0, 0xf1, 0xb6, 0xa8,
+ 0x31, 0xc3, 0x99, 0xe2, 0x69, 0x77, 0x26, 0x61
+};
+
+static const u_char md5_test2_msg[] = {
+ 0x61, 0x62, 0x63
+};
+
+static const u_char md5_test2_msg_digest[] = {
+ 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0,
+ 0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1, 0x7f, 0x72
+};
+
+static const u_char md5_test3_msg[] = {
+ 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20,
+ 0x64, 0x69, 0x67, 0x65, 0x73, 0x74
+};
+
+static const u_char md5_test3_msg_digest[] = {
+ 0xf9, 0x6b, 0x69, 0x7d, 0x7c, 0xb7, 0x93, 0x8d,
+ 0x52, 0x5a, 0x2f, 0x31, 0xaa, 0xf1, 0x61, 0xd0
+};
+
+static const u_char md5_test4_msg[] = {
+ 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
+ 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7a
+};
+
+static const u_char md5_test4_msg_digest[] = {
+ 0xc3, 0xfc, 0xd3, 0xd7, 0x61, 0x92, 0xe4, 0x00,
+ 0x7d, 0xfb, 0x49, 0x6c, 0xca, 0x67, 0xe1, 0x3b
+};
+
+static const u_char md5_test5_msg[] = {
+ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+ 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
+ 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5a, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
+ 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
+ 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76,
+ 0x77, 0x78, 0x79, 0x7a, 0x30, 0x31, 0x32, 0x33,
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39
+};
+
+static const u_char md5_test5_msg_digest[] = {
+ 0xd1, 0x74, 0xab, 0x98, 0xd2, 0x77, 0xd9, 0xf5,
+ 0xa5, 0x61, 0x1c, 0x2c, 0x9f, 0x41, 0x9d, 0x9f
+};
+
+static const u_char md5_test6_msg[] = {
+ 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
+ 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34,
+ 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32,
+ 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30,
+ 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
+ 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34,
+ 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32,
+ 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30
+};
+
+static const u_char md5_test6_msg_digest[] = {
+ 0x57, 0xed, 0xf4, 0xa2, 0x2b, 0xe3, 0xc9, 0x55,
+ 0xac, 0x49, 0xda, 0x2e, 0x21, 0x07, 0xb6, 0x7a
+};
+
+static const hash_testvector_t md5_hash_testvectors[] = {
+ { sizeof(md5_test0_msg), md5_test0_msg, md5_test0_msg_digest },
+ { sizeof(md5_test1_msg), md5_test1_msg, md5_test1_msg_digest },
+ { sizeof(md5_test2_msg), md5_test2_msg, md5_test2_msg_digest },
+ { sizeof(md5_test3_msg), md5_test3_msg, md5_test3_msg_digest },
+ { sizeof(md5_test4_msg), md5_test4_msg, md5_test4_msg_digest },
+ { sizeof(md5_test5_msg), md5_test5_msg, md5_test5_msg_digest },
+ { sizeof(md5_test6_msg), md5_test6_msg, md5_test6_msg_digest },
+ { 0, NULL, NULL }
+};
+
+/* MD5 hmac test vectors
+ * from RFC 2202 "Test Cases for HMAC-MD5 and HMAC-SHA-1"
+ * September 1997, P. Cheng, IBM & R. Glenn, NIST
+ */
+
+static const u_char md5_hmac1_key[] = {
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b
+};
+
+static const u_char md5_hmac1_msg[] = {
+ 0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65
+};
+
+static const u_char md5_hmac1[] = {
+ 0x92, 0x94, 0x72, 0x7a, 0x36, 0x38, 0xbb, 0x1c,
+ 0x13, 0xf4, 0x8e, 0xf8, 0x15, 0x8b, 0xfc, 0x9d
+};
+
+static const u_char md5_hmac2_key[] = {
+ 0x4a, 0x65, 0x66, 0x65
+};
+
+static const u_char md5_hmac2_msg[] = {
+ 0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x20,
+ 0x79, 0x61, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x20,
+ 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x68,
+ 0x69, 0x6e, 0x67, 0x3f
+};
+
+static const u_char md5_hmac2[] = {
+ 0x75, 0x0c, 0x78, 0x3e, 0x6a, 0xb0, 0xb5, 0x03,
+ 0xea, 0xa8, 0x6e, 0x31, 0x0a, 0x5d, 0xb7, 0x38
+};
+
+static const u_char md5_hmac3_key[] = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
+};
+
+static const u_char md5_hmac3_msg[] = {
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd
+};
+
+static const u_char md5_hmac3[] = {
+ 0x56, 0xbe, 0x34, 0x52, 0x1d, 0x14, 0x4c, 0x88,
+ 0xdb, 0xb8, 0xc7, 0x33, 0xf0, 0xe8, 0xb3, 0xf6
+};
+
+static const u_char md5_hmac4_key[] = {
+ 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
+};
+
+static const u_char md5_hmac4_msg[] = {
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd
+};
+
+static const u_char md5_hmac4[] = {
+ 0x69, 0x7e, 0xaf, 0x0a, 0xca, 0x3a, 0x3a, 0xea,
+ 0x3a, 0x75, 0x16, 0x47, 0x46, 0xff, 0xaa, 0x79
+};
+
+static const u_char md5_hmac6_key[] = {
+ 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,
+};
+
+static const u_char md5_hmac6_msg[] = {
+ 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69,
+ 0x6e, 0x67, 0x20, 0x4c, 0x61, 0x72, 0x67, 0x65,
+ 0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42,
+ 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a,
+ 0x65, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x2d, 0x20,
+ 0x48, 0x61, 0x73, 0x68, 0x20, 0x4b, 0x65, 0x79,
+ 0x20, 0x46, 0x69, 0x72, 0x73, 0x74
+};
+
+static const u_char md5_hmac6[] = {
+ 0x6b, 0x1a, 0xb7, 0xfe, 0x4b, 0xd7, 0xbf, 0x8f,
+ 0x0b, 0x62, 0xe6, 0xce, 0x61, 0xb9, 0xd0, 0xcd
+};
+
+static const u_char md5_hmac7_msg[] = {
+ 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69,
+ 0x6e, 0x67, 0x20, 0x4c, 0x61, 0x72, 0x67, 0x65,
+ 0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42,
+ 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a,
+ 0x65, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x61, 0x6e,
+ 0x64, 0x20, 0x4c, 0x61, 0x72, 0x67, 0x65, 0x72,
+ 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x4f, 0x6e,
+ 0x65, 0x20, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x2d,
+ 0x53, 0x69, 0x7a, 0x65, 0x20, 0x44, 0x61, 0x74,
+ 0x61
+};
+
+static const u_char md5_hmac7[] = {
+ 0x6f, 0x63, 0x0f, 0xad, 0x67, 0xcd, 0xa0, 0xee,
+ 0x1f, 0xb1, 0xf5, 0x62, 0xdb, 0x3a, 0xa5, 0x3e
+};
+
+static const hmac_testvector_t md5_hmac_testvectors[] = {
+ { sizeof(md5_hmac1_key), md5_hmac1_key, sizeof(md5_hmac1_msg), md5_hmac1_msg, md5_hmac1 },
+ { sizeof(md5_hmac2_key), md5_hmac2_key, sizeof(md5_hmac2_msg), md5_hmac2_msg, md5_hmac2 },
+ { sizeof(md5_hmac3_key), md5_hmac3_key, sizeof(md5_hmac3_msg), md5_hmac3_msg, md5_hmac3 },
+ { sizeof(md5_hmac4_key), md5_hmac4_key, sizeof(md5_hmac4_msg), md5_hmac4_msg, md5_hmac4 },
+ { sizeof(md5_hmac6_key), md5_hmac6_key, sizeof(md5_hmac6_msg), md5_hmac6_msg, md5_hmac6 },
+ { sizeof(md5_hmac6_key), md5_hmac6_key, sizeof(md5_hmac7_msg), md5_hmac7_msg, md5_hmac7 },
+ { 0, NULL, 0, NULL, NULL }
+};
+
+static struct hash_desc crypto_hasher_md5 =
+{
+ algo_type: IKE_ALG_HASH,
+ algo_id: OAKLEY_MD5,
+ algo_next: NULL,
+ hash_ctx_size: sizeof(MD5_CTX),
+ hash_block_size: MD5_BLOCK_SIZE,
+ hash_digest_size: MD5_DIGEST_SIZE,
+ hash_testvectors: md5_hash_testvectors,
+ hmac_testvectors: md5_hmac_testvectors,
+ hash_init: (void (*)(void *)) MD5Init,
+ hash_update: (void (*)(void *, const u_int8_t *, size_t)) MD5Update,
+ hash_final: (void (*)(u_char *, void *)) MD5Final
+};
+
+/* SHA-1 test vectors
+ * from "The Secure Hash Algorithm Validation System (SHAVS)"
+ * July 22, 2004, Lawrence E. Bassham III, NIST
+ */
+
+static const u_char sha1_short2_msg[] = {
+ 0x5e
+};
+
+static const u_char sha1_short2_msg_digest[] = {
+ 0x5e, 0x6f, 0x80, 0xa3, 0x4a, 0x97, 0x98, 0xca,
+ 0xfc, 0x6a, 0x5d, 0xb9, 0x6c, 0xc5, 0x7b, 0xa4,
+ 0xc4, 0xdb, 0x59, 0xc2
+};
+
+static const u_char sha1_short4_msg[] = {
+ 0x9a, 0x7d, 0xfd, 0xf1, 0xec, 0xea, 0xd0, 0x6e,
+ 0xd6, 0x46, 0xaa, 0x55, 0xfe, 0x75, 0x71, 0x46
+};
+
+static const u_char sha1_short4_msg_digest[] = {
+ 0x82, 0xab, 0xff, 0x66, 0x05, 0xdb, 0xe1, 0xc1,
+ 0x7d, 0xef, 0x12, 0xa3, 0x94, 0xfa, 0x22, 0xa8,
+ 0x2b, 0x54, 0x4a, 0x35
+};
+
+static const u_char sha1_long2_msg[] = {
+ 0xf7, 0x8f, 0x92, 0x14, 0x1b, 0xcd, 0x17, 0x0a,
+ 0xe8, 0x9b, 0x4f, 0xba, 0x15, 0xa1, 0xd5, 0x9f,
+ 0x3f, 0xd8, 0x4d, 0x22, 0x3c, 0x92, 0x51, 0xbd,
+ 0xac, 0xbb, 0xae, 0x61, 0xd0, 0x5e, 0xd1, 0x15,
+ 0xa0, 0x6a, 0x7c, 0xe1, 0x17, 0xb7, 0xbe, 0xea,
+ 0xd2, 0x44, 0x21, 0xde, 0xd9, 0xc3, 0x25, 0x92,
+ 0xbd, 0x57, 0xed, 0xea, 0xe3, 0x9c, 0x39, 0xfa,
+ 0x1f, 0xe8, 0x94, 0x6a, 0x84, 0xd0, 0xcf, 0x1f,
+ 0x7b, 0xee, 0xad, 0x17, 0x13, 0xe2, 0xe0, 0x95,
+ 0x98, 0x97, 0x34, 0x7f, 0x67, 0xc8, 0x0b, 0x04,
+ 0x00, 0xc2, 0x09, 0x81, 0x5d, 0x6b, 0x10, 0xa6,
+ 0x83, 0x83, 0x6f, 0xd5, 0x56, 0x2a, 0x56, 0xca,
+ 0xb1, 0xa2, 0x8e, 0x81, 0xb6, 0x57, 0x66, 0x54,
+ 0x63, 0x1c, 0xf1, 0x65, 0x66, 0xb8, 0x6e, 0x3b,
+ 0x33, 0xa1, 0x08, 0xb0, 0x53, 0x07, 0xc0, 0x0a,
+ 0xff, 0x14, 0xa7, 0x68, 0xed, 0x73, 0x50, 0x60,
+ 0x6a, 0x0f, 0x85, 0xe6, 0xa9, 0x1d, 0x39, 0x6f,
+ 0x5b, 0x5c, 0xbe, 0x57, 0x7f, 0x9b, 0x38, 0x80,
+ 0x7c, 0x7d, 0x52, 0x3d, 0x6d, 0x79, 0x2f, 0x6e,
+ 0xbc, 0x24, 0xa4, 0xec, 0xf2, 0xb3, 0xa4, 0x27,
+ 0xcd, 0xbb, 0xfb
+};
+
+static const u_char sha1_long2_msg_digest[] = {
+ 0xcb, 0x00, 0x82, 0xc8, 0xf1, 0x97, 0xd2, 0x60,
+ 0x99, 0x1b, 0xa6, 0xa4, 0x60, 0xe7, 0x6e, 0x20,
+ 0x2b, 0xad, 0x27, 0xb3
+};
+
+static const hash_testvector_t sha1_hash_testvectors[] = {
+ { sizeof(sha1_short2_msg), sha1_short2_msg, sha1_short2_msg_digest },
+ { sizeof(sha1_short4_msg), sha1_short4_msg, sha1_short4_msg_digest },
+ { sizeof(sha1_long2_msg), sha1_long2_msg, sha1_long2_msg_digest },
+ { 0, NULL, NULL }
+};
+
+/* SHA-1 hmac test vectors
+ * from RFC 2202 "Test Cases for HMAC-MD5 and HMAC-SHA-1"
+ * September 1997, P. Cheng, IBM & R. Glenn, NIST
+ */
+
+static const u_char sha1_hmac1_key[] = {
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b
+};
+
+static const u_char sha1_hmac1[] = {
+ 0xb6, 0x17, 0x31, 0x86, 0x55, 0x05, 0x72, 0x64,
+ 0xe2, 0x8b, 0xc0, 0xb6, 0xfb, 0x37, 0x8c, 0x8e,
+ 0xf1, 0x46, 0xbe, 0x00
+};
+
+static const u_char sha1_hmac2[] = {
+ 0xef, 0xfc, 0xdf, 0x6a, 0xe5, 0xeb, 0x2f, 0xa2,
+ 0xd2, 0x74, 0x16, 0xd5, 0xf1, 0x84, 0xdf, 0x9c,
+ 0x25, 0x9a, 0x7c, 0x79
+};
+
+static const u_char sha1_hmac3_key[] = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa
+};
+
+static const u_char sha1_hmac3[] = {
+ 0x12, 0x5d, 0x73, 0x42, 0xb9, 0xac, 0x11, 0xcd,
+ 0x91, 0xa3, 0x9a, 0xf4, 0x8a, 0xa1, 0x7b, 0x4f,
+ 0x63, 0xf1, 0x75, 0xd3
+};
+
+static const u_char sha1_hmac4[] = {
+ 0x4c, 0x90, 0x07, 0xf4, 0x02, 0x62, 0x50, 0xc6,
+ 0xbc, 0x84, 0x14, 0xf9, 0xbf, 0x50, 0xc8, 0x6c,
+ 0x2d, 0x72, 0x35, 0xda
+};
+
+static const u_char sha1_hmac6[] = {
+ 0xaa, 0x4a, 0xe5, 0xe1, 0x52, 0x72, 0xd0, 0x0e,
+ 0x95, 0x70, 0x56, 0x37, 0xce, 0x8a, 0x3b, 0x55,
+ 0xed, 0x40, 0x21, 0x12
+};
+
+static const u_char sha1_hmac7[] = {
+ 0xe8, 0xe9, 0x9d, 0x0f, 0x45, 0x23, 0x7d, 0x78,
+ 0x6d, 0x6b, 0xba, 0xa7, 0x96, 0x5c, 0x78, 0x08,
+ 0xbb, 0xff, 0x1a, 0x91
+};
+
+static const hmac_testvector_t sha1_hmac_testvectors[] = {
+ { sizeof(sha1_hmac1_key), sha1_hmac1_key, sizeof(md5_hmac1_msg), md5_hmac1_msg, sha1_hmac1 },
+ { sizeof(md5_hmac2_key), md5_hmac2_key, sizeof(md5_hmac2_msg), md5_hmac2_msg, sha1_hmac2 },
+ { sizeof(sha1_hmac3_key), sha1_hmac3_key, sizeof(md5_hmac3_msg), md5_hmac3_msg, sha1_hmac3 },
+ { sizeof(md5_hmac4_key), md5_hmac4_key, sizeof(md5_hmac4_msg), md5_hmac4_msg, sha1_hmac4 },
+ { sizeof(md5_hmac6_key), md5_hmac6_key, sizeof(md5_hmac6_msg), md5_hmac6_msg, sha1_hmac6 },
+ { sizeof(md5_hmac6_key), md5_hmac6_key, sizeof(md5_hmac7_msg), md5_hmac7_msg, sha1_hmac7 },
+ { 0, NULL, 0, NULL, NULL }
+};
+
+static struct hash_desc crypto_hasher_sha1 =
+{
+ algo_type: IKE_ALG_HASH,
+ algo_id: OAKLEY_SHA,
+ algo_next: NULL,
+ hash_ctx_size: sizeof(SHA1_CTX),
+ hash_block_size: SHA1_BLOCK_SIZE,
+ hash_digest_size: SHA1_DIGEST_SIZE,
+ hash_testvectors: sha1_hash_testvectors,
+ hmac_testvectors: sha1_hmac_testvectors,
+ hash_init: (void (*)(void *)) SHA1Init,
+ hash_update: (void (*)(void *, const u_int8_t *, size_t)) SHA1Update,
+ hash_final: (void (*)(u_char *, void *)) SHA1Final
+};
+
+void
+init_crypto(void)
+{
+ if (mpz_init_set_str(&groupgenerator, MODP_GENERATOR, 10) != 0
+ || mpz_init_set_str(&modp1024_modulus, MODP1024_MODULUS, 16) != 0
+ || mpz_init_set_str(&modp1536_modulus, MODP1536_MODULUS, 16) != 0
+ || mpz_init_set_str(&modp2048_modulus, MODP2048_MODULUS, 16) != 0
+ || mpz_init_set_str(&modp3072_modulus, MODP3072_MODULUS, 16) != 0
+ || mpz_init_set_str(&modp4096_modulus, MODP4096_MODULUS, 16) != 0
+ || mpz_init_set_str(&modp6144_modulus, MODP6144_MODULUS, 16) != 0
+ || mpz_init_set_str(&modp8192_modulus, MODP8192_MODULUS, 16) != 0)
+ exit_log("mpz_init_set_str() failed in init_crypto()");
+
+ ike_alg_add((struct ike_alg *) &crypto_encryptor_3des);
+ ike_alg_add((struct ike_alg *) &crypto_hasher_sha1);
+ ike_alg_add((struct ike_alg *) &crypto_hasher_md5);
+ ike_alg_init();
+ ike_alg_test();
+}
+
+/* Oakley group description
+ *
+ * See RFC2409 "The Internet key exchange (IKE)" 6.
+ */
+
+const struct oakley_group_desc unset_group = {0, NULL, 0}; /* magic signifier */
+
+const struct oakley_group_desc oakley_group[OAKLEY_GROUP_SIZE] = {
+# define BYTES(bits) (((bits) + BITS_PER_BYTE - 1) / BITS_PER_BYTE)
+ { OAKLEY_GROUP_MODP1024, &modp1024_modulus, BYTES(1024) },
+ { OAKLEY_GROUP_MODP1536, &modp1536_modulus, BYTES(1536) },
+ { OAKLEY_GROUP_MODP2048, &modp2048_modulus, BYTES(2048) },
+ { OAKLEY_GROUP_MODP3072, &modp3072_modulus, BYTES(3072) },
+ { OAKLEY_GROUP_MODP4096, &modp4096_modulus, BYTES(4096) },
+ { OAKLEY_GROUP_MODP6144, &modp6144_modulus, BYTES(6144) },
+ { OAKLEY_GROUP_MODP8192, &modp8192_modulus, BYTES(8192) },
+# undef BYTES
+};
+
+const struct oakley_group_desc *
+lookup_group(u_int16_t group)
+{
+ int i;
+
+ for (i = 0; i != elemsof(oakley_group); i++)
+ if (group == oakley_group[i].group)
+ return &oakley_group[i];
+ return NULL;
+}
+
+/* Encryption Routines
+ *
+ * Each uses and updates the state object's st_new_iv.
+ * This must already be initialized.
+ */
+
+/* encrypt or decrypt part of an IKE message using DES
+ * See RFC 2409 "IKE" Appendix B
+ */
+static void __attribute__ ((unused))
+do_des(bool enc, void *buf, size_t buf_len, struct state *st)
+{
+ des_key_schedule ks;
+
+ (void) des_set_key((des_cblock *)st->st_enc_key.ptr, ks);
+
+ passert(st->st_new_iv_len >= DES_CBC_BLOCK_SIZE);
+ st->st_new_iv_len = DES_CBC_BLOCK_SIZE; /* truncate */
+
+ des_ncbc_encrypt((des_cblock *)buf, (des_cblock *)buf, buf_len,
+ ks,
+ (des_cblock *)st->st_new_iv, enc);
+}
+
+/* encrypt or decrypt part of an IKE message using 3DES
+ * See RFC 2409 "IKE" Appendix B
+ */
+static void
+do_3des(u_int8_t *buf, size_t buf_len, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc)
+{
+ des_key_schedule ks[3];
+
+ passert (!key_size || (key_size==(DES_CBC_BLOCK_SIZE * 3)))
+ (void) des_set_key((des_cblock *)key + 0, ks[0]);
+ (void) des_set_key((des_cblock *)key + 1, ks[1]);
+ (void) des_set_key((des_cblock *)key + 2, ks[2]);
+
+ des_ede3_cbc_encrypt((des_cblock *)buf, (des_cblock *)buf, buf_len,
+ ks[0], ks[1], ks[2],
+ (des_cblock *)iv, enc);
+}
+
+/* hash and prf routines */
+void
+crypto_cbc_encrypt(const struct encrypt_desc *e, bool enc, u_int8_t *buf, size_t size, struct state *st)
+{
+ passert(st->st_new_iv_len >= e->enc_blocksize);
+ st->st_new_iv_len = e->enc_blocksize; /* truncate */
+
+ e->do_crypt(buf, size, st->st_enc_key.ptr, st->st_enc_key.len, st->st_new_iv, enc);
+ /*
+ e->set_key(&ctx, st->st_enc_key.ptr, st->st_enc_key.len);
+ e->cbc_crypt(&ctx, buf, size, st->st_new_iv, enc);
+ */
+}
+
+/* HMAC package
+ * rfc2104.txt specifies how HMAC works.
+ */
+
+void
+hmac_init(struct hmac_ctx *ctx,
+ const struct hash_desc *h,
+ const u_char *key, size_t key_len)
+{
+ int k;
+
+ ctx->h = h;
+ ctx->hmac_digest_size = h->hash_digest_size;
+
+ /* Prepare the two pads for the HMAC */
+
+ memset(ctx->buf1, '\0', h->hash_block_size);
+
+ if (key_len <= h->hash_block_size)
+ {
+ memcpy(ctx->buf1, key, key_len);
+ }
+ else
+ {
+ h->hash_init(&ctx->hash_ctx);
+ h->hash_update(&ctx->hash_ctx, key, key_len);
+ h->hash_final(ctx->buf1, &ctx->hash_ctx);
+ }
+
+ memcpy(ctx->buf2, ctx->buf1, h->hash_block_size);
+
+ for (k = 0; k < h->hash_block_size; k++)
+ {
+ ctx->buf1[k] ^= HMAC_IPAD;
+ ctx->buf2[k] ^= HMAC_OPAD;
+ }
+
+ hmac_reinit(ctx);
+}
+
+void
+hmac_reinit(struct hmac_ctx *ctx)
+{
+ ctx->h->hash_init(&ctx->hash_ctx);
+ ctx->h->hash_update(&ctx->hash_ctx, ctx->buf1, ctx->h->hash_block_size);
+}
+
+void
+hmac_update(struct hmac_ctx *ctx,
+ const u_char *data, size_t data_len)
+{
+ ctx->h->hash_update(&ctx->hash_ctx, data, data_len);
+}
+
+void
+hmac_final(u_char *output, struct hmac_ctx *ctx)
+{
+ const struct hash_desc *h = ctx->h;
+
+ h->hash_final(output, &ctx->hash_ctx);
+
+ h->hash_init(&ctx->hash_ctx);
+ h->hash_update(&ctx->hash_ctx, ctx->buf2, h->hash_block_size);
+ h->hash_update(&ctx->hash_ctx, output, h->hash_digest_size);
+ h->hash_final(output, &ctx->hash_ctx);
+}
diff --git a/src/pluto/crypto.h b/src/pluto/crypto.h
new file mode 100644
index 000000000..48c983349
--- /dev/null
+++ b/src/pluto/crypto.h
@@ -0,0 +1,108 @@
+/* crypto interfaces
+ * Copyright (C) 1998, 1999 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: crypto.h,v 1.6 2005/04/07 20:13:30 as Exp $
+ */
+
+#include <gmp.h> /* GNU MP library */
+
+#include "libsha2/sha2.h"
+#include "ike_alg.h"
+
+extern void init_crypto(void);
+
+/* Oakley group descriptions */
+
+extern MP_INT groupgenerator; /* MODP group generator (2) */
+
+struct oakley_group_desc {
+ u_int16_t group;
+ MP_INT *modulus;
+ size_t bytes;
+};
+
+extern const struct oakley_group_desc unset_group; /* magic signifier */
+extern const struct oakley_group_desc *lookup_group(u_int16_t group);
+#define OAKLEY_GROUP_SIZE 7
+extern const struct oakley_group_desc oakley_group[OAKLEY_GROUP_SIZE];
+
+/* unification of cryptographic encoding/decoding algorithms
+ * The IV is taken from and returned to st->st_new_iv.
+ * This allows the old IV to be retained.
+ * Use update_iv to commit to the new IV (for example, once a packet has
+ * been validated).
+ */
+
+#define MAX_OAKLEY_KEY_LEN0 (3 * DES_CBC_BLOCK_SIZE)
+#define MAX_OAKLEY_KEY_LEN (256/BITS_PER_BYTE)
+
+struct state; /* forward declaration, dammit */
+
+void crypto_cbc_encrypt(const struct encrypt_desc *e, bool enc, u_int8_t *buf, size_t size, struct state *st);
+
+#define update_iv(st) memcpy((st)->st_iv, (st)->st_new_iv \
+ , (st)->st_iv_len = (st)->st_new_iv_len)
+
+#define set_ph1_iv(st, iv) \
+ passert((st)->st_ph1_iv_len <= sizeof((st)->st_ph1_iv)); \
+ memcpy((st)->st_ph1_iv, (iv), (st)->st_ph1_iv_len);
+
+/* unification of cryptographic hashing mechanisms */
+
+#ifndef NO_HASH_CTX
+union hash_ctx {
+ MD5_CTX ctx_md5;
+ SHA1_CTX ctx_sha1;
+ sha256_context ctx_sha256;
+ sha512_context ctx_sha512;
+ };
+
+/* HMAC package
+ * Note that hmac_ctx can be (and is) copied since there are
+ * no persistent pointers into it.
+ */
+
+struct hmac_ctx {
+ const struct hash_desc *h; /* underlying hash function */
+ size_t hmac_digest_size; /* copy of h->hash_digest_size */
+ union hash_ctx hash_ctx; /* ctx for hash function */
+ u_char buf1[MAX_HASH_BLOCK_SIZE];
+ u_char buf2[MAX_HASH_BLOCK_SIZE];
+ };
+
+extern void hmac_init(
+ struct hmac_ctx *ctx,
+ const struct hash_desc *h,
+ const u_char *key,
+ size_t key_len);
+
+#define hmac_init_chunk(ctx, h, ch) hmac_init((ctx), (h), (ch).ptr, (ch).len)
+
+extern void hmac_reinit(struct hmac_ctx *ctx); /* saves recreating pads */
+
+extern void hmac_update(
+ struct hmac_ctx *ctx,
+ const u_char *data,
+ size_t data_len);
+
+#define hmac_update_chunk(ctx, ch) hmac_update((ctx), (ch).ptr, (ch).len)
+
+extern void hmac_final(u_char *output, struct hmac_ctx *ctx);
+
+#define hmac_final_chunk(ch, name, ctx) { \
+ pfreeany((ch).ptr); \
+ (ch).len = (ctx)->hmac_digest_size; \
+ (ch).ptr = alloc_bytes((ch).len, name); \
+ hmac_final((ch).ptr, (ctx)); \
+ }
+#endif
diff --git a/src/pluto/db_ops.c b/src/pluto/db_ops.c
new file mode 100644
index 000000000..bbcd7918f
--- /dev/null
+++ b/src/pluto/db_ops.c
@@ -0,0 +1,439 @@
+/* Dynamic db (proposal, transforms, attributes) handling.
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: db_ops.c,v 1.4 2005/04/07 20:13:44 as Exp $
+ */
+
+/*
+ * The stratedy is to have (full contained) struct db_prop in db_context
+ * pointing to ONE dynamically sizable transform vector (trans0).
+ * Each transform stores attrib. in ONE dyn. sizable attribute vector (attrs0)
+ * in a "serialized" way (attributes storage is used in linear sequence for
+ * subsecuent transforms).
+ *
+ * Resizing for both trans0 and attrs0 is supported:
+ * - For trans0: quite simple, just allocate and copy trans. vector content
+ * also update trans_cur (by offset)
+ * - For attrs0: after allocating and copying attrs, I must rewrite each
+ * trans->attrs present in trans0; to achieve this, calculate
+ * attrs pointer offset (new minus old) and iterate over
+ * each transform "adding" this difference.
+ * also update attrs_cur (by offset)
+ *
+ * db_context structure:
+ * +---------------------+
+ * | prop |
+ * | .protoid |
+ * | .trans | --+
+ * | .trans_cnt | |
+ * +---------------------+ <-+
+ * | trans0 | ----> { trans#1 | ... | trans#i | ... }
+ * +---------------------+ ^
+ * | trans_cur | ----------------------' current transf.
+ * +---------------------+
+ * | attrs0 | ----> { attr#1 | ... | attr#j | ... }
+ * +---------------------+ ^
+ * | attrs_cur | ---------------------' current attr.
+ * +---------------------+
+ * | max_trans,max_attrs | max_trans/attrs: number of elem. of each vector
+ * +---------------------+
+ *
+ * See testing examples at end for interface usage.
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <malloc.h>
+#include <sys/types.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "state.h"
+#include "packet.h"
+#include "spdb.h"
+#include "db_ops.h"
+#include "log.h"
+#include "whack.h"
+
+#include <assert.h>
+
+#ifndef NO_PLUTO
+#else
+#define passert(x) assert(x)
+extern int debug; /* eg: spi.c */
+#define DBG(cond, action) { if (debug) { action ; } }
+#define DBG_log(x, args...) fprintf(stderr, x "\n" , ##args);
+#define alloc_thing(thing, name) alloc_bytes(sizeof (thing), name)
+void * alloc_bytes(size_t size, const char *name) {
+ void *p=malloc(size);
+ if (p == NULL)
+ fprintf(stderr, "unable to malloc %lu bytes for %s",
+ (unsigned long) size, name);
+ memset(p, '\0', size);
+ return p;
+}
+#define pfreeany(ptr) free(ptr)
+
+#endif
+
+#ifdef NOT_YET
+/*
+ * Allocator cache:
+ * Because of the single-threaded nature of pluto/spdb.c,
+ * alloc()/free() is exercised many times with very small
+ * lifetime objects.
+ * Just caching last object (currently it will select the
+ * largest) will avoid this allocation mas^Wperturbations
+ *
+ */
+struct db_ops_alloc_cache {
+ void *ptr;
+ int size;
+};
+#endif
+
+#ifndef NO_DB_OPS_STATS
+/*
+ * stats: do account for allocations
+ * displayed in db_ops_show_status()
+ */
+struct db_ops_stats {
+ int st_curr_cnt; /* current number of allocations */
+ int st_total_cnt; /* total allocations so far */
+ size_t st_maxsz; /* max. size requested */
+};
+#define DB_OPS_ZERO { 0, 0, 0};
+#define DB_OPS_STATS_DESC "{curr_cnt, total_cnt, maxsz}"
+#define DB_OPS_STATS_STR(name) name "={%d,%d,%d} "
+#define DB_OPS_STATS_F(st) (st).st_curr_cnt, (st).st_total_cnt, (int)(st).st_maxsz
+static struct db_ops_stats db_context_st = DB_OPS_ZERO;
+static struct db_ops_stats db_trans_st = DB_OPS_ZERO;
+static struct db_ops_stats db_attrs_st = DB_OPS_ZERO;
+static __inline__ void * alloc_bytes_st (size_t size, const char *str, struct db_ops_stats *st)
+{
+ void *ptr = alloc_bytes(size, str);
+ if (ptr) {
+ st->st_curr_cnt++;
+ st->st_total_cnt++;
+ if (size > st->st_maxsz) st->st_maxsz=size;
+ }
+ return ptr;
+}
+#define ALLOC_BYTES_ST(z,s,st) alloc_bytes_st(z, s, &st);
+#define PFREE_ST(p,st) do { st.st_curr_cnt--; pfree(p); } while (0);
+
+#else
+
+#define ALLOC_BYTES_ST(z,s,n) alloc_bytes(z, s);
+#define PFREE_ST(p,n) pfree(p);
+
+#endif /* NO_DB_OPS_STATS */
+/* Initialize db object
+ * max_trans and max_attrs can be 0, will be dynamically expanded
+ * as a result of "add" operations
+ */
+int
+db_prop_init(struct db_context *ctx, u_int8_t protoid, int max_trans, int max_attrs)
+{
+ int ret=-1;
+
+ ctx->trans0 = NULL;
+ ctx->attrs0 = NULL;
+
+ if (max_trans > 0) { /* quite silly if not */
+ ctx->trans0 = ALLOC_BYTES_ST ( sizeof (struct db_trans) * max_trans,
+ "db_context->trans", db_trans_st);
+ if (!ctx->trans0) goto out;
+ }
+
+ if (max_attrs > 0) { /* quite silly if not */
+ ctx->attrs0 = ALLOC_BYTES_ST (sizeof (struct db_attr) * max_attrs,
+ "db_context->attrs", db_attrs_st);
+ if (!ctx->attrs0) goto out;
+ }
+ ret = 0;
+out:
+ if (ret < 0 && ctx->trans0) {
+ PFREE_ST(ctx->trans0, db_trans_st);
+ ctx->trans0 = NULL;
+ }
+ ctx->max_trans = max_trans;
+ ctx->max_attrs = max_attrs;
+ ctx->trans_cur = ctx->trans0;
+ ctx->attrs_cur = ctx->attrs0;
+ ctx->prop.protoid = protoid;
+ ctx->prop.trans = ctx->trans0;
+ ctx->prop.trans_cnt = 0;
+ return ret;
+}
+
+/* Expand storage for transforms by number delta_trans */
+static int
+db_trans_expand(struct db_context *ctx, int delta_trans)
+{
+ int ret = -1;
+ struct db_trans *new_trans, *old_trans;
+ int max_trans = ctx->max_trans + delta_trans;
+ int offset;
+
+ old_trans = ctx->trans0;
+ new_trans = ALLOC_BYTES_ST ( sizeof (struct db_trans) * max_trans,
+ "db_context->trans (expand)", db_trans_st);
+ if (!new_trans)
+ goto out;
+ memcpy(new_trans, old_trans, ctx->max_trans * sizeof(struct db_trans));
+
+ /* update trans0 (obviously) */
+ ctx->trans0 = ctx->prop.trans = new_trans;
+ /* update trans_cur (by offset) */
+ offset = (char *)(new_trans) - (char *)(old_trans);
+
+ {
+ char *cctx = (char *)(ctx->trans_cur);
+
+ cctx += offset;
+ ctx->trans_cur = (struct db_trans *)cctx;
+ }
+ /* update elem count */
+ ctx->max_trans = max_trans;
+ PFREE_ST(old_trans, db_trans_st);
+ ret = 0;
+out:
+ return ret;
+}
+/*
+ * Expand storage for attributes by delta_attrs number AND
+ * rewrite trans->attr pointers
+ */
+static int
+db_attrs_expand(struct db_context *ctx, int delta_attrs)
+{
+ int ret = -1;
+ struct db_attr *new_attrs, *old_attrs;
+ struct db_trans *t;
+ int ti;
+ int max_attrs = ctx->max_attrs + delta_attrs;
+ int offset;
+
+ old_attrs = ctx->attrs0;
+ new_attrs = ALLOC_BYTES_ST ( sizeof (struct db_attr) * max_attrs,
+ "db_context->attrs (expand)", db_attrs_st);
+ if (!new_attrs)
+ goto out;
+
+ memcpy(new_attrs, old_attrs, ctx->max_attrs * sizeof(struct db_attr));
+
+ /* update attrs0 and attrs_cur (obviously) */
+ offset = (char *)(new_attrs) - (char *)(old_attrs);
+
+ {
+ char *actx = (char *)(ctx->attrs0);
+
+ actx += offset;
+ ctx->attrs0 = (struct db_attr *)actx;
+
+ actx = (char *)ctx->attrs_cur;
+ actx += offset;
+ ctx->attrs_cur = (struct db_attr *)actx;
+ }
+
+ /* for each transform, rewrite attrs pointer by offsetting it */
+ for (t=ctx->prop.trans, ti=0; ti < ctx->prop.trans_cnt; t++, ti++) {
+ char *actx = (char *)(t->attrs);
+
+ actx += offset;
+ t->attrs = (struct db_attr *)actx;
+ }
+ /* update elem count */
+ ctx->max_attrs = max_attrs;
+ PFREE_ST(old_attrs, db_attrs_st);
+ ret = 0;
+out:
+ return ret;
+}
+/* Allocate a new db object */
+struct db_context *
+db_prop_new(u_int8_t protoid, int max_trans, int max_attrs)
+{
+ struct db_context *ctx;
+ ctx = ALLOC_BYTES_ST ( sizeof (struct db_context), "db_context", db_context_st);
+ if (!ctx) goto out;
+
+ if (db_prop_init(ctx, protoid, max_trans, max_attrs) < 0) {
+ PFREE_ST(ctx, db_context_st);
+ ctx=NULL;
+ }
+out:
+ return ctx;
+}
+/* Free a db object */
+void
+db_destroy(struct db_context *ctx)
+{
+ if (ctx->trans0) PFREE_ST(ctx->trans0, db_trans_st);
+ if (ctx->attrs0) PFREE_ST(ctx->attrs0, db_attrs_st);
+ PFREE_ST(ctx, db_context_st);
+}
+/* Start a new transform, expand trans0 is needed */
+int
+db_trans_add(struct db_context *ctx, u_int8_t transid)
+{
+ /* skip incrementing current trans pointer the 1st time*/
+ if (ctx->trans_cur && ctx->trans_cur->attr_cnt)
+ ctx->trans_cur++;
+ /*
+ * Strategy: if more space is needed, expand by
+ * <current_size>/2 + 1
+ *
+ * This happens to produce a "reasonable" sequence
+ * after few allocations, eg.:
+ * 0,1,2,4,8,13,20,31,47
+ */
+ if ((ctx->trans_cur - ctx->trans0) >= ctx->max_trans) {
+ /* XXX:jjo if fails should shout and flag it */
+ if (db_trans_expand(ctx, ctx->max_trans/2 + 1)<0)
+ return -1;
+ }
+ ctx->trans_cur->transid = transid;
+ ctx->trans_cur->attrs=ctx->attrs_cur;
+ ctx->trans_cur->attr_cnt = 0;
+ ctx->prop.trans_cnt++;
+ return 0;
+}
+/* Add attr copy to current transform, expanding attrs0 if needed */
+int
+db_attr_add(struct db_context *ctx, const struct db_attr *a)
+{
+ /*
+ * Strategy: if more space is needed, expand by
+ * <current_size>/2 + 1
+ */
+ if ((ctx->attrs_cur - ctx->attrs0) >= ctx->max_attrs) {
+ /* XXX:jjo if fails should shout and flag it */
+ if (db_attrs_expand(ctx, ctx->max_attrs/2 + 1) < 0)
+ return -1;
+ }
+ *ctx->attrs_cur++=*a;
+ ctx->trans_cur->attr_cnt++;
+ return 0;
+}
+/* Add attr copy (by value) to current transform,
+ * expanding attrs0 if needed, just calls db_attr_add().
+ */
+int
+db_attr_add_values(struct db_context *ctx, u_int16_t type, u_int16_t val)
+{
+ struct db_attr attr;
+ attr.type = type;
+ attr.val = val;
+ return db_attr_add (ctx, &attr);
+}
+#ifndef NO_DB_OPS_STATS
+int
+db_ops_show_status(void)
+{
+ whack_log(RC_COMMENT, "stats " __FILE__ ": "
+ DB_OPS_STATS_DESC " :"
+ DB_OPS_STATS_STR("context")
+ DB_OPS_STATS_STR("trans")
+ DB_OPS_STATS_STR("attrs"),
+ DB_OPS_STATS_F(db_context_st),
+ DB_OPS_STATS_F(db_trans_st),
+ DB_OPS_STATS_F(db_attrs_st)
+ );
+ return 0;
+}
+#endif /* NO_DB_OPS_STATS */
+/*
+ * From below to end just testing stuff ....
+ */
+#ifdef TEST
+static void db_prop_print(struct db_prop *p)
+{
+ struct db_trans *t;
+ struct db_attr *a;
+ int ti, ai;
+ enum_names *n, *n_at, *n_av;
+ printf("protoid=\"%s\"\n", enum_name(&protocol_names, p->protoid));
+ for (ti=0, t=p->trans; ti< p->trans_cnt; ti++, t++) {
+ switch( t->transid) {
+ case PROTO_ISAKMP:
+ n=&isakmp_transformid_names;break;
+ case PROTO_IPSEC_ESP:
+ n=&esp_transformid_names;break;
+ default:
+ continue;
+ }
+ printf(" transid=\"%s\"\n",
+ enum_name(n, t->transid));
+ for (ai=0, a=t->attrs; ai < t->attr_cnt; ai++, a++) {
+ int i;
+ switch( t->transid) {
+ case PROTO_ISAKMP:
+ n_at=&oakley_attr_names;
+ i=a->type|ISAKMP_ATTR_AF_TV;
+ n_av=oakley_attr_val_descs[(i)&ISAKMP_ATTR_RTYPE_MASK];
+ break;
+ case PROTO_IPSEC_ESP:
+ n_at=&ipsec_attr_names;
+ i=a->type|ISAKMP_ATTR_AF_TV;
+ n_av=ipsec_attr_val_descs[(i)&ISAKMP_ATTR_RTYPE_MASK];
+ break;
+ default:
+ continue;
+ }
+ printf(" type=\"%s\" value=\"%s\"\n",
+ enum_name(n_at, i),
+ enum_name(n_av, a->val));
+ }
+ }
+
+}
+static void db_print(struct db_context *ctx)
+{
+ printf("trans_cur diff=%d, attrs_cur diff=%d\n",
+ ctx->trans_cur - ctx->trans0,
+ ctx->attrs_cur - ctx->attrs0);
+ db_prop_print(&ctx->prop);
+}
+
+void
+passert_fail(const char *pred_str, const char *file_str, unsigned long line_no);
+void abort(void);
+void
+passert_fail(const char *pred_str, const char *file_str, unsigned long line_no)
+{
+ fprintf(stderr, "ASSERTION FAILED at %s:%lu: %s", file_str, line_no, pred_str);
+ abort(); /* exiting correctly doesn't always work */
+}
+int main(void) {
+ struct db_context *ctx=db_prop_new(PROTO_ISAKMP, 0, 0);
+ db_trans_add(ctx, KEY_IKE);
+ db_attr_add_values(ctx, OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC);
+ db_attr_add_values(ctx, OAKLEY_HASH_ALGORITHM, OAKLEY_MD5);
+ db_attr_add_values(ctx, OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_SIG);
+ db_attr_add_values(ctx, OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024);
+ db_trans_add(ctx, KEY_IKE);
+ db_attr_add_values(ctx, OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_AES_CBC);
+ db_attr_add_values(ctx, OAKLEY_HASH_ALGORITHM, OAKLEY_MD5);
+ db_attr_add_values(ctx, OAKLEY_AUTHENTICATION_METHOD, OAKLEY_PRESHARED_KEY);
+ db_attr_add_values(ctx, OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1536);
+ db_trans_add(ctx, ESP_3DES);
+ db_attr_add_values(ctx, AUTH_ALGORITHM, AUTH_ALGORITHM_HMAC_SHA1);
+ db_print(ctx);
+ db_destroy(ctx);
+ return 0;
+}
+#endif
diff --git a/src/pluto/db_ops.h b/src/pluto/db_ops.h
new file mode 100644
index 000000000..433e75280
--- /dev/null
+++ b/src/pluto/db_ops.h
@@ -0,0 +1,56 @@
+/* Dynamic db (proposal, transforms, attributes) handling.
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: db_ops.h,v 1.3 2004/09/17 12:37:37 as Exp $
+ */
+
+#ifndef _DB_OPS_H
+#define _DB_OPS_H
+
+/*
+ * Main db object, (quite proposal "oriented")
+ */
+#ifndef NO_DB_CONTEXT
+struct db_context {
+ struct db_prop prop; /* proposal buffer (not pointer) */
+ struct db_trans *trans0; /* transf. list, dynamically sized */
+ struct db_trans *trans_cur; /* current transform ptr */
+ struct db_attr *attrs0; /* attr. list, dynamically sized */
+ struct db_attr *attrs_cur; /* current attribute ptr */
+ int max_trans; /* size of trans list */
+ int max_attrs; /* size of attrs list */
+};
+/*
+ * Allocate a new db object
+ */
+struct db_context * db_prop_new(u_int8_t protoid, int max_trans, int max_attrs);
+/* Initialize object for proposal building */
+int db_prop_init(struct db_context *ctx, u_int8_t protoid, int max_trans, int max_attrs);
+/* Free all resourses for this db */
+void db_destroy(struct db_context *ctx);
+
+/* Start a new transform */
+int db_trans_add(struct db_context *ctx, u_int8_t transid);
+/* Add a new attribute by copying db_attr content */
+int db_attr_add(struct db_context *db_ctx, const struct db_attr *attr);
+/* Add a new attribute by value */
+int db_attr_add_values(struct db_context *ctx, u_int16_t type, u_int16_t val);
+
+/* Get proposal from db object */
+static __inline__ struct db_prop *db_prop_get(struct db_context *ctx) {
+ return &ctx->prop;
+}
+/* Show stats (allocation, etc) */
+#endif /* NO_DB_CONTEXT */
+int db_ops_show_status(void);
+#endif /* _DB_OPS_H */
diff --git a/src/pluto/defs.c b/src/pluto/defs.c
new file mode 100644
index 000000000..9ae32a480
--- /dev/null
+++ b/src/pluto/defs.c
@@ -0,0 +1,374 @@
+/* misc. universal things
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: defs.c,v 1.9 2006/01/04 21:00:43 as Exp $
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "whack.h" /* for RC_LOG_SERIOUS */
+
+const chunk_t empty_chunk = { NULL, 0 };
+
+bool
+all_zero(const unsigned char *m, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i != len; i++)
+ if (m[i] != '\0')
+ return FALSE;
+ return TRUE;
+}
+
+/* memory allocation
+ *
+ * LEAK_DETECTIVE puts a wrapper around each allocation and maintains
+ * a list of live ones. If a dead one is freed, an assertion MIGHT fail.
+ * If the live list is currupted, that will often be detected.
+ * In the end, report_leaks() is called, and the names of remaining
+ * live allocations are printed. At the moment, it is hoped, not that
+ * the list is empty, but that there will be no surprises.
+ *
+ * Accepted Leaks:
+ * - "struct iface" and "device name" (for "discovered" net interfaces)
+ * - "struct event in event_schedule()" (events not associated with states)
+ * - "Pluto lock name" (one only, needed until end -- why bother?)
+ */
+
+#ifdef LEAK_DETECTIVE
+
+/* this magic number is 3671129837 decimal (623837458 complemented) */
+#define LEAK_MAGIC 0xDAD0FEEDul
+
+union mhdr {
+ struct {
+ const char *name;
+ union mhdr *older, *newer;
+ unsigned long magic;
+ } i; /* info */
+ unsigned long junk; /* force maximal alignment */
+};
+
+static union mhdr *allocs = NULL;
+
+void *alloc_bytes(size_t size, const char *name)
+{
+ union mhdr *p = malloc(sizeof(union mhdr) + size);
+
+ if (p == NULL)
+ exit_log("unable to malloc %lu bytes for %s"
+ , (unsigned long) size, name);
+ p->i.name = name;
+ p->i.older = allocs;
+ if (allocs != NULL)
+ allocs->i.newer = p;
+ allocs = p;
+ p->i.newer = NULL;
+ p->i.magic = LEAK_MAGIC;
+
+ memset(p+1, '\0', size);
+ return p+1;
+}
+
+void *
+clone_bytes(const void *orig, size_t size, const char *name)
+{
+ void *p = alloc_bytes(size, name);
+
+ memcpy(p, orig, size);
+ return p;
+}
+
+void
+pfree(void *ptr)
+{
+ union mhdr *p;
+
+ passert(ptr != NULL);
+ p = ((union mhdr *)ptr) - 1;
+ passert(p->i.magic == LEAK_MAGIC);
+ if (p->i.older != NULL)
+ {
+ passert(p->i.older->i.newer == p);
+ p->i.older->i.newer = p->i.newer;
+ }
+ if (p->i.newer == NULL)
+ {
+ passert(p == allocs);
+ allocs = p->i.older;
+ }
+ else
+ {
+ passert(p->i.newer->i.older == p);
+ p->i.newer->i.older = p->i.older;
+ }
+ p->i.magic = ~LEAK_MAGIC;
+ free(p);
+}
+
+void
+report_leaks(void)
+{
+ union mhdr
+ *p = allocs,
+ *pprev = NULL;
+ unsigned long n = 0;
+
+ while (p != NULL)
+ {
+ passert(p->i.magic == LEAK_MAGIC);
+ passert(pprev == p->i.newer);
+ pprev = p;
+ p = p->i.older;
+ n++;
+ if (p == NULL || pprev->i.name != p->i.name)
+ {
+ if (n != 1)
+ plog("leak: %lu * %s", n, pprev->i.name);
+ else
+ plog("leak: %s", pprev->i.name);
+ n = 0;
+ }
+ }
+}
+
+#else /* !LEAK_DETECTIVE */
+
+void *alloc_bytes(size_t size, const char *name)
+{
+ void *p = malloc(size);
+
+ if (p == NULL)
+ exit_log("unable to malloc %lu bytes for %s"
+ , (unsigned long) size, name);
+ memset(p, '\0', size);
+ return p;
+}
+
+void *clone_bytes(const void *orig, size_t size, const char *name)
+{
+ void *p = malloc(size);
+
+ if (p == NULL)
+ exit_log("unable to malloc %lu bytes for %s"
+ , (unsigned long) size, name);
+ memcpy(p, orig, size);
+ return p;
+}
+#endif /* !LEAK_DETECTIVE */
+
+/* Note that there may be as many as six IDs that are temporary at
+ * one time before unsharing the two ends of a connection. So we need
+ * at least six temporary buffers for DER_ASN1_DN IDs.
+ * We rotate them. Be careful!
+ */
+#define MAX_BUF 10
+
+char*
+temporary_cyclic_buffer(void)
+{
+ static char buf[MAX_BUF][BUF_LEN]; /* MAX_BUF internal buffers */
+ static int counter = 0; /* cyclic counter */
+
+ if (++counter == MAX_BUF) counter = 0; /* next internal buffer */
+ return buf[counter]; /* assign temporary buffer */
+}
+
+/* concatenates two sub paths into a string with a maximum size of BUF_LEN
+ * use for temporary storage only
+ */
+const char*
+concatenate_paths(const char *a, const char *b)
+{
+ char *c;
+
+ if (*b == '/' || *b == '.')
+ return b;
+
+ c = temporary_cyclic_buffer();
+ snprintf(c, BUF_LEN, "%s/%s", a, b);
+ return c;
+}
+
+/* compare two chunks, returns zero if a equals b
+ * negative/positive if a is earlier/later in the alphabet than b
+ */
+int
+cmp_chunk(chunk_t a, chunk_t b)
+{
+ int cmp_len, len, cmp_value;
+
+ cmp_len = a.len - b.len;
+ len = (cmp_len < 0)? a.len : b.len;
+ cmp_value = memcmp(a.ptr, b.ptr, len);
+
+ return (cmp_value == 0)? cmp_len : cmp_value;
+};
+
+/* moves a chunk to a memory position, chunk is freed afterwards
+ * position pointer is advanced after the insertion point
+ */
+void
+mv_chunk(u_char **pos, chunk_t content)
+{
+ if (content.len > 0)
+ {
+ chunkcpy(*pos, content);
+ freeanychunk(content);
+ }
+}
+
+/*
+ * write the binary contents of a chunk_t to a file
+ */
+bool
+write_chunk(const char *filename, const char *label, chunk_t ch
+, mode_t mask, bool force)
+{
+ mode_t oldmask;
+ FILE *fd;
+
+ if (!force)
+ {
+ fd = fopen(filename, "r");
+ if (fd)
+ {
+ fclose(fd);
+ plog(" %s file '%s' already exists", label, filename);
+ return FALSE;
+ }
+ }
+
+ /* set umask */
+ oldmask = umask(mask);
+
+ fd = fopen(filename, "w");
+
+ if (fd)
+ {
+ fwrite(ch.ptr, sizeof(u_char), ch.len, fd);
+ fclose(fd);
+ plog(" written %s file '%s' (%d bytes)", label, filename, (int)ch.len);
+ umask(oldmask);
+ return TRUE;
+ }
+ else
+ {
+ plog(" could not open %s file '%s' for writing", label, filename);
+ umask(oldmask);
+ return FALSE;
+ }
+}
+
+/* Names of the months */
+
+static const char* months[] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+
+/*
+ * Display a date either in local or UTC time
+ */
+char*
+timetoa(const time_t *time, bool utc)
+{
+ static char buf[TIMETOA_BUF];
+
+ if (*time == UNDEFINED_TIME)
+ 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;
+}
+
+/* checks if the expiration date has been reached and
+ * warns during the warning_interval of the imminent
+ * expiry. strict=TRUE declares a fatal error,
+ * strict=FALSE issues a warning upon expiry.
+ */
+const char*
+check_expiry(time_t expiration_date, int warning_interval, bool strict)
+{
+ time_t now;
+ int time_left;
+
+ if (expiration_date == UNDEFINED_TIME)
+ return "ok (expires never)";
+
+ /* determine the current time */
+ time(&now);
+
+ time_left = (expiration_date - now);
+ if (time_left < 0)
+ return strict? "fatal (expired)" : "warning (expired)";
+
+ if (time_left > 86400*warning_interval)
+ return "ok";
+ {
+ static char buf[35]; /* temporary storage */
+ const char* unit = "second";
+
+ if (time_left > 172800)
+ {
+ time_left /= 86400;
+ unit = "day";
+ }
+ else if (time_left > 7200)
+ {
+ time_left /= 3600;
+ unit = "hour";
+ }
+ else if (time_left > 120)
+ {
+ time_left /= 60;
+ unit = "minute";
+ }
+ snprintf(buf, 35, "warning (expires in %d %s%s)", time_left,
+ unit, (time_left == 1)?"":"s");
+ return buf;
+ }
+}
+
+
+/*
+ * Filter eliminating the directory entries '.' and '..'
+ */
+int
+file_select(const struct dirent *entry)
+{
+ return strcmp(entry->d_name, "." ) &&
+ strcmp(entry->d_name, "..");
+}
+
+
diff --git a/src/pluto/defs.h b/src/pluto/defs.h
new file mode 100644
index 000000000..3bfb29a22
--- /dev/null
+++ b/src/pluto/defs.h
@@ -0,0 +1,145 @@
+/* misc. universal things
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: defs.h,v 1.10 2006/01/04 21:00:43 as Exp $
+ */
+
+#ifndef _DEFS_H
+#define _DEFS_H
+
+#include <sys/types.h>
+
+#ifdef KLIPS
+# define USED_BY_KLIPS /* ignore */
+#else
+# define USED_BY_KLIPS UNUSED
+#endif
+
+#ifdef DEBUG
+# define USED_BY_DEBUG /* ignore */
+#else
+# define USED_BY_DEBUG UNUSED
+#endif
+
+/* Length of temporary buffers */
+
+#define BUF_LEN 512
+
+/* type of serial number of a state object
+ * Needed in connections.h and state.h; here to simplify dependencies.
+ */
+typedef unsigned long so_serial_t;
+#define SOS_NOBODY 0 /* null serial number */
+#define SOS_FIRST 1 /* first normal serial number */
+
+/* memory allocation */
+
+extern void *alloc_bytes(size_t size, const char *name);
+#define alloc_thing(thing, name) (alloc_bytes(sizeof(thing), (name)))
+
+extern void *clone_bytes(const void *orig, size_t size, const char *name);
+#define clone_thing(orig, name) clone_bytes((const void *)&(orig), sizeof(orig), (name))
+#define clone_str(str, name) \
+ ((str) == NULL? NULL : clone_bytes((str), strlen((str))+1, (name)))
+
+#ifdef LEAK_DETECTIVE
+ extern void pfree(void *ptr);
+ extern void report_leaks(void);
+#else
+# define pfree(ptr) free(ptr) /* ordinary stdc free */
+#endif
+#define pfreeany(p) { if ((p) != NULL) pfree(p); }
+#define replace(p, q) { pfreeany(p); (p) = (q); }
+
+
+/* chunk is a simple pointer-and-size abstraction */
+
+struct chunk {
+ u_char *ptr;
+ size_t len;
+ };
+typedef struct chunk chunk_t;
+
+#define setchunk(ch, addr, size) { (ch).ptr = (addr); (ch).len = (size); }
+#define strchunk(str) { str, sizeof(str) }
+/* NOTE: freeanychunk, unlike pfreeany, NULLs .ptr */
+#define freeanychunk(ch) { pfreeany((ch).ptr); (ch).ptr = NULL; }
+#define clonetochunk(ch, addr, size, name) \
+ { (ch).ptr = clone_bytes((addr), (ch).len = (size), name); }
+#define clonereplacechunk(ch, addr, size, name) \
+ { pfreeany((ch).ptr); clonetochunk(ch, addr, size, name); }
+#define chunkcpy(dst, chunk) \
+ { memcpy(dst, chunk.ptr, chunk.len); dst += chunk.len;}
+#define same_chunk(a, b) \
+ ( (a).len == (b).len && memcmp((a).ptr, (b).ptr, (b).len) == 0 )
+
+extern char* temporary_cyclic_buffer(void);
+extern const char* concatenate_paths(const char *a, const char *b);
+
+extern const chunk_t empty_chunk;
+
+/* compare two chunks */
+extern int cmp_chunk(chunk_t a, chunk_t b);
+
+/* move a chunk to a memory position and free it after insertion */
+extern void mv_chunk(u_char **pos, chunk_t content);
+
+/* write the binary contents of a chunk_t to a file */
+extern bool write_chunk(const char *filename, const char *label, chunk_t ch
+ ,mode_t mask, bool force);
+
+/* display a date either in local or UTC time */
+extern char* timetoa(const time_t *time, bool utc);
+
+/* warns a predefined interval before expiry */
+extern const char* check_expiry(time_t expiration_date,
+ int warning_interval, bool strict);
+
+#define MAX_PROMPT_PASS_TRIALS 5
+#define PROMPT_PASS_LEN 64
+
+/* struct used to prompt for a secret passphrase
+ * from a console with file descriptor fd
+ */
+typedef struct {
+ char secret[PROMPT_PASS_LEN+1];
+ bool prompt;
+ int fd;
+} prompt_pass_t;
+
+/* no time defined in time_t */
+#define UNDEFINED_TIME 0
+
+/* size of timetoa string buffer */
+#define TIMETOA_BUF 30
+
+/* filter eliminating the directory entries '.' and '..' */
+typedef struct dirent dirent_t;
+extern int file_select(const dirent_t *entry);
+
+/* cleanly exit Pluto */
+
+extern void exit_pluto(int /*status*/) NEVER_RETURNS;
+
+
+/* zero all bytes */
+#define zero(x) memset((x), '\0', sizeof(*(x)))
+
+/* are all bytes 0? */
+extern bool all_zero(const unsigned char *m, size_t len);
+
+/* pad_up(n, m) is the amount to add to n to make it a multiple of m */
+#define pad_up(n, m) (((m) - 1) - (((n) + (m) - 1) % (m)))
+
+#endif /* _DEFS_H */
diff --git a/src/pluto/demux.c b/src/pluto/demux.c
new file mode 100644
index 000000000..7e59b184d
--- /dev/null
+++ b/src/pluto/demux.c
@@ -0,0 +1,2499 @@
+/* demultiplex incoming IKE messages
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: demux.c,v 1.14 2006/06/22 11:58:25 as Exp $
+ */
+
+/* Ordering Constraints on Payloads
+ *
+ * rfc2409: The Internet Key Exchange (IKE)
+ *
+ * 5 Exchanges:
+ * "The SA payload MUST precede all other payloads in a phase 1 exchange."
+ *
+ * "Except where otherwise noted, there are no requirements for ISAKMP
+ * payloads in any message to be in any particular order."
+ *
+ * 5.3 Phase 1 Authenticated With a Revised Mode of Public Key Encryption:
+ *
+ * "If the HASH payload is sent it MUST be the first payload of the
+ * second message exchange and MUST be followed by the encrypted
+ * nonce. If the HASH payload is not sent, the first payload of the
+ * second message exchange MUST be the encrypted nonce."
+ *
+ * "Save the requirements on the location of the optional HASH payload
+ * and the mandatory nonce payload there are no further payload
+ * requirements. All payloads-- in whatever order-- following the
+ * encrypted nonce MUST be encrypted with Ke_i or Ke_r depending on the
+ * direction."
+ *
+ * 5.5 Phase 2 - Quick Mode
+ *
+ * "In Quick Mode, a HASH payload MUST immediately follow the ISAKMP
+ * header and a SA payload MUST immediately follow the HASH."
+ * [NOTE: there may be more than one SA payload, so this is not
+ * totally reasonable. Probably all SAs should be so constrained.]
+ *
+ * "If ISAKMP is acting as a client negotiator on behalf of another
+ * party, the identities of the parties MUST be passed as IDci and
+ * then IDcr."
+ *
+ * "With the exception of the HASH, SA, and the optional ID payloads,
+ * there are no payload ordering restrictions on Quick Mode."
+ */
+
+/* Unfolding of Identity -- a central mystery
+ *
+ * This concerns Phase 1 identities, those of the IKE hosts.
+ * These are the only ones that are authenticated. Phase 2
+ * identities are for IPsec SAs.
+ *
+ * There are three case of interest:
+ *
+ * (1) We initiate, based on a whack command specifying a Connection.
+ * We know the identity of the peer from the Connection.
+ *
+ * (2) (to be implemented) we initiate based on a flow from our client
+ * to some IP address.
+ * We immediately know one of the peer's client IP addresses from
+ * the flow. We must use this to figure out the peer's IP address
+ * and Id. To be solved.
+ *
+ * (3) We respond to an IKE negotiation.
+ * We immediately know the peer's IP address.
+ * We get an ID Payload in Main I2.
+ *
+ * Unfortunately, this is too late for a number of things:
+ * - the ISAKMP SA proposals have already been made (Main I1)
+ * AND one accepted (Main R1)
+ * - the SA includes a specification of the type of ID
+ * authentication so this is negotiated without being told the ID.
+ * - with Preshared Key authentication, Main I2 is encrypted
+ * using the key, so it cannot be decoded to reveal the ID
+ * without knowing (or guessing) which key to use.
+ *
+ * There are three reasonable choices here for the responder:
+ * + assume that the initiator is making wise offers since it
+ * knows the IDs involved. We can balk later (but not gracefully)
+ * when we find the actual initiator ID
+ * + attempt to infer identity by IP address. Again, we can balk
+ * when the true identity is revealed. Actually, it is enough
+ * to infer properties of the identity (eg. SA properties and
+ * PSK, if needed).
+ * + make all properties universal so discrimination based on
+ * identity isn't required. For example, always accept the same
+ * kinds of encryption. Accept Public Key Id authentication
+ * since the Initiator presumably has our public key and thinks
+ * we must have / can find his. This approach is weakest
+ * for preshared key since the actual key must be known to
+ * decrypt the Initiator's ID Payload.
+ * These choices can be blended. For example, a class of Identities
+ * can be inferred, sufficient to select a preshared key but not
+ * sufficient to infer a unique identity.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h> /* only used for belt-and-suspenders select call */
+#include <sys/poll.h> /* only used for forensic poll call */
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/queue.h>
+
+#if defined(IP_RECVERR) && defined(MSG_ERRQUEUE)
+# include <asm/types.h> /* for __u8, __u32 */
+# include <linux/errqueue.h>
+# include <sys/uio.h> /* struct iovec */
+#endif
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "cookie.h"
+#include "connections.h"
+#include "state.h"
+#include "packet.h"
+#include "md5.h"
+#include "sha1.h"
+#include "crypto.h" /* requires sha1.h and md5.h */
+#include "ike_alg.h"
+#include "log.h"
+#include "demux.h" /* needs packet.h */
+#include "ipsec_doi.h" /* needs demux.h and state.h */
+#include "timer.h"
+#include "whack.h" /* requires connections.h */
+#include "server.h"
+#include "nat_traversal.h"
+#include "vendor.h"
+#include "modecfg.h"
+
+/* This file does basic header checking and demux of
+ * incoming packets.
+ */
+
+/* forward declarations */
+static bool read_packet(struct msg_digest *md);
+static void process_packet(struct msg_digest **mdp);
+
+/* Reply messages are built in this buffer.
+ * Only one state transition function can be using it at a time
+ * so suspended STFs must save and restore it.
+ * It could be an auto variable of complete_state_transition except for the fact
+ * that when a suspended STF resumes, its reply message buffer
+ * must be at the same location -- there are pointers into it.
+ */
+u_int8_t reply_buffer[MAX_OUTPUT_UDP_SIZE];
+
+/* state_microcode is a tuple of information parameterizing certain
+ * centralized processing of a packet. For example, it roughly
+ * specifies what payloads are expected in this message.
+ * The microcode is selected primarily based on the state.
+ * In Phase 1, the payload structure often depends on the
+ * authentication technique, so that too plays a part in selecting
+ * the state_microcode to use.
+ */
+
+struct state_microcode {
+ enum state_kind state, next_state;
+ lset_t flags;
+ lset_t req_payloads; /* required payloads (allows just one) */
+ lset_t opt_payloads; /* optional payloads (any mumber) */
+ /* if not ISAKMP_NEXT_NONE, process_packet will emit HDR with this as np */
+ u_int8_t first_out_payload;
+ enum event_type timeout_event;
+ state_transition_fn *processor;
+};
+
+/* State Microcode Flags, in several groups */
+
+/* Oakley Auth values: to which auth values does this entry apply?
+ * Most entries will use SMF_ALL_AUTH because they apply to all.
+ * Note: SMF_ALL_AUTH matches 0 for those circumstances when no auth
+ * has been set.
+ */
+#define SMF_ALL_AUTH LRANGE(0, OAKLEY_AUTH_ROOF-1)
+#define SMF_PSK_AUTH LELEM(OAKLEY_PRESHARED_KEY)
+#define SMF_DS_AUTH (LELEM(OAKLEY_DSS_SIG) | LELEM(OAKLEY_RSA_SIG))
+#define SMF_PKE_AUTH (LELEM(OAKLEY_RSA_ENC) | LELEM(OAKLEY_ELGAMAL_ENC))
+#define SMF_RPKE_AUTH (LELEM(OAKLEY_RSA_ENC_REV) | LELEM(OAKLEY_ELGAMAL_ENC_REV))
+
+/* misc flags */
+
+#define SMF_INITIATOR LELEM(OAKLEY_AUTH_ROOF + 0)
+#define SMF_FIRST_ENCRYPTED_INPUT LELEM(OAKLEY_AUTH_ROOF + 1)
+#define SMF_INPUT_ENCRYPTED LELEM(OAKLEY_AUTH_ROOF + 2)
+#define SMF_OUTPUT_ENCRYPTED LELEM(OAKLEY_AUTH_ROOF + 3)
+#define SMF_RETRANSMIT_ON_DUPLICATE LELEM(OAKLEY_AUTH_ROOF + 4)
+
+#define SMF_ENCRYPTED (SMF_INPUT_ENCRYPTED | SMF_OUTPUT_ENCRYPTED)
+
+/* this state generates a reply message */
+#define SMF_REPLY LELEM(OAKLEY_AUTH_ROOF + 5)
+
+/* this state completes P1, so any pending P2 negotiations should start */
+#define SMF_RELEASE_PENDING_P2 LELEM(OAKLEY_AUTH_ROOF + 6)
+
+/* end of flags */
+
+
+static state_transition_fn /* forward declaration */
+ unexpected,
+ informational;
+
+/* state_microcode_table is a table of all state_microcode tuples.
+ * It must be in order of state (the first element).
+ * After initialization, ike_microcode_index[s] points to the
+ * first entry in state_microcode_table for state s.
+ * Remember that each state name in Main or Quick Mode describes
+ * what has happened in the past, not what this message is.
+ */
+
+static const struct state_microcode
+ *ike_microcode_index[STATE_IKE_ROOF - STATE_IKE_FLOOR];
+
+static const struct state_microcode state_microcode_table[] = {
+#define PT(n) ISAKMP_NEXT_##n
+#define P(n) LELEM(PT(n))
+
+ /***** Phase 1 Main Mode *****/
+
+ /* No state for main_outI1: --> HDR, SA */
+
+ /* STATE_MAIN_R0: I1 --> R1
+ * HDR, SA --> HDR, SA
+ */
+ { STATE_MAIN_R0, STATE_MAIN_R1
+ , SMF_ALL_AUTH | SMF_REPLY
+ , P(SA), P(VID) | P(CR), PT(NONE)
+ , EVENT_RETRANSMIT, main_inI1_outR1},
+
+ /* STATE_MAIN_I1: R1 --> I2
+ * HDR, SA --> auth dependent
+ * SMF_PSK_AUTH, SMF_DS_AUTH: --> HDR, KE, Ni
+ * SMF_PKE_AUTH:
+ * --> HDR, KE, [ HASH(1), ] <IDi1_b>PubKey_r, <Ni_b>PubKey_r
+ * SMF_RPKE_AUTH:
+ * --> HDR, [ HASH(1), ] <Ni_b>Pubkey_r, <KE_b>Ke_i, <IDi1_b>Ke_i [,<<Cert-I_b>Ke_i]
+ * Note: since we don't know auth at start, we cannot differentiate
+ * microcode entries based on it.
+ */
+ { STATE_MAIN_I1, STATE_MAIN_I2
+ , SMF_ALL_AUTH | SMF_INITIATOR | SMF_REPLY
+ , P(SA), P(VID) | P(CR), PT(NONE) /* don't know yet */
+ , EVENT_RETRANSMIT, main_inR1_outI2 },
+
+ /* STATE_MAIN_R1: I2 --> R2
+ * SMF_PSK_AUTH, SMF_DS_AUTH: HDR, KE, Ni --> HDR, KE, Nr
+ * SMF_PKE_AUTH: HDR, KE, [ HASH(1), ] <IDi1_b>PubKey_r, <Ni_b>PubKey_r
+ * --> HDR, KE, <IDr1_b>PubKey_i, <Nr_b>PubKey_i
+ * SMF_RPKE_AUTH:
+ * HDR, [ HASH(1), ] <Ni_b>Pubkey_r, <KE_b>Ke_i, <IDi1_b>Ke_i [,<<Cert-I_b>Ke_i]
+ * --> HDR, <Nr_b>PubKey_i, <KE_b>Ke_r, <IDr1_b>Ke_r
+ */
+ { STATE_MAIN_R1, STATE_MAIN_R2
+ , SMF_PSK_AUTH | SMF_DS_AUTH | SMF_REPLY
+ , P(KE) | P(NONCE), P(VID) | P(CR) | P(NATD_RFC), PT(KE)
+ , EVENT_RETRANSMIT, main_inI2_outR2 },
+
+ { STATE_MAIN_R1, STATE_UNDEFINED
+ , SMF_PKE_AUTH | SMF_REPLY
+ , P(KE) | P(ID) | P(NONCE), P(VID) | P(CR) | P(HASH), PT(KE)
+ , EVENT_RETRANSMIT, unexpected /* ??? not yet implemented */ },
+
+ { STATE_MAIN_R1, STATE_UNDEFINED
+ , SMF_RPKE_AUTH | SMF_REPLY
+ , P(NONCE) | P(KE) | P(ID), P(VID) | P(CR) | P(HASH) | P(CERT), PT(NONCE)
+ , EVENT_RETRANSMIT, unexpected /* ??? not yet implemented */ },
+
+ /* for states from here on, output message must be encrypted */
+
+ /* STATE_MAIN_I2: R2 --> I3
+ * SMF_PSK_AUTH: HDR, KE, Nr --> HDR*, IDi1, HASH_I
+ * SMF_DS_AUTH: HDR, KE, Nr --> HDR*, IDi1, [ CERT, ] SIG_I
+ * SMF_PKE_AUTH: HDR, KE, <IDr1_b>PubKey_i, <Nr_b>PubKey_i
+ * --> HDR*, HASH_I
+ * SMF_RPKE_AUTH: HDR, <Nr_b>PubKey_i, <KE_b>Ke_r, <IDr1_b>Ke_r
+ * --> HDR*, HASH_I
+ */
+ { STATE_MAIN_I2, STATE_MAIN_I3
+ , SMF_PSK_AUTH | SMF_DS_AUTH | SMF_INITIATOR | SMF_OUTPUT_ENCRYPTED | SMF_REPLY
+ , P(KE) | P(NONCE), P(VID) | P(CR) | P(NATD_RFC), PT(ID)
+ , EVENT_RETRANSMIT, main_inR2_outI3 },
+
+ { STATE_MAIN_I2, STATE_UNDEFINED
+ , SMF_PKE_AUTH | SMF_INITIATOR | SMF_OUTPUT_ENCRYPTED | SMF_REPLY
+ , P(KE) | P(ID) | P(NONCE), P(VID) | P(CR), PT(HASH)
+ , EVENT_RETRANSMIT, unexpected /* ??? not yet implemented */ },
+
+ { STATE_MAIN_I2, STATE_UNDEFINED
+ , SMF_ALL_AUTH | SMF_INITIATOR | SMF_OUTPUT_ENCRYPTED | SMF_REPLY
+ , P(NONCE) | P(KE) | P(ID), P(VID) | P(CR), PT(HASH)
+ , EVENT_RETRANSMIT, unexpected /* ??? not yet implemented */ },
+
+ /* for states from here on, input message must be encrypted */
+
+ /* STATE_MAIN_R2: I3 --> R3
+ * SMF_PSK_AUTH: HDR*, IDi1, HASH_I --> HDR*, IDr1, HASH_R
+ * SMF_DS_AUTH: HDR*, IDi1, [ CERT, ] SIG_I --> HDR*, IDr1, [ CERT, ] SIG_R
+ * SMF_PKE_AUTH, SMF_RPKE_AUTH: HDR*, HASH_I --> HDR*, HASH_R
+ */
+ { STATE_MAIN_R2, STATE_MAIN_R3
+ , SMF_PSK_AUTH | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED
+ | SMF_REPLY | SMF_RELEASE_PENDING_P2
+ , P(ID) | P(HASH), P(VID) | P(CR), PT(NONE)
+ , EVENT_SA_REPLACE, main_inI3_outR3 },
+
+ { STATE_MAIN_R2, STATE_MAIN_R3
+ , SMF_DS_AUTH | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED
+ | SMF_REPLY | SMF_RELEASE_PENDING_P2
+ , P(ID) | P(SIG), P(VID) | P(CR) | P(CERT), PT(NONE)
+ , EVENT_SA_REPLACE, main_inI3_outR3 },
+
+ { STATE_MAIN_R2, STATE_UNDEFINED
+ , SMF_PKE_AUTH | SMF_RPKE_AUTH | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED
+ | SMF_REPLY | SMF_RELEASE_PENDING_P2
+ , P(HASH), P(VID) | P(CR), PT(NONE)
+ , EVENT_SA_REPLACE, unexpected /* ??? not yet implemented */ },
+
+ /* STATE_MAIN_I3: R3 --> done
+ * SMF_PSK_AUTH: HDR*, IDr1, HASH_R --> done
+ * SMF_DS_AUTH: HDR*, IDr1, [ CERT, ] SIG_R --> done
+ * SMF_PKE_AUTH, SMF_RPKE_AUTH: HDR*, HASH_R --> done
+ * May initiate quick mode by calling quick_outI1
+ */
+ { STATE_MAIN_I3, STATE_MAIN_I4
+ , SMF_PSK_AUTH | SMF_INITIATOR
+ | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2
+ , P(ID) | P(HASH), P(VID) | P(CR), PT(NONE)
+ , EVENT_SA_REPLACE, main_inR3 },
+
+ { STATE_MAIN_I3, STATE_MAIN_I4
+ , SMF_DS_AUTH | SMF_INITIATOR
+ | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2
+ , P(ID) | P(SIG), P(VID) | P(CR) | P(CERT), PT(NONE)
+ , EVENT_SA_REPLACE, main_inR3 },
+
+ { STATE_MAIN_I3, STATE_UNDEFINED
+ , SMF_PKE_AUTH | SMF_RPKE_AUTH | SMF_INITIATOR
+ | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2
+ , P(HASH), P(VID) | P(CR), PT(NONE)
+ , EVENT_SA_REPLACE, unexpected /* ??? not yet implemented */ },
+
+ /* STATE_MAIN_R3: can only get here due to packet loss */
+ { STATE_MAIN_R3, STATE_UNDEFINED
+ , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_RETRANSMIT_ON_DUPLICATE
+ , LEMPTY, LEMPTY
+ , PT(NONE), EVENT_NULL, unexpected },
+
+ /* STATE_MAIN_I4: can only get here due to packet loss */
+ { STATE_MAIN_I4, STATE_UNDEFINED
+ , SMF_ALL_AUTH | SMF_INITIATOR | SMF_ENCRYPTED
+ , LEMPTY, LEMPTY
+ , PT(NONE), EVENT_NULL, unexpected },
+
+
+ /***** Phase 2 Quick Mode *****/
+
+ /* No state for quick_outI1:
+ * --> HDR*, HASH(1), SA, Nr [, KE ] [, IDci, IDcr ]
+ */
+
+ /* STATE_QUICK_R0:
+ * HDR*, HASH(1), SA, Ni [, KE ] [, IDci, IDcr ] -->
+ * HDR*, HASH(2), SA, Nr [, KE ] [, IDci, IDcr ]
+ * Installs inbound IPsec SAs.
+ * Because it may suspend for asynchronous DNS, first_out_payload
+ * is set to NONE to suppress early emission of HDR*.
+ * ??? it is legal to have multiple SAs, but we don't support it yet.
+ */
+ { STATE_QUICK_R0, STATE_QUICK_R1
+ , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY
+ , P(HASH) | P(SA) | P(NONCE), /* P(SA) | */ P(KE) | P(ID) | P(NATOA_RFC), PT(NONE)
+ , EVENT_RETRANSMIT, quick_inI1_outR1 },
+
+ /* STATE_QUICK_I1:
+ * HDR*, HASH(2), SA, Nr [, KE ] [, IDci, IDcr ] -->
+ * HDR*, HASH(3)
+ * Installs inbound and outbound IPsec SAs, routing, etc.
+ * ??? it is legal to have multiple SAs, but we don't support it yet.
+ */
+ { STATE_QUICK_I1, STATE_QUICK_I2
+ , SMF_ALL_AUTH | SMF_INITIATOR | SMF_ENCRYPTED | SMF_REPLY
+ , P(HASH) | P(SA) | P(NONCE), /* P(SA) | */ P(KE) | P(ID) | P(NATOA_RFC), PT(HASH)
+ , EVENT_SA_REPLACE, quick_inR1_outI2 },
+
+ /* STATE_QUICK_R1: HDR*, HASH(3) --> done
+ * Installs outbound IPsec SAs, routing, etc.
+ */
+ { STATE_QUICK_R1, STATE_QUICK_R2
+ , SMF_ALL_AUTH | SMF_ENCRYPTED
+ , P(HASH), LEMPTY, PT(NONE)
+ , EVENT_SA_REPLACE, quick_inI2 },
+
+ /* STATE_QUICK_I2: can only happen due to lost packet */
+ { STATE_QUICK_I2, STATE_UNDEFINED
+ , SMF_ALL_AUTH | SMF_INITIATOR | SMF_ENCRYPTED | SMF_RETRANSMIT_ON_DUPLICATE
+ , LEMPTY, LEMPTY, PT(NONE)
+ , EVENT_NULL, unexpected },
+
+ /* STATE_QUICK_R2: can only happen due to lost packet */
+ { STATE_QUICK_R2, STATE_UNDEFINED
+ , SMF_ALL_AUTH | SMF_ENCRYPTED
+ , LEMPTY, LEMPTY, PT(NONE)
+ , EVENT_NULL, unexpected },
+
+
+ /***** informational messages *****/
+
+ /* STATE_INFO: */
+ { STATE_INFO, STATE_UNDEFINED
+ , SMF_ALL_AUTH
+ , LEMPTY, LEMPTY, PT(NONE)
+ , EVENT_NULL, informational },
+
+ /* STATE_INFO_PROTECTED: */
+ { STATE_INFO_PROTECTED, STATE_UNDEFINED
+ , SMF_ALL_AUTH | SMF_ENCRYPTED
+ , P(HASH), LEMPTY, PT(NONE)
+ , EVENT_NULL, informational },
+
+ /* XAUTH state transitions */
+ { STATE_XAUTH_I0, STATE_XAUTH_I1
+ , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY
+ , P(ATTR) | P(HASH), P(VID), PT(HASH)
+ , EVENT_RETRANSMIT, xauth_inI0 },
+
+ { STATE_XAUTH_R1, STATE_XAUTH_R2
+ , SMF_ALL_AUTH | SMF_ENCRYPTED
+ , P(ATTR) | P(HASH), P(VID), PT(HASH)
+ , EVENT_RETRANSMIT, xauth_inR1 },
+
+ { STATE_XAUTH_I1, STATE_XAUTH_I2
+ , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY | SMF_RELEASE_PENDING_P2
+ , P(ATTR) | P(HASH), P(VID), PT(HASH)
+ , EVENT_SA_REPLACE, xauth_inI1 },
+
+ { STATE_XAUTH_R2, STATE_XAUTH_R3
+ , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2
+ , P(ATTR) | P(HASH), P(VID), PT(NONE)
+ , EVENT_SA_REPLACE, xauth_inR2 },
+
+ { STATE_XAUTH_I2, STATE_UNDEFINED
+ , SMF_ALL_AUTH | SMF_ENCRYPTED
+ , LEMPTY, LEMPTY, PT(NONE)
+ , EVENT_NULL, unexpected },
+
+ { STATE_XAUTH_R3, STATE_UNDEFINED
+ , SMF_ALL_AUTH | SMF_ENCRYPTED
+ , LEMPTY, LEMPTY, PT(NONE)
+ , EVENT_NULL, unexpected },
+
+ /* ModeCfg pull mode state transitions */
+
+ { STATE_MODE_CFG_R0, STATE_MODE_CFG_R1
+ , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY | SMF_RELEASE_PENDING_P2
+ , P(ATTR) | P(HASH), P(VID), PT(HASH)
+ , EVENT_SA_REPLACE, modecfg_inR0 },
+
+ { STATE_MODE_CFG_I1, STATE_MODE_CFG_I2
+ , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2
+ , P(ATTR) | P(HASH), P(VID), PT(HASH)
+ , EVENT_SA_REPLACE, modecfg_inI1 },
+
+ { STATE_MODE_CFG_R1, STATE_UNDEFINED
+ , SMF_ALL_AUTH | SMF_ENCRYPTED
+ , LEMPTY, LEMPTY, PT(NONE)
+ , EVENT_NULL, unexpected },
+
+ { STATE_MODE_CFG_I2, STATE_UNDEFINED
+ , SMF_ALL_AUTH | SMF_ENCRYPTED
+ , LEMPTY, LEMPTY, PT(NONE)
+ , EVENT_NULL, unexpected },
+
+ /* ModeCfg push mode state transitions */
+
+ { STATE_MODE_CFG_I0, STATE_MODE_CFG_I3
+ , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY | SMF_RELEASE_PENDING_P2
+ , P(ATTR) | P(HASH), P(VID), PT(HASH)
+ , EVENT_SA_REPLACE, modecfg_inI0 },
+
+ { STATE_MODE_CFG_R3, STATE_MODE_CFG_R4
+ , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2
+ , P(ATTR) | P(HASH), P(VID), PT(HASH)
+ , EVENT_SA_REPLACE, modecfg_inR3 },
+
+ { STATE_MODE_CFG_I3, STATE_UNDEFINED
+ , SMF_ALL_AUTH | SMF_ENCRYPTED
+ , LEMPTY, LEMPTY, PT(NONE)
+ , EVENT_NULL, unexpected },
+
+ { STATE_MODE_CFG_R4, STATE_UNDEFINED
+ , SMF_ALL_AUTH | SMF_ENCRYPTED
+ , LEMPTY, LEMPTY, PT(NONE)
+ , EVENT_NULL, unexpected },
+
+#undef P
+#undef PT
+};
+
+void
+init_demux(void)
+{
+ /* fill ike_microcode_index:
+ * make ike_microcode_index[s] point to first entry in
+ * state_microcode_table for state s (backward scan makes this easier).
+ * Check that table is in order -- catch coding errors.
+ * For what it's worth, this routine is idempotent.
+ */
+ const struct state_microcode *t;
+
+ for (t = &state_microcode_table[elemsof(state_microcode_table) - 1];;)
+ {
+ passert(STATE_IKE_FLOOR <= t->state && t->state < STATE_IKE_ROOF);
+ ike_microcode_index[t->state - STATE_IKE_FLOOR] = t;
+ if (t == state_microcode_table)
+ break;
+ t--;
+ passert(t[0].state <= t[1].state);
+ }
+}
+
+/* Process any message on the MSG_ERRQUEUE
+ *
+ * This information is generated because of the IP_RECVERR socket option.
+ * The API is sparsely documented, and may be LINUX-only, and only on
+ * fairly recent versions at that (hence the conditional compilation).
+ *
+ * - ip(7) describes IP_RECVERR
+ * - recvmsg(2) describes MSG_ERRQUEUE
+ * - readv(2) describes iovec
+ * - cmsg(3) describes how to process auxilliary messages
+ *
+ * ??? we should link this message with one we've sent
+ * so that the diagnostic can refer to that negotiation.
+ *
+ * ??? how long can the messge be?
+ *
+ * ??? poll(2) has a very incomplete description of the POLL* events.
+ * We assume that POLLIN, POLLOUT, and POLLERR are all we need to deal with
+ * and that POLLERR will be on iff there is a MSG_ERRQUEUE message.
+ *
+ * We have to code around a couple of surprises:
+ *
+ * - Select can say that a socket is ready to read from, and
+ * yet a read will hang. It turns out that a message available on the
+ * MSG_ERRQUEUE will cause select to say something is pending, but
+ * a normal read will hang. poll(2) can tell when a MSG_ERRQUEUE
+ * message is pending.
+ *
+ * This is dealt with by calling check_msg_errqueue after select
+ * has indicated that there is something to read, but before the
+ * read is performed. check_msg_errqueue will return TRUE if there
+ * is something left to read.
+ *
+ * - A write to a socket may fail because there is a pending MSG_ERRQUEUE
+ * message, without there being anything wrong with the write. This
+ * makes for confusing diagnostics.
+ *
+ * To avoid this, we call check_msg_errqueue before a write. True,
+ * there is a race condition (a MSG_ERRQUEUE message might arrive
+ * between the check and the write), but we should eliminate many
+ * of the problematic events. To narrow the window, the poll(2)
+ * will await until an event happens (in the case or a write,
+ * POLLOUT; this should be benign for POLLIN).
+ */
+
+#if defined(IP_RECVERR) && defined(MSG_ERRQUEUE)
+static bool
+check_msg_errqueue(const struct iface *ifp, short interest)
+{
+ struct pollfd pfd;
+
+ pfd.fd = ifp->fd;
+ pfd.events = interest | POLLPRI | POLLOUT;
+
+ while (pfd.revents = 0
+ , poll(&pfd, 1, -1) > 0 && (pfd.revents & POLLERR))
+ {
+ u_int8_t buffer[3000]; /* hope that this is big enough */
+ union
+ {
+ struct sockaddr sa;
+ struct sockaddr_in sa_in4;
+ struct sockaddr_in6 sa_in6;
+ } from;
+
+ int from_len = sizeof(from);
+
+ int packet_len;
+
+ struct msghdr emh;
+ struct iovec eiov;
+ union {
+ /* force alignment (not documented as necessary) */
+ struct cmsghdr ecms;
+
+ /* how much space is enough? */
+ unsigned char space[256];
+ } ecms_buf;
+
+ struct cmsghdr *cm;
+ char fromstr[sizeof(" for message to port 65536") + INET6_ADDRSTRLEN];
+ struct state *sender = NULL;
+
+ zero(&from.sa);
+ from_len = sizeof(from);
+
+ emh.msg_name = &from.sa; /* ??? filled in? */
+ emh.msg_namelen = sizeof(from);
+ emh.msg_iov = &eiov;
+ emh.msg_iovlen = 1;
+ emh.msg_control = &ecms_buf;
+ emh.msg_controllen = sizeof(ecms_buf);
+ emh.msg_flags = 0;
+
+ eiov.iov_base = buffer; /* see readv(2) */
+ eiov.iov_len = sizeof(buffer);
+
+ packet_len = recvmsg(ifp->fd, &emh, MSG_ERRQUEUE);
+
+ if (packet_len == -1)
+ {
+ log_errno((e, "recvmsg(,, MSG_ERRQUEUE) on %s failed in comm_handle"
+ , ifp->rname));
+ break;
+ }
+ else if (packet_len == sizeof(buffer))
+ {
+ plog("MSG_ERRQUEUE message longer than %lu bytes; truncated"
+ , (unsigned long) sizeof(buffer));
+ }
+ else
+ {
+ sender = find_sender((size_t) packet_len, buffer);
+ }
+
+ DBG_cond_dump(DBG_ALL, "rejected packet:\n", buffer, packet_len);
+ DBG_cond_dump(DBG_ALL, "control:\n", emh.msg_control, emh.msg_controllen);
+ /* ??? Andi Kleen <ak@suse.de> and misc documentation
+ * suggests that name will have the original destination
+ * of the packet. We seem to see msg_namelen == 0.
+ * Andi says that this is a kernel bug and has fixed it.
+ * Perhaps in 2.2.18/2.4.0.
+ */
+ passert(emh.msg_name == &from.sa);
+ DBG_cond_dump(DBG_ALL, "name:\n", emh.msg_name
+ , emh.msg_namelen);
+
+ fromstr[0] = '\0'; /* usual case :-( */
+ switch (from.sa.sa_family)
+ {
+ char as[INET6_ADDRSTRLEN];
+
+ case AF_INET:
+ if (emh.msg_namelen == sizeof(struct sockaddr_in))
+ snprintf(fromstr, sizeof(fromstr)
+ , " for message to %s port %u"
+ , inet_ntop(from.sa.sa_family
+ , &from.sa_in4.sin_addr, as, sizeof(as))
+ , ntohs(from.sa_in4.sin_port));
+ break;
+ case AF_INET6:
+ if (emh.msg_namelen == sizeof(struct sockaddr_in6))
+ snprintf(fromstr, sizeof(fromstr)
+ , " for message to %s port %u"
+ , inet_ntop(from.sa.sa_family
+ , &from.sa_in6.sin6_addr, as, sizeof(as))
+ , ntohs(from.sa_in6.sin6_port));
+ break;
+ }
+
+ for (cm = CMSG_FIRSTHDR(&emh)
+ ; cm != NULL
+ ; cm = CMSG_NXTHDR(&emh,cm))
+ {
+ if (cm->cmsg_level == SOL_IP
+ && cm->cmsg_type == IP_RECVERR)
+ {
+ /* ip(7) and recvmsg(2) specify:
+ * ee_origin is SO_EE_ORIGIN_ICMP for ICMP
+ * or SO_EE_ORIGIN_LOCAL for locally generated errors.
+ * ee_type and ee_code are from the ICMP header.
+ * ee_info is the discovered MTU for EMSGSIZE errors
+ * ee_data is not used.
+ *
+ * ??? recvmsg(2) says "SOCK_EE_OFFENDER" but
+ * means "SO_EE_OFFENDER". The OFFENDER is really
+ * the router that complained. As such, the port
+ * is meaningless.
+ */
+
+ /* ??? cmsg(3) claims that CMSG_DATA returns
+ * void *, but RFC 2292 and /usr/include/bits/socket.h
+ * say unsigned char *. The manual is being fixed.
+ */
+ struct sock_extended_err *ee = (void *)CMSG_DATA(cm);
+ const char *offstr = "unspecified";
+ char offstrspace[INET6_ADDRSTRLEN];
+ char orname[50];
+
+ if (cm->cmsg_len > CMSG_LEN(sizeof(struct sock_extended_err)))
+ {
+ const struct sockaddr *offender = SO_EE_OFFENDER(ee);
+
+ switch (offender->sa_family)
+ {
+ case AF_INET:
+ offstr = inet_ntop(offender->sa_family
+ , &((const struct sockaddr_in *)offender)->sin_addr
+ , offstrspace, sizeof(offstrspace));
+ break;
+ case AF_INET6:
+ offstr = inet_ntop(offender->sa_family
+ , &((const struct sockaddr_in6 *)offender)->sin6_addr
+ , offstrspace, sizeof(offstrspace));
+ break;
+ default:
+ offstr = "unknown";
+ break;
+ }
+ }
+
+ switch (ee->ee_origin)
+ {
+ case SO_EE_ORIGIN_NONE:
+ snprintf(orname, sizeof(orname), "none");
+ break;
+ case SO_EE_ORIGIN_LOCAL:
+ snprintf(orname, sizeof(orname), "local");
+ break;
+ case SO_EE_ORIGIN_ICMP:
+ snprintf(orname, sizeof(orname)
+ , "ICMP type %d code %d (not authenticated)"
+ , ee->ee_type, ee->ee_code
+ );
+ break;
+ case SO_EE_ORIGIN_ICMP6:
+ snprintf(orname, sizeof(orname)
+ , "ICMP6 type %d code %d (not authenticated)"
+ , ee->ee_type, ee->ee_code
+ );
+ break;
+ default:
+ snprintf(orname, sizeof(orname), "invalid origin %lu"
+ , (unsigned long) ee->ee_origin);
+ break;
+ }
+
+ {
+ struct state *old_state = cur_state;
+
+ cur_state = sender;
+
+ /* note dirty trick to suppress ~ at start of format
+ * if we know what state to blame.
+ */
+ if ((packet_len == 1) && (buffer[0] = 0xff)
+#ifdef DEBUG
+ && ((cur_debugging & DBG_NATT) == 0)
+#endif
+ ) {
+ /* don't log NAT-T keepalive related errors unless NATT debug is
+ * enabled
+ */
+ }
+ else
+ plog((sender != NULL) + "~"
+ "ERROR: asynchronous network error report on %s"
+ "%s"
+ ", complainant %s"
+ ": %s"
+ " [errno %lu, origin %s"
+ /* ", pad %d, info %ld" */
+ /* ", data %ld" */
+ "]"
+ , ifp->rname
+ , fromstr
+ , offstr
+ , strerror(ee->ee_errno)
+ , (unsigned long) ee->ee_errno
+ , orname
+ /* , ee->ee_pad, (unsigned long)ee->ee_info */
+ /* , (unsigned long)ee->ee_data */
+ );
+ cur_state = old_state;
+ }
+ }
+ else
+ {
+ /* .cmsg_len is a kernel_size_t(!), but the value
+ * certainly ought to fit in an unsigned long.
+ */
+ plog("unknown cmsg: level %d, type %d, len %lu"
+ , cm->cmsg_level, cm->cmsg_type
+ , (unsigned long) cm->cmsg_len);
+ }
+ }
+ }
+ return (pfd.revents & interest) != 0;
+}
+#endif /* defined(IP_RECVERR) && defined(MSG_ERRQUEUE) */
+
+bool
+send_packet(struct state *st, const char *where)
+{
+ struct connection *c = st->st_connection;
+ int port_buf;
+ bool err;
+ u_int8_t ike_pkt[MAX_OUTPUT_UDP_SIZE];
+ u_int8_t *ptr;
+ unsigned long len;
+
+ if (c->interface->ike_float && st->st_tpacket.len != 1)
+ {
+ if ((unsigned long) st->st_tpacket.len > (MAX_OUTPUT_UDP_SIZE-sizeof(u_int32_t)))
+ {
+ DBG_log("send_packet(): really too big");
+ return FALSE;
+ }
+ ptr = ike_pkt;
+ /** Add Non-ESP marker **/
+ memset(ike_pkt, 0, sizeof(u_int32_t));
+ memcpy(ike_pkt + sizeof(u_int32_t), st->st_tpacket.ptr,
+ (unsigned long)st->st_tpacket.len);
+ len = (unsigned long) st->st_tpacket.len + sizeof(u_int32_t);
+ }
+ else
+ {
+ ptr = st->st_tpacket.ptr;
+ len = (unsigned long) st->st_tpacket.len;
+ }
+
+ DBG(DBG_RAW,
+ {
+ DBG_log("sending %lu bytes for %s through %s to %s:%u:"
+ , (unsigned long) st->st_tpacket.len
+ , where
+ , c->interface->rname
+ , ip_str(&c->spd.that.host_addr)
+ , (unsigned)c->spd.that.host_port);
+ DBG_dump_chunk(NULL, st->st_tpacket);
+ });
+
+ /* XXX: Not very clean. We manipulate the port of the ip_address to
+ * have a port in the sockaddr*, but we retain the original port
+ * and restore it afterwards.
+ */
+
+ port_buf = portof(&c->spd.that.host_addr);
+ setportof(htons(c->spd.that.host_port), &c->spd.that.host_addr);
+
+#if defined(IP_RECVERR) && defined(MSG_ERRQUEUE)
+ (void) check_msg_errqueue(c->interface, POLLOUT);
+#endif /* defined(IP_RECVERR) && defined(MSG_ERRQUEUE) */
+
+ err = sendto(c->interface->fd
+ , ptr, len, 0
+ , sockaddrof(&c->spd.that.host_addr)
+ , sockaddrlenof(&c->spd.that.host_addr)) != (ssize_t)len;
+
+ /* restore port */
+ setportof(port_buf, &c->spd.that.host_addr);
+
+ if (err)
+ {
+ /* do not log NAT-T Keep Alive packets */
+ if (streq(where, "NAT-T Keep Alive"))
+ return FALSE;
+ log_errno((e, "sendto on %s to %s:%u failed in %s"
+ , c->interface->rname
+ , ip_str(&c->spd.that.host_addr)
+ , (unsigned)c->spd.that.host_port
+ , where));
+ return FALSE;
+ }
+ else
+ {
+ return TRUE;
+ }
+}
+
+static stf_status
+unexpected(struct msg_digest *md)
+{
+ loglog(RC_LOG_SERIOUS, "unexpected message received in state %s"
+ , enum_name(&state_names, md->st->st_state));
+ return STF_IGNORE;
+}
+
+static stf_status
+informational(struct msg_digest *md UNUSED)
+{
+ struct payload_digest *const n_pld = md->chain[ISAKMP_NEXT_N];
+
+ /* If the Notification Payload is not null... */
+ if (n_pld != NULL)
+ {
+ pb_stream *const n_pbs = &n_pld->pbs;
+ struct isakmp_notification *const n = &n_pld->payload.notification;
+ int disp_len;
+ char disp_buf[200];
+
+ /* Switch on Notification Type (enum) */
+ switch (n->isan_type)
+ {
+ case R_U_THERE:
+ return dpd_inI_outR(md->st, n, n_pbs);
+
+ case R_U_THERE_ACK:
+ return dpd_inR(md->st, n, n_pbs);
+ default:
+ if (pbs_left(n_pbs) >= sizeof(disp_buf)-1)
+ disp_len = sizeof(disp_buf)-1;
+ else
+ disp_len = pbs_left(n_pbs);
+ memcpy(disp_buf, n_pbs->cur, disp_len);
+ disp_buf[disp_len] = '\0';
+ break;
+ }
+ }
+ return STF_IGNORE;
+}
+
+/* message digest allocation and deallocation */
+
+static struct msg_digest *md_pool = NULL;
+
+/* free_md_pool is only used to avoid leak reports */
+void
+free_md_pool(void)
+{
+ for (;;)
+ {
+ struct msg_digest *md = md_pool;
+
+ if (md == NULL)
+ break;
+ md_pool = md->next;
+ pfree(md);
+ }
+}
+
+static struct msg_digest *
+alloc_md(void)
+{
+ struct msg_digest *md = md_pool;
+
+ /* convenient initializer:
+ * - all pointers NULL
+ * - .note = NOTHING_WRONG
+ * - .encrypted = FALSE
+ */
+ static const struct msg_digest blank_md;
+
+ if (md == NULL)
+ md = alloc_thing(struct msg_digest, "msg_digest");
+ else
+ md_pool = md->next;
+
+ *md = blank_md;
+ md->digest_roof = md->digest;
+
+ /* note: although there may be multiple msg_digests at once
+ * (due to suspended state transitions), there is a single
+ * global reply_buffer. It will need to be saved and restored.
+ */
+ init_pbs(&md->reply, reply_buffer, sizeof(reply_buffer), "reply packet");
+
+ return md;
+}
+
+void
+release_md(struct msg_digest *md)
+{
+ freeanychunk(md->raw_packet);
+ pfreeany(md->packet_pbs.start);
+ md->packet_pbs.start = NULL;
+ md->next = md_pool;
+ md_pool = md;
+}
+
+/* wrapper for read_packet and process_packet
+ *
+ * The main purpose of this wrapper is to factor out teardown code
+ * from the many return points in process_packet. This amounts to
+ * releasing the msg_digest and resetting global variables.
+ *
+ * When processing of a packet is suspended (STF_SUSPEND),
+ * process_packet sets md to NULL to prevent the msg_digest being freed.
+ * Someone else must ensure that msg_digest is freed eventually.
+ *
+ * read_packet is broken out to minimize the lifetime of the
+ * enormous input packet buffer, an auto.
+ */
+void
+comm_handle(const struct iface *ifp)
+{
+ static struct msg_digest *md;
+
+#if defined(IP_RECVERR) && defined(MSG_ERRQUEUE)
+ /* Even though select(2) says that there is a message,
+ * it might only be a MSG_ERRQUEUE message. At least
+ * sometimes that leads to a hanging recvfrom. To avoid
+ * what appears to be a kernel bug, check_msg_errqueue
+ * uses poll(2) and tells us if there is anything for us
+ * to read.
+ *
+ * This is early enough that teardown isn't required:
+ * just return on failure.
+ */
+ if (!check_msg_errqueue(ifp, POLLIN))
+ return; /* no normal message to read */
+#endif /* defined(IP_RECVERR) && defined(MSG_ERRQUEUE) */
+
+ md = alloc_md();
+ md->iface = ifp;
+
+ if (read_packet(md))
+ process_packet(&md);
+
+ if (md != NULL)
+ release_md(md);
+
+ cur_state = NULL;
+ reset_cur_connection();
+ cur_from = NULL;
+}
+
+/* read the message.
+ * Since we don't know its size, we read it into
+ * an overly large buffer and then copy it to a
+ * new, properly sized buffer.
+ */
+static bool
+read_packet(struct msg_digest *md)
+{
+ const struct iface *ifp = md->iface;
+ int packet_len;
+ u_int8_t *buffer;
+ u_int8_t *buffer_nat;
+ union
+ {
+ struct sockaddr sa;
+ struct sockaddr_in sa_in4;
+ struct sockaddr_in6 sa_in6;
+ } from;
+ int from_len = sizeof(from);
+ err_t from_ugh = NULL;
+ static const char undisclosed[] = "unknown source";
+
+ happy(anyaddr(addrtypeof(&ifp->addr), &md->sender));
+ zero(&from.sa);
+ ioctl(ifp->fd, FIONREAD, &packet_len);
+ buffer = alloc_bytes(packet_len, "buffer read packet");
+ packet_len = recvfrom(ifp->fd, buffer, packet_len, 0
+ , &from.sa, &from_len);
+
+ /* First: digest the from address.
+ * We presume that nothing here disturbs errno.
+ */
+ if (packet_len == -1
+ && from_len == sizeof(from)
+ && all_zero((const void *)&from.sa, sizeof(from)))
+ {
+ /* "from" is untouched -- not set by recvfrom */
+ from_ugh = undisclosed;
+ }
+ else if (from_len
+ < (int) (offsetof(struct sockaddr, sa_family) + sizeof(from.sa.sa_family)))
+ {
+ from_ugh = "truncated";
+ }
+ else
+ {
+ const struct af_info *afi = aftoinfo(from.sa.sa_family);
+
+ if (afi == NULL)
+ {
+ from_ugh = "unexpected Address Family";
+ }
+ else if (from_len != (int)afi->sa_sz)
+ {
+ from_ugh = "wrong length";
+ }
+ else
+ {
+ switch (from.sa.sa_family)
+ {
+ case AF_INET:
+ from_ugh = initaddr((void *) &from.sa_in4.sin_addr
+ , sizeof(from.sa_in4.sin_addr), AF_INET, &md->sender);
+ md->sender_port = ntohs(from.sa_in4.sin_port);
+ break;
+ case AF_INET6:
+ from_ugh = initaddr((void *) &from.sa_in6.sin6_addr
+ , sizeof(from.sa_in6.sin6_addr), AF_INET6, &md->sender);
+ md->sender_port = ntohs(from.sa_in6.sin6_port);
+ break;
+ }
+ }
+ }
+
+ /* now we report any actual I/O error */
+ if (packet_len == -1)
+ {
+ if (from_ugh == undisclosed
+ && errno == ECONNREFUSED)
+ {
+ /* Tone down scary message for vague event:
+ * We get "connection refused" in response to some
+ * datagram we sent, but we cannot tell which one.
+ */
+ plog("some IKE message we sent has been rejected with ECONNREFUSED (kernel supplied no details)");
+ }
+ else if (from_ugh != NULL)
+ {
+ log_errno((e, "recvfrom on %s failed; Pluto cannot decode source sockaddr in rejection: %s"
+ , ifp->rname, from_ugh));
+ }
+ else
+ {
+ log_errno((e, "recvfrom on %s from %s:%u failed"
+ , ifp->rname
+ , ip_str(&md->sender), (unsigned)md->sender_port));
+ }
+
+ return FALSE;
+ }
+ else if (from_ugh != NULL)
+ {
+ plog("recvfrom on %s returned misformed source sockaddr: %s"
+ , ifp->rname, from_ugh);
+ return FALSE;
+ }
+ cur_from = &md->sender;
+ cur_from_port = md->sender_port;
+
+ if (ifp->ike_float == TRUE)
+ {
+ u_int32_t non_esp;
+
+ if (packet_len < (int)sizeof(u_int32_t))
+ {
+ plog("recvfrom %s:%u too small packet (%d)"
+ , ip_str(cur_from), (unsigned) cur_from_port, packet_len);
+ return FALSE;
+ }
+ memcpy(&non_esp, buffer, sizeof(u_int32_t));
+ if (non_esp != 0)
+ {
+ plog("recvfrom %s:%u has no Non-ESP marker"
+ , ip_str(cur_from), (unsigned) cur_from_port);
+ return FALSE;
+ }
+ packet_len -= sizeof(u_int32_t);
+ buffer_nat = alloc_bytes(packet_len, "buffer read packet");
+ memcpy(buffer_nat, buffer + sizeof(u_int32_t), packet_len);
+ pfree(buffer);
+ buffer = buffer_nat;
+ }
+
+ /* Clone actual message contents
+ * and set up md->packet_pbs to describe it.
+ */
+ init_pbs(&md->packet_pbs, buffer, packet_len, "packet");
+
+ DBG(DBG_RAW | DBG_CRYPT | DBG_PARSING | DBG_CONTROL,
+ {
+ DBG_log(BLANK_FORMAT);
+ DBG_log("*received %d bytes from %s:%u on %s"
+ , (int) pbs_room(&md->packet_pbs)
+ , ip_str(cur_from), (unsigned) cur_from_port
+ , ifp->rname);
+ });
+
+ DBG(DBG_RAW,
+ DBG_dump("", md->packet_pbs.start, pbs_room(&md->packet_pbs)));
+
+ if ((pbs_room(&md->packet_pbs)==1) && (md->packet_pbs.start[0]==0xff))
+ {
+ /**
+ * NAT-T Keep-alive packets should be discared by kernel ESPinUDP
+ * layer. But boggus keep-alive packets (sent with a non-esp marker)
+ * can reach this point. Complain and discard them.
+ */
+ DBG(DBG_NATT,
+ DBG_log("NAT-T keep-alive (boggus ?) should not reach this point. "
+ "Ignored. Sender: %s:%u", ip_str(cur_from),
+ (unsigned) cur_from_port);
+ )
+ return FALSE;
+ }
+
+#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;
+ }
+
+ return TRUE;
+}
+
+/* process an input packet, possibly generating a reply.
+ *
+ * If all goes well, this routine eventually calls a state-specific
+ * transition function.
+ */
+static void
+process_packet(struct msg_digest **mdp)
+{
+ struct msg_digest *md = *mdp;
+ const struct state_microcode *smc;
+ bool new_iv_set = FALSE;
+ bool restore_iv = FALSE;
+ u_char new_iv[MAX_DIGEST_LEN];
+ u_int new_iv_len = 0;
+
+ struct state *st = NULL;
+ enum state_kind from_state = STATE_UNDEFINED; /* state we started in */
+
+#define SEND_NOTIFICATION(t) { \
+ if (st) send_notification_from_state(st, from_state, t); \
+ else send_notification_from_md(md, t); }
+
+ if (!in_struct(&md->hdr, &isakmp_hdr_desc, &md->packet_pbs, &md->message_pbs))
+ {
+ /* Identify specific failures:
+ * - bad ISAKMP major/minor version numbers
+ */
+ 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);
+ return;
+ }
+ else if ((hdr->isa_version & ISA_MIN_MASK) != ISAKMP_MINOR_VERSION)
+ {
+ SEND_NOTIFICATION(INVALID_MINOR_VERSION);
+ return;
+ }
+ }
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED);
+ return;
+ }
+
+ if (md->packet_pbs.roof != md->message_pbs.roof)
+ {
+ plog("size (%u) differs from size specified in ISAKMP HDR (%u)"
+ , (unsigned) pbs_room(&md->packet_pbs), md->hdr.isa_length);
+#ifdef CISCO_QUIRKS
+ if (pbs_room(&md->packet_pbs) - md->hdr.isa_length == 16)
+ plog("Cisco VPN client appends 16 surplus NULL bytes");
+ else
+#endif
+ return;
+ }
+
+ switch (md->hdr.isa_xchg)
+ {
+#ifdef NOTYET
+ case ISAKMP_XCHG_NONE:
+ case ISAKMP_XCHG_BASE:
+#endif
+
+ case ISAKMP_XCHG_IDPROT: /* part of a Main Mode exchange */
+ if (md->hdr.isa_msgid != MAINMODE_MSGID)
+ {
+ plog("Message ID was 0x%08lx but should be zero in Main Mode",
+ (unsigned long) md->hdr.isa_msgid);
+ SEND_NOTIFICATION(INVALID_MESSAGE_ID);
+ return;
+ }
+
+ if (is_zero_cookie(md->hdr.isa_icookie))
+ {
+ plog("Initiator Cookie must not be zero in Main Mode message");
+ SEND_NOTIFICATION(INVALID_COOKIE);
+ return;
+ }
+
+ if (is_zero_cookie(md->hdr.isa_rcookie))
+ {
+ /* initial message from initiator
+ * ??? what if this is a duplicate of another message?
+ */
+ if (md->hdr.isa_flags & ISAKMP_FLAG_ENCRYPTION)
+ {
+ plog("initial Main Mode message is invalid:"
+ " its Encrypted Flag is on");
+ SEND_NOTIFICATION(INVALID_FLAGS);
+ return;
+ }
+
+ /* don't build a state until the message looks tasty */
+ from_state = STATE_MAIN_R0;
+ }
+ else
+ {
+ /* not an initial message */
+
+ st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie
+ , &md->sender, md->hdr.isa_msgid);
+
+ if (st == NULL)
+ {
+ /* perhaps this is a first message from the responder
+ * and contains a responder cookie that we've not yet seen.
+ */
+ st = find_state(md->hdr.isa_icookie, zero_cookie
+ , &md->sender, md->hdr.isa_msgid);
+
+ if (st == NULL)
+ {
+ plog("Main Mode message is part of an unknown exchange");
+ /* XXX Could send notification back */
+ return;
+ }
+ }
+ set_cur_state(st);
+ from_state = st->st_state;
+ }
+ break;
+
+#ifdef NOTYET
+ case ISAKMP_XCHG_AO:
+ case ISAKMP_XCHG_AGGR:
+#endif
+
+ case ISAKMP_XCHG_INFO: /* an informational exchange */
+ st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie
+ , &md->sender, MAINMODE_MSGID);
+
+ if (st != NULL)
+ set_cur_state(st);
+
+ if (md->hdr.isa_flags & ISAKMP_FLAG_ENCRYPTION)
+ {
+ if (st == NULL)
+ {
+ plog("Informational Exchange is for an unknown (expired?) SA");
+ /* XXX Could send notification back */
+ return;
+ }
+
+ if (!IS_ISAKMP_ENCRYPTED(st->st_state))
+ {
+ loglog(RC_LOG_SERIOUS, "encrypted Informational Exchange message is invalid"
+ " because no key is known");
+ /* XXX Could send notification back */
+ return;
+ }
+
+ if (md->hdr.isa_msgid == MAINMODE_MSGID)
+ {
+ loglog(RC_LOG_SERIOUS, "Informational Exchange message is invalid because"
+ " it has a Message ID of 0");
+ /* XXX Could send notification back */
+ return;
+ }
+
+ if (!reserve_msgid(st, md->hdr.isa_msgid))
+ {
+ loglog(RC_LOG_SERIOUS, "Informational Exchange message is invalid because"
+ " it has a previously used Message ID (0x%08lx)"
+ , (unsigned long)md->hdr.isa_msgid);
+ /* XXX Could send notification back */
+ return;
+ }
+
+ if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state))
+ {
+ memcpy(st->st_ph1_iv, st->st_new_iv, st->st_new_iv_len);
+ st->st_ph1_iv_len = st->st_new_iv_len;
+
+ /* backup new_iv */
+ new_iv_len = st->st_new_iv_len;
+ passert(new_iv_len <= MAX_DIGEST_LEN)
+ memcpy(new_iv, st->st_new_iv, new_iv_len);
+ restore_iv = TRUE;
+ }
+ init_phase2_iv(st, &md->hdr.isa_msgid);
+ new_iv_set = TRUE;
+
+ from_state = STATE_INFO_PROTECTED;
+ }
+ else
+ {
+ if (st != NULL && IS_ISAKMP_ENCRYPTED(st->st_state))
+ {
+ loglog(RC_LOG_SERIOUS, "Informational Exchange message"
+ " must be encrypted");
+ /* XXX Could send notification back */
+ return;
+ }
+ from_state = STATE_INFO;
+ }
+ break;
+
+ case ISAKMP_XCHG_QUICK: /* part of a Quick Mode exchange */
+ if (is_zero_cookie(md->hdr.isa_icookie))
+ {
+ plog("Quick Mode message is invalid because"
+ " it has an Initiator Cookie of 0");
+ SEND_NOTIFICATION(INVALID_COOKIE);
+ return;
+ }
+
+ if (is_zero_cookie(md->hdr.isa_rcookie))
+ {
+ plog("Quick Mode message is invalid because"
+ " it has a Responder Cookie of 0");
+ SEND_NOTIFICATION(INVALID_COOKIE);
+ return;
+ }
+
+ if (md->hdr.isa_msgid == MAINMODE_MSGID)
+ {
+ plog("Quick Mode message is invalid because"
+ " it has a Message ID of 0");
+ SEND_NOTIFICATION(INVALID_MESSAGE_ID);
+ return;
+ }
+
+ st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie
+ , &md->sender, md->hdr.isa_msgid);
+
+ if (st == NULL)
+ {
+ /* No appropriate Quick Mode state.
+ * See if we have a Main Mode state.
+ * ??? what if this is a duplicate of another message?
+ */
+ st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie
+ , &md->sender, MAINMODE_MSGID);
+
+ if (st == NULL)
+ {
+ plog("Quick Mode message is for a non-existent (expired?)"
+ " ISAKMP SA");
+ /* XXX Could send notification back */
+ return;
+ }
+
+ set_cur_state(st);
+
+ if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state))
+ {
+ loglog(RC_LOG_SERIOUS, "Quick Mode message is unacceptable because"
+ " it is for an incomplete ISAKMP SA");
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED /* XXX ? */);
+ return;
+ }
+
+ /* only accept this new Quick Mode exchange if it has a unique message ID */
+ if (!reserve_msgid(st, md->hdr.isa_msgid))
+ {
+ loglog(RC_LOG_SERIOUS, "Quick Mode I1 message is unacceptable because"
+ " it uses a previously used Message ID 0x%08lx"
+ " (perhaps this is a duplicated packet)"
+ , (unsigned long) md->hdr.isa_msgid);
+ SEND_NOTIFICATION(INVALID_MESSAGE_ID);
+ return;
+ }
+
+ /* Quick Mode Initial IV */
+ init_phase2_iv(st, &md->hdr.isa_msgid);
+ new_iv_set = TRUE;
+
+ from_state = STATE_QUICK_R0;
+ }
+ else
+ {
+ set_cur_state(st);
+ from_state = st->st_state;
+ }
+
+ break;
+
+ case ISAKMP_XCHG_MODE_CFG:
+ if (is_zero_cookie(md->hdr.isa_icookie))
+ {
+ plog("ModeCfg message is invalid because"
+ " it has an Initiator Cookie of 0");
+ /* XXX Could send notification back */
+ return;
+ }
+
+ if (is_zero_cookie(md->hdr.isa_rcookie))
+ {
+ plog("ModeCfg message is invalid because"
+ " it has a Responder Cookie of 0");
+ /* XXX Could send notification back */
+ return;
+ }
+
+ if (md->hdr.isa_msgid == 0)
+ {
+ plog("ModeCfg message is invalid because"
+ " it has a Message ID of 0");
+ /* XXX Could send notification back */
+ return;
+ }
+
+ st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie
+ , &md->sender, md->hdr.isa_msgid);
+
+ if (st == NULL)
+ {
+ bool has_xauth_policy;
+
+ /* No appropriate ModeCfg state.
+ * See if we have a Main Mode state.
+ * ??? what if this is a duplicate of another message?
+ */
+ st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie
+ , &md->sender, 0);
+
+ if (st == NULL)
+ {
+ plog("ModeCfg message is for a non-existent (expired?)"
+ " ISAKMP SA");
+ /* XXX Could send notification back */
+ return;
+ }
+
+ set_cur_state(st);
+
+ /* the XAUTH_STATUS message might have a new msgid */
+ if (st->st_state == STATE_XAUTH_I1)
+ {
+ init_phase2_iv(st, &md->hdr.isa_msgid);
+ new_iv_set = TRUE;
+ from_state = st->st_state;
+ break;
+ }
+
+ if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state))
+ {
+ loglog(RC_LOG_SERIOUS, "ModeCfg message is unacceptable because"
+ " it is for an incomplete ISAKMP SA (state=%s)"
+ , enum_name(&state_names, st->st_state));
+ /* XXX Could send notification back */
+ return;
+ }
+ init_phase2_iv(st, &md->hdr.isa_msgid);
+ new_iv_set = TRUE;
+
+ /*
+ * okay, now we have to figure out if we are receiving a bogus
+ * new message in an oustanding XAUTH server conversation
+ * (i.e. a reply to our challenge)
+ * (this occurs with some broken other implementations).
+ *
+ * or if receiving for the first time, an XAUTH challenge.
+ *
+ * or if we are getting a MODECFG request.
+ *
+ * we distinguish these states because we can not both be an
+ * XAUTH server and client, and our policy tells us which
+ * one we are.
+ *
+ * to complicate further, it is normal to start a new msgid
+ * when going from one state to another, or when restarting
+ * the challenge.
+ *
+ */
+
+ has_xauth_policy = (st->st_connection->policy
+ & (POLICY_XAUTH_RSASIG | POLICY_XAUTH_PSK))
+ != LEMPTY;
+
+ if (has_xauth_policy && !st->st_xauth.started
+ && IS_PHASE1(st->st_state))
+ {
+ from_state = STATE_XAUTH_I0;
+ }
+ else if (st->st_connection->spd.that.modecfg
+ && IS_PHASE1(st->st_state))
+ {
+ from_state = STATE_MODE_CFG_R0;
+ }
+ else if (st->st_connection->spd.this.modecfg
+ && IS_PHASE1(st->st_state))
+ {
+ from_state = STATE_MODE_CFG_I0;
+ }
+ else
+ {
+ /* XXX check if we are being a mode config server here */
+ plog("received ModeCfg message when in state %s, and we aren't mode config client"
+ , enum_name(&state_names, st->st_state));
+ return;
+ }
+ }
+ else
+ {
+ set_cur_state(st);
+ from_state = st->st_state;
+ }
+ break;
+
+#ifdef NOTYET
+ case ISAKMP_XCHG_NGRP:
+ case ISAKMP_XCHG_ACK_INFO:
+#endif
+
+ default:
+ plog("unsupported exchange type %s in message"
+ , enum_show(&exchange_names, md->hdr.isa_xchg));
+ SEND_NOTIFICATION(UNSUPPORTED_EXCHANGE_TYPE);
+ return;
+ }
+
+ /* We have found a from_state, and perhaps a state object.
+ * If we need to build a new state object,
+ * we wait until the packet has been sanity checked.
+ */
+
+ /* We don't support the Commit Flag. It is such a bad feature.
+ * It isn't protected -- neither encrypted nor authenticated.
+ * A man in the middle turns it on, leading to DoS.
+ * We just ignore it, with a warning.
+ * By placing the check here, we could easily add a policy bit
+ * to a connection to suppress the warning. This might be useful
+ * because the Commit Flag is expected from some peers.
+ */
+ if (md->hdr.isa_flags & ISAKMP_FLAG_COMMIT)
+ {
+ plog("IKE message has the Commit Flag set but Pluto doesn't implement this feature; ignoring flag");
+ }
+
+ /* Set smc to describe this state's properties.
+ * Look up the appropriate microcode based on state and
+ * possibly Oakley Auth type.
+ */
+ passert(STATE_IKE_FLOOR <= from_state && from_state <= STATE_IKE_ROOF);
+ smc = ike_microcode_index[from_state - STATE_IKE_FLOOR];
+
+ if (st != NULL)
+ {
+ u_int16_t auth;
+
+ switch (st->st_oakley.auth)
+ {
+ case XAUTHInitPreShared:
+ case XAUTHRespPreShared:
+ auth = OAKLEY_PRESHARED_KEY;
+ break;
+ case XAUTHInitRSA:
+ case XAUTHRespRSA:
+ auth = OAKLEY_RSA_SIG;
+ break;
+ default:
+ auth = st->st_oakley.auth;
+ }
+
+ while (!LHAS(smc->flags, auth))
+ {
+ smc++;
+ passert(smc->state == from_state);
+ }
+ }
+
+ /* Ignore a packet if the state has a suspended state transition
+ * Probably a duplicated packet but the original packet is not yet
+ * recorded in st->st_rpacket, so duplicate checking won't catch.
+ * ??? Should the packet be recorded earlier to improve diagnosis?
+ */
+ if (st != NULL && st->st_suspended_md != NULL)
+ {
+ loglog(RC_LOG, "discarding packet received during DNS lookup in %s"
+ , enum_name(&state_names, st->st_state));
+ return;
+ }
+
+ /* Detect and handle duplicated packets.
+ * This won't work for the initial packet of an exchange
+ * because we won't have a state object to remember it.
+ * If we are in a non-receiving state (terminal), and the preceding
+ * state did transmit, then the duplicate may indicate that that
+ * transmission wasn't received -- retransmit it.
+ * Otherwise, just discard it.
+ * ??? Notification packets are like exchanges -- I hope that
+ * they are idempotent!
+ */
+ if (st != NULL
+ && st->st_rpacket.ptr != NULL
+ && st->st_rpacket.len == pbs_room(&md->packet_pbs)
+ && memcmp(st->st_rpacket.ptr, md->packet_pbs.start, st->st_rpacket.len) == 0)
+ {
+ if (smc->flags & SMF_RETRANSMIT_ON_DUPLICATE)
+ {
+ if (st->st_retransmit < MAXIMUM_RETRANSMISSIONS)
+ {
+ st->st_retransmit++;
+ loglog(RC_RETRANSMISSION
+ , "retransmitting in response to duplicate packet; already %s"
+ , enum_name(&state_names, st->st_state));
+ send_packet(st, "retransmit in response to duplicate");
+ }
+ else
+ {
+ loglog(RC_LOG_SERIOUS, "discarding duplicate packet -- exhausted retransmission; already %s"
+ , enum_name(&state_names, st->st_state));
+ }
+ }
+ else
+ {
+ loglog(RC_LOG_SERIOUS, "discarding duplicate packet; already %s"
+ , enum_name(&state_names, st->st_state));
+ }
+ return;
+ }
+
+ if (md->hdr.isa_flags & ISAKMP_FLAG_ENCRYPTION)
+ {
+ DBG(DBG_CRYPT, DBG_log("received encrypted packet from %s:%u"
+ , ip_str(&md->sender), (unsigned)md->sender_port));
+
+ if (st == NULL)
+ {
+ plog("discarding encrypted message for an unknown ISAKMP SA");
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED /* XXX ? */);
+ return;
+ }
+ if (st->st_skeyid_e.ptr == (u_char *) NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "discarding encrypted message"
+ " because we haven't yet negotiated keying materiel");
+ SEND_NOTIFICATION(INVALID_FLAGS);
+ return;
+ }
+
+ /* Mark as encrypted */
+ md->encrypted = TRUE;
+
+ DBG(DBG_CRYPT, DBG_log("decrypting %u bytes using algorithm %s"
+ , (unsigned) pbs_left(&md->message_pbs)
+ , enum_show(&oakley_enc_names, st->st_oakley.encrypt)));
+
+ /* do the specified decryption
+ *
+ * IV is from st->st_iv or (if new_iv_set) st->st_new_iv.
+ * The new IV is placed in st->st_new_iv
+ *
+ * See RFC 2409 "IKE" Appendix B
+ *
+ * XXX The IV should only be updated really if the packet
+ * is successfully processed.
+ * We should keep this value, check for a success return
+ * value from the parsing routines and then replace.
+ *
+ * Each post phase 1 exchange generates IVs from
+ * the last phase 1 block, not the last block sent.
+ */
+ {
+ const struct encrypt_desc *e = st->st_oakley.encrypter;
+
+ if (pbs_left(&md->message_pbs) % e->enc_blocksize != 0)
+ {
+ loglog(RC_LOG_SERIOUS, "malformed message: not a multiple of encryption blocksize");
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED);
+ return;
+ }
+
+ /* XXX Detect weak keys */
+
+ /* grab a copy of raw packet (for duplicate packet detection) */
+ clonetochunk(md->raw_packet, md->packet_pbs.start
+ , pbs_room(&md->packet_pbs), "raw packet");
+
+ /* Decrypt everything after header */
+ if (!new_iv_set)
+ {
+ /* use old IV */
+ passert(st->st_iv_len <= sizeof(st->st_new_iv));
+ st->st_new_iv_len = st->st_iv_len;
+ memcpy(st->st_new_iv, st->st_iv, st->st_new_iv_len);
+ }
+ crypto_cbc_encrypt(e, FALSE, md->message_pbs.cur,
+ pbs_left(&md->message_pbs) , st);
+ if (restore_iv)
+ {
+ memcpy(st->st_new_iv, new_iv, new_iv_len);
+ st->st_new_iv_len = new_iv_len;
+ }
+ }
+
+ DBG_cond_dump(DBG_CRYPT, "decrypted:\n", md->message_pbs.cur
+ , md->message_pbs.roof - md->message_pbs.cur);
+
+ DBG_cond_dump(DBG_CRYPT, "next IV:"
+ , st->st_new_iv, st->st_new_iv_len);
+ }
+ else
+ {
+ /* packet was not encryped -- should it have been? */
+
+ if (smc->flags & SMF_INPUT_ENCRYPTED)
+ {
+ loglog(RC_LOG_SERIOUS, "packet rejected: should have been encrypted");
+ SEND_NOTIFICATION(INVALID_FLAGS);
+ return;
+ }
+ }
+
+ /* Digest the message.
+ * Padding must be removed to make hashing work.
+ * Padding comes from encryption (so this code must be after decryption).
+ * Padding rules are described before the definition of
+ * struct isakmp_hdr in packet.h.
+ */
+ {
+ struct payload_digest *pd = md->digest;
+ int np = md->hdr.isa_np;
+ lset_t needed = smc->req_payloads;
+ const char *excuse
+ = LIN(SMF_PSK_AUTH | SMF_FIRST_ENCRYPTED_INPUT, smc->flags)
+ ? "probable authentication failure (mismatch of preshared secrets?): "
+ : "";
+
+ while (np != ISAKMP_NEXT_NONE)
+ {
+ struct_desc *sd = np < ISAKMP_NEXT_ROOF? payload_descs[np] : NULL;
+
+ if (pd == &md->digest[PAYLIMIT])
+ {
+ loglog(RC_LOG_SERIOUS, "more than %d payloads in message; ignored", PAYLIMIT);
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED);
+ return;
+ }
+
+ switch (np)
+ {
+ case ISAKMP_NEXT_NATD_RFC:
+ case ISAKMP_NEXT_NATOA_RFC:
+ if (!st || !(st->nat_traversal & NAT_T_WITH_RFC_VALUES))
+ {
+ /*
+ * don't accept NAT-D/NAT-OA reloc directly in message, unless
+ * we're using NAT-T RFC
+ */
+ sd = NULL;
+ }
+ break;
+ }
+
+ if (sd == NULL)
+ {
+ /* payload type is out of range or requires special handling */
+ switch (np)
+ {
+ case ISAKMP_NEXT_ID:
+ sd = IS_PHASE1(from_state)
+ ? &isakmp_identification_desc : &isakmp_ipsec_identification_desc;
+ break;
+ case ISAKMP_NEXT_NATD_DRAFTS:
+ np = ISAKMP_NEXT_NATD_RFC; /* NAT-D relocated */
+ sd = payload_descs[np];
+ break;
+ case ISAKMP_NEXT_NATOA_DRAFTS:
+ np = ISAKMP_NEXT_NATOA_RFC; /* NAT-OA relocated */
+ sd = payload_descs[np];
+ break;
+ default:
+ loglog(RC_LOG_SERIOUS, "%smessage ignored because it contains an unknown or"
+ " unexpected payload type (%s) at the outermost level"
+ , excuse, enum_show(&payload_names, np));
+ SEND_NOTIFICATION(INVALID_PAYLOAD_TYPE);
+ return;
+ }
+ }
+
+ {
+ lset_t s = LELEM(np);
+
+ if (LDISJOINT(s
+ , needed | smc->opt_payloads| LELEM(ISAKMP_NEXT_N) | LELEM(ISAKMP_NEXT_D)))
+ {
+ loglog(RC_LOG_SERIOUS, "%smessage ignored because it "
+ "contains an unexpected payload type (%s)"
+ , excuse, enum_show(&payload_names, np));
+ SEND_NOTIFICATION(INVALID_PAYLOAD_TYPE);
+ return;
+ }
+ needed &= ~s;
+ }
+
+ if (!in_struct(&pd->payload, sd, &md->message_pbs, &pd->pbs))
+ {
+ loglog(RC_LOG_SERIOUS, "%smalformed payload in packet", excuse);
+ if (md->hdr.isa_xchg != ISAKMP_XCHG_INFO)
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED);
+ return;
+ }
+
+ /* place this payload at the end of the chain for this type */
+ {
+ struct payload_digest **p;
+
+ for (p = &md->chain[np]; *p != NULL; p = &(*p)->next)
+ ;
+ *p = pd;
+ pd->next = NULL;
+ }
+
+ np = pd->payload.generic.isag_np;
+ pd++;
+
+ /* since we've digested one payload happily, it is probably
+ * the case that any decryption worked. So we will not suggest
+ * encryption failure as an excuse for subsequent payload
+ * problems.
+ */
+ excuse = "";
+ }
+
+ md->digest_roof = pd;
+
+ DBG(DBG_PARSING,
+ if (pbs_left(&md->message_pbs) != 0)
+ DBG_log("removing %d bytes of padding", (int) pbs_left(&md->message_pbs)));
+
+ md->message_pbs.roof = md->message_pbs.cur;
+
+ /* check that all mandatory payloads appeared */
+
+ if (needed != 0)
+ {
+ loglog(RC_LOG_SERIOUS, "message for %s is missing payloads %s"
+ , enum_show(&state_names, from_state)
+ , bitnamesof(payload_name, needed));
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED);
+ return;
+ }
+ }
+
+ /* more sanity checking: enforce most ordering constraints */
+
+ if (IS_PHASE1(from_state))
+ {
+ /* rfc2409: The Internet Key Exchange (IKE), 5 Exchanges:
+ * "The SA payload MUST precede all other payloads in a phase 1 exchange."
+ */
+ if (md->chain[ISAKMP_NEXT_SA] != NULL
+ && md->hdr.isa_np != ISAKMP_NEXT_SA)
+ {
+ loglog(RC_LOG_SERIOUS, "malformed Phase 1 message: does not start with an SA payload");
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED);
+ return;
+ }
+ }
+ else if (IS_QUICK(from_state))
+ {
+ /* rfc2409: The Internet Key Exchange (IKE), 5.5 Phase 2 - Quick Mode
+ *
+ * "In Quick Mode, a HASH payload MUST immediately follow the ISAKMP
+ * header and a SA payload MUST immediately follow the HASH."
+ * [NOTE: there may be more than one SA payload, so this is not
+ * totally reasonable. Probably all SAs should be so constrained.]
+ *
+ * "If ISAKMP is acting as a client negotiator on behalf of another
+ * party, the identities of the parties MUST be passed as IDci and
+ * then IDcr."
+ *
+ * "With the exception of the HASH, SA, and the optional ID payloads,
+ * there are no payload ordering restrictions on Quick Mode."
+ */
+
+ if (md->hdr.isa_np != ISAKMP_NEXT_HASH)
+ {
+ loglog(RC_LOG_SERIOUS, "malformed Quick Mode message: does not start with a HASH payload");
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED);
+ return;
+ }
+
+ {
+ struct payload_digest *p;
+ int i;
+
+ for (p = md->chain[ISAKMP_NEXT_SA], i = 1; p != NULL
+ ; p = p->next, i++)
+ {
+ if (p != &md->digest[i])
+ {
+ loglog(RC_LOG_SERIOUS, "malformed Quick Mode message: SA payload is in wrong position");
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED);
+ return;
+ }
+ }
+ }
+
+ /* rfc2409: The Internet Key Exchange (IKE), 5.5 Phase 2 - Quick Mode:
+ * "If ISAKMP is acting as a client negotiator on behalf of another
+ * party, the identities of the parties MUST be passed as IDci and
+ * then IDcr."
+ */
+ {
+ struct payload_digest *id = md->chain[ISAKMP_NEXT_ID];
+
+ if (id != NULL)
+ {
+ if (id->next == NULL || id->next->next != NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "malformed Quick Mode message:"
+ " if any ID payload is present,"
+ " there must be exactly two");
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED);
+ return;
+ }
+ if (id+1 != id->next)
+ {
+ loglog(RC_LOG_SERIOUS, "malformed Quick Mode message:"
+ " the ID payloads are not adjacent");
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED);
+ return;
+ }
+ }
+ }
+ }
+
+ /* Ignore payloads that we don't handle:
+ * Delete, Notification, VendorID
+ */
+ /* XXX Handle deletions */
+ /* XXX Handle Notifications */
+ /* XXX Handle VID payloads */
+ {
+ struct payload_digest *p;
+
+ for (p = md->chain[ISAKMP_NEXT_N]; p != NULL; p = p->next)
+ {
+ if (p->payload.notification.isan_type != R_U_THERE
+ && p->payload.notification.isan_type != R_U_THERE_ACK)
+ {
+ loglog(RC_LOG_SERIOUS, "ignoring informational payload, type %s"
+ , enum_show(&notification_names, p->payload.notification.isan_type));
+ }
+ DBG_cond_dump(DBG_PARSING, "info:", p->pbs.cur, pbs_left(&p->pbs));
+ }
+
+ for (p = md->chain[ISAKMP_NEXT_D]; p != NULL; p = p->next)
+ {
+ accept_delete(st, md, p);
+ DBG_cond_dump(DBG_PARSING, "del:", p->pbs.cur, pbs_left(&p->pbs));
+ }
+
+ for (p = md->chain[ISAKMP_NEXT_VID]; p != NULL; p = p->next)
+ {
+ handle_vendorid(md, p->pbs.cur, pbs_left(&p->pbs));
+ }
+ }
+ md->from_state = from_state;
+ md->smc = smc;
+ md->st = st;
+
+ /* possibly fill in hdr */
+ if (smc->first_out_payload != ISAKMP_NEXT_NONE)
+ echo_hdr(md, (smc->flags & SMF_OUTPUT_ENCRYPTED) != 0
+ , smc->first_out_payload);
+
+ complete_state_transition(mdp, smc->processor(md));
+}
+
+/* complete job started by the state-specific state transition function */
+
+void
+complete_state_transition(struct msg_digest **mdp, stf_status result)
+{
+ bool has_xauth_policy;
+ bool is_xauth_server;
+ struct msg_digest *md = *mdp;
+ const struct state_microcode *smc = md->smc;
+ enum state_kind from_state = md->from_state;
+ struct state *st;
+
+ cur_state = st = md->st; /* might have changed */
+
+ /* If state has DPD support, import it */
+ if (st && md->dpd)
+ st->st_dpd = TRUE;
+
+ switch (result)
+ {
+ case STF_IGNORE:
+ break;
+
+ case STF_SUSPEND:
+ /* the stf didn't complete its job: don't relase md */
+ *mdp = NULL;
+ break;
+
+ case STF_OK:
+ /* advance the state */
+ st->st_state = smc->next_state;
+
+ /* Delete previous retransmission event.
+ * New event will be scheduled below.
+ */
+ delete_event(st);
+
+ /* replace previous receive packet with latest */
+
+ pfreeany(st->st_rpacket.ptr);
+
+ if (md->encrypted)
+ {
+ /* if encrypted, duplication already done */
+ st->st_rpacket = md->raw_packet;
+ md->raw_packet.ptr = NULL;
+ }
+ else
+ {
+ clonetochunk(st->st_rpacket
+ , md->packet_pbs.start
+ , pbs_room(&md->packet_pbs), "raw packet");
+ }
+
+ /* free previous transmit packet */
+ freeanychunk(st->st_tpacket);
+
+ /* if requested, send the new reply packet */
+ if (smc->flags & SMF_REPLY)
+ {
+ close_output_pbs(&md->reply); /* good form, but actually a no-op */
+
+ clonetochunk(st->st_tpacket, md->reply.start
+ , pbs_offset(&md->reply), "reply packet");
+
+ if (nat_traversal_enabled)
+ nat_traversal_change_port_lookup(md, md->st);
+
+ /* actually send the packet
+ * Note: this is a great place to implement "impairments"
+ * for testing purposes. Suppress or duplicate the
+ * send_packet call depending on st->st_state.
+ */
+ send_packet(st, enum_name(&state_names, from_state));
+ }
+
+ /* Schedule for whatever timeout is specified */
+ {
+ time_t delay;
+ enum event_type kind = smc->timeout_event;
+ bool agreed_time = FALSE;
+ struct connection *c = st->st_connection;
+
+ switch (kind)
+ {
+ case EVENT_RETRANSMIT: /* Retransmit packet */
+ delay = EVENT_RETRANSMIT_DELAY_0;
+ break;
+
+ case EVENT_SA_REPLACE: /* SA replacement event */
+ if (IS_PHASE1(st->st_state))
+ {
+ /* Note: we will defer to the "negotiated" (dictated)
+ * lifetime if we are POLICY_DONT_REKEY.
+ * This allows the other side to dictate
+ * a time we would not otherwise accept
+ * but it prevents us from having to initiate
+ * rekeying. The negative consequences seem
+ * minor.
+ */
+ delay = c->sa_ike_life_seconds;
+ if ((c->policy & POLICY_DONT_REKEY)
+ || delay >= st->st_oakley.life_seconds)
+ {
+ agreed_time = TRUE;
+ delay = st->st_oakley.life_seconds;
+ }
+ }
+ else
+ {
+ /* Delay is min of up to four things:
+ * each can limit the lifetime.
+ */
+ delay = c->sa_ipsec_life_seconds;
+ if (st->st_ah.present
+ && delay >= st->st_ah.attrs.life_seconds)
+ {
+ agreed_time = TRUE;
+ delay = st->st_ah.attrs.life_seconds;
+ }
+ if (st->st_esp.present
+ && delay >= st->st_esp.attrs.life_seconds)
+ {
+ agreed_time = TRUE;
+ delay = st->st_esp.attrs.life_seconds;
+ }
+ if (st->st_ipcomp.present
+ && delay >= st->st_ipcomp.attrs.life_seconds)
+ {
+ agreed_time = TRUE;
+ delay = st->st_ipcomp.attrs.life_seconds;
+ }
+ }
+
+ /* By default, we plan to rekey.
+ *
+ * If there isn't enough time to rekey, plan to
+ * expire.
+ *
+ * If we are --dontrekey, a lot more rules apply.
+ * If we are the Initiator, use REPLACE_IF_USED.
+ * If we are the Responder, and the dictated time
+ * was unacceptable (too large), plan to REPLACE
+ * (the only way to ratchet down the time).
+ * If we are the Responder, and the dictated time
+ * is acceptable, plan to EXPIRE.
+ *
+ * Important policy lies buried here.
+ * For example, we favour the initiator over the
+ * responder by making the initiator start rekeying
+ * sooner. Also, fuzz is only added to the
+ * initiator's margin.
+ *
+ * Note: for ISAKMP SA, we let the negotiated
+ * time stand (implemented by earlier logic).
+ */
+ if (agreed_time
+ && (c->policy & POLICY_DONT_REKEY))
+ {
+ kind = (smc->flags & SMF_INITIATOR)
+ ? EVENT_SA_REPLACE_IF_USED
+ : EVENT_SA_EXPIRE;
+ }
+ if (kind != EVENT_SA_EXPIRE)
+ {
+ unsigned long marg = c->sa_rekey_margin;
+
+ if (smc->flags & SMF_INITIATOR)
+ marg += marg
+ * c->sa_rekey_fuzz / 100.E0
+ * (rand() / (RAND_MAX + 1.E0));
+ else
+ marg /= 2;
+
+ if ((unsigned long)delay > marg)
+ {
+ delay -= marg;
+ st->st_margin = marg;
+ }
+ else
+ {
+ kind = EVENT_SA_EXPIRE;
+ }
+ }
+ break;
+
+ case EVENT_NULL: /* non-event */
+ case EVENT_REINIT_SECRET: /* Refresh cookie secret */
+ default:
+ bad_case(kind);
+ }
+ event_schedule(kind, delay, st);
+ }
+
+ /* tell whack and log of progress */
+ {
+ const char *story = state_story[st->st_state - STATE_MAIN_R0];
+ enum rc_type w = RC_NEW_STATE + st->st_state;
+ char sadetails[128];
+
+ sadetails[0]='\0';
+
+ if (IS_IPSEC_SA_ESTABLISHED(st->st_state))
+ {
+ char *b = sadetails;
+ const char *ini = " {";
+ const char *fin = "";
+
+ /* -1 is to leave space for "fin" */
+
+ if (st->st_esp.present)
+ {
+ snprintf(b, sizeof(sadetails)-(b-sadetails)-1
+ , "%sESP=>0x%08x <0x%08x"
+ , ini
+ , ntohl(st->st_esp.attrs.spi)
+ , ntohl(st->st_esp.our_spi));
+ ini = " ";
+ fin = "}";
+ }
+ /* advance b to end of string */
+ b = b + strlen(b);
+
+ if (st->st_ah.present)
+ {
+ snprintf(b, sizeof(sadetails)-(b-sadetails)-1
+ , "%sAH=>0x%08x <0x%08x"
+ , ini
+ , ntohl(st->st_ah.attrs.spi)
+ , ntohl(st->st_ah.our_spi));
+ ini = " ";
+ fin = "}";
+ }
+ /* advance b to end of string */
+ b = b + strlen(b);
+
+ if (st->st_ipcomp.present)
+ {
+ snprintf(b, sizeof(sadetails)-(b-sadetails)-1
+ , "%sIPCOMP=>0x%08x <0x%08x"
+ , ini
+ , ntohl(st->st_ipcomp.attrs.spi)
+ , ntohl(st->st_ipcomp.our_spi));
+ ini = " ";
+ fin = "}";
+ }
+ /* advance b to end of string */
+ b = b + strlen(b);
+
+ if (st->nat_traversal)
+ {
+ char oa[ADDRTOT_BUF];
+ addrtot(&st->nat_oa, 0, oa, sizeof(oa));
+ snprintf(b, sizeof(sadetails)-(b-sadetails)-1
+ , "%sNATOA=%s"
+ , ini, oa);
+ ini = " ";
+ fin = "}";
+ }
+
+ /* advance b to end of string */
+ b = b + strlen(b);
+
+ if (st->st_dpd)
+ {
+ snprintf(b, sizeof(sadetails)-(b-sadetails)-1
+ , "%sDPD"
+ , ini);
+ ini = " ";
+ fin = "}";
+ }
+
+ strcat(b, fin);
+ }
+
+ if (IS_ISAKMP_SA_ESTABLISHED(st->st_state)
+ || IS_IPSEC_SA_ESTABLISHED(st->st_state))
+ {
+ /* log our success */
+ plog("%s%s", story, sadetails);
+ w = RC_SUCCESS;
+ }
+
+ /* tell whack our progress */
+ whack_log(w
+ , "%s: %s%s"
+ , enum_name(&state_names, st->st_state)
+ , story, sadetails);
+ }
+
+ has_xauth_policy = (st->st_connection->policy
+ & (POLICY_XAUTH_RSASIG | POLICY_XAUTH_PSK))
+ != LEMPTY;
+ is_xauth_server = (st->st_connection->policy
+ & POLICY_XAUTH_SERVER)
+ != LEMPTY;
+
+ /* Should we start XAUTH as a server */
+ if (has_xauth_policy && is_xauth_server
+ && IS_ISAKMP_SA_ESTABLISHED(st->st_state)
+ && !st->st_xauth.started)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("starting XAUTH server")
+ )
+ xauth_send_request(st);
+ break;
+ }
+
+ /* Wait for XAUTH request from server */
+ if (has_xauth_policy && !is_xauth_server
+ && IS_ISAKMP_SA_ESTABLISHED(st->st_state)
+ && !st->st_xauth.started)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("waiting for XAUTH request from server")
+ )
+ break;
+ }
+
+ /* Should we start ModeConfig as a client? */
+ if (st->st_connection->spd.this.modecfg
+ && IS_ISAKMP_SA_ESTABLISHED(st->st_state)
+ && !(st->st_connection->policy & POLICY_MODECFG_PUSH)
+ && !st->st_modecfg.started)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("starting ModeCfg client in pull mode")
+ )
+ modecfg_send_request(st);
+ break;
+ }
+
+ /* Should we start ModeConfig as a server? */
+ if (st->st_connection->spd.that.modecfg
+ && IS_ISAKMP_SA_ESTABLISHED(st->st_state)
+ && !st->st_modecfg.started
+ && (st->st_connection->policy & POLICY_MODECFG_PUSH))
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("starting ModeCfg server in push mode")
+ )
+ modecfg_send_set(st);
+ break;
+ }
+
+ /* Wait for ModeConfig set from server */
+ if (st->st_connection->spd.this.modecfg
+ && IS_ISAKMP_SA_ESTABLISHED(st->st_state)
+ && !st->st_modecfg.vars_set)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("waiting for ModeCfg set from server")
+ )
+ break;
+ }
+
+ if (smc->flags & SMF_RELEASE_PENDING_P2)
+ {
+ /* Initiate any Quick Mode negotiations that
+ * were waiting to piggyback on this Keying Channel.
+ *
+ * ??? there is a potential race condition
+ * if we are the responder: the initial Phase 2
+ * message might outrun the final Phase 1 message.
+ * I think that retransmission will recover.
+ */
+ unpend(st);
+ }
+
+ if (IS_ISAKMP_SA_ESTABLISHED(st->st_state)
+ || IS_IPSEC_SA_ESTABLISHED(st->st_state))
+ release_whack(st);
+ break;
+
+ case STF_INTERNAL_ERROR:
+ whack_log(RC_INTERNALERR + md->note
+ , "%s: internal error"
+ , enum_name(&state_names, st->st_state));
+
+ DBG(DBG_CONTROL,
+ DBG_log("state transition function for %s had internal error"
+ , enum_name(&state_names, from_state)));
+ break;
+
+ default: /* a shortcut to STF_FAIL, setting md->note */
+ passert(result > STF_FAIL);
+ md->note = result - STF_FAIL;
+ result = STF_FAIL;
+ /* FALL THROUGH ... */
+ case STF_FAIL:
+ /* As it is, we act as if this message never happened:
+ * whatever retrying was in place, remains in place.
+ */
+ whack_log(RC_NOTIFICATION + md->note
+ , "%s: %s"
+ , enum_name(&state_names, (st == NULL)? STATE_MAIN_R0:st->st_state)
+ , enum_name(&notification_names, md->note));
+
+ SEND_NOTIFICATION(md->note);
+
+ DBG(DBG_CONTROL,
+ DBG_log("state transition function for %s failed: %s"
+ , enum_name(&state_names, from_state)
+ , enum_name(&notification_names, md->note)));
+ break;
+ }
+}
diff --git a/src/pluto/demux.h b/src/pluto/demux.h
new file mode 100644
index 000000000..373dd6315
--- /dev/null
+++ b/src/pluto/demux.h
@@ -0,0 +1,93 @@
+/* demultiplex incoming IKE messages
+ * Copyright (C) 1998-2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: demux.h,v 1.4 2004/07/22 22:57:25 as Exp $
+ */
+
+#include "packet.h"
+
+struct state; /* forward declaration of tag */
+extern void init_demux(void);
+extern bool send_packet(struct state *st, const char *where);
+extern void comm_handle(const struct iface *ifp);
+
+extern u_int8_t reply_buffer[MAX_OUTPUT_UDP_SIZE];
+
+/* State transition function infrastructure
+ *
+ * com_handle parses a message, decides what state object it applies to,
+ * and calls the appropriate state transition function (STF).
+ * These declarations define the interface to these functions.
+ *
+ * Each STF must be able to be restarted up to any failure point:
+ * a later message will cause the state to be re-entered. This
+ * explains the use of the replace macro and the care in handling
+ * MP_INT members of struct state.
+ */
+
+struct payload_digest {
+ pb_stream pbs;
+ union payload payload;
+ struct payload_digest *next; /* of same kind */
+};
+
+/* message digest
+ * Note: raw_packet and packet_pbs are "owners" of space on heap.
+ */
+
+struct msg_digest {
+ struct msg_digest *next; /* for free list */
+ chunk_t raw_packet; /* if encrypted, received packet before decryption */
+ const struct iface *iface; /* interface on which message arrived */
+ ip_address sender; /* where message came from */
+ u_int16_t sender_port; /* host order */
+ pb_stream packet_pbs; /* whole packet */
+ pb_stream message_pbs; /* message to be processed */
+ struct isakmp_hdr hdr; /* message's header */
+ bool encrypted; /* was it encrypted? */
+ enum state_kind from_state; /* state we started in */
+ const struct state_microcode *smc; /* microcode for initial state */
+ struct state *st; /* current state object */
+ pb_stream reply; /* room for reply */
+ pb_stream rbody; /* room for reply body (after header) */
+ notification_t note; /* reason for failure */
+ bool dpd; /* peer supports RFC 3706 DPD */
+ bool openpgp; /* peer supports OpenPGP certificates */
+
+# define PAYLIMIT 40
+ struct payload_digest
+ digest[PAYLIMIT],
+ *digest_roof,
+ *chain[ISAKMP_NEXT_ROOF];
+ unsigned short nat_traversal_vid;
+};
+
+extern void release_md(struct msg_digest *md);
+
+/* status for state-transition-function
+ * Note: STF_FAIL + notification_t means fail with that notification
+ */
+
+typedef enum {
+ STF_IGNORE, /* don't respond */
+ STF_SUSPEND, /* unfinished -- don't release resources */
+ STF_OK, /* success */
+ STF_INTERNAL_ERROR, /* discard everything, we failed */
+ STF_FAIL /* discard everything, something failed. notification_t added. */
+} stf_status;
+
+typedef stf_status state_transition_fn(struct msg_digest *md);
+
+extern void complete_state_transition(struct msg_digest **mdp, stf_status result);
+
+extern void free_md_pool(void);
diff --git a/src/pluto/dnskey.c b/src/pluto/dnskey.c
new file mode 100644
index 000000000..23863b0a2
--- /dev/null
+++ b/src/pluto/dnskey.c
@@ -0,0 +1,1962 @@
+/* Find public key in DNS
+ * Copyright (C) 2000-2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: dnskey.c,v 1.5 2005/09/08 16:26:30 as Exp $
+ */
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <netdb.h> /* ??? for h_errno */
+#include <sys/queue.h>
+
+#include <freeswan.h>
+#include <ipsec_policy.h>
+
+#include "constants.h"
+#include "adns.h" /* needs <resolv.h> */
+#include "defs.h"
+#include "log.h"
+#include "id.h"
+#include "connections.h"
+#include "keys.h" /* needs connections.h */
+#include "dnskey.h"
+#include "packet.h"
+#include "timer.h"
+
+/* somebody has to decide */
+#define MAX_TXT_RDATA ((MAX_KEY_BYTES * 8 / 6) + 40) /* somewhat arbitrary overkill */
+
+/* ADNS stuff */
+
+int adns_qfd = NULL_FD, /* file descriptor for sending queries to adns (O_NONBLOCK) */
+ adns_afd = NULL_FD; /* file descriptor for receiving answers from adns */
+static pid_t adns_pid = 0;
+const char *pluto_adns_option = NULL; /* path from --pluto_adns */
+
+int adns_restart_count;
+#define ADNS_RESTART_MAX 20
+
+void
+init_adns(void)
+{
+ const char *adns_path = pluto_adns_option;
+#ifndef USE_LWRES
+ static const char adns_name[] = "_pluto_adns";
+ const char *helper_bin_dir = getenv("IPSEC_LIBDIR");
+#else /* USE_LWRES */
+ static const char adns_name[] = "lwdnsq";
+ const char *helper_bin_dir = getenv("IPSEC_EXECDIR");
+#endif /* USE_LWRES */
+ char adns_path_space[4096]; /* plenty long? */
+ int qfds[2];
+ int afds[2];
+
+ /* find a pathname to the ADNS program */
+ if (adns_path == NULL)
+ {
+ /* pathname was not specified as an option: build it.
+ * First, figure out the directory to be used.
+ */
+ ssize_t n;
+
+ if (helper_bin_dir != NULL)
+ {
+ n = strlen(helper_bin_dir);
+ if ((size_t)n <= sizeof(adns_path_space) - sizeof(adns_name))
+ {
+ strcpy(adns_path_space, helper_bin_dir);
+ if (n > 0 && adns_path_space[n -1] != '/')
+ adns_path_space[n++] = '/';
+ }
+ }
+ else
+ {
+ /* The program will be in the same directory as Pluto,
+ * so we use the sympolic link /proc/self/exe to
+ * tell us of the path prefix.
+ */
+ n = readlink("/proc/self/exe", adns_path_space, sizeof(adns_path_space));
+
+ if (n < 0)
+ exit_log_errno((e
+ , "readlink(\"/proc/self/exe\") failed in init_adns()"));
+
+ }
+
+ if ((size_t)n > sizeof(adns_path_space) - sizeof(adns_name))
+ exit_log("path to %s is too long", adns_name);
+
+ while (n > 0 && adns_path_space[n - 1] != '/')
+ n--;
+
+ strcpy(adns_path_space + n, adns_name);
+ adns_path = adns_path_space;
+ }
+ if (access(adns_path, X_OK) < 0)
+ exit_log_errno((e, "%s missing or not executable", adns_path));
+
+ if (pipe(qfds) != 0 || pipe(afds) != 0)
+ exit_log_errno((e, "pipe(2) failed in init_adns()"));
+
+ adns_pid = fork();
+ switch (adns_pid)
+ {
+ case -1:
+ exit_log_errno((e, "fork() failed in init_adns()"));
+
+ case 0:
+ /* child */
+ {
+ /* Make stdin and stdout our pipes.
+ * Take care to handle case where pipes already use these fds.
+ */
+ if (afds[1] == 0)
+ afds[1] = dup(afds[1]); /* avoid being overwritten */
+ if (qfds[0] != 0)
+ {
+ dup2(qfds[0], 0);
+ close(qfds[0]);
+ }
+ if (afds[1] != 1)
+ {
+ dup2(afds[1], 1);
+ close(qfds[1]);
+ }
+ if (afds[0] > 1)
+ close(afds[0]);
+ if (afds[1] > 1)
+ close(afds[1]);
+
+ DBG(DBG_DNS, execlp(adns_path, adns_name, "-d", NULL));
+
+ execlp(adns_path, adns_name, NULL);
+ exit_log_errno((e, "execlp of %s failed", adns_path));
+ }
+
+ default:
+ /* parent */
+ close(qfds[0]);
+ adns_qfd = qfds[1];
+ adns_afd = afds[0];
+ close(afds[1]);
+ fcntl(adns_qfd, F_SETFD, FD_CLOEXEC);
+ fcntl(adns_afd, F_SETFD, FD_CLOEXEC);
+ fcntl(adns_qfd, F_SETFL, O_NONBLOCK);
+ break;
+ }
+}
+
+void
+stop_adns(void)
+{
+ close_any(adns_qfd);
+ adns_qfd = NULL_FD;
+ close_any(adns_afd);
+ adns_afd = NULL_FD;
+
+ if (adns_pid != 0)
+ {
+ int status;
+ pid_t p = waitpid(adns_pid, &status, 0);
+
+ if (p == -1)
+ {
+ log_errno((e, "waitpid for ADNS process failed"));
+ }
+ else if (WIFEXITED(status))
+ {
+ if (WEXITSTATUS(status) != 0)
+ plog("ADNS process exited with status %d"
+ , (int) WEXITSTATUS(status));
+ }
+ else if (WIFSIGNALED(status))
+ {
+ plog("ADNS process terminated by signal %d", (int)WTERMSIG(status));
+ }
+ else
+ {
+ plog("wait for end of ADNS process returned odd status 0x%x\n"
+ , status);
+ }
+ }
+}
+
+
+
+/* tricky macro to pass any hot potato */
+#define TRY(x) { err_t ugh = x; if (ugh != NULL) return ugh; }
+
+
+/* Process TXT X-IPsec-Server record, accumulating relevant ones
+ * in cr->gateways_from_dns, a list sorted by "preference".
+ *
+ * Format of TXT record body: X-IPsec-Server ( nnn ) = iii kkk
+ * nnn is a 16-bit unsigned integer preference
+ * iii is @FQDN or dotted-decimal IPv4 address or colon-hex IPv6 address
+ * kkk is an optional RSA public signing key in base 64.
+ *
+ * NOTE: we've got to be very wary of anything we find -- bad guys
+ * might have prepared it.
+ */
+
+#define our_TXT_attr_string "X-IPsec-Server"
+static const char our_TXT_attr[] = our_TXT_attr_string;
+
+static err_t
+decode_iii(u_char **pp, struct id *gw_id)
+{
+ u_char *p = *pp + strspn(*pp, " \t");
+ u_char *e = p + strcspn(p, " \t");
+ u_char under = *e;
+
+ if (p == e)
+ return "TXT " our_TXT_attr_string " badly formed (no gateway specified)";
+
+ *e = '\0';
+ if (*p == '@')
+ {
+ /* gateway specification in this record is @FQDN */
+ err_t ugh = atoid(p, gw_id, FALSE);
+
+ if (ugh != NULL)
+ return builddiag("malformed FQDN in TXT " our_TXT_attr_string ": %s"
+ , ugh);
+ }
+ else
+ {
+ /* gateway specification is numeric */
+ ip_address ip;
+ err_t ugh = tnatoaddr(p, e-p
+ , strchr(p, ':') == NULL? AF_INET : AF_INET6
+ , &ip);
+
+ if (ugh != NULL)
+ return builddiag("malformed IP address in TXT " our_TXT_attr_string ": %s"
+ , ugh);
+
+ if (isanyaddr(&ip))
+ return "gateway address must not be 0.0.0.0 or 0::0";
+
+ iptoid(&ip, gw_id);
+ }
+
+ *e = under;
+ *pp = e + strspn(e, " \t");
+
+ return NULL;
+}
+
+static err_t
+process_txt_rr_body(u_char *str
+, bool doit /* should we capture information? */
+, enum dns_auth_level dns_auth_level
+, struct adns_continuation *const cr)
+{
+ const struct id *client_id = &cr->id; /* subject of query */
+ u_char *p = str;
+ unsigned long pref = 0;
+ struct gw_info gi;
+
+ p += strspn(p, " \t"); /* ignore leading whitespace */
+
+ /* is this for us? */
+ if (strncasecmp(p, our_TXT_attr, sizeof(our_TXT_attr)-1) != 0)
+ return NULL; /* neither interesting nor bad */
+
+ p += sizeof(our_TXT_attr) - 1; /* ignore our attribute name */
+ p += strspn(p, " \t"); /* ignore leading whitespace */
+
+ /* decode '(' nnn ')' */
+ if (*p != '(')
+ return "X-IPsec-Server missing '('";
+
+ {
+ char *e;
+
+ p++;
+ pref = strtoul(p, &e, 0);
+ if ((u_char *)e == p)
+ return "malformed X-IPsec-Server priority";
+
+ p = e + strspn(e, " \t");
+
+ if (*p != ')')
+ return "X-IPsec-Server priority missing ')'";
+
+ p++;
+ p += strspn(p, " \t");
+
+ if (pref > 0xFFFF)
+ return "X-IPsec-Server priority larger than 0xFFFF";
+ }
+
+ /* time for '=' */
+
+ if (*p != '=')
+ return "X-IPsec-Server priority missing '='";
+
+ p++;
+ p += strspn(p, " \t");
+
+ /* Decode iii (Security Gateway ID). */
+
+ zero(&gi); /* before first use */
+
+ TRY(decode_iii(&p, &gi.gw_id)); /* will need to unshare_id_content */
+
+ if (!cr->sgw_specified)
+ {
+ /* we don't know the peer's ID (because we are initiating
+ * and we don't know who to initiate with.
+ * So we're looking for gateway specs with an IP address
+ */
+ if (!id_is_ipaddr(&gi.gw_id))
+ {
+ DBG(DBG_DNS,
+ {
+ char cidb[BUF_LEN];
+ char gwidb[BUF_LEN];
+
+ idtoa(client_id, cidb, sizeof(cidb));
+ idtoa(&gi.gw_id, gwidb, sizeof(gwidb));
+ DBG_log("TXT %s record for %s: security gateway %s;"
+ " ignored because gateway's IP is unspecified"
+ , our_TXT_attr, cidb, gwidb);
+ });
+ return NULL; /* we cannot use this record, but it isn't wrong */
+ }
+ }
+ else
+ {
+ /* We do know the peer's ID (because we are responding)
+ * So we're looking for gateway specs specifying this known ID.
+ */
+ const struct id *peer_id = &cr->sgw_id;
+
+ if (!same_id(peer_id, &gi.gw_id))
+ {
+ DBG(DBG_DNS,
+ {
+ char cidb[BUF_LEN];
+ char gwidb[BUF_LEN];
+ char pidb[BUF_LEN];
+
+ idtoa(client_id, cidb, sizeof(cidb));
+ idtoa(&gi.gw_id, gwidb, sizeof(gwidb));
+ idtoa(peer_id, pidb, sizeof(pidb));
+ DBG_log("TXT %s record for %s: security gateway %s;"
+ " ignored -- looking to confirm %s as gateway"
+ , our_TXT_attr, cidb, gwidb, pidb);
+ });
+ return NULL; /* we cannot use this record, but it isn't wrong */
+ }
+ }
+
+ if (doit)
+ {
+ /* really accept gateway */
+ struct gw_info **gwip; /* gateway insertion point */
+
+ gi.client_id = *client_id; /* will need to unshare_id_content */
+
+ /* decode optional kkk: base 64 encoding of key */
+
+ gi.gw_key_present = *p != '\0';
+ if (gi.gw_key_present)
+ {
+ /* Decode base 64 encoding of key.
+ * Similar code is in process_lwdnsq_key.
+ */
+ u_char kb[RSA_MAX_ENCODING_BYTES]; /* plenty of space for binary form of public key */
+ chunk_t kbc;
+ struct RSA_public_key r;
+
+ err_t ugh = ttodatav(p, 0, 64, kb, sizeof(kb), &kbc.len
+ , diag_space, sizeof(diag_space), TTODATAV_SPACECOUNTS);
+
+ if (ugh != NULL)
+ return builddiag("malformed key data: %s", ugh);
+
+ if (kbc.len > sizeof(kb))
+ return builddiag("key data larger than %lu bytes"
+ , (unsigned long) sizeof(kb));
+
+ kbc.ptr = kb;
+ ugh = unpack_RSA_public_key(&r, &kbc);
+ if (ugh != NULL)
+ return builddiag("invalid key data: %s", ugh);
+
+ /* now find a key entry to put it in */
+ gi.key = public_key_from_rsa(&r);
+
+ free_RSA_public_content(&r);
+
+ unreference_key(&cr->last_info);
+ cr->last_info = reference_key(gi.key);
+ }
+
+ /* we're home free! Allocate everything and add to gateways list. */
+ gi.refcnt = 1;
+ gi.pref = pref;
+ gi.key->dns_auth_level = dns_auth_level;
+ gi.key->last_tried_time = gi.key->last_worked_time = NO_TIME;
+
+ /* find insertion point */
+ for (gwip = &cr->gateways_from_dns; *gwip != NULL && (*gwip)->pref < pref; gwip = &(*gwip)->next)
+ ;
+
+ DBG(DBG_DNS,
+ {
+ char cidb[BUF_LEN];
+ char gwidb[BUF_LEN];
+
+ idtoa(client_id, cidb, sizeof(cidb));
+ idtoa(&gi.gw_id, gwidb, sizeof(gwidb));
+ if (gi.gw_key_present)
+ {
+ DBG_log("gateway for %s is %s with key %s"
+ , cidb, gwidb, gi.key->u.rsa.keyid);
+ }
+ else
+ {
+ DBG_log("gateway for %s is %s; no key specified"
+ , cidb, gwidb);
+ }
+ });
+
+ gi.next = *gwip;
+ *gwip = clone_thing(gi, "gateway info");
+ unshare_id_content(&(*gwip)->gw_id);
+ unshare_id_content(&(*gwip)->client_id);
+ }
+
+ return NULL;
+}
+
+static const char *
+rr_typename(int type)
+{
+ switch (type)
+ {
+ case T_TXT:
+ return "TXT";
+ case T_KEY:
+ return "KEY";
+ default:
+ return "???";
+ }
+}
+
+
+#ifdef USE_LWRES
+
+# ifdef USE_KEYRR
+static err_t
+process_lwdnsq_key(u_char *str
+, enum dns_auth_level dns_auth_level
+, struct adns_continuation *const cr)
+{
+ /* fields of KEY record. See RFC 2535 3.1 KEY RDATA format. */
+ unsigned long flags /* 16 bits */
+ , protocol /* 8 bits */
+ , algorithm; /* 8 bits */
+
+ char *rest = str
+ , *p
+ , *endofnumber;
+
+ /* flags */
+ p = strsep(&rest, " \t");
+ if (p == NULL)
+ return "lwdnsq KEY: missing flags";
+
+ flags = strtoul(p, &endofnumber, 10);
+ if (*endofnumber != '\0')
+ return "lwdnsq KEY: malformed flags";
+
+ /* protocol */
+ p = strsep(&rest, " \t");
+ if (p == NULL)
+ return "lwdnsq KEY: missing protocol";
+
+ protocol = strtoul(p, &endofnumber, 10);
+ if (*endofnumber != '\0')
+ return "lwdnsq KEY: malformed protocol";
+
+ /* algorithm */
+ p = strsep(&rest, " \t");
+ if (p == NULL)
+ return "lwdnsq KEY: missing algorithm";
+
+ algorithm = strtoul(p, &endofnumber, 10);
+ if (*endofnumber != '\0')
+ return "lwdnsq KEY: malformed algorithm";
+
+ /* is this key interesting? */
+ if (protocol == 4 /* IPSEC (RFC 2535 3.1.3) */
+ && algorithm == 1 /* RSA/MD5 (RFC 2535 3.2) */
+ && (flags & 0x8000ul) == 0 /* use for authentication (3.1.2) */
+ && (flags & 0x2CF0ul) == 0) /* must be zero */
+ {
+ /* Decode base 64 encoding of key.
+ * Similar code is in process_txt_rr_body.
+ */
+ u_char kb[RSA_MAX_ENCODING_BYTES]; /* plenty of space for binary form of public key */
+ chunk_t kbc;
+ err_t ugh = ttodatav(rest, 0, 64, kb, sizeof(kb), &kbc.len
+ , diag_space, sizeof(diag_space), TTODATAV_IGNORESPACE);
+
+ if (ugh != NULL)
+ return builddiag("malformed key data: %s", ugh);
+
+ if (kbc.len > sizeof(kb))
+ return builddiag("key data larger than %lu bytes"
+ , (unsigned long) sizeof(kb));
+
+ kbc.ptr = kb;
+ TRY(add_public_key(&cr->id, dns_auth_level, PUBKEY_ALG_RSA, &kbc
+ , &cr->keys_from_dns));
+
+ /* keep a reference to last one */
+ unreference_key(&cr->last_info);
+ cr->last_info = reference_key(cr->keys_from_dns->key);
+ }
+ return NULL;
+}
+# endif /* USE_KEYRR */
+
+#else /* ! USE_LWRES */
+
+/* structure of Query Reply (RFC 1035 4.1.1):
+ *
+ * +---------------------+
+ * | Header |
+ * +---------------------+
+ * | Question | the question for the name server
+ * +---------------------+
+ * | Answer | RRs answering the question
+ * +---------------------+
+ * | Authority | RRs pointing toward an authority
+ * +---------------------+
+ * | Additional | RRs holding additional information
+ * +---------------------+
+ */
+
+/* Header section format (as modified by RFC 2535 6.1):
+ * 1 1 1 1 1 1
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | ID |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * |QR| Opcode |AA|TC|RD|RA| Z|AD|CD| RCODE |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | QDCOUNT |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | ANCOUNT |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | NSCOUNT |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | ARCOUNT |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+struct qr_header {
+ u_int16_t id; /* 16-bit identifier to match query */
+
+ u_int16_t stuff; /* packed crud: */
+
+#define QRS_QR 0x8000 /* QR: on if this is a response */
+
+#define QRS_OPCODE_SHIFT 11 /* OPCODE field */
+#define QRS_OPCODE_MASK 0xF
+#define QRSO_QUERY 0 /* standard query */
+#define QRSO_IQUERY 1 /* inverse query */
+#define QRSO_STATUS 2 /* server status request query */
+
+#define QRS_AA 0x0400 /* AA: on if Authoritative Answer */
+#define QRS_TC 0x0200 /* TC: on if truncation happened */
+#define QRS_RD 0x0100 /* RD: on if recursion desired */
+#define QRS_RA 0x0080 /* RA: on if recursion available */
+#define QRS_Z 0x0040 /* Z: reserved; must be zero */
+#define QRS_AD 0x0020 /* AD: on if authentic data (RFC 2535) */
+#define QRS_CD 0x0010 /* AD: on if checking disabled (RFC 2535) */
+
+#define QRS_RCODE_SHIFT 0 /* RCODE field: response code */
+#define QRS_RCODE_MASK 0xF
+#define QRSR_OK 0
+
+
+ u_int16_t qdcount; /* number of entries in question section */
+ u_int16_t ancount; /* number of resource records in answer section */
+ u_int16_t nscount; /* number of name server resource records in authority section */
+ u_int16_t arcount; /* number of resource records in additional records section */
+};
+
+static field_desc qr_header_fields[] = {
+ { ft_nat, 16/BITS_PER_BYTE, "ID", NULL },
+ { ft_nat, 16/BITS_PER_BYTE, "stuff", NULL },
+ { ft_nat, 16/BITS_PER_BYTE, "QD Count", NULL },
+ { ft_nat, 16/BITS_PER_BYTE, "Answer Count", NULL },
+ { ft_nat, 16/BITS_PER_BYTE, "Authority Count", NULL },
+ { ft_nat, 16/BITS_PER_BYTE, "Additional Count", NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+static struct_desc qr_header_desc = {
+ "Query Response Header",
+ qr_header_fields,
+ sizeof(struct qr_header)
+};
+
+/* Messages for codes in RCODE (see RFC 1035 4.1.1) */
+static const err_t rcode_text[QRS_RCODE_MASK + 1] = {
+ NULL, /* not an error */
+ "Format error - The name server was unable to interpret the query",
+ "Server failure - The name server was unable to process this query"
+ " due to a problem with the name server",
+ "Name Error - Meaningful only for responses from an authoritative name"
+ " server, this code signifies that the domain name referenced in"
+ " the query does not exist",
+ "Not Implemented - The name server does not support the requested"
+ " kind of query",
+ "Refused - The name server refuses to perform the specified operation"
+ " for policy reasons",
+ /* the rest are reserved for future use */
+ };
+
+/* throw away a possibly compressed domain name */
+
+static err_t
+eat_name(pb_stream *pbs)
+{
+ u_char name_buf[NS_MAXDNAME + 2];
+ u_char *ip = pbs->cur;
+ unsigned oi = 0;
+ unsigned jump_count = 0;
+
+ for (;;)
+ {
+ u_int8_t b;
+
+ if (ip >= pbs->roof)
+ return "ran out of message while skipping domain name";
+
+ b = *ip++;
+ if (jump_count == 0)
+ pbs->cur = ip;
+
+ if (b == 0)
+ break;
+
+ switch (b & 0xC0)
+ {
+ case 0x00:
+ /* we grab the next b characters */
+ if (oi + b > NS_MAXDNAME)
+ return "domain name too long";
+
+ if (pbs->roof - ip <= b)
+ return "domain name falls off end of message";
+
+ if (oi != 0)
+ name_buf[oi++] = '.';
+
+ memcpy(name_buf + oi, ip, b);
+ oi += b;
+ ip += b;
+ if (jump_count == 0)
+ pbs->cur = ip;
+ break;
+
+ case 0xC0:
+ {
+ unsigned ix;
+
+ if (ip >= pbs->roof)
+ return "ran out of message in middle of compressed domain name";
+
+ ix = ((b & ~0xC0u) << 8) | *ip++;
+ if (jump_count == 0)
+ pbs->cur = ip;
+
+ if (ix >= pbs_room(pbs))
+ return "impossible compressed domain name";
+
+ /* Avoid infinite loop.
+ * There can be no more jumps than there are bytes
+ * in the packet. Not a tight limit, but good enough.
+ */
+ jump_count++;
+ if (jump_count > pbs_room(pbs))
+ return "loop in compressed domain name";
+
+ ip = pbs->start + ix;
+ }
+ break;
+
+ default:
+ return "invalid code in label";
+ }
+ }
+
+ name_buf[oi++] = '\0';
+
+ DBG(DBG_DNS, DBG_log("skipping name %s", name_buf));
+
+ return NULL;
+}
+
+static err_t
+eat_name_helpfully(pb_stream *pbs, const char *context)
+{
+ err_t ugh = eat_name(pbs);
+
+ return ugh == NULL? ugh
+ : builddiag("malformed name within DNS record of %s: %s", context, ugh);
+}
+
+/* non-variable part of 4.1.2 Question Section entry:
+ * 1 1 1 1 1 1
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | |
+ * / QNAME /
+ * / /
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | QTYPE |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | QCLASS |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+
+struct qs_fixed {
+ u_int16_t qtype;
+ u_int16_t qclass;
+};
+
+static field_desc qs_fixed_fields[] = {
+ { ft_loose_enum, 16/BITS_PER_BYTE, "QTYPE", &rr_qtype_names },
+ { ft_loose_enum, 16/BITS_PER_BYTE, "QCLASS", &rr_class_names },
+ { ft_end, 0, NULL, NULL }
+};
+
+static struct_desc qs_fixed_desc = {
+ "Question Section entry fixed part",
+ qs_fixed_fields,
+ sizeof(struct qs_fixed)
+};
+
+/* 4.1.3. Resource record format:
+ * 1 1 1 1 1 1
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | |
+ * / /
+ * / NAME /
+ * | |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | TYPE |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | CLASS |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | TTL |
+ * | |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | RDLENGTH |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
+ * / RDATA /
+ * / /
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+
+struct rr_fixed {
+ u_int16_t type;
+ u_int16_t class;
+ u_int32_t ttl; /* actually signed */
+ u_int16_t rdlength;
+};
+
+
+static field_desc rr_fixed_fields[] = {
+ { ft_loose_enum, 16/BITS_PER_BYTE, "type", &rr_type_names },
+ { ft_loose_enum, 16/BITS_PER_BYTE, "class", &rr_class_names },
+ { ft_nat, 32/BITS_PER_BYTE, "TTL", NULL },
+ { ft_nat, 16/BITS_PER_BYTE, "RD length", NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+static struct_desc rr_fixed_desc = {
+ "Resource Record fixed part",
+ rr_fixed_fields,
+ /* note: following is tricky: avoids padding problems */
+ offsetof(struct rr_fixed, rdlength) + sizeof(u_int16_t)
+};
+
+/* RFC 1035 3.3.14: TXT RRs have text in the RDATA field.
+ * It is in the form of a sequence of <character-string>s as described in 3.3.
+ * unpack_txt_rdata() deals with this peculiar representation.
+ */
+
+/* RFC 2535 3.1 KEY RDATA format:
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | flags | protocol | algorithm |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | /
+ * / public key /
+ * / /
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
+ */
+
+struct key_rdata {
+ u_int16_t flags;
+ u_int8_t protocol;
+ u_int8_t algorithm;
+};
+
+static field_desc key_rdata_fields[] = {
+ { ft_nat, 16/BITS_PER_BYTE, "flags", NULL },
+ { ft_nat, 8/BITS_PER_BYTE, "protocol", NULL },
+ { ft_nat, 8/BITS_PER_BYTE, "algorithm", NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+static struct_desc key_rdata_desc = {
+ "KEY RR RData fixed part",
+ key_rdata_fields,
+ sizeof(struct key_rdata)
+};
+
+/* RFC 2535 4.1 SIG RDATA format:
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | type covered | algorithm | labels |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | original TTL |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | signature expiration |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | signature inception |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | key tag | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ signer's name +
+ * | /
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-/
+ * / /
+ * / signature /
+ * / /
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+struct sig_rdata {
+ u_int16_t type_covered;
+ u_int8_t algorithm;
+ u_int8_t labels;
+ u_int32_t original_ttl;
+ u_int32_t sig_expiration;
+ u_int32_t sig_inception;
+ u_int16_t key_tag;
+};
+
+static field_desc sig_rdata_fields[] = {
+ { ft_nat, 16/BITS_PER_BYTE, "type_covered", NULL},
+ { ft_nat, 8/BITS_PER_BYTE, "algorithm", NULL},
+ { ft_nat, 8/BITS_PER_BYTE, "labels", NULL},
+ { ft_nat, 32/BITS_PER_BYTE, "original ttl", NULL},
+ { ft_nat, 32/BITS_PER_BYTE, "sig expiration", NULL},
+ { ft_nat, 32/BITS_PER_BYTE, "sig inception", NULL},
+ { ft_nat, 16/BITS_PER_BYTE, "key tag", NULL},
+ { ft_end, 0, NULL, NULL }
+};
+
+static struct_desc sig_rdata_desc = {
+ "SIG RR RData fixed part",
+ sig_rdata_fields,
+ sizeof(struct sig_rdata)
+};
+
+/* handle a KEY Resource Record. */
+
+#ifdef USE_KEYRR
+static err_t
+process_key_rr(u_char *ptr, size_t len
+, bool doit /* should we capture information? */
+, enum dns_auth_level dns_auth_level
+, struct adns_continuation *const cr)
+{
+ pb_stream pbs;
+ struct key_rdata kr;
+
+ if (len < sizeof(struct key_rdata))
+ return "KEY Resource Record's RD Length is too small";
+
+ init_pbs(&pbs, ptr, len, "KEY RR");
+
+ if (!in_struct(&kr, &key_rdata_desc, &pbs, NULL))
+ return "failed to get fixed part of KEY Resource Record RDATA";
+
+ if (kr.protocol == 4 /* IPSEC (RFC 2535 3.1.3) */
+ && kr.algorithm == 1 /* RSA/MD5 (RFC 2535 3.2) */
+ && (kr.flags & 0x8000) == 0 /* use for authentication (3.1.2) */
+ && (kr.flags & 0x2CF0) == 0) /* must be zero */
+ {
+ /* we have what seems to be a tasty key */
+
+ if (doit)
+ {
+ chunk_t k;
+
+ setchunk(k, pbs.cur, pbs_left(&pbs));
+ TRY(add_public_key(&cr->id, dns_auth_level, PUBKEY_ALG_RSA, &k
+ , &cr->keys_from_dns));
+ }
+ }
+ return NULL;
+}
+#endif /* USE_KEYRR */
+
+
+/* unpack TXT rr RDATA into C string.
+ * A sequence of <character-string>s as described in RFC 1035 3.3.
+ * We concatenate them.
+ */
+static err_t
+unpack_txt_rdata(u_char *d, size_t dlen, const u_char *s, size_t slen)
+{
+ size_t i = 0
+ , o = 0;
+
+ while (i < slen)
+ {
+ size_t cl = s[i++];
+
+ if (i + cl > slen)
+ return "TXT rr RDATA representation malformed";
+
+ if (o + cl >= dlen)
+ return "TXT rr RDATA too large";
+
+ memcpy(d + o, s + i, cl);
+ i += cl;
+ o += cl;
+ }
+ d[o] = '\0';
+ if (strlen(d) != o)
+ return "TXT rr RDATA contains a NUL";
+
+ return NULL;
+}
+
+static err_t
+process_txt_rr(u_char *rdata, size_t rdlen
+, bool doit /* should we capture information? */
+, enum dns_auth_level dns_auth_level
+, struct adns_continuation *const cr)
+{
+ u_char str[RSA_MAX_ENCODING_BYTES * 8 / 6 + 20]; /* space for unpacked RDATA */
+
+ TRY(unpack_txt_rdata(str, sizeof(str), rdata, rdlen));
+ return process_txt_rr_body(str, doit, dns_auth_level, cr);
+}
+
+static err_t
+process_answer_section(pb_stream *pbs
+, bool doit /* should we capture information? */
+, enum dns_auth_level *dns_auth_level
+, u_int16_t ancount /* number of RRs in the answer section */
+, struct adns_continuation *const cr)
+{
+ const int type = cr->query.type; /* type of RR of interest */
+ unsigned c;
+
+ DBG(DBG_DNS, DBG_log("*Answer Section:"));
+
+ for (c = 0; c != ancount; c++)
+ {
+ struct rr_fixed rrf;
+ size_t tail;
+
+ /* ??? do we need to match the name? */
+
+ TRY(eat_name_helpfully(pbs, "Answer Section"));
+
+ if (!in_struct(&rrf, &rr_fixed_desc, pbs, NULL))
+ return "failed to get fixed part of Answer Section Resource Record";
+
+ if (rrf.rdlength > pbs_left(pbs))
+ return "RD Length extends beyond end of message";
+
+ /* ??? should we care about ttl? */
+
+ tail = rrf.rdlength;
+
+ if (rrf.type == type && rrf.class == C_IN)
+ {
+ err_t ugh = NULL;
+
+ switch (type)
+ {
+#ifdef USE_KEYRR
+ case T_KEY:
+ ugh = process_key_rr(pbs->cur, tail, doit, *dns_auth_level, cr);
+ break;
+#endif /* USE_KEYRR */
+ case T_TXT:
+ ugh = process_txt_rr(pbs->cur, tail, doit, *dns_auth_level, cr);
+ break;
+ case T_SIG:
+ /* Check if SIG RR authenticates what we are learning.
+ * The RRset covered by a SIG must have the same owner,
+ * class, and type.
+ * For us, the class is always C_IN, so that matches.
+ * We decode the SIG RR's fixed part to check
+ * that the type_covered field matches our query type
+ * (this may be redundant).
+ * We don't check the owner (apparently this is the
+ * name on the record) -- we assume that it matches
+ * or we would not have been given this SIG in the
+ * Answer Section.
+ *
+ * We only look on first pass, and only if we've something
+ * to learn. This cuts down on useless decoding.
+ */
+ if (!doit && *dns_auth_level == DAL_UNSIGNED)
+ {
+ struct sig_rdata sr;
+
+ if (!in_struct(&sr, &sig_rdata_desc, pbs, NULL))
+ ugh = "failed to get fixed part of SIG Resource Record RDATA";
+ else if (sr.type_covered == type)
+ *dns_auth_level = DAL_SIGNED;
+ }
+ break;
+ default:
+ ugh = builddiag("unexpected RR type %d", type);
+ break;
+ }
+ if (ugh != NULL)
+ return ugh;
+ }
+ in_raw(NULL, tail, pbs, "RR RDATA");
+ }
+
+ return doit
+ && cr->gateways_from_dns == NULL
+#ifdef USE_KEYRR
+ && cr->keys_from_dns == NULL
+#endif /* USE_KEYRR */
+ ? builddiag("no suitable %s record found in DNS", rr_typename(type))
+ : NULL;
+}
+
+/* process DNS answer -- TXT or KEY query */
+
+static err_t
+process_dns_answer(struct adns_continuation *const cr
+, u_char ans[], int anslen)
+{
+ const int type = cr->query.type; /* type of record being sought */
+ int r; /* all-purpose return value holder */
+ u_int16_t c; /* number of current RR in current answer section */
+ pb_stream pbs;
+ u_int8_t *ans_start; /* saved position of answer section */
+ struct qr_header qr_header;
+ enum dns_auth_level dns_auth_level;
+
+ init_pbs(&pbs, ans, anslen, "Query Response Message");
+
+ /* decode and check header */
+
+ if (!in_struct(&qr_header, &qr_header_desc, &pbs, NULL))
+ return "malformed header";
+
+ /* ID: nothing to do with us */
+
+ /* stuff -- lots of things */
+ if ((qr_header.stuff & QRS_QR) == 0)
+ return "not a response?!?";
+
+ if (((qr_header.stuff >> QRS_OPCODE_SHIFT) & QRS_OPCODE_MASK) != QRSO_QUERY)
+ return "unexpected opcode";
+
+ /* I don't think we care about AA */
+
+ if (qr_header.stuff & QRS_TC)
+ return "response truncated";
+
+ /* I don't think we care about RD, RA, or CD */
+
+ /* AD means "authentic data" */
+ dns_auth_level = qr_header.stuff & QRS_AD? DAL_UNSIGNED : DAL_NOTSEC;
+
+ if (qr_header.stuff & QRS_Z)
+ return "Z bit is not zero";
+
+ r = (qr_header.stuff >> QRS_RCODE_SHIFT) & QRS_RCODE_MASK;
+ if (r != 0)
+ return r < (int)elemsof(rcode_text)? rcode_text[r] : "unknown rcode";
+
+ if (qr_header.ancount == 0)
+ return builddiag("no %s RR found by DNS", rr_typename(type));
+
+ /* end of header checking */
+
+ /* Question Section processing */
+
+ /* 4.1.2. Question section format:
+ * 1 1 1 1 1 1
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | |
+ * / QNAME /
+ * / /
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | QTYPE |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | QCLASS |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+
+ DBG(DBG_DNS, DBG_log("*Question Section:"));
+
+ for (c = 0; c != qr_header.qdcount; c++)
+ {
+ struct qs_fixed qsf;
+
+ TRY(eat_name_helpfully(&pbs, "Question Section"));
+
+ if (!in_struct(&qsf, &qs_fixed_desc, &pbs, NULL))
+ return "failed to get fixed part of Question Section";
+
+ if (qsf.qtype != type)
+ return "unexpected QTYPE in Question Section";
+
+ if (qsf.qclass != C_IN)
+ return "unexpected QCLASS in Question Section";
+ }
+
+ /* rest of sections are made up of Resource Records */
+
+ /* Answer Section processing -- error checking, noting T_SIG */
+
+ ans_start = pbs.cur; /* remember start of answer section */
+
+ TRY(process_answer_section(&pbs, FALSE, &dns_auth_level
+ , qr_header.ancount, cr));
+
+ /* Authority Section processing (just sanity checking) */
+
+ DBG(DBG_DNS, DBG_log("*Authority Section:"));
+
+ for (c = 0; c != qr_header.nscount; c++)
+ {
+ struct rr_fixed rrf;
+ size_t tail;
+
+ TRY(eat_name_helpfully(&pbs, "Authority Section"));
+
+ if (!in_struct(&rrf, &rr_fixed_desc, &pbs, NULL))
+ return "failed to get fixed part of Authority Section Resource Record";
+
+ if (rrf.rdlength > pbs_left(&pbs))
+ return "RD Length extends beyond end of message";
+
+ /* ??? should we care about ttl? */
+
+ tail = rrf.rdlength;
+
+ in_raw(NULL, tail, &pbs, "RR RDATA");
+ }
+
+ /* Additional Section processing (just sanity checking) */
+
+ DBG(DBG_DNS, DBG_log("*Additional Section:"));
+
+ for (c = 0; c != qr_header.arcount; c++)
+ {
+ struct rr_fixed rrf;
+ size_t tail;
+
+ TRY(eat_name_helpfully(&pbs, "Additional Section"));
+
+ if (!in_struct(&rrf, &rr_fixed_desc, &pbs, NULL))
+ return "failed to get fixed part of Additional Section Resource Record";
+
+ if (rrf.rdlength > pbs_left(&pbs))
+ return "RD Length extends beyond end of message";
+
+ /* ??? should we care about ttl? */
+
+ tail = rrf.rdlength;
+
+ in_raw(NULL, tail, &pbs, "RR RDATA");
+ }
+
+ /* done all sections */
+
+ /* ??? is padding legal, or can we complain if more left in record? */
+
+ /* process Answer Section again -- accept contents */
+
+ pbs.cur = ans_start; /* go back to start of answer section */
+
+ return process_answer_section(&pbs, TRUE, &dns_auth_level
+ , qr_header.ancount, cr);
+}
+
+#endif /* ! USE_LWRES */
+
+
+/****************************************************************/
+
+static err_t
+build_dns_name(u_char name_buf[NS_MAXDNAME + 2]
+, unsigned long serial USED_BY_DEBUG
+, const struct id *id
+, const char *typename USED_BY_DEBUG
+, const char *gwname USED_BY_DEBUG)
+{
+ /* note: all end in "." to suppress relative searches */
+ id = resolve_myid(id);
+ switch (id->kind)
+ {
+ case ID_IPV4_ADDR:
+ {
+ /* XXX: this is really ugly and only temporary until addrtot can
+ * generate the correct format
+ */
+ const unsigned char *b;
+ size_t bl USED_BY_DEBUG = addrbytesptr(&id->ip_addr, &b);
+
+ passert(bl == 4);
+ snprintf(name_buf, NS_MAXDNAME + 2, "%d.%d.%d.%d.in-addr.arpa."
+ , b[3], b[2], b[1], b[0]);
+ break;
+ }
+
+ case ID_IPV6_ADDR:
+ {
+ /* ??? is this correct? */
+ const unsigned char *b;
+ size_t bl;
+ u_char *op = name_buf;
+ static const char suffix[] = "IP6.INT.";
+
+ for (bl = addrbytesptr(&id->ip_addr, &b); bl-- != 0; )
+ {
+ if (op + 4 + sizeof(suffix) >= name_buf + NS_MAXDNAME + 1)
+ return "IPv6 reverse name too long";
+ op += sprintf(op, "%x.%x.", b[bl] & 0xF, b[bl] >> 4);
+ }
+ strcpy(op, suffix);
+ break;
+ }
+
+ case ID_FQDN:
+ /* strip trailing "." characters, then add one */
+ {
+ size_t il = id->name.len;
+
+ while (il > 0 && id->name.ptr[il - 1] == '.')
+ il--;
+ if (il > NS_MAXDNAME)
+ return "FQDN too long for domain name";
+
+ memcpy(name_buf, id->name.ptr, il);
+ strcpy(name_buf + il, ".");
+ }
+ break;
+
+ default:
+ return "can only query DNS for key for ID that is a FQDN, IPV4_ADDR, or IPV6_ADDR";
+ }
+
+ DBG(DBG_CONTROL | DBG_DNS, DBG_log("DNS query %lu for %s for %s (gw: %s)"
+ , serial, typename, name_buf, gwname));
+ return NULL;
+}
+
+void
+gw_addref(struct gw_info *gw)
+{
+ if (gw != NULL)
+ {
+ DBG(DBG_DNS, DBG_log("gw_addref: %p refcnt: %d++", gw, gw->refcnt))
+ gw->refcnt++;
+ }
+}
+
+void
+gw_delref(struct gw_info **gwp)
+{
+ struct gw_info *gw = *gwp;
+
+ if (gw != NULL)
+ {
+ DBG(DBG_DNS, DBG_log("gw_delref: %p refcnt: %d--", gw, gw->refcnt));
+
+ passert(gw->refcnt != 0);
+ gw->refcnt--;
+ if (gw->refcnt == 0)
+ {
+ free_id_content(&gw->client_id);
+ free_id_content(&gw->gw_id);
+ if (gw->gw_key_present)
+ unreference_key(&gw->key);
+ gw_delref(&gw->next);
+ pfree(gw); /* trickery could make this a tail-call */
+ }
+ *gwp = NULL;
+ }
+}
+
+static int adns_in_flight = 0; /* queries outstanding */
+
+/* Start an asynchronous DNS query.
+ *
+ * For KEY record, the result will be a list in cr->keys_from_dns.
+ * For TXT records, the result will be a list in cr->gateways_from_dns.
+ *
+ * If sgw_id is null, only consider TXT records that specify an
+ * IP address for the gatway: we need this in the initiation case.
+ *
+ * If sgw_id is non-null, only consider TXT records that specify
+ * this id as the security gatway; this is useful to the Responder
+ * for confirming claims of gateways.
+ *
+ * Continuation cr gives information for continuing when the result shows up.
+ *
+ * Two kinds of errors must be handled: synchronous (immediate)
+ * and asynchronous. Synchronous errors are indicated by the returned
+ * value of start_adns_query; in this case, the continuation will
+ * have been freed and the continuation routine will not be called.
+ * Asynchronous errors are indicated by the ugh parameter passed to the
+ * continuation routine.
+ *
+ * After the continuation routine has completed, handle_adns_answer
+ * will free the continuation. The continuation routine should have
+ * freed any axiliary resources.
+ *
+ * Note: in the synchronous error case, start_adns_query will have
+ * freed the continuation; this means that the caller will have to
+ * be very careful to release any auxiliary resources that were in
+ * the continuation record without using the continuation record.
+ *
+ * Either there will be an error result passed to the continuation routine,
+ * or the results will be in cr->keys_from_dns or cr->gateways_from_dns.
+ * The result variables must by left NULL by the continutation routine.
+ * The continuation routine is responsible for establishing and
+ * disestablishing any logging context (whack_log_fd, cur_*).
+ */
+
+static struct adns_continuation *continuations = NULL; /* newest of queue */
+static struct adns_continuation *next_query = NULL; /* oldest not sent */
+
+static struct adns_continuation *
+continuation_for_qtid(unsigned long qtid)
+{
+ struct adns_continuation *cr = NULL;
+
+ if (qtid != 0)
+ for (cr = continuations; cr != NULL && cr->qtid != qtid; cr = cr->previous)
+ ;
+ return cr;
+}
+
+static void
+release_adns_continuation(struct adns_continuation *cr)
+{
+ passert(cr != next_query);
+ gw_delref(&cr->gateways_from_dns);
+#ifdef USE_KEYRR
+ free_public_keys(&cr->keys_from_dns);
+#endif /* USE_KEYRR */
+ unshare_id_content(&cr->id);
+ unshare_id_content(&cr->sgw_id);
+
+ /* unlink from doubly-linked list */
+ if (cr->next == NULL)
+ {
+ passert(continuations == cr);
+ continuations = cr->previous;
+ }
+ else
+ {
+ passert(cr->next->previous == cr);
+ cr->next->previous = cr->previous;
+ }
+
+ if (cr->previous != NULL)
+ {
+ passert(cr->previous->next == cr);
+ cr->previous->next = cr->next;
+ }
+
+ pfree(cr);
+}
+
+err_t
+start_adns_query(const struct id *id /* domain to query */
+, const struct id *sgw_id /* if non-null, any accepted gw_info must match */
+, int type /* T_TXT or T_KEY, selecting rr type of interest */
+, cont_fn_t cont_fn
+, struct adns_continuation *cr)
+{
+ static unsigned long qtid = 1; /* query transaction id; NOTE: static */
+ const char *typename = rr_typename(type);
+ char gwidb[BUF_LEN];
+
+ if(adns_pid == 0
+ && adns_restart_count < ADNS_RESTART_MAX)
+ {
+ plog("ADNS helper was not running. Restarting attempt %d",adns_restart_count);
+ init_adns();
+ }
+
+
+ /* Splice this in at head of doubly-linked list of continuations.
+ * Note: this must be done before any release_adns_continuation().
+ */
+ cr->next = NULL;
+ cr->previous = continuations;
+ if (continuations != NULL)
+ {
+ passert(continuations->next == NULL);
+ continuations->next = cr;
+ }
+ continuations = cr;
+
+ cr->qtid = qtid++;
+ cr->type = type;
+ cr->cont_fn = cont_fn;
+ cr->id = *id;
+ unshare_id_content(&cr->id);
+ cr->sgw_specified = sgw_id != NULL;
+ cr->sgw_id = cr->sgw_specified? *sgw_id : empty_id;
+ unshare_id_content(&cr->sgw_id);
+ cr->gateways_from_dns = NULL;
+#ifdef USE_KEYRR
+ cr->keys_from_dns = NULL;
+#endif /* USE_KEYRR */
+
+#ifdef DEBUG
+ cr->debugging = cur_debugging;
+#else
+ cr->debugging = LEMPTY;
+#endif
+
+ idtoa(&cr->sgw_id, gwidb, sizeof(gwidb));
+
+ zero(&cr->query);
+
+ {
+ err_t ugh = build_dns_name(cr->query.name_buf, cr->qtid
+ , id, typename, gwidb);
+
+ if (ugh != NULL)
+ {
+ release_adns_continuation(cr);
+ return ugh;
+ }
+ }
+
+ if (next_query == NULL)
+ next_query = cr;
+
+ unsent_ADNS_queries = TRUE;
+
+ return NULL;
+}
+
+/* send remaining ADNS queries (until pipe full or none left)
+ *
+ * This is a co-routine, so it uses static variables to
+ * preserve state across calls.
+ */
+bool unsent_ADNS_queries = FALSE;
+
+void
+send_unsent_ADNS_queries(void)
+{
+ static const unsigned char *buf_end = NULL; /* NOTE STATIC */
+ static const unsigned char *buf_cur = NULL; /* NOTE STATIC */
+
+ if (adns_qfd == NULL_FD)
+ return; /* nothing useful to do */
+
+ for (;;)
+ {
+ if (buf_cur != buf_end)
+ {
+ static int try = 0; /* NOTE STATIC */
+ size_t n = buf_end - buf_cur;
+ ssize_t r = write(adns_qfd, buf_cur, n);
+
+ if (r == -1)
+ {
+ switch (errno)
+ {
+ case EINTR:
+ continue; /* try again now */
+ case EAGAIN:
+ DBG(DBG_DNS, DBG_log("EAGAIN writing to ADNS"));
+ break; /* try again later */
+ default:
+ try++;
+ log_errno((e, "error %d writing DNS query", try));
+ break; /* try again later */
+ }
+ unsent_ADNS_queries = TRUE;
+ break; /* done! */
+ }
+ else
+ {
+ passert(r >= 0);
+ try = 0;
+ buf_cur += r;
+ }
+ }
+ else
+ {
+ if (next_query == NULL)
+ {
+ unsent_ADNS_queries = FALSE;
+ break; /* done! */
+ }
+
+#ifdef USE_LWRES
+ next_query->used = FALSE;
+ {
+ /* NOTE STATIC: */
+ static unsigned char qbuf[LWDNSQ_CMDBUF_LEN + 1]; /* room for NUL */
+
+ snprintf(qbuf, sizeof(qbuf), "%s %lu %s\n"
+ , rr_typename(next_query->type)
+ , next_query->qtid
+ , next_query->query.name_buf);
+ DBG(DBG_DNS, DBG_log("lwdnsq query: %.*s", (int)(strlen(qbuf) - 1), qbuf));
+ buf_cur = qbuf;
+ buf_end = qbuf + strlen(qbuf);
+ }
+#else /* !USE_LWRES */
+ next_query->query.debugging = next_query->debugging;
+ next_query->query.serial = next_query->qtid;
+ next_query->query.len = sizeof(next_query->query);
+ next_query->query.qmagic = ADNS_Q_MAGIC;
+ next_query->query.type = next_query->type;
+ buf_cur = (const void *)&next_query->query;
+ buf_end = buf_cur + sizeof(next_query->query);
+#endif /* !USE_LWRES */
+ next_query = next_query->next;
+ adns_in_flight++;
+ }
+ }
+}
+
+#ifdef USE_LWRES
+/* Process a line of lwdnsq answer.
+ * Returns with error message iff lwdnsq result is malformed.
+ * Most errors will be in DNS data and will be handled by cr->cont_fn.
+ */
+static err_t
+process_lwdnsq_answer(char *ts)
+{
+ err_t ugh = NULL;
+ char *rest;
+ char *p;
+ char *endofnumber;
+ struct adns_continuation *cr = NULL;
+ unsigned long qtid;
+ time_t anstime; /* time of answer */
+ char *atype; /* type of answer */
+ long ttl; /* ttl of answer; int, but long for conversion */
+ bool AuthenticatedData = FALSE;
+ static char scratch_null_str[] = ""; /* cannot be const, but isn't written */
+
+ /* query transaction id */
+ rest = ts;
+ p = strsep(&rest, " \t");
+ if (p == NULL)
+ return "lwdnsq: answer missing query transaction ID";
+
+ qtid = strtoul(p, &endofnumber, 10);
+ if (*endofnumber != '\0')
+ return "lwdnsq: malformed query transaction ID";
+
+ cr = continuation_for_qtid(qtid);
+ if (qtid != 0 && cr == NULL)
+ return "lwdnsq: unrecognized qtid"; /* can't happen! */
+
+ /* time */
+ p = strsep(&rest, " \t");
+ if (p == NULL)
+ return "lwdnsq: missing time";
+
+ anstime = strtoul(p, &endofnumber, 10);
+ if (*endofnumber != '\0')
+ return "lwdnsq: malformed time";
+
+ /* TTL */
+ p = strsep(&rest, " \t");
+ if (p == NULL)
+ return "lwdnsq: missing TTL";
+
+ ttl = strtol(p, &endofnumber, 10);
+ if (*endofnumber != '\0')
+ return "lwdnsq: malformed TTL";
+
+ /* type */
+ atype = strsep(&rest, " \t");
+ if (atype == NULL)
+ return "lwdnsq: missing type";
+
+ /* if rest is NULL, make it "", otherwise eat whitespace after type */
+ rest = rest == NULL? scratch_null_str : rest + strspn(rest, " \t");
+
+ if (strncasecmp(atype, "AD-", 3) == 0)
+ {
+ AuthenticatedData = TRUE;
+ atype += 3;
+ }
+
+ /* deal with each type */
+
+ if (cr == NULL)
+ {
+ /* we don't actually know which this applies to */
+ return builddiag("lwdnsq: 0 qtid invalid with %s", atype);
+ }
+ else if (strcaseeq(atype, "START"))
+ {
+ /* ignore */
+ }
+ else if (strcaseeq(atype, "DONE"))
+ {
+ if (!cr->used)
+ {
+ /* "no results returned by lwdnsq" should not happen */
+ cr->cont_fn(cr
+ , cr->gateways_from_dns == NULL
+#ifdef USE_KEYRR
+ && cr->keys_from_dns == NULL
+#endif /* USE_KEYRR */
+ ? "no results returned by lwdnsq" : NULL);
+ cr->used = TRUE;
+ }
+ reset_globals();
+ release_adns_continuation(cr);
+ adns_in_flight--;
+ }
+ else if (strcaseeq(atype, "RETRY"))
+ {
+ if (!cr->used)
+ {
+ cr->cont_fn(cr, rest);
+ cr->used = TRUE;
+ }
+ }
+ else if (strcaseeq(atype, "FATAL"))
+ {
+ if (!cr->used)
+ {
+ cr->cont_fn(cr, rest);
+ cr->used = TRUE;
+ }
+ }
+ else if (strcaseeq(atype, "DNSSEC"))
+ {
+ /* ignore */
+ }
+ else if (strcaseeq(atype, "NAME"))
+ {
+ /* ignore */
+ }
+ else if (strcaseeq(atype, "TXT"))
+ {
+ char *end = rest + strlen(rest);
+ err_t txt_ugh;
+
+ if (*rest == '"' && end[-1] == '"')
+ {
+ /* strip those pesky quotes */
+ rest++;
+ *--end = '\0';
+ }
+
+ txt_ugh = process_txt_rr_body(rest
+ , TRUE
+ , AuthenticatedData? DAL_SIGNED : DAL_NOTSEC
+ , cr);
+
+ if (txt_ugh != NULL)
+ {
+ DBG(DBG_DNS,
+ DBG_log("error processing TXT resource record (%s) while processing: %s"
+ , txt_ugh, rest));
+ cr->cont_fn(cr, txt_ugh);
+ cr->used = TRUE;
+ }
+ }
+ else if (strcaseeq(atype, "SIG"))
+ {
+ /* record the SIG records for posterity */
+ if (cr->last_info != NULL)
+ {
+ pfreeany(cr->last_info->dns_sig);
+ cr->last_info->dns_sig = clone_str(rest, "sigrecord");
+ }
+ }
+ else if (strcaseeq(atype, "A"))
+ {
+ /* ignore */
+ }
+ else if (strcaseeq(atype, "AAAA"))
+ {
+ /* ignore */
+ }
+ else if (strcaseeq(atype, "CNAME"))
+ {
+ /* ignore */
+ }
+ else if (strcaseeq(atype, "CNAMEFROM"))
+ {
+ /* ignore */
+ }
+ else if (strcaseeq(atype, "PTR"))
+ {
+ /* ignore */
+ }
+#ifdef USE_KEYRR
+ else if (strcaseeq(atype, "KEY"))
+ {
+ err_t key_ugh = process_lwdnsq_key(rest
+ , AuthenticatedData? DAL_SIGNED : DAL_NOTSEC
+ , cr);
+
+ if (key_ugh != NULL)
+ {
+ DBG(DBG_DNS,
+ DBG_log("error processing KEY resource record (%s) while processing: %s"
+ , key_ugh, rest));
+ cr->cont_fn(cr, key_ugh);
+ cr->used = TRUE;
+ }
+ }
+#endif /* USE_KEYRR */
+ else
+ {
+ ugh = "lwdnsq: unrecognized type";
+ }
+ return ugh;
+}
+#endif /* USE_LWRES */
+
+static void
+recover_adns_die(void)
+{
+ struct adns_continuation *cr = NULL;
+
+ adns_pid = 0;
+ if(adns_restart_count < ADNS_RESTART_MAX) {
+ adns_restart_count++;
+
+ /* next DNS query will restart it */
+
+ /* we have to walk the list of the outstanding requests,
+ * and redo them!
+ */
+
+ cr = continuations;
+
+ /* find the head of the list */
+ if(continuations != NULL) {
+ for (; cr->previous != NULL; cr = cr->previous);
+ }
+
+ next_query = cr;
+
+ if(next_query != NULL) {
+ unsent_ADNS_queries = TRUE;
+ }
+ }
+}
+
+void reset_adns_restart_count(void)
+{
+ adns_restart_count=0;
+}
+
+void
+handle_adns_answer(void)
+{
+ /* These are retained across calls to handle_adns_answer. */
+ static size_t buflen = 0; /* bytes in answer buffer */
+#ifndef USE_LWRES
+ static struct adns_answer buf;
+#else /* USE_LWRES */
+ static char buf[LWDNSQ_RESULT_LEN_MAX];
+ static char buf_copy[LWDNSQ_RESULT_LEN_MAX];
+#endif /* USE_LWRES */
+
+ ssize_t n;
+
+ passert(buflen < sizeof(buf));
+ n = read(adns_afd, (unsigned char *)&buf + buflen, sizeof(buf) - buflen);
+
+ if (n < 0)
+ {
+ if (errno != EINTR)
+ {
+ log_errno((e, "error reading answer from adns"));
+ /* ??? how can we recover? */
+ }
+ n = 0; /* now n reflects amount read */
+ }
+ else if (n == 0)
+ {
+ /* EOF */
+ if (adns_in_flight != 0)
+ {
+ plog("EOF from ADNS with %d queries outstanding (restarts %d)"
+ , adns_in_flight, adns_restart_count);
+ recover_adns_die();
+ }
+ if (buflen != 0)
+ {
+ plog("EOF from ADNS with %lu bytes of a partial answer outstanding"
+ "(restarts %d)"
+ , (unsigned long)buflen
+ , adns_restart_count);
+ recover_adns_die();
+ }
+ stop_adns();
+ return;
+ }
+ else
+ {
+ passert(adns_in_flight > 0);
+ }
+
+ buflen += n;
+#ifndef USE_LWRES
+ while (buflen >= offsetof(struct adns_answer, ans) && buflen >= buf.len)
+ {
+ /* we've got a tasty answer -- process it */
+ err_t ugh;
+ struct adns_continuation *cr = continuation_for_qtid(buf.serial); /* assume it works */
+ const char *typename = rr_typename(cr->query.type);
+ const char *name_buf = cr->query.name_buf;
+
+#ifdef USE_KEYRR
+ passert(cr->keys_from_dns == NULL);
+#endif /* USE_KEYRR */
+ passert(cr->gateways_from_dns == NULL);
+ adns_in_flight--;
+ if (buf.result == -1)
+ {
+ /* newer resolvers support statp->res_h_errno as well as h_errno.
+ * That might be better, but older resolvers don't.
+ * See resolver(3), if you have it.
+ * The undocumented(!) h_errno values are defined in
+ * /usr/include/netdb.h.
+ */
+ switch (buf.h_errno_val)
+ {
+ case NO_DATA:
+ ugh = builddiag("no %s record for %s", typename, name_buf);
+ break;
+ case HOST_NOT_FOUND:
+ ugh = builddiag("no host %s for %s record", name_buf, typename);
+ break;
+ default:
+ ugh = builddiag("failure querying DNS for %s of %s: %s"
+ , typename, name_buf, hstrerror(buf.h_errno_val));
+ break;
+ }
+ }
+ else if (buf.result > (int) sizeof(buf.ans))
+ {
+ ugh = builddiag("(INTERNAL ERROR) answer too long (%ld) for buffer"
+ , (long)buf.result);
+ }
+ else
+ {
+ ugh = process_dns_answer(cr, buf.ans, buf.result);
+ if (ugh != NULL)
+ ugh = builddiag("failure processing %s record of DNS answer for %s: %s"
+ , typename, name_buf, ugh);
+ }
+ DBG(DBG_RAW | DBG_CRYPT | DBG_PARSING | DBG_CONTROL | DBG_DNS,
+ DBG_log(BLANK_FORMAT);
+ if (ugh == NULL)
+ DBG_log("asynch DNS answer %lu for %s of %s"
+ , cr->query.serial, typename, name_buf);
+ else
+ DBG_log("asynch DNS answer %lu %s", cr->query.serial, ugh);
+ );
+
+ passert(GLOBALS_ARE_RESET());
+ cr->cont_fn(cr, ugh);
+ reset_globals();
+ release_adns_continuation(cr);
+
+ /* shift out answer that we've consumed */
+ buflen -= buf.len;
+ memmove((unsigned char *)&buf, (unsigned char *)&buf + buf.len, buflen);
+ }
+#else /* USE_LWRES */
+ for (;;)
+ {
+ err_t ugh;
+ char *nlp = memchr(buf, '\n', buflen);
+
+ if (nlp == NULL)
+ break;
+
+ /* we've got a line */
+ *nlp++ = '\0';
+
+ DBG(DBG_RAW | DBG_CRYPT | DBG_PARSING | DBG_CONTROL | DBG_DNS
+ , DBG_log("lwdns: %s", buf));
+
+ /* process lwdnsq_answer may modify buf, so make a copy. */
+ buf_copy[0]='\0';
+ strncat(buf_copy, buf, sizeof(buf_copy));
+
+ ugh = process_lwdnsq_answer(buf_copy);
+ if (ugh != NULL)
+ plog("failure processing lwdnsq output: %s; record: %s"
+ , ugh, buf);
+
+ passert(GLOBALS_ARE_RESET());
+ reset_globals();
+
+ /* shift out answer that we've consumed */
+ buflen -= nlp - buf;
+ memmove(buf, nlp, buflen);
+ }
+#endif /* USE_LWRES */
+}
diff --git a/src/pluto/dnskey.h b/src/pluto/dnskey.h
new file mode 100644
index 000000000..0b9f0ee33
--- /dev/null
+++ b/src/pluto/dnskey.h
@@ -0,0 +1,84 @@
+/* Find public key in DNS
+ * Copyright (C) 2000-2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: dnskey.h,v 1.1 2004/03/15 20:35:28 as Exp $
+ */
+
+extern int
+ adns_qfd, /* file descriptor for sending queries to adns */
+ adns_afd; /* file descriptor for receiving answers from adns */
+extern const char *pluto_adns_option; /* path from --pluto_adns */
+extern void init_adns(void);
+extern void stop_adns(void);
+extern void handle_adns_answer(void);
+
+extern bool unsent_ADNS_queries;
+extern void send_unsent_ADNS_queries(void);
+
+/* (common prefix of) stuff remembered between async query and answer.
+ * Filled in by start_adns_query.
+ * Freed by call to release_adns_continuation.
+ */
+
+struct adns_continuation; /* forward declaration (not far!) */
+
+typedef void (*cont_fn_t)(struct adns_continuation *cr, err_t ugh);
+
+struct adns_continuation {
+ unsigned long qtid; /* query transaction id number */
+ int type; /* T_TXT or T_KEY, selecting rr type of interest */
+ cont_fn_t cont_fn; /* function to carry on suspended work */
+ struct id id; /* subject of query */
+ bool sgw_specified;
+ struct id sgw_id; /* peer, if constrained */
+ lset_t debugging; /* only used #ifdef DEBUG, but don't want layout to change */
+ struct gw_info *gateways_from_dns; /* answer, if looking for our TXT rrs */
+#ifdef USE_KEYRR
+ struct pubkey_list *keys_from_dns; /* answer, if looking for KEY rrs */
+#endif
+ struct adns_continuation *previous, *next;
+ struct pubkey *last_info; /* the last structure we accumulated */
+#ifdef USE_LWRES
+ bool used; /* have we called the cont_fn yet? */
+ struct {
+ u_char name_buf[NS_MAXDNAME + 2];
+ } query;
+#else /* ! USE_LWRES */
+ struct adns_query query;
+#endif /* ! USE_LWRES */
+};
+
+extern err_t start_adns_query(const struct id *id /* domain to query */
+ , const struct id *sgw_id /* if non-null, any accepted gw_info must match */
+ , int type /* T_TXT or T_KEY, selecting rr type of interest */
+ , cont_fn_t cont_fn /* continuation function */
+ , struct adns_continuation *cr);
+
+
+/* Gateway info gleaned from reverse DNS of client */
+struct gw_info {
+ unsigned refcnt; /* reference counted! */
+ unsigned pref; /* preference: lower is better */
+#define NO_TIME ((time_t) -2) /* time_t value meaning "not_yet" */
+ struct id client_id; /* id of client of peer */
+ struct id gw_id; /* id of peer (if id_is_ipaddr, .ip_addr is address) */
+ bool gw_key_present;
+ struct pubkey *key;
+ struct gw_info *next;
+};
+
+extern void gw_addref(struct gw_info *gw)
+ , gw_delref(struct gw_info **gwp);
+
+extern void reset_adns_restart_count(void);
+
diff --git a/src/pluto/dsa.c b/src/pluto/dsa.c
new file mode 100644
index 000000000..c5982fbf4
--- /dev/null
+++ b/src/pluto/dsa.c
@@ -0,0 +1,476 @@
+/* dsa.c - DSA signature scheme
+ * Copyright (C) 1998 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef PLUTO
+#include <gmp.h>
+#include <freeswan.h>
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "rnd.h"
+#include "gcryptfix.h"
+#else /*! PLUTO */
+/* #include <config.h> */
+#endif /* !PLUTO */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef PLUTO
+/* #include <assert.h> */
+/* #include "util.h" */
+/* #include "mpi.h" */
+/* #include "cipher.h" */
+#endif
+
+#include "dsa.h"
+
+typedef struct {
+ MPI p; /* prime */
+ MPI q; /* group order */
+ MPI g; /* group generator */
+ MPI y; /* g^x mod p */
+} DSA_public_key;
+
+
+typedef struct {
+ MPI p; /* prime */
+ MPI q; /* group order */
+ MPI g; /* group generator */
+ MPI y; /* g^x mod p */
+ MPI x; /* secret exponent */
+} DSA_secret_key;
+
+
+static MPI gen_k( MPI q );
+static void test_keys( DSA_secret_key *sk, unsigned qbits );
+static int check_secret_key( DSA_secret_key *sk );
+static void generate( DSA_secret_key *sk, unsigned nbits, MPI **ret_factors );
+static void sign(MPI r, MPI s, MPI input, DSA_secret_key *skey);
+static int verify(MPI r, MPI s, MPI input, DSA_public_key *pkey);
+
+static void
+progress( int c )
+{
+ fputc( c, stderr );
+}
+
+
+/****************
+ * Generate a random secret exponent k less than q
+ */
+static MPI
+gen_k( MPI q )
+{
+ MPI k = mpi_alloc_secure( mpi_get_nlimbs(q) );
+ unsigned int nbits = mpi_get_nbits(q);
+ unsigned int nbytes = (nbits+7)/8;
+ char *rndbuf = NULL;
+
+ if( DBG_CIPHER )
+ log_debug("choosing a random k ");
+ for(;;) {
+ if( DBG_CIPHER )
+ progress('.');
+
+ if( !rndbuf || nbits < 32 ) {
+ m_free(rndbuf);
+ rndbuf = get_random_bits( nbits, 1, 1 );
+ }
+ else { /* change only some of the higher bits */
+ /* we could imporove this by directly requesting more memory
+ * at the first call to get_random_bits() and use this the here
+ * maybe it is easier to do this directly in random.c */
+ char *pp = get_random_bits( 32, 1, 1 );
+ memcpy( rndbuf,pp, 4 );
+ m_free(pp);
+ }
+ mpi_set_buffer( k, rndbuf, nbytes, 0 );
+ if( mpi_test_bit( k, nbits-1 ) )
+ mpi_set_highbit( k, nbits-1 );
+ else {
+ mpi_set_highbit( k, nbits-1 );
+ mpi_clear_bit( k, nbits-1 );
+ }
+
+ if( !(mpi_cmp( k, q ) < 0) ) { /* check: k < q */
+ if( DBG_CIPHER )
+ progress('+');
+ continue; /* no */
+ }
+ if( !(mpi_cmp_ui( k, 0 ) > 0) ) { /* check: k > 0 */
+ if( DBG_CIPHER )
+ progress('-');
+ continue; /* no */
+ }
+ break; /* okay */
+ }
+ m_free(rndbuf);
+ if( DBG_CIPHER )
+ progress('\n');
+
+ return k;
+}
+
+
+static void
+test_keys( DSA_secret_key *sk, unsigned qbits )
+{
+ DSA_public_key pk;
+ MPI test = mpi_alloc( qbits / BITS_PER_MPI_LIMB );
+ MPI out1_a = mpi_alloc( qbits / BITS_PER_MPI_LIMB );
+ MPI out1_b = mpi_alloc( qbits / BITS_PER_MPI_LIMB );
+
+ pk.p = sk->p;
+ pk.q = sk->q;
+ pk.g = sk->g;
+ pk.y = sk->y;
+ /*mpi_set_bytes( test, qbits, get_random_byte, 0 );*/
+ { char *p = get_random_bits( qbits, 0, 0 );
+ mpi_set_buffer( test, p, (qbits+7)/8, 0 );
+ m_free(p);
+ }
+
+ sign( out1_a, out1_b, test, sk );
+ if( !verify( out1_a, out1_b, test, &pk ) )
+ log_fatal("DSA:: sign, verify failed\n");
+
+ mpi_free( test );
+ mpi_free( out1_a );
+ mpi_free( out1_b );
+}
+
+
+
+/****************
+ * Generate a DSA key pair with a key of size NBITS
+ * Returns: 2 structures filled with all needed values
+ * and an array with the n-1 factors of (p-1)
+ */
+static void
+generate( DSA_secret_key *sk, unsigned nbits, MPI **ret_factors )
+{
+ MPI p; /* the prime */
+ MPI q; /* the 160 bit prime factor */
+ MPI g; /* the generator */
+ MPI y; /* g^x mod p */
+ MPI x; /* the secret exponent */
+ MPI h, e; /* helper */
+ unsigned qbits;
+ byte *rndbuf;
+
+ assert( nbits >= 512 && nbits <= 1024 );
+
+ qbits = 160;
+ p = generate_elg_prime( 1, nbits, qbits, NULL, ret_factors );
+ /* get q out of factors */
+ q = mpi_copy((*ret_factors)[0]);
+ if( mpi_get_nbits(q) != qbits )
+ BUG();
+
+ /* find a generator g (h and e are helpers)*/
+ /* e = (p-1)/q */
+ e = mpi_alloc( mpi_get_nlimbs(p) );
+ mpi_sub_ui( e, p, 1 );
+ mpi_fdiv_q( e, e, q );
+ g = mpi_alloc( mpi_get_nlimbs(p) );
+ h = mpi_alloc_set_ui( 1 ); /* we start with 2 */
+ do {
+ mpi_add_ui( h, h, 1 );
+ /* g = h^e mod p */
+ mpi_powm( g, h, e, p );
+ } while( !mpi_cmp_ui( g, 1 ) ); /* continue until g != 1 */
+
+ /* select a random number which has these properties:
+ * 0 < x < q-1
+ * This must be a very good random number because this
+ * is the secret part. */
+ if( DBG_CIPHER )
+ log_debug("choosing a random x ");
+ assert( qbits >= 160 );
+ x = mpi_alloc_secure( mpi_get_nlimbs(q) );
+ mpi_sub_ui( h, q, 1 ); /* put q-1 into h */
+ rndbuf = NULL;
+ do {
+ if( DBG_CIPHER )
+ progress('.');
+ if( !rndbuf )
+ rndbuf = get_random_bits( qbits, 2, 1 );
+ else { /* change only some of the higher bits (= 2 bytes)*/
+ char *r = get_random_bits( 16, 2, 1 );
+ memcpy(rndbuf, r, 16/8 );
+ m_free(r);
+ }
+ mpi_set_buffer( x, rndbuf, (qbits+7)/8, 0 );
+ mpi_clear_highbit( x, qbits+1 );
+ } while( !( mpi_cmp_ui( x, 0 )>0 && mpi_cmp( x, h )<0 ) );
+ m_free(rndbuf);
+ mpi_free( e );
+ mpi_free( h );
+
+ /* y = g^x mod p */
+ y = mpi_alloc( mpi_get_nlimbs(p) );
+ mpi_powm( y, g, x, p );
+
+ if( DBG_CIPHER ) {
+ progress('\n');
+ log_mpidump("dsa p= ", p );
+ log_mpidump("dsa q= ", q );
+ log_mpidump("dsa g= ", g );
+ log_mpidump("dsa y= ", y );
+ log_mpidump("dsa x= ", x );
+ }
+
+ /* copy the stuff to the key structures */
+ sk->p = p;
+ sk->q = q;
+ sk->g = g;
+ sk->y = y;
+ sk->x = x;
+
+ /* now we can test our keys (this should never fail!) */
+ test_keys( sk, qbits );
+}
+
+
+
+/****************
+ * Test whether the secret key is valid.
+ * Returns: if this is a valid key.
+ */
+static int
+check_secret_key( DSA_secret_key *sk )
+{
+ int rc;
+ MPI y = mpi_alloc( mpi_get_nlimbs(sk->y) );
+
+ mpi_powm( y, sk->g, sk->x, sk->p );
+ rc = !mpi_cmp( y, sk->y );
+ mpi_free( y );
+ return rc;
+}
+
+
+
+/****************
+ * Make a DSA signature from HASH and put it into r and s.
+ */
+
+static void
+sign(MPI r, MPI s, MPI hash, DSA_secret_key *skey )
+{
+ MPI k;
+ MPI kinv;
+ MPI tmp;
+
+ /* select a random k with 0 < k < q */
+ k = gen_k( skey->q );
+
+ /* r = (a^k mod p) mod q */
+ mpi_powm( r, skey->g, k, skey->p );
+ mpi_fdiv_r( r, r, skey->q );
+
+ /* kinv = k^(-1) mod q */
+ kinv = mpi_alloc( mpi_get_nlimbs(k) );
+ mpi_invm(kinv, k, skey->q );
+
+ /* s = (kinv * ( hash + x * r)) mod q */
+ tmp = mpi_alloc( mpi_get_nlimbs(skey->p) );
+ mpi_mul( tmp, skey->x, r );
+ mpi_add( tmp, tmp, hash );
+ mpi_mulm( s , kinv, tmp, skey->q );
+
+ mpi_free(k);
+ mpi_free(kinv);
+ mpi_free(tmp);
+}
+
+
+/****************
+ * Returns true if the signature composed from R and S is valid.
+ */
+static int
+verify(MPI r, MPI s, MPI hash, DSA_public_key *pkey )
+{
+ int rc;
+ MPI w, u1, u2, v;
+ MPI base[3];
+ MPI exp[3];
+
+
+ if( !(mpi_cmp_ui( r, 0 ) > 0 && mpi_cmp( r, pkey->q ) < 0) )
+ return 0; /* assertion 0 < r < q failed */
+ if( !(mpi_cmp_ui( s, 0 ) > 0 && mpi_cmp( s, pkey->q ) < 0) )
+ return 0; /* assertion 0 < s < q failed */
+
+ w = mpi_alloc( mpi_get_nlimbs(pkey->q) );
+ u1 = mpi_alloc( mpi_get_nlimbs(pkey->q) );
+ u2 = mpi_alloc( mpi_get_nlimbs(pkey->q) );
+ v = mpi_alloc( mpi_get_nlimbs(pkey->p) );
+
+ /* w = s^(-1) mod q */
+ mpi_invm( w, s, pkey->q );
+
+ /* u1 = (hash * w) mod q */
+ mpi_mulm( u1, hash, w, pkey->q );
+
+ /* u2 = r * w mod q */
+ mpi_mulm( u2, r, w, pkey->q );
+
+ /* v = g^u1 * y^u2 mod p mod q */
+ base[0] = pkey->g; exp[0] = u1;
+ base[1] = pkey->y; exp[1] = u2;
+ base[2] = NULL; exp[2] = NULL;
+ mpi_mulpowm( v, base, exp, pkey->p );
+ mpi_fdiv_r( v, v, pkey->q );
+
+ rc = !mpi_cmp( v, r );
+
+ mpi_free(w);
+ mpi_free(u1);
+ mpi_free(u2);
+ mpi_free(v);
+ return rc;
+}
+
+
+/*********************************************
+ ************** interface ******************
+ *********************************************/
+
+int
+dsa_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
+{
+ DSA_secret_key sk;
+
+ if( algo != PUBKEY_ALGO_DSA )
+ return G10ERR_PUBKEY_ALGO;
+
+ generate( &sk, nbits, retfactors );
+ skey[0] = sk.p;
+ skey[1] = sk.q;
+ skey[2] = sk.g;
+ skey[3] = sk.y;
+ skey[4] = sk.x;
+ return 0;
+}
+
+
+int
+dsa_check_secret_key( int algo, MPI *skey )
+{
+ DSA_secret_key sk;
+
+ if( algo != PUBKEY_ALGO_DSA )
+ return G10ERR_PUBKEY_ALGO;
+ if( !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4] )
+ return G10ERR_BAD_MPI;
+
+ sk.p = skey[0];
+ sk.q = skey[1];
+ sk.g = skey[2];
+ sk.y = skey[3];
+ sk.x = skey[4];
+ if( !check_secret_key( &sk ) )
+ return G10ERR_BAD_SECKEY;
+
+ return 0;
+}
+
+
+
+int
+dsa_sign( int algo, MPI *resarr, MPI data, MPI *skey )
+{
+ DSA_secret_key sk;
+
+ if( algo != PUBKEY_ALGO_DSA )
+ return G10ERR_PUBKEY_ALGO;
+ if( !data || !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4] )
+ return G10ERR_BAD_MPI;
+
+ sk.p = skey[0];
+ sk.q = skey[1];
+ sk.g = skey[2];
+ sk.y = skey[3];
+ sk.x = skey[4];
+ resarr[0] = mpi_alloc( mpi_get_nlimbs( sk.p ) );
+ resarr[1] = mpi_alloc( mpi_get_nlimbs( sk.p ) );
+ sign( resarr[0], resarr[1], data, &sk );
+ return 0;
+}
+
+int
+dsa_verify( int algo, MPI hash, MPI *data, MPI *pkey,
+ int (*cmp)(void *, MPI) UNUSED, void *opaquev UNUSED)
+{
+ DSA_public_key pk;
+
+ if( algo != PUBKEY_ALGO_DSA )
+ return G10ERR_PUBKEY_ALGO;
+ if( !data[0] || !data[1] || !hash
+ || !pkey[0] || !pkey[1] || !pkey[2] || !pkey[3] )
+ return G10ERR_BAD_MPI;
+
+ pk.p = pkey[0];
+ pk.q = pkey[1];
+ pk.g = pkey[2];
+ pk.y = pkey[3];
+ if( !verify( data[0], data[1], hash, &pk ) )
+ return G10ERR_BAD_SIGN;
+ return 0;
+}
+
+
+
+unsigned
+dsa_get_nbits( int algo, MPI *pkey )
+{
+ if( algo != PUBKEY_ALGO_DSA )
+ return 0;
+ return mpi_get_nbits( pkey[0] );
+}
+
+
+/****************
+ * Return some information about the algorithm. We need algo here to
+ * distinguish different flavors of the algorithm.
+ * Returns: A pointer to string describing the algorithm or NULL if
+ * the ALGO is invalid.
+ * Usage: Bit 0 set : allows signing
+ * 1 set : allows encryption
+ */
+const char *
+dsa_get_info( int algo, int *npkey, int *nskey, int *nenc, int *nsig,
+ int *use )
+{
+ *npkey = 4;
+ *nskey = 5;
+ *nenc = 0;
+ *nsig = 2;
+
+ switch( algo ) {
+ case PUBKEY_ALGO_DSA: *use = PUBKEY_USAGE_SIG; return "DSA";
+ default: *use = 0; return NULL;
+ }
+}
+
+
diff --git a/src/pluto/dsa.h b/src/pluto/dsa.h
new file mode 100644
index 000000000..1456d65b6
--- /dev/null
+++ b/src/pluto/dsa.h
@@ -0,0 +1,32 @@
+/* dsa.h - DSA signature scheme
+ * Copyright (C) 1998 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+#ifndef G10_DSA_H
+#define G10_DSA_H
+
+int dsa_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors );
+int dsa_check_secret_key( int algo, MPI *skey );
+int dsa_sign( int algo, MPI *resarr, MPI data, MPI *skey );
+int dsa_verify( int algo, MPI hash, MPI *data, MPI *pkey,
+ int (*cmp)(void *, MPI), void *opaquev );
+unsigned dsa_get_nbits( int algo, MPI *pkey );
+const char *dsa_get_info( int algo, int *npkey, int *nskey,
+ int *nenc, int *nsig, int *use );
+
+#endif /*G10_DSA_H*/
diff --git a/src/pluto/elgamal.c b/src/pluto/elgamal.c
new file mode 100644
index 000000000..0c099bb90
--- /dev/null
+++ b/src/pluto/elgamal.c
@@ -0,0 +1,613 @@
+/* elgamal.c - ElGamal Public Key encryption
+ * Copyright (C) 1998 Free Software Foundation, Inc.
+ *
+ * For a description of the algorithm, see:
+ * Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996.
+ * ISBN 0-471-11709-9. Pages 476 ff.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef PLUTO
+#include <gmp.h>
+#include <freeswan.h>
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "rnd.h"
+#include "gcryptfix.h"
+#else /*! PLUTO */
+/* #include <config.h> */
+#endif /* !PLUTO */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef PLUTO
+/* #include "util.h" */
+/* #include "mpi.h" */
+/* #include "cipher.h" */
+#endif
+
+#include "elgamal.h"
+
+typedef struct {
+ MPI p; /* prime */
+ MPI g; /* group generator */
+ MPI y; /* g^x mod p */
+} ELG_public_key;
+
+
+typedef struct {
+ MPI p; /* prime */
+ MPI g; /* group generator */
+ MPI y; /* g^x mod p */
+ MPI x; /* secret exponent */
+} ELG_secret_key;
+
+
+static void test_keys( ELG_secret_key *sk, unsigned nbits );
+static MPI gen_k( MPI p );
+static void generate( ELG_secret_key *sk, unsigned nbits, MPI **factors );
+static int check_secret_key( ELG_secret_key *sk );
+static void encrypt(MPI a, MPI b, MPI input, ELG_public_key *pkey );
+static void decrypt(MPI output, MPI a, MPI b, ELG_secret_key *skey );
+static void sign(MPI a, MPI b, MPI input, ELG_secret_key *skey);
+static int verify(MPI a, MPI b, MPI input, ELG_public_key *pkey);
+
+
+static void
+progress( int c )
+{
+ fputc( c, stderr );
+}
+
+
+static void
+test_keys( ELG_secret_key *sk, unsigned nbits )
+{
+ ELG_public_key pk;
+ MPI test = mpi_alloc( 0 );
+ MPI out1_a = mpi_alloc( nbits / BITS_PER_MPI_LIMB );
+ MPI out1_b = mpi_alloc( nbits / BITS_PER_MPI_LIMB );
+ MPI out2 = mpi_alloc( nbits / BITS_PER_MPI_LIMB );
+
+ pk.p = sk->p;
+ pk.g = sk->g;
+ pk.y = sk->y;
+
+ /*mpi_set_bytes( test, nbits, get_random_byte, 0 );*/
+ { char *p = get_random_bits( nbits, 0, 0 );
+ mpi_set_buffer( test, p, (nbits+7)/8, 0 );
+ m_free(p);
+ }
+
+ encrypt( out1_a, out1_b, test, &pk );
+ decrypt( out2, out1_a, out1_b, sk );
+ if( mpi_cmp( test, out2 ) )
+ log_fatal("ElGamal operation: encrypt, decrypt failed\n");
+
+ sign( out1_a, out1_b, test, sk );
+ if( !verify( out1_a, out1_b, test, &pk ) )
+ log_fatal("ElGamal operation: sign, verify failed\n");
+
+ mpi_free( test );
+ mpi_free( out1_a );
+ mpi_free( out1_b );
+ mpi_free( out2 );
+}
+
+
+/****************
+ * generate a random secret exponent k from prime p, so
+ * that k is relatively prime to p-1
+ */
+static MPI
+gen_k( MPI p )
+{
+ MPI k = mpi_alloc_secure( 0 );
+ MPI temp = mpi_alloc( mpi_get_nlimbs(p) );
+ MPI p_1 = mpi_copy(p);
+ unsigned int nbits = mpi_get_nbits(p);
+ unsigned int nbytes = (nbits+7)/8;
+ char *rndbuf = NULL;
+
+ if( DBG_CIPHER )
+ log_debug("choosing a random k ");
+ mpi_sub_ui( p_1, p, 1);
+ for(;;) {
+ if( DBG_CIPHER )
+ progress('.');
+ if( !rndbuf || nbits < 32 ) {
+ m_free(rndbuf);
+ rndbuf = get_random_bits( nbits, 1, 1 );
+ }
+ else { /* change only some of the higher bits */
+ /* we could imporove this by directly requesting more memory
+ * at the first call to get_random_bits() and use this the here
+ * maybe it is easier to do this directly in random.c */
+ char *pp = get_random_bits( 32, 1, 1 );
+ memcpy( rndbuf,pp, 4 );
+ m_free(pp);
+ }
+ mpi_set_buffer( k, rndbuf, nbytes, 0 );
+
+ for(;;) {
+ /* make sure that the number is of the exact lenght */
+ if( mpi_test_bit( k, nbits-1 ) )
+ mpi_set_highbit( k, nbits-1 );
+ else {
+ mpi_set_highbit( k, nbits-1 );
+ mpi_clear_bit( k, nbits-1 );
+ }
+ if( !(mpi_cmp( k, p_1 ) < 0) ) { /* check: k < (p-1) */
+ if( DBG_CIPHER )
+ progress('+');
+ break; /* no */
+ }
+ if( !(mpi_cmp_ui( k, 0 ) > 0) ) { /* check: k > 0 */
+ if( DBG_CIPHER )
+ progress('-');
+ break; /* no */
+ }
+ if( mpi_gcd( temp, k, p_1 ) )
+ goto found; /* okay, k is relatively prime to (p-1) */
+ mpi_add_ui( k, k, 1 );
+ }
+ }
+ found:
+ m_free(rndbuf);
+ if( DBG_CIPHER )
+ progress('\n');
+ mpi_free(p_1);
+ mpi_free(temp);
+
+ return k;
+}
+
+/****************
+ * Generate a key pair with a key of size NBITS
+ * Returns: 2 structures filles with all needed values
+ * and an array with n-1 factors of (p-1)
+ */
+static void
+generate( ELG_secret_key *sk, unsigned nbits, MPI **ret_factors )
+{
+ MPI p; /* the prime */
+ MPI p_min1;
+ MPI g;
+ MPI x; /* the secret exponent */
+ MPI y;
+ MPI temp;
+ unsigned qbits;
+ byte *rndbuf;
+
+ p_min1 = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+ temp = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+ if( nbits < 512 )
+ qbits = 120;
+ else if( nbits <= 1024 )
+ qbits = 160;
+ else if( nbits <= 2048 )
+ qbits = 200;
+ else
+ qbits = 240;
+ g = mpi_alloc(1);
+ p = generate_elg_prime( 0, nbits, qbits, g, ret_factors );
+ mpi_sub_ui(p_min1, p, 1);
+
+
+ /* select a random number which has these properties:
+ * 0 < x < p-1
+ * This must be a very good random number because this is the
+ * secret part. The prime is public and may be shared anyway,
+ * so a random generator level of 1 is used for the prime.
+ */
+ x = mpi_alloc_secure( nbits/BITS_PER_MPI_LIMB );
+ if( DBG_CIPHER )
+ log_debug("choosing a random x ");
+ rndbuf = NULL;
+ do {
+ if( DBG_CIPHER )
+ progress('.');
+ if( rndbuf ) { /* change only some of the higher bits */
+ if( nbits < 16 ) {/* should never happen ... */
+ m_free(rndbuf);
+ rndbuf = get_random_bits( nbits, 2, 1 );
+ }
+ else {
+ char *r = get_random_bits( 16, 2, 1 );
+ memcpy(rndbuf, r, 16/8 );
+ m_free(r);
+ }
+ }
+ else
+ rndbuf = get_random_bits( nbits, 2, 1 );
+ mpi_set_buffer( x, rndbuf, (nbits+7)/8, 0 );
+ mpi_clear_highbit( x, nbits+1 );
+ } while( !( mpi_cmp_ui( x, 0 )>0 && mpi_cmp( x, p_min1 )<0 ) );
+ m_free(rndbuf);
+
+ y = mpi_alloc(nbits/BITS_PER_MPI_LIMB);
+ mpi_powm( y, g, x, p );
+
+ if( DBG_CIPHER ) {
+ progress('\n');
+ log_mpidump("elg p= ", p );
+ log_mpidump("elg g= ", g );
+ log_mpidump("elg y= ", y );
+ log_mpidump("elg x= ", x );
+ }
+
+ /* copy the stuff to the key structures */
+ sk->p = p;
+ sk->g = g;
+ sk->y = y;
+ sk->x = x;
+
+ /* now we can test our keys (this should never fail!) */
+ test_keys( sk, nbits - 64 );
+
+ mpi_free( p_min1 );
+ mpi_free( temp );
+}
+
+
+/****************
+ * Test whether the secret key is valid.
+ * Returns: if this is a valid key.
+ */
+static int
+check_secret_key( ELG_secret_key *sk )
+{
+ int rc;
+ MPI y = mpi_alloc( mpi_get_nlimbs(sk->y) );
+
+ mpi_powm( y, sk->g, sk->x, sk->p );
+ rc = !mpi_cmp( y, sk->y );
+ mpi_free( y );
+ return rc;
+}
+
+
+static void
+encrypt(MPI a, MPI b, MPI input, ELG_public_key *pkey )
+{
+ MPI k;
+
+ /* Note: maybe we should change the interface, so that it
+ * is possible to check that input is < p and return an
+ * error code.
+ */
+
+ k = gen_k( pkey->p );
+ mpi_powm( a, pkey->g, k, pkey->p );
+ /* b = (y^k * input) mod p
+ * = ((y^k mod p) * (input mod p)) mod p
+ * and because input is < p
+ * = ((y^k mod p) * input) mod p
+ */
+ mpi_powm( b, pkey->y, k, pkey->p );
+ mpi_mulm( b, b, input, pkey->p );
+ #if 0
+ if( DBG_CIPHER ) {
+ log_mpidump("elg encrypted y= ", pkey->y);
+ log_mpidump("elg encrypted p= ", pkey->p);
+ log_mpidump("elg encrypted k= ", k);
+ log_mpidump("elg encrypted M= ", input);
+ log_mpidump("elg encrypted a= ", a);
+ log_mpidump("elg encrypted b= ", b);
+ }
+ #endif
+ mpi_free(k);
+}
+
+
+
+
+static void
+decrypt(MPI output, MPI a, MPI b, ELG_secret_key *skey )
+{
+ MPI t1 = mpi_alloc_secure( mpi_get_nlimbs( skey->p ) );
+
+ /* output = b/(a^x) mod p */
+
+ mpi_powm( t1, a, skey->x, skey->p );
+ mpi_invm( t1, t1, skey->p );
+ mpi_mulm( output, b, t1, skey->p );
+ #if 0
+ if( DBG_CIPHER ) {
+ log_mpidump("elg decrypted x= ", skey->x);
+ log_mpidump("elg decrypted p= ", skey->p);
+ log_mpidump("elg decrypted a= ", a);
+ log_mpidump("elg decrypted b= ", b);
+ log_mpidump("elg decrypted M= ", output);
+ }
+ #endif
+ mpi_free(t1);
+}
+
+
+/****************
+ * Make an Elgamal signature out of INPUT
+ */
+
+static void
+sign(MPI a, MPI b, MPI input, ELG_secret_key *skey )
+{
+ MPI k;
+ MPI t = mpi_alloc( mpi_get_nlimbs(a) );
+ MPI inv = mpi_alloc( mpi_get_nlimbs(a) );
+ MPI p_1 = mpi_copy(skey->p);
+
+ /*
+ * b = (t * inv) mod (p-1)
+ * b = (t * inv(k,(p-1),(p-1)) mod (p-1)
+ * b = (((M-x*a) mod (p-1)) * inv(k,(p-1),(p-1))) mod (p-1)
+ *
+ */
+ mpi_sub_ui(p_1, p_1, 1);
+ k = gen_k( skey->p );
+ mpi_powm( a, skey->g, k, skey->p );
+ mpi_mul(t, skey->x, a );
+ mpi_subm(t, input, t, p_1 );
+ while( mpi_is_neg(t) )
+ mpi_add(t, t, p_1);
+ mpi_invm(inv, k, p_1 );
+ mpi_mulm(b, t, inv, p_1 );
+
+ #if 0
+ if( DBG_CIPHER ) {
+ log_mpidump("elg sign p= ", skey->p);
+ log_mpidump("elg sign g= ", skey->g);
+ log_mpidump("elg sign y= ", skey->y);
+ log_mpidump("elg sign x= ", skey->x);
+ log_mpidump("elg sign k= ", k);
+ log_mpidump("elg sign M= ", input);
+ log_mpidump("elg sign a= ", a);
+ log_mpidump("elg sign b= ", b);
+ }
+ #endif
+ mpi_free(k);
+ mpi_free(t);
+ mpi_free(inv);
+ mpi_free(p_1);
+}
+
+
+/****************
+ * Returns true if the signature composed of A and B is valid.
+ */
+static int
+verify(MPI a, MPI b, MPI input, ELG_public_key *pkey )
+{
+ int rc;
+ MPI t1;
+ MPI t2;
+ MPI base[4];
+ MPI exp[4];
+
+ if( !(mpi_cmp_ui( a, 0 ) > 0 && mpi_cmp( a, pkey->p ) < 0) )
+ return 0; /* assertion 0 < a < p failed */
+
+ t1 = mpi_alloc( mpi_get_nlimbs(a) );
+ t2 = mpi_alloc( mpi_get_nlimbs(a) );
+
+ #if 0
+ /* t1 = (y^a mod p) * (a^b mod p) mod p */
+ mpi_powm( t1, pkey->y, a, pkey->p );
+ mpi_powm( t2, a, b, pkey->p );
+ mpi_mulm( t1, t1, t2, pkey->p );
+
+ /* t2 = g ^ input mod p */
+ mpi_powm( t2, pkey->g, input, pkey->p );
+
+ rc = !mpi_cmp( t1, t2 );
+ #elif 0
+ /* t1 = (y^a mod p) * (a^b mod p) mod p */
+ base[0] = pkey->y; exp[0] = a;
+ base[1] = a; exp[1] = b;
+ base[2] = NULL; exp[2] = NULL;
+ mpi_mulpowm( t1, base, exp, pkey->p );
+
+ /* t2 = g ^ input mod p */
+ mpi_powm( t2, pkey->g, input, pkey->p );
+
+ rc = !mpi_cmp( t1, t2 );
+ #else
+ /* t1 = g ^ - input * y ^ a * a ^ b mod p */
+ mpi_invm(t2, pkey->g, pkey->p );
+ base[0] = t2 ; exp[0] = input;
+ base[1] = pkey->y; exp[1] = a;
+ base[2] = a; exp[2] = b;
+ base[3] = NULL; exp[3] = NULL;
+ mpi_mulpowm( t1, base, exp, pkey->p );
+ rc = !mpi_cmp_ui( t1, 1 );
+
+ #endif
+
+ mpi_free(t1);
+ mpi_free(t2);
+ return rc;
+}
+
+/*********************************************
+ ************** interface ******************
+ *********************************************/
+
+int
+elg_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
+{
+ ELG_secret_key sk;
+
+ if( !is_ELGAMAL(algo) )
+ return G10ERR_PUBKEY_ALGO;
+
+ generate( &sk, nbits, retfactors );
+ skey[0] = sk.p;
+ skey[1] = sk.g;
+ skey[2] = sk.y;
+ skey[3] = sk.x;
+ return 0;
+}
+
+
+int
+elg_check_secret_key( int algo, MPI *skey )
+{
+ ELG_secret_key sk;
+
+ if( !is_ELGAMAL(algo) )
+ return G10ERR_PUBKEY_ALGO;
+ if( !skey[0] || !skey[1] || !skey[2] || !skey[3] )
+ return G10ERR_BAD_MPI;
+
+ sk.p = skey[0];
+ sk.g = skey[1];
+ sk.y = skey[2];
+ sk.x = skey[3];
+ if( !check_secret_key( &sk ) )
+ return G10ERR_BAD_SECKEY;
+
+ return 0;
+}
+
+
+
+int
+elg_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
+{
+ ELG_public_key pk;
+
+ if( !is_ELGAMAL(algo) )
+ return G10ERR_PUBKEY_ALGO;
+ if( !data || !pkey[0] || !pkey[1] || !pkey[2] )
+ return G10ERR_BAD_MPI;
+
+ pk.p = pkey[0];
+ pk.g = pkey[1];
+ pk.y = pkey[2];
+ resarr[0] = mpi_alloc( mpi_get_nlimbs( pk.p ) );
+ resarr[1] = mpi_alloc( mpi_get_nlimbs( pk.p ) );
+ encrypt( resarr[0], resarr[1], data, &pk );
+ return 0;
+}
+
+int
+elg_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
+{
+ ELG_secret_key sk;
+
+ if( !is_ELGAMAL(algo) )
+ return G10ERR_PUBKEY_ALGO;
+ if( !data[0] || !data[1]
+ || !skey[0] || !skey[1] || !skey[2] || !skey[3] )
+ return G10ERR_BAD_MPI;
+
+ sk.p = skey[0];
+ sk.g = skey[1];
+ sk.y = skey[2];
+ sk.x = skey[3];
+ *result = mpi_alloc_secure( mpi_get_nlimbs( sk.p ) );
+ decrypt( *result, data[0], data[1], &sk );
+ return 0;
+}
+
+int
+elg_sign( int algo, MPI *resarr, MPI data, MPI *skey )
+{
+ ELG_secret_key sk;
+
+ if( !is_ELGAMAL(algo) )
+ return G10ERR_PUBKEY_ALGO;
+ if( !data || !skey[0] || !skey[1] || !skey[2] || !skey[3] )
+ return G10ERR_BAD_MPI;
+
+ sk.p = skey[0];
+ sk.g = skey[1];
+ sk.y = skey[2];
+ sk.x = skey[3];
+ resarr[0] = mpi_alloc( mpi_get_nlimbs( sk.p ) );
+ resarr[1] = mpi_alloc( mpi_get_nlimbs( sk.p ) );
+ sign( resarr[0], resarr[1], data, &sk );
+ return 0;
+}
+
+int
+elg_verify( int algo, MPI hash, MPI *data, MPI *pkey,
+ int (*cmp)(void *, MPI) UNUSED, void *opaquev UNUSED)
+{
+ ELG_public_key pk;
+
+ if( !is_ELGAMAL(algo) )
+ return G10ERR_PUBKEY_ALGO;
+ if( !data[0] || !data[1] || !hash
+ || !pkey[0] || !pkey[1] || !pkey[2] )
+ return G10ERR_BAD_MPI;
+
+ pk.p = pkey[0];
+ pk.g = pkey[1];
+ pk.y = pkey[2];
+ if( !verify( data[0], data[1], hash, &pk ) )
+ return G10ERR_BAD_SIGN;
+ return 0;
+}
+
+
+
+unsigned
+elg_get_nbits( int algo, MPI *pkey )
+{
+ if( !is_ELGAMAL(algo) )
+ return 0;
+ return mpi_get_nbits( pkey[0] );
+}
+
+
+/****************
+ * Return some information about the algorithm. We need algo here to
+ * distinguish different flavors of the algorithm.
+ * Returns: A pointer to string describing the algorithm or NULL if
+ * the ALGO is invalid.
+ * Usage: Bit 0 set : allows signing
+ * 1 set : allows encryption
+ * NOTE: This function allows signing also for ELG-E, which is not
+ * okay but a bad hack to allow to work with old gpg keys. The real check
+ * is done in the gnupg ocde depending on the packet version.
+ */
+const char *
+elg_get_info( int algo, int *npkey, int *nskey, int *nenc, int *nsig,
+ int *use )
+{
+ *npkey = 3;
+ *nskey = 4;
+ *nenc = 2;
+ *nsig = 2;
+
+ switch( algo ) {
+ case PUBKEY_ALGO_ELGAMAL:
+ *use = PUBKEY_USAGE_SIG|PUBKEY_USAGE_ENC;
+ return "ELG";
+ case PUBKEY_ALGO_ELGAMAL_E:
+ *use = PUBKEY_USAGE_SIG|PUBKEY_USAGE_ENC;
+ return "ELG-E";
+ default: *use = 0; return NULL;
+ }
+}
+
+
diff --git a/src/pluto/elgamal.h b/src/pluto/elgamal.h
new file mode 100644
index 000000000..f104c2a52
--- /dev/null
+++ b/src/pluto/elgamal.h
@@ -0,0 +1,35 @@
+/* elgamal.h
+ * Copyright (C) 1998 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+#ifndef G10_ELGAMAL_H
+#define G10_ELGAMAL_H
+
+int elg_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors );
+int elg_check_secret_key( int algo, MPI *skey );
+int elg_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey );
+int elg_decrypt( int algo, MPI *result, MPI *data, MPI *skey );
+int elg_sign( int algo, MPI *resarr, MPI data, MPI *skey );
+int elg_verify( int algo, MPI hash, MPI *data, MPI *pkey,
+ int (*cmp)(void *, MPI), void *opaquev );
+unsigned elg_get_nbits( int algo, MPI *pkey );
+const char *elg_get_info( int algo, int *npkey, int *nskey,
+ int *nenc, int *nsig, int *use );
+
+
+#endif /*G10_ELGAMAL_H*/
diff --git a/src/pluto/fetch.c b/src/pluto/fetch.c
new file mode 100644
index 000000000..e3e56d3a8
--- /dev/null
+++ b/src/pluto/fetch.c
@@ -0,0 +1,1081 @@
+/* Dynamic fetching of X.509 CRLs
+ * Copyright (C) 2002 Stephane Laroche <stephane.laroche@colubris.com>
+ * Copyright (C) 2002-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.
+ *
+ * RCSID $Id: fetch.c,v 1.12 2006/05/16 14:19:27 as Exp $
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <time.h>
+#include <string.h>
+
+#ifdef THREADS
+#include <pthread.h>
+#endif
+
+#ifdef LIBCURL
+#include <curl/curl.h>
+#endif
+
+#include <freeswan.h>
+
+#ifdef LIBLDAP
+#include <ldap.h>
+#endif
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "id.h"
+#include "asn1.h"
+#include "pem.h"
+#include "x509.h"
+#include "ca.h"
+#include "whack.h"
+#include "ocsp.h"
+#include "crl.h"
+#include "fetch.h"
+
+fetch_req_t empty_fetch_req = {
+ NULL , /* next */
+ 0 , /* installed */
+ 0 , /* trials */
+ { NULL, 0}, /* issuer */
+ { NULL, 0}, /* authKeyID */
+ { NULL, 0}, /* authKeySerialNumber */
+ NULL /* distributionPoints */
+};
+
+/* chained list of crl fetch requests */
+static fetch_req_t *crl_fetch_reqs = NULL;
+
+/* chained list of ocsp fetch requests */
+static ocsp_location_t *ocsp_fetch_reqs = NULL;
+
+#ifdef THREADS
+static pthread_t thread;
+static pthread_mutex_t certs_and_keys_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t authcert_list_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t crl_list_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t ocsp_cache_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t ca_info_list_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t crl_fetch_list_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t ocsp_fetch_list_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t fetch_wake_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t fetch_wake_cond = PTHREAD_COND_INITIALIZER;
+
+/*
+ * lock access to my certs and keys
+ */
+void
+lock_certs_and_keys(const char *who)
+{
+ pthread_mutex_lock(&certs_and_keys_mutex);
+ DBG(DBG_CONTROLMORE,
+ DBG_log("certs and keys locked by '%s'", who)
+ )
+}
+
+/*
+ * unlock access to my certs and keys
+ */
+void
+unlock_certs_and_keys(const char *who)
+{
+ DBG(DBG_CONTROLMORE,
+ DBG_log("certs and keys unlocked by '%s'", who)
+ )
+ pthread_mutex_unlock(&certs_and_keys_mutex);
+}
+
+/*
+ * lock access to the chained authcert list
+ */
+void
+lock_authcert_list(const char *who)
+{
+ pthread_mutex_lock(&authcert_list_mutex);
+ DBG(DBG_CONTROLMORE,
+ DBG_log("authcert list locked by '%s'", who)
+ )
+}
+
+/*
+ * unlock access to the chained authcert list
+ */
+void
+unlock_authcert_list(const char *who)
+{
+ DBG(DBG_CONTROLMORE,
+ DBG_log("authcert list unlocked by '%s'", who)
+ )
+ pthread_mutex_unlock(&authcert_list_mutex);
+}
+
+/*
+ * lock access to the chained crl list
+ */
+void
+lock_crl_list(const char *who)
+{
+ pthread_mutex_lock(&crl_list_mutex);
+ DBG(DBG_CONTROLMORE,
+ DBG_log("crl list locked by '%s'", who)
+ )
+}
+
+/*
+ * unlock access to the chained crl list
+ */
+void
+unlock_crl_list(const char *who)
+{
+ DBG(DBG_CONTROLMORE,
+ DBG_log("crl list unlocked by '%s'", who)
+ )
+ pthread_mutex_unlock(&crl_list_mutex);
+}
+
+/*
+ * lock access to the ocsp cache
+ */
+extern void
+lock_ocsp_cache(const char *who)
+{
+ pthread_mutex_lock(&ocsp_cache_mutex);
+ DBG(DBG_CONTROLMORE,
+ DBG_log("ocsp cache locked by '%s'", who)
+ )
+}
+
+/*
+ * unlock access to the ocsp cache
+ */
+extern void
+unlock_ocsp_cache(const char *who)
+{
+ DBG(DBG_CONTROLMORE,
+ DBG_log("ocsp cache unlocked by '%s'", who)
+ )
+ pthread_mutex_unlock(&ocsp_cache_mutex);
+}
+
+/*
+ * lock access to the ca info list
+ */
+extern void
+lock_ca_info_list(const char *who)
+{
+ pthread_mutex_lock(&ca_info_list_mutex);
+ DBG(DBG_CONTROLMORE,
+ DBG_log("ca info list locked by '%s'", who)
+ )
+}
+
+/*
+ * unlock access to the ca info list
+ */
+extern void
+unlock_ca_info_list(const char *who)
+{
+ DBG(DBG_CONTROLMORE,
+ DBG_log("ca info list unlocked by '%s'", who)
+ )
+ pthread_mutex_unlock(&ca_info_list_mutex);
+}
+
+/*
+ * lock access to the chained crl fetch request list
+ */
+static void
+lock_crl_fetch_list(const char *who)
+{
+ pthread_mutex_lock(&crl_fetch_list_mutex);
+ DBG(DBG_CONTROLMORE,
+ DBG_log("crl fetch request list locked by '%s'", who)
+ )
+}
+
+/*
+ * unlock access to the chained crl fetch request list
+ */
+static void
+unlock_crl_fetch_list(const char *who)
+{
+ DBG(DBG_CONTROLMORE,
+ DBG_log("crl fetch request list unlocked by '%s'", who)
+ )
+ pthread_mutex_unlock(&crl_fetch_list_mutex);
+}
+
+/*
+ * lock access to the chained ocsp fetch request list
+ */
+static void
+lock_ocsp_fetch_list(const char *who)
+{
+ pthread_mutex_lock(&ocsp_fetch_list_mutex);
+ DBG(DBG_CONTROLMORE,
+ DBG_log("ocsp fetch request list locked by '%s'", who)
+ )
+}
+
+/*
+ * unlock access to the chained ocsp fetch request list
+ */
+static void
+unlock_ocsp_fetch_list(const char *who)
+{
+ DBG(DBG_CONTROLMORE,
+ DBG_log("ocsp fetch request list unlocked by '%s'", who)
+ )
+ pthread_mutex_unlock(&ocsp_fetch_list_mutex);
+}
+
+/*
+ * wakes up the sleeping fetch thread
+ */
+void
+wake_fetch_thread(const char *who)
+{
+ if (crl_check_interval > 0)
+ {
+ DBG(DBG_CONTROLMORE,
+ DBG_log("fetch thread wake call by '%s'", who)
+ )
+ pthread_mutex_lock(&fetch_wake_mutex);
+ pthread_cond_signal(&fetch_wake_cond);
+ pthread_mutex_unlock(&fetch_wake_mutex);
+ }
+}
+#else /* !THREADS */
+#define lock_crl_fetch_list(who) /* do nothing */
+#define unlock_crl_fetch_list(who) /* do nothing */
+#define lock_ocsp_fetch_list(who) /* do nothing */
+#define unlock_ocsp_fetch_list(who) /* do nothing */
+#endif /* !THREADS */
+
+/*
+ * free the dynamic memory used to store fetch requests
+ */
+static void
+free_fetch_request(fetch_req_t *req)
+{
+ pfree(req->issuer.ptr);
+ pfreeany(req->authKeySerialNumber.ptr);
+ pfreeany(req->authKeyID.ptr);
+ free_generalNames(req->distributionPoints, TRUE);
+ pfree(req);
+}
+
+/* writes data into a dynamically resizeable chunk_t
+ * needed for libcurl responses
+ */
+size_t
+write_buffer(void *ptr, size_t size, size_t nmemb, void *data)
+{
+ size_t realsize = size * nmemb;
+ chunk_t *mem = (chunk_t*)data;
+
+ mem->ptr = (u_char *)realloc(mem->ptr, mem->len + realsize);
+ if (mem->ptr) {
+ memcpy(&(mem->ptr[mem->len]), ptr, realsize);
+ mem->len += realsize;
+ }
+ return realsize;
+}
+
+#ifdef THREADS
+/*
+ * fetches a binary blob from a url with libcurl
+ */
+static err_t
+fetch_curl(char *url, chunk_t *blob)
+{
+#ifdef LIBCURL
+ char errorbuffer[CURL_ERROR_SIZE] = "";
+ chunk_t response = empty_chunk;
+ CURLcode res;
+
+ /* get it with libcurl */
+ CURL *curl = curl_easy_init();
+
+ if (curl != NULL)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("Trying cURL '%s'", url)
+ )
+
+ curl_easy_setopt(curl, CURLOPT_URL, url);
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_buffer);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response);
+ curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &errorbuffer);
+ curl_easy_setopt(curl, CURLOPT_FAILONERROR, TRUE);
+ curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, FETCH_CMD_TIMEOUT);
+
+ res = curl_easy_perform(curl);
+
+ if (res == CURLE_OK)
+ {
+ blob->len = response.len;
+ blob->ptr = alloc_bytes(response.len, "curl blob");
+ memcpy(blob->ptr, response.ptr, response.len);
+ }
+ else
+ {
+ plog("fetching uri (%s) with libcurl failed: %s", url, errorbuffer);
+ }
+ curl_easy_cleanup(curl);
+ /* not using freeanychunk because of realloc (no leak detective) */
+ curl_free(response.ptr);
+ }
+ return strlen(errorbuffer) > 0 ? "libcurl error" : NULL;
+#else /* !LIBCURL */
+ return "warning: not compiled with libcurl support";
+#endif /* !LIBCURL */
+}
+
+#ifdef LIBLDAP
+/*
+ * parses the result returned by an ldap query
+ */
+static err_t
+parse_ldap_result(LDAP * ldap, LDAPMessage *result, chunk_t *blob)
+{
+ err_t ugh = NULL;
+
+ LDAPMessage * entry = ldap_first_entry(ldap, result);
+
+ if (entry != NULL)
+ {
+ BerElement *ber = NULL;
+ char *attr;
+
+ attr = ldap_first_attribute(ldap, entry, &ber);
+
+ if (attr != NULL)
+ {
+ struct berval **values = ldap_get_values_len(ldap, entry, attr);
+
+ if (values != NULL)
+ {
+ if (values[0] != NULL)
+ {
+ blob->len = values[0]->bv_len;
+ blob->ptr = alloc_bytes(blob->len, "ldap blob");
+ memcpy(blob->ptr, values[0]->bv_val, blob->len);
+ if (values[1] != NULL)
+ {
+ plog("warning: more than one value was fetched from LDAP URL");
+ }
+ }
+ else
+ {
+ ugh = "no values in attribute";
+ }
+ ldap_value_free_len(values);
+ }
+ else
+ {
+ ugh = ldap_err2string(ldap_result2error(ldap, entry, 0));
+ }
+ ldap_memfree(attr);
+ }
+ else
+ {
+ ugh = ldap_err2string(ldap_result2error(ldap, entry, 0));
+ }
+ ber_free(ber, 0);
+ }
+ else
+ {
+ ugh = ldap_err2string(ldap_result2error(ldap, result, 0));
+ }
+ return ugh;
+}
+
+/*
+ * fetches a binary blob from an ldap url
+ */
+static err_t
+fetch_ldap_url(char *url, chunk_t *blob)
+{
+ LDAPURLDesc *lurl;
+ err_t ugh = NULL;
+ int rc;
+
+ DBG(DBG_CONTROL,
+ DBG_log("Trying LDAP URL '%s'", url)
+ )
+
+ rc = ldap_url_parse(url, &lurl);
+
+ if (rc == LDAP_SUCCESS)
+ {
+ LDAP *ldap = ldap_init(lurl->lud_host, lurl->lud_port);
+
+ if (ldap != NULL)
+ {
+ int ldap_version = LDAP_VERSION3;
+ struct timeval timeout;
+
+ timeout.tv_sec = FETCH_CMD_TIMEOUT;
+ timeout.tv_usec = 0;
+ ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &ldap_version);
+ ldap_set_option(ldap, LDAP_OPT_NETWORK_TIMEOUT, &timeout);
+
+ rc = ldap_simple_bind_s(ldap, NULL, NULL);
+
+ if (rc == LDAP_SUCCESS)
+ {
+ LDAPMessage *result;
+
+ timeout.tv_sec = FETCH_CMD_TIMEOUT;
+ timeout.tv_usec = 0;
+
+ rc = ldap_search_st(ldap, lurl->lud_dn
+ , lurl->lud_scope
+ , lurl->lud_filter
+ , lurl->lud_attrs
+ , 0, &timeout, &result);
+
+ if (rc == LDAP_SUCCESS)
+ {
+ ugh = parse_ldap_result(ldap, result, blob);
+ ldap_msgfree(result);
+ }
+ else
+ {
+ ugh = ldap_err2string(rc);
+ }
+ }
+ else
+ {
+ ugh = ldap_err2string(rc);
+ }
+ ldap_unbind_s(ldap);
+ }
+ else
+ {
+ ugh = "ldap init";
+ }
+ ldap_free_urldesc(lurl);
+ }
+ else
+ {
+ ugh = ldap_err2string(rc);
+ }
+ return ugh;
+}
+#else /* !LIBLDAP */
+static err_t
+fetch_ldap_url(char *url, chunk_t *blob)
+{
+ return "LDAP URL fetching not activated in pluto source code";
+}
+#endif /* !LIBLDAP */
+
+/*
+ * fetch an ASN.1 blob coded in PEM or DER format from a URL
+ */
+static err_t
+fetch_asn1_blob(char *url, chunk_t *blob)
+{
+ err_t ugh = NULL;
+
+ if (strlen(url) >= 4 && strncasecmp(url, "ldap", 4) == 0)
+ {
+ ugh = fetch_ldap_url(url, blob);
+ }
+ else
+ {
+ ugh = fetch_curl(url, blob);
+ }
+ if (ugh != NULL)
+ return ugh;
+
+ if (is_asn1(*blob))
+ {
+ DBG(DBG_PARSING,
+ DBG_log(" fetched blob coded in DER format")
+ )
+ }
+ else
+ {
+ bool pgp = FALSE;
+
+ ugh = pemtobin(blob, NULL, "", &pgp);
+ if (ugh == NULL)
+ {
+ if (is_asn1(*blob))
+ {
+ DBG(DBG_PARSING,
+ DBG_log(" fetched blob coded in PEM format")
+ )
+ }
+ else
+ {
+ ugh = "blob coded in unknown format";
+ pfree(blob->ptr);
+ }
+ }
+ else
+ {
+ pfree(blob->ptr);
+ }
+ }
+ return ugh;
+}
+
+/*
+ * complete a distributionPoint URI with ca information
+ */
+static char*
+complete_uri(chunk_t distPoint, const char *ldaphost)
+{
+ char *uri;
+ char *ptr = distPoint.ptr;
+ size_t len = distPoint.len;
+
+ char *symbol = memchr(ptr, ':', len);
+
+ if (symbol != NULL)
+ {
+ size_t type_len = symbol - ptr;
+
+ if (type_len >= 4 && strncasecmp(ptr, "ldap", 4) == 0)
+ {
+ ptr = symbol + 1;
+ len -= (type_len + 1);
+
+ if (len > 2 && *ptr++ == '/' && *ptr++ == '/')
+ {
+ len -= 2;
+ symbol = memchr(ptr, '/', len);
+
+ if (symbol != NULL && symbol - ptr == 0 && ldaphost != NULL)
+ {
+ uri = alloc_bytes(distPoint.len+strlen(ldaphost)+1, "uri");
+
+ /* insert the ldaphost into the uri */
+ sprintf(uri, "%.*s%s%.*s"
+ , (int)(distPoint.len - len), distPoint.ptr
+ , ldaphost
+ , (int)len, symbol);
+ return uri;
+ }
+ }
+ }
+ }
+
+ /* default action: copy distributionPoint without change */
+ uri = alloc_bytes(distPoint.len+1, "uri");
+ sprintf(uri, "%.*s", (int)distPoint.len, distPoint.ptr);
+ return uri;
+}
+
+/*
+ * try to fetch the crls defined by the fetch requests
+ */
+static void
+fetch_crls(bool cache_crls)
+{
+ fetch_req_t *req;
+ fetch_req_t **reqp;
+
+ lock_crl_fetch_list("fetch_crls");
+ req = crl_fetch_reqs;
+ reqp = &crl_fetch_reqs;
+
+ while (req != NULL)
+ {
+ bool valid_crl = FALSE;
+ chunk_t blob = empty_chunk;
+ generalName_t *gn = req->distributionPoints;
+ const char *ldaphost;
+ ca_info_t *ca;
+
+ lock_ca_info_list("fetch_crls");
+
+ ca = get_ca_info(req->issuer, req->authKeySerialNumber, req->authKeyID);
+ ldaphost = (ca == NULL)? NULL : ca->ldaphost;
+
+ while (gn != NULL)
+ {
+ char *uri = complete_uri(gn->name, ldaphost);
+
+ err_t ugh = fetch_asn1_blob(uri, &blob);
+ pfree(uri);
+
+ if (ugh != NULL)
+ {
+ plog("fetch failed: %s", ugh);
+ }
+ else
+ {
+ chunk_t crl_uri;
+
+ clonetochunk(crl_uri, gn->name.ptr, gn->name.len, "crl uri");
+ if (insert_crl(blob, crl_uri, cache_crls))
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("we have a valid crl")
+ )
+ valid_crl = TRUE;
+ break;
+ }
+ }
+ gn = gn->next;
+ }
+
+ unlock_ca_info_list("fetch_crls");
+
+ if (valid_crl)
+ {
+ /* delete fetch request */
+ fetch_req_t *req_free = req;
+
+ req = req->next;
+ *reqp = req;
+ free_fetch_request(req_free);
+ }
+ else
+ {
+ /* try again next time */
+ req->trials++;
+ reqp = &req->next;
+ req = req->next;
+ }
+ }
+ unlock_crl_fetch_list("fetch_crls");
+}
+
+static void
+fetch_ocsp_status(ocsp_location_t* location)
+{
+#ifdef LIBCURL
+ chunk_t request;
+ chunk_t response = empty_chunk;
+
+ CURL* curl;
+ CURLcode res;
+
+ request = build_ocsp_request(location);
+
+ DBG(DBG_CONTROL,
+ DBG_log("sending ocsp request to location '%.*s'"
+ , (int)location->uri.len, location->uri.ptr)
+ )
+ DBG(DBG_RAW,
+ DBG_dump_chunk("OCSP request", request)
+ )
+
+ /* send via http post using libcurl */
+ curl = curl_easy_init();
+
+ if (curl != NULL)
+ {
+ char errorbuffer[CURL_ERROR_SIZE];
+ struct curl_slist *headers = NULL;
+ char* uri = alloc_bytes(location->uri.len+1, "ocsp uri");
+
+ /* we need a null terminated string for curl */
+ memcpy(uri, location->uri.ptr, location->uri.len);
+ *(uri + location->uri.len) = '\0';
+
+ /* set content type header */
+ headers = curl_slist_append(headers, "Content-Type: application/ocsp-request");
+ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
+
+ curl_easy_setopt(curl, CURLOPT_URL, uri);
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_buffer);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response);
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request.ptr);
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, request.len);
+ curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &errorbuffer);
+ curl_easy_setopt(curl, CURLOPT_FAILONERROR, TRUE);
+ curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, FETCH_CMD_TIMEOUT);
+
+ res = curl_easy_perform(curl);
+
+ if (res == CURLE_OK)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("received ocsp response")
+ )
+ DBG(DBG_RAW,
+ DBG_dump_chunk("OCSP response:\n", response)
+ )
+ parse_ocsp(location, response);
+ }
+ else
+ {
+ plog("failed to fetch ocsp status from '%s': %s", uri, errorbuffer);
+ }
+ curl_slist_free_all(headers);
+ curl_easy_cleanup(curl);
+ pfree(uri);
+ /* not using freeanychunk because of realloc (no leak detective) */
+ curl_free(response.ptr);
+ }
+ freeanychunk(location->nonce);
+ freeanychunk(request);
+
+ /* increment the trial counter of the unresolved fetch requests */
+ {
+ ocsp_certinfo_t *certinfo = location->certinfo;
+
+ while (certinfo != NULL)
+ {
+ certinfo->trials++;
+ certinfo = certinfo->next;
+ }
+ }
+ return;
+#else /* !LIBCURL */
+ plog("ocsp error: pluto wasn't compiled with libcurl support");
+#endif /* !LIBCURL */
+}
+
+/*
+ * try to fetch the necessary ocsp information
+ */
+static void
+fetch_ocsp(void)
+{
+ ocsp_location_t *location;
+
+ lock_ocsp_fetch_list("fetch_ocsp");
+ location = ocsp_fetch_reqs;
+
+ /* fetch the ocps status for all locations */
+ while (location != NULL)
+ {
+ if (location->certinfo != NULL)
+ fetch_ocsp_status(location);
+ location = location->next;
+ }
+
+ unlock_ocsp_fetch_list("fetch_ocsp");
+}
+
+static void*
+fetch_thread(void *arg)
+{
+ struct timespec wait_interval;
+
+ DBG(DBG_CONTROL,
+ DBG_log("fetch thread started")
+ )
+
+ pthread_mutex_lock(&fetch_wake_mutex);
+
+ while(1)
+ {
+ int status;
+
+ wait_interval.tv_nsec = 0;
+ wait_interval.tv_sec = time(NULL) + crl_check_interval;
+
+ DBG(DBG_CONTROL,
+ DBG_log("next regular crl check in %ld seconds", crl_check_interval)
+ )
+ status = pthread_cond_timedwait(&fetch_wake_cond, &fetch_wake_mutex
+ , &wait_interval);
+
+ if (status == ETIMEDOUT)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log(" ");
+ DBG_log("*time to check crls and the ocsp cache")
+ )
+ check_ocsp();
+ check_crls();
+ }
+ else
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("fetch thread was woken up")
+ )
+ }
+ fetch_ocsp();
+ fetch_crls(cache_crls);
+ }
+}
+#endif /* THREADS*/
+
+/*
+ * initializes curl and starts the fetching thread
+ */
+void
+init_fetch(void)
+{
+ int status;
+
+#ifdef LIBCURL
+ /* init curl */
+ status = curl_global_init(CURL_GLOBAL_NOTHING);
+ if (status != CURLE_OK)
+ {
+ plog("libcurl could not be initialized, status = %d", status);
+ }
+#endif /* LIBCURL */
+
+ if (crl_check_interval > 0)
+ {
+#ifdef THREADS
+ status = pthread_create( &thread, NULL, fetch_thread, NULL);
+ if (status != 0)
+ {
+ plog("fetching thread could not be started, status = %d", status);
+ }
+#else /* !THREADS */
+ plog("warning: not compiled with pthread support");
+#endif /* !THREADS */
+ }
+}
+
+void
+free_crl_fetch(void)
+{
+ lock_crl_fetch_list("free_crl_fetch");
+
+ while (crl_fetch_reqs != NULL)
+ {
+ fetch_req_t *req = crl_fetch_reqs;
+ crl_fetch_reqs = req->next;
+ free_fetch_request(req);
+ }
+
+ unlock_crl_fetch_list("free_crl_fetch");
+
+#ifdef LIBCURL
+ if (crl_check_interval > 0)
+ {
+ /* cleanup curl */
+ curl_global_cleanup();
+ }
+#endif /* LIBCURL */
+}
+
+/*
+ * free the chained list of ocsp requests
+ */
+void
+free_ocsp_fetch(void)
+{
+ lock_ocsp_fetch_list("free_ocsp_fetch");
+ free_ocsp_locations(&ocsp_fetch_reqs);
+ unlock_ocsp_fetch_list("free_ocsp_fetch");
+}
+
+
+/*
+ * add additional distribution points
+ */
+void
+add_distribution_points(const generalName_t *newPoints ,generalName_t **distributionPoints)
+{
+ while (newPoints != NULL)
+ {
+ /* skip empty distribution point */
+ if (newPoints->name.len > 0)
+ {
+ bool add = TRUE;
+ generalName_t *gn = *distributionPoints;
+
+ while (gn != NULL)
+ {
+ if (gn->kind == newPoints->kind
+ && gn->name.len == newPoints->name.len
+ && memcmp(gn->name.ptr, newPoints->name.ptr, gn->name.len) == 0)
+ {
+ /* skip if the distribution point is already present */
+ add = FALSE;
+ break;
+ }
+ gn = gn->next;
+ }
+
+ if (add)
+ {
+ /* clone additional distribution point */
+ gn = clone_thing(*newPoints, "generalName");
+ clonetochunk(gn->name, newPoints->name.ptr, newPoints->name.len
+ , "crl uri");
+
+ /* insert additional CRL distribution point */
+ gn->next = *distributionPoints;
+ *distributionPoints = gn;
+ }
+ }
+ newPoints = newPoints->next;
+ }
+}
+
+fetch_req_t*
+build_crl_fetch_request(chunk_t issuer, chunk_t authKeySerialNumber
+, chunk_t authKeyID, const generalName_t *gn)
+{
+ fetch_req_t *req = alloc_thing(fetch_req_t, "fetch request");
+ *req = empty_fetch_req;
+
+ /* note current time */
+ req->installed = time(NULL);
+
+ /* clone fields */
+ clonetochunk(req->issuer, issuer.ptr, issuer.len, "issuer");
+ if (authKeySerialNumber.ptr != NULL)
+ {
+ clonetochunk(req->authKeySerialNumber, authKeySerialNumber.ptr
+ , authKeySerialNumber.len, "authKeySerialNumber");
+ }
+ if (authKeyID.ptr != NULL)
+ {
+ clonetochunk(req->authKeyID, authKeyID.ptr, authKeyID.len, "authKeyID");
+ }
+
+ /* copy distribution points */
+ add_distribution_points(gn, &req->distributionPoints);
+
+ return req;
+}
+
+/*
+ * add a crl fetch request to the chained list
+ */
+void
+add_crl_fetch_request(fetch_req_t *req)
+{
+ fetch_req_t *r;
+
+ lock_crl_fetch_list("add_crl_fetch_request");
+ r = crl_fetch_reqs;
+
+ while (r != NULL)
+ {
+ if ((req->authKeyID.ptr != NULL)? same_keyid(req->authKeyID, r->authKeyID)
+ : (same_dn(req->issuer, r->issuer)
+ && same_serial(req->authKeySerialNumber, r->authKeySerialNumber)))
+ {
+ /* there is already a fetch request */
+ DBG(DBG_CONTROL,
+ DBG_log("crl fetch request already exists")
+ )
+
+ /* there might be new distribution points */
+ add_distribution_points(req->distributionPoints, &r->distributionPoints);
+
+ unlock_crl_fetch_list("add_crl_fetch_request");
+ free_fetch_request(req);
+ return;
+ }
+ r = r->next;
+ }
+
+ /* insert new fetch request at the head of the queue */
+ req->next = crl_fetch_reqs;
+ crl_fetch_reqs = req;
+
+ DBG(DBG_CONTROL,
+ DBG_log("crl fetch request added")
+ )
+ unlock_crl_fetch_list("add_crl_fetch_request");
+}
+
+/*
+ * add an ocsp fetch request to the chained list
+ */
+void
+add_ocsp_fetch_request(ocsp_location_t *location, chunk_t serialNumber)
+{
+ ocsp_certinfo_t certinfo;
+
+ certinfo.serialNumber = serialNumber;
+
+ lock_ocsp_fetch_list("add_ocsp_fetch_request");
+ add_certinfo(location, &certinfo, &ocsp_fetch_reqs, TRUE);
+ unlock_ocsp_fetch_list("add_ocsp_fetch_request");
+}
+
+/*
+ * list all distribution points
+ */
+void
+list_distribution_points(const generalName_t *gn)
+{
+ bool first_gn = TRUE;
+
+ while (gn != NULL)
+ {
+ whack_log(RC_COMMENT, " %s '%.*s'", (first_gn)? "distPts: "
+ :" ", (int)gn->name.len, gn->name.ptr);
+ first_gn = FALSE;
+ gn = gn->next;
+ }
+}
+
+/*
+ * list all fetch requests in the chained list
+ */
+void
+list_crl_fetch_requests(bool utc)
+{
+ fetch_req_t *req;
+
+ lock_crl_fetch_list("list_crl_fetch_requests");
+ req = crl_fetch_reqs;
+
+ if (req != NULL)
+ {
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of CRL fetch requests:");
+ whack_log(RC_COMMENT, " ");
+ }
+
+ while (req != NULL)
+ {
+ u_char buf[BUF_LEN];
+
+ whack_log(RC_COMMENT, "%s, trials: %d"
+ , timetoa(&req->installed, utc), req->trials);
+ dntoa(buf, BUF_LEN, req->issuer);
+ whack_log(RC_COMMENT, " issuer: '%s'", buf);
+ if (req->authKeyID.ptr != NULL)
+ {
+ datatot(req->authKeyID.ptr, req->authKeyID.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " authkey: %s", buf);
+ }
+ if (req->authKeySerialNumber.ptr != NULL)
+ {
+ datatot(req->authKeySerialNumber.ptr, req->authKeySerialNumber.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " aserial: %s", buf);
+ }
+ list_distribution_points(req->distributionPoints);
+ req = req->next;
+ }
+ unlock_crl_fetch_list("list_crl_fetch_requests");
+}
+
+void
+list_ocsp_fetch_requests(bool utc)
+{
+ lock_ocsp_fetch_list("list_ocsp_fetch_requests");
+ list_ocsp_locations(ocsp_fetch_reqs, TRUE, utc, FALSE);
+ unlock_ocsp_fetch_list("list_ocsp_fetch_requests");
+
+}
diff --git a/src/pluto/fetch.h b/src/pluto/fetch.h
new file mode 100644
index 000000000..6303f37e4
--- /dev/null
+++ b/src/pluto/fetch.h
@@ -0,0 +1,79 @@
+/* Dynamic fetching of X.509 CRLs
+ * Copyright (C) 2002 Stephane Laroche <stephane.laroche@colubris.com>
+ * Copyright (C) 2002-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.
+ *
+ * RCSID $Id: fetch.h,v 1.6 2005/11/25 10:08:00 as Exp $
+ */
+
+#include "x509.h"
+
+#define FETCH_CMD_TIMEOUT 10 /* seconds */
+
+struct ocsp_location; /* forward declaration of ocsp_location defined in ocsp.h */
+
+typedef enum {
+ FETCH_GET = 1,
+ FETCH_POST = 2
+} fetch_request_t;
+
+typedef struct fetch_req fetch_req_t;
+
+struct fetch_req {
+ fetch_req_t *next;
+ time_t installed;
+ int trials;
+ chunk_t issuer;
+ chunk_t authKeyID;
+ chunk_t authKeySerialNumber;
+ generalName_t *distributionPoints;
+};
+
+#ifdef THREADS
+extern void lock_crl_list(const char *who);
+extern void unlock_crl_list(const char *who);
+extern void lock_ocsp_cache(const char *who);
+extern void unlock_ocsp_cache(const char *who);
+extern void lock_ca_info_list(const char *who);
+extern void unlock_ca_info_list(const char *who);
+extern void lock_authcert_list(const char *who);
+extern void unlock_authcert_list(const char *who);
+extern void lock_certs_and_keys(const char *who);
+extern void unlock_certs_and_keys(const char *who);
+extern void wake_fetch_thread(const char *who);
+#else
+#define lock_crl_list(who) /* do nothing */
+#define unlock_crl_list(who) /* do nothing */
+#define lock_ocsp_cache(who) /* do nothing */
+#define unlock_ocsp_cache(who) /* do nothing */
+#define lock_ca_info_list(who) /* do nothing */
+#define unlock_ca_info_list(who) /* do nothing */
+#define lock_authcert_list(who) /* do nothing */
+#define unlock_authcert_list(who) /* do nothing */
+#define lock_certs_and_keys(who) /* do nothing */
+#define unlock_certs_and_keys(who) /* do nothing */
+#define wake_fetch_thread(who) /* do nothing */
+#endif
+extern void init_fetch(void);
+extern void free_crl_fetch(void);
+extern void free_ocsp_fetch(void);
+extern void add_distribution_points(const generalName_t *newPoints
+ , generalName_t **distributionPoints);
+extern fetch_req_t* build_crl_fetch_request(chunk_t issuer, chunk_t authKeySerialNumber
+ , chunk_t authKeyID, const generalName_t *gn);
+extern void add_crl_fetch_request(fetch_req_t *req);
+extern void add_ocsp_fetch_request(struct ocsp_location *location, chunk_t serialNumber);
+extern void list_distribution_points(const generalName_t *gn);
+extern void list_crl_fetch_requests(bool utc);
+extern void list_ocsp_fetch_requests(bool utc);
+extern size_t write_buffer(void *ptr, size_t size, size_t nmemb, void *data);
+
diff --git a/src/pluto/foodgroups.c b/src/pluto/foodgroups.c
new file mode 100644
index 000000000..c92bdb3d4
--- /dev/null
+++ b/src/pluto/foodgroups.c
@@ -0,0 +1,462 @@
+/* Implement policy groups-style control files (aka "foodgroups")
+ * Copyright (C) 2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: foodgroups.c,v 1.2 2004/04/01 18:28:32 as Exp $
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <sys/queue.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "connections.h"
+#include "foodgroups.h"
+#include "kernel.h"
+#include "lex.h"
+#include "log.h"
+#include "whack.h"
+
+
+/* Food group config files are found in directory fg_path */
+
+#ifndef POLICYGROUPSDIR
+#define POLICYGROUPSDIR IPSEC_CONFDIR "/ipsec.d/policies"
+#endif
+
+const char *policygroups_dir = POLICYGROUPSDIR;
+
+static char *fg_path = NULL;
+static size_t fg_path_space = 0;
+
+
+/* Groups is a list of connections that are policy groups.
+ * The list is updated as group connections are added and deleted.
+ */
+
+struct fg_groups {
+ struct fg_groups *next;
+ struct connection *connection;
+};
+
+static struct fg_groups *groups = NULL;
+
+
+/* Targets is a list of pairs: subnet and its policy group.
+ * This list is bulk-updated on whack --listen and
+ * incrementally updated when group connections are deleted.
+ *
+ * It is ordered by source subnet, and if those are equal, then target subnet.
+ * A subnet is compared by comparing the network, and if those are equal,
+ * comparing the mask.
+ */
+
+struct fg_targets {
+ struct fg_targets *next;
+ struct fg_groups *group;
+ ip_subnet subnet;
+ char *name; /* name of instance of group conn */
+};
+
+static struct fg_targets *targets = NULL;
+
+struct fg_targets *new_targets;
+
+/* ipcmp compares the two ip_address values a and b.
+ * It returns -1, 0, or +1 if a is, respectively,
+ * less than, equal to, or greater than b.
+ */
+static int
+ipcmp(ip_address *a, ip_address *b)
+{
+ if (addrtypeof(a) != addrtypeof(b))
+ {
+ return addrtypeof(a) < addrtypeof(b)? -1 : 1;
+ }
+ else if (sameaddr(a, b))
+ {
+ return 0;
+ }
+ else
+ {
+ const struct sockaddr *sa = sockaddrof(a)
+ , *sb = sockaddrof(b);
+
+ passert(addrtypeof(a) == AF_INET); /* not yet implemented IPv6 version :-( */
+ return (ntohl(((const struct sockaddr_in *)sa)->sin_addr.s_addr)
+ < ntohl(((const struct sockaddr_in *)sb)->sin_addr.s_addr))
+ ? -1 : 1;
+ }
+}
+
+/* subnetcmp compares the two ip_subnet values a and b.
+ * It returns -1, 0, or +1 if a is, respectively,
+ * less than, equal to, or greater than b.
+ */
+static int
+subnetcmp(const ip_subnet *a, const ip_subnet *b)
+{
+ ip_address neta, maska, netb, maskb;
+ int r;
+
+ networkof(a, &neta);
+ maskof(a, &maska);
+ networkof(b, &netb);
+ maskof(b, &maskb);
+ r = ipcmp(&neta, &netb);
+ if (r == 0)
+ r = ipcmp(&maska, &maskb);
+ return r;
+}
+
+static void
+read_foodgroup(struct fg_groups *g)
+{
+ const char *fgn = g->connection->name;
+ const ip_subnet *lsn = &g->connection->spd.this.client;
+ size_t plen = strlen(policygroups_dir) + 1 + strlen(fgn) + 1;
+ struct file_lex_position flp_space;
+
+ if (plen > fg_path_space)
+ {
+ pfreeany(fg_path);
+ fg_path_space = plen + 10;
+ fg_path = alloc_bytes(fg_path_space, "policy group path");
+ }
+ snprintf(fg_path, fg_path_space, "%s/%s", policygroups_dir, fgn);
+ if (!lexopen(&flp_space, fg_path, TRUE))
+ {
+ DBG(DBG_CONTROL, DBG_log("no group file \"%s\"", fg_path));
+ }
+ else
+ {
+ plog("loading group \"%s\"", fg_path);
+ for (;;)
+ {
+ switch (flp->bdry)
+ {
+ case B_none:
+ {
+ /* !!! this test is not sufficient for distinguishing address families.
+ * We need a notation to specify that a FQDN is to be resolved to IPv6.
+ */
+ const struct af_info *afi = strchr(tok, ':') == NULL
+ ? &af_inet4_info: &af_inet6_info;
+ ip_subnet sn;
+ err_t ugh;
+
+ if (strchr(tok, '/') == NULL)
+ {
+ /* no /, so treat as /32 or V6 equivalent */
+ ip_address t;
+
+ ugh = ttoaddr(tok, 0, afi->af, &t);
+ if (ugh == NULL)
+ ugh = addrtosubnet(&t, &sn);
+ }
+ else
+ {
+ ugh = ttosubnet(tok, 0, afi->af, &sn);
+ }
+
+ if (ugh != NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "\"%s\" line %d: %s \"%s\""
+ , flp->filename, flp->lino, ugh, tok);
+ }
+ else if (afi->af != AF_INET)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "\"%s\" line %d: unsupported Address Family \"%s\""
+ , flp->filename, flp->lino, tok);
+ }
+ else
+ {
+ /* Find where new entry ought to go in new_targets. */
+ struct fg_targets **pp;
+ int r;
+
+ for (pp = &new_targets; ; pp = &(*pp)->next)
+ {
+ if (*pp == NULL)
+ {
+ r = -1; /* end of list is infinite */
+ break;
+ }
+ r = subnetcmp(lsn, &(*pp)->group->connection->spd.this.client);
+ if (r == 0)
+ r = subnetcmp(&sn, &(*pp)->subnet);
+ if (r <= 0)
+ break;
+ }
+
+ if (r == 0)
+ {
+ char source[SUBNETTOT_BUF];
+
+ subnettot(lsn, 0, source, sizeof(source));
+ loglog(RC_LOG_SERIOUS
+ , "\"%s\" line %d: subnet \"%s\", source %s, already \"%s\""
+ , flp->filename
+ , flp->lino
+ , tok
+ , source
+ , (*pp)->group->connection->name);
+ }
+ else
+ {
+ struct fg_targets *f = alloc_thing(struct fg_targets, "fg_target");
+
+ f->next = *pp;
+ f->group = g;
+ f->subnet = sn;
+ f->name = NULL;
+ *pp = f;
+ }
+ }
+ }
+ (void)shift(); /* next */
+ continue;
+
+ case B_record:
+ flp->bdry = B_none; /* eat the Record Boundary */
+ (void)shift(); /* get real first token */
+ continue;
+
+ case B_file:
+ break; /* done */
+ }
+ break; /* if we reach here, out of loop */
+ }
+ lexclose();
+ }
+}
+
+static void
+free_targets(void)
+{
+ while (targets != NULL)
+ {
+ struct fg_targets *t = targets;
+
+ targets = t->next;
+ pfreeany(t->name);
+ pfree(t);
+ }
+}
+
+void
+load_groups(void)
+{
+ passert(new_targets == NULL);
+
+ /* for each group, add config file targets into new_targets */
+ {
+ struct fg_groups *g;
+
+ for (g = groups; g != NULL; g = g->next)
+ if (oriented(*g->connection))
+ read_foodgroup(g);
+ }
+
+ /* dump new_targets */
+ DBG(DBG_CONTROL,
+ {
+ struct fg_targets *t;
+
+ for (t = new_targets; t != NULL; t = t->next)
+ {
+ char asource[SUBNETTOT_BUF];
+ char atarget[SUBNETTOT_BUF];
+
+ subnettot(&t->group->connection->spd.this.client
+ , 0, asource, sizeof(asource));
+ subnettot(&t->subnet, 0, atarget, sizeof(atarget));
+ DBG_log("%s->%s %s"
+ , asource, atarget
+ , t->group->connection->name);
+ }
+ });
+
+ /* determine and deal with differences between targets and new_targets.
+ * structured like a merge.
+ */
+ {
+ struct fg_targets *op = targets
+ , *np = new_targets;
+
+ while (op != NULL && np != NULL)
+ {
+ int r = subnetcmp(&op->group->connection->spd.this.client
+ , &np->group->connection->spd.this.client);
+
+ if (r == 0)
+ r = subnetcmp(&op->subnet, &np->subnet);
+
+ if (r == 0 && op->group == np->group)
+ {
+ /* unchanged -- steal name & skip over */
+ np->name = op->name;
+ op->name = NULL;
+ op = op->next;
+ np = np->next;
+ }
+ else
+ {
+ /* note: following cases overlap! */
+ if (r <= 0)
+ {
+ remove_group_instance(op->group->connection, op->name);
+ op = op->next;
+ }
+ if (r >= 0)
+ {
+ np->name = add_group_instance(np->group->connection, &np->subnet);
+ np = np->next;
+ }
+ }
+ }
+ for (; op != NULL; op = op->next)
+ remove_group_instance(op->group->connection, op->name);
+ for (; np != NULL; np = np->next)
+ np->name = add_group_instance(np->group->connection, &np->subnet);
+
+ /* update: new_targets replaces targets */
+ free_targets();
+ targets = new_targets;
+ new_targets = NULL;
+ }
+}
+
+
+void
+add_group(struct connection *c)
+{
+ struct fg_groups *g = alloc_thing(struct fg_groups, "policy group");
+
+ g->next = groups;
+ groups = g;
+
+ g->connection = c;
+}
+
+static struct fg_groups *
+find_group(const struct connection *c)
+{
+ struct fg_groups *g;
+
+ for (g = groups; g != NULL && g->connection != c; g = g->next)
+ ;
+ return g;
+}
+
+void
+route_group(struct connection *c)
+{
+ /* it makes no sense to route a connection that is ISAKMP-only */
+ if (!NEVER_NEGOTIATE(c->policy) && !HAS_IPSEC_POLICY(c->policy))
+ {
+ loglog(RC_ROUTE, "cannot route an ISAKMP-only group connection");
+ }
+ else
+ {
+ struct fg_groups *g = find_group(c);
+ struct fg_targets *t;
+
+ passert(g != NULL);
+ g->connection->policy |= POLICY_GROUTED;
+ for (t = targets; t != NULL; t = t->next)
+ {
+ if (t->group == g)
+ {
+ struct connection *ci = con_by_name(t->name, FALSE);
+
+ if (ci != NULL)
+ {
+ set_cur_connection(ci);
+ if (!trap_connection(ci))
+ whack_log(RC_ROUTE, "could not route");
+ set_cur_connection(c);
+ }
+ }
+ }
+ }
+}
+
+void
+unroute_group(struct connection *c)
+{
+ struct fg_groups *g = find_group(c);
+ struct fg_targets *t;
+
+ passert(g != NULL);
+ g->connection->policy &= ~POLICY_GROUTED;
+ for (t = targets; t != NULL; t = t->next)
+ {
+ if (t->group == g)
+ {
+ struct connection *ci = con_by_name(t->name, FALSE);
+
+ if (ci != NULL)
+ {
+ set_cur_connection(ci);
+ unroute_connection(ci);
+ set_cur_connection(c);
+ }
+ }
+ }
+}
+
+void
+delete_group(const struct connection *c)
+{
+ struct fg_groups *g;
+
+ /* find and remove from groups */
+ {
+ struct fg_groups **pp;
+
+ for (pp = &groups; (g = *pp)->connection != c; pp = &(*pp)->next)
+ ;
+
+ *pp = g->next;
+ }
+
+ /* find and remove from targets */
+ {
+ struct fg_targets **pp;
+
+ for (pp = &targets; *pp != NULL; )
+ {
+ struct fg_targets *t = *pp;
+
+ if (t->group == g)
+ {
+ *pp = t->next;
+ remove_group_instance(t->group->connection, t->name);
+ pfree(t);
+ /* pp is ready for next iteration */
+ }
+ else
+ {
+ pp = &t->next;
+ }
+ }
+ }
+
+ pfree(g);
+}
diff --git a/src/pluto/foodgroups.h b/src/pluto/foodgroups.h
new file mode 100644
index 000000000..7cbbccc44
--- /dev/null
+++ b/src/pluto/foodgroups.h
@@ -0,0 +1,24 @@
+/* Implement policygroups-style control files (aka "foodgroups")
+ * Copyright (C) 2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: foodgroups.h,v 1.1 2004/03/15 20:35:28 as Exp $
+ */
+
+struct connection; /* forward declaration */
+extern void add_group(struct connection *c);
+extern void route_group(struct connection *c);
+extern void unroute_group(struct connection *c);
+extern void delete_group(const struct connection *c);
+
+extern const char *policygroups_dir;
+extern void load_groups(void);
diff --git a/src/pluto/gcryptfix.c b/src/pluto/gcryptfix.c
new file mode 100644
index 000000000..1ebacdcf6
--- /dev/null
+++ b/src/pluto/gcryptfix.c
@@ -0,0 +1,283 @@
+/* Routines to make gcrypt routines feel at home in Pluto.
+ * Copyright (C) 1999 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: gcryptfix.c,v 1.1 2004/03/15 20:35:28 as Exp $
+ */
+
+#include <stdlib.h>
+
+#include <gmp.h>
+#include <freeswan.h>
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "rnd.h"
+#include "gcryptfix.h" /* includes <gmp.h> "defs.h" "rnd.h" */
+
+MPI
+mpi_alloc( unsigned nlimbs UNUSED )
+{
+ MPI n = alloc_bytes(sizeof *n, "mpi_alloc");
+
+ mpz_init(n);
+ return n;
+}
+
+MPI
+mpi_alloc_secure( unsigned nlimbs )
+{
+ return mpi_alloc(nlimbs);
+}
+
+MPI
+mpi_alloc_set_ui( unsigned long u)
+{
+ MPI n = alloc_bytes(sizeof *n, "mpi_copy");
+
+ mpz_init_set_ui(n, u);
+ return n;
+}
+
+MPI
+mpi_copy( MPI a )
+{
+ MPI n = alloc_bytes(sizeof *n, "mpi_copy");
+
+ mpz_init_set(n, a);
+ return n;
+}
+
+void
+mpi_free( MPI a )
+{
+ mpz_clear(a);
+ pfree(a);
+}
+
+int
+mpi_divisible_ui(MPI dividend, ulong divisor )
+{
+ ulong rem;
+ mpz_t remtoo;
+
+ mpz_init(remtoo);
+ rem = mpz_mod_ui(remtoo, dividend, divisor);
+ mpz_clear(remtoo);
+ return rem == 0;
+}
+
+unsigned
+mpi_trailing_zeros( MPI a )
+{
+ return mpz_scan1(a, 0);
+}
+
+unsigned
+mpi_get_nbits( MPI a )
+{
+ return mpz_sizeinbase(a, 2);
+}
+
+int
+mpi_test_bit( MPI a, unsigned n )
+{
+ /* inspired by gmp/mpz/clrbit.c */
+ mp_size_t li = n / mp_bits_per_limb;
+
+ if (li >= a->_mp_size)
+ return 0;
+ return (a->_mp_d[li] & ((mp_limb_t) 1 << (n % mp_bits_per_limb))) != 0;
+}
+
+void
+mpi_set_bit( MPI a, unsigned n )
+{
+ mpz_setbit(a, n);
+}
+
+void
+mpi_clear_bit( MPI a, unsigned n )
+{
+ mpz_clrbit(a, n);
+}
+
+void
+mpi_clear_highbit( MPI a, unsigned n )
+{
+ /* This seems whacky, but what do I know. */
+ mpz_fdiv_r_2exp(a, a, n);
+}
+
+void
+mpi_set_highbit( MPI a, unsigned n )
+{
+ /* This seems whacky, but what do I know. */
+ mpz_fdiv_r_2exp(a, a, n+1);
+ mpz_setbit(a, n);
+}
+
+void
+mpi_set_buffer( MPI a, const u_char *buffer, unsigned nbytes, int sign )
+{
+ /* this is a lot like n_to_mpz */
+ size_t i;
+
+ passert(sign == 0); /* we won't hit any negative numbers */
+ mpz_init_set_ui(a, 0);
+
+ for (i = 0; i != nbytes; i++)
+ {
+ mpz_mul_ui(a, a, 1 << BITS_PER_BYTE);
+ mpz_add_ui(a, a, buffer[i]);
+ }
+}
+
+u_char *
+get_random_bits(size_t nbits, int level UNUSED, int secure UNUSED)
+{
+ size_t nbytes = (nbits+7)/8;
+ u_char *b = alloc_bytes(nbytes, "random bytes");
+
+ get_rnd_bytes(b, nbytes);
+ return b;
+}
+/**************** from gnupg-1.0.0/mpi/mpi-mpow.c
+ * RES = (BASE[0] ^ EXP[0]) * (BASE[1] ^ EXP[1]) * ... * mod M
+ */
+#define barrett_mulm( w, u, v, m, y, k, r1, r2 ) mpi_mulm( (w), (u), (v), (m) )
+
+static int
+build_index( MPI *exparray, int k, int i, int t )
+{
+ int j, bitno;
+ int index = 0;
+
+ bitno = t-i;
+ for(j=k-1; j >= 0; j-- ) {
+ index <<= 1;
+ if( mpi_test_bit( exparray[j], bitno ) )
+ index |= 1;
+ }
+ /*log_debug("t=%d i=%d index=%d\n", t, i, index );*/
+ return index;
+}
+
+void
+mpi_mulpowm( MPI res, MPI *basearray, MPI *exparray, MPI m)
+{
+ int k; /* number of elements */
+ int t; /* bit size of largest exponent */
+ int i, j, idx;
+ MPI *G; /* table with precomputed values of size 2^k */
+ MPI tmp;
+ #ifdef USE_BARRETT
+ MPI barrett_y, barrett_r1, barrett_r2;
+ int barrett_k;
+ #endif
+
+ for(k=0; basearray[k]; k++ )
+ ;
+ passert(k);
+ for(t=0, i=0; (tmp=exparray[i]); i++ ) {
+ /*log_mpidump("exp: ", tmp );*/
+ j = mpi_get_nbits(tmp);
+ if( j > t )
+ t = j;
+ }
+ /*log_mpidump("mod: ", m );*/
+ passert(i==k);
+ passert(t);
+ passert( k < 10 );
+
+#ifdef PLUTO
+ m_alloc_ptrs_clear(G, 1<<k);
+#else
+ G = m_alloc_clear( (1<<k) * sizeof *G );
+#endif
+
+ #ifdef USE_BARRETT
+ barrett_y = init_barrett( m, &barrett_k, &barrett_r1, &barrett_r2 );
+ #endif
+ /* and calculate */
+ tmp = mpi_alloc( mpi_get_nlimbs(m)+1 );
+ mpi_set_ui( res, 1 );
+ for(i = 1; i <= t; i++ ) {
+ barrett_mulm(tmp, res, res, m, barrett_y, barrett_k,
+ barrett_r1, barrett_r2 );
+ idx = build_index( exparray, k, i, t );
+ passert( idx >= 0 && idx < (1<<k) );
+ if( !G[idx] ) {
+ if( !idx )
+ G[0] = mpi_alloc_set_ui( 1 );
+ else {
+ for(j=0; j < k; j++ ) {
+ if( (idx & (1<<j) ) ) {
+ if( !G[idx] )
+ G[idx] = mpi_copy( basearray[j] );
+ else
+ barrett_mulm( G[idx], G[idx], basearray[j],
+ m, barrett_y, barrett_k, barrett_r1, barrett_r2 );
+ }
+ }
+ if( !G[idx] )
+ G[idx] = mpi_alloc(0);
+ }
+ }
+ barrett_mulm(res, tmp, G[idx], m, barrett_y, barrett_k, barrett_r1, barrett_r2 );
+ }
+
+ /* cleanup */
+ mpi_free(tmp);
+ #ifdef USE_BARRETT
+ mpi_free(barrett_y);
+ mpi_free(barrett_r1);
+ mpi_free(barrett_r2);
+ #endif
+ for(i=0; i < (1<<k); i++ )
+ mpi_free(G[i]);
+ m_free(G);
+}
+
+void
+log_mpidump( const char *text UNUSED, MPI a )
+{
+ /* Print number in hex -- helpful to see if they match bytes.
+ * Humans are not going to do arithmetic with the large numbers!
+ * Much code adapted from mpz_to_n.
+ */
+ u_char buf[8048]; /* this ought to be big enough */
+ size_t len = (mpz_sizeinbase(a, 16) + 1) / 2; /* bytes */
+ MP_INT temp1, temp2;
+ int i;
+
+ passert(len <= sizeof(buf));
+
+ mpz_init(&temp1);
+ mpz_init(&temp2);
+
+ mpz_set(&temp1, a);
+
+ for (i = len-1; i >= 0; i--)
+ {
+ buf[i] = mpz_mdivmod_ui(&temp2, NULL, &temp1, 1 << BITS_PER_BYTE);
+ mpz_set(&temp1, &temp2);
+ }
+
+ passert(mpz_sgn(&temp1) == 0); /* we must have done all the bits */
+ mpz_clear(&temp1);
+ mpz_clear(&temp2);
+
+#ifdef DEBUG
+ DBG_dump(text, buf, len);
+#endif /* DEBUG */
+}
diff --git a/src/pluto/gcryptfix.h b/src/pluto/gcryptfix.h
new file mode 100644
index 000000000..637ecbc8d
--- /dev/null
+++ b/src/pluto/gcryptfix.h
@@ -0,0 +1,111 @@
+/* Definitions to make gcrypt routines feel at home in Pluto.
+ * Copyright (C) 1999 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: gcryptfix.h,v 1.1 2004/03/15 20:35:28 as Exp $
+ */
+
+#define DBG_CIPHER 1 /* some day we'll do this right */
+
+/* Simulate MPI routines with gmp routines.
+ * gmp's MP_INT is a stuct; MPI's MPI is a pointer to an analogous struct.
+ * gmp's mpz_t is an array of one of these structs to enable magic pointer
+ * conversions to make the notation convenient (but confusing).
+ */
+typedef u_char byte;
+typedef MP_INT *MPI;
+
+#define BITS_PER_MPI_LIMB mp_bits_per_limb
+
+extern MPI mpi_alloc( unsigned nlimbs );
+extern MPI mpi_alloc_secure( unsigned nlimbs );
+#define mpi_alloc_like(n) mpi_alloc(mpi_get_nlimbs(n))
+extern MPI mpi_alloc_set_ui( unsigned long u);
+#define mpi_set_ui(w, u) mpz_set_ui(w, u)
+#define mpi_set(w, u) mpz_set(w, u)
+extern void mpi_free( MPI a );
+extern MPI mpi_copy( MPI a );
+extern unsigned mpi_get_nbits( MPI a );
+#define mpi_get_nlimbs(a) ((a)->_mp_alloc) /* dirty, but useless */
+extern void mpi_set_buffer( MPI a, const u_char *buffer, unsigned nbytes, int sign );
+extern unsigned mpi_trailing_zeros( MPI a );
+extern int mpi_test_bit( MPI a, unsigned n );
+extern void mpi_set_bit( MPI a, unsigned n );
+extern void mpi_clear_bit( MPI a, unsigned n );
+extern void mpi_clear_highbit( MPI a, unsigned n );
+extern void mpi_set_highbit( MPI a, unsigned n );
+#define mpi_cmp_ui(u, v) mpz_cmp_ui((u), (v))
+#define mpi_cmp(u, v) mpz_cmp((u), (v))
+#define mpi_is_neg(n) (mpz_sgn(n) < 0)
+#define mpi_add(w, u, v) mpz_add((w), (u), (v))
+#define mpi_add_ui(w, u, v) mpz_add_ui((w), (u), (v))
+#define mpi_sub_ui(w, u, v) mpz_sub_ui((w), (u), (v))
+#define mpi_subm( w, u, v, m) { mpz_sub( (w), (u), (v)) ; mpz_fdiv_r((w), (w), (m)); }
+#define mpi_mul( w, u, v) mpz_mul( (w), (u), (v))
+#define mpi_mul_ui( w, u, v) mpz_mul_ui( (w), (u), (v))
+#define mpi_mulm( w, u, v, m) { mpz_mul( (w), (u), (v)) ; mpz_fdiv_r((w), (w), (m)); }
+#define mpi_fdiv_q(quot, dividend, divisor) mpz_fdiv_q((quot), (dividend), (divisor))
+#define mpi_fdiv_r( rem, dividend, divisor ) mpz_fdiv_r( (rem), (dividend), (divisor) )
+#define mpi_fdiv_r_ui( rem, dividend, divisor ) mpz_fdiv_r_ui( (rem), (dividend), (divisor) )
+#define mpi_tdiv_q_2exp( w, u, count ) mpz_tdiv_q_2exp( (w), (u), (count) )
+extern int mpi_divisible_ui(MPI dividend, ulong divisor );
+#define mpi_powm( res, base, exp, mod) mpz_powm( res, base, exp, mod)
+extern void mpi_mulpowm( MPI res, MPI *basearray, MPI *exparray, MPI mod);
+#define mpi_gcd( g, a, b ) ( mpz_gcd( (g), (a), (b) ), !mpi_cmp_ui( (g), 1))
+#define mpi_invm( x, a, n ) mpz_invert( (x), (a), (n) )
+
+#ifdef DEBUG
+# define log_debug(f...) DBG_log(f)
+#else
+# define log_debug(f...) do ; while (0) /* do nothing, carefully */
+#endif
+#define log_fatal(f...) exit_log(f) /* overreaction? */
+extern void log_mpidump( const char *text, MPI a );
+
+#define assert(p) passert(p)
+#define BUG() passert(FALSE)
+
+#define m_alloc_ptrs_clear(pp, n) { \
+ int c = (n); \
+ (pp) = alloc_bytes((n) * sizeof(*(pp)), "m_alloc_ptrs_clear"); \
+ while (c > 0) (pp)[--c] = NULL; \
+ }
+
+extern u_char *get_random_bits(size_t nbits, int level, int secure);
+#define m_alloc(sz) alloc_bytes((sz), "m_alloc") /* not initialized */
+#define m_free(n) pfree(n) /* always freeing something from get_random_bits */
+
+/* declarations from gnupg-1.0.0/include/cipher.h */
+/*-- primegen.c --*/
+MPI generate_secret_prime( unsigned nbits );
+MPI generate_public_prime( unsigned nbits );
+MPI generate_elg_prime( int mode, unsigned pbits, unsigned qbits,
+ MPI g, MPI **factors );
+
+#define PUBKEY_ALGO_ELGAMAL_E 16 /* encrypt only ElGamal (but not for v3)*/
+#define PUBKEY_ALGO_DSA 17
+#define PUBKEY_ALGO_ELGAMAL 20 /* sign and encrypt elgamal */
+
+#define is_ELGAMAL(a) ((a)==PUBKEY_ALGO_ELGAMAL || (a)==PUBKEY_ALGO_ELGAMAL_E)
+
+#define PUBKEY_USAGE_SIG 1 /* key is good for signatures */
+#define PUBKEY_USAGE_ENC 2 /* key is good for encryption */
+
+/* from gnupg-1.0.0/include/errors.h */
+
+#define G10ERR_PUBKEY_ALGO 4 /* Unknown pubkey algorithm */
+#define G10ERR_BAD_SECKEY 7 /* Bad secret key */
+#define G10ERR_BAD_SIGN 8 /* Bad signature */
+#define G10ERR_BAD_MPI 30
+
+/*-- smallprime.c --*/
+extern ushort small_prime_numbers[];
diff --git a/src/pluto/id.c b/src/pluto/id.c
new file mode 100644
index 000000000..4e75ec2e9
--- /dev/null
+++ b/src/pluto/id.c
@@ -0,0 +1,509 @@
+/* identity representation, as in IKE ID Payloads (RFC 2407 DOI 4.6.2.1)
+ * Copyright (C) 1999-2001 D. Hugh Redelmeier
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: id.c,v 1.4 2005/08/15 20:07:08 as Exp $
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#ifndef HOST_NAME_MAX /* POSIX 1003.1-2001 says <unistd.h> defines this */
+# define HOST_NAME_MAX 255 /* upper bound, according to SUSv2 */
+#endif
+#include <sys/queue.h>
+
+#include <freeswan.h>
+#include <ipsec_policy.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "id.h"
+#include "log.h"
+#include "connections.h"
+#include "packet.h"
+#include "whack.h"
+
+const struct id empty_id; /* ID_NONE */
+
+enum myid_state myid_state = MYID_UNKNOWN;
+struct id myids[MYID_SPECIFIED+1]; /* %myid */
+char *myid_str[MYID_SPECIFIED+1]; /* string form of IDs */
+
+/* initialize id module
+ * Fills in myid from environment variable IPSECmyid or defaultrouteaddr
+ */
+void
+init_id(void)
+{
+ passert(empty_id.kind == ID_NONE);
+ myid_state = MYID_UNKNOWN;
+ {
+ enum myid_state s;
+
+ for (s = MYID_UNKNOWN; s <= MYID_SPECIFIED; s++)
+ {
+ myids[s] = empty_id;
+ myid_str[s] = NULL;
+ }
+ }
+ set_myid(MYID_SPECIFIED, getenv("IPSECmyid"));
+ set_myid(MYID_IP, getenv("defaultrouteaddr"));
+ set_myFQDN();
+}
+
+static void
+calc_myid_str(enum myid_state s)
+{
+ /* preformat the ID name */
+ char buf[BUF_LEN];
+
+ idtoa(&myids[s], buf, BUF_LEN);
+ replace(myid_str[s], clone_str(buf, "myid string"));
+}
+
+
+void
+set_myid(enum myid_state s, char *idstr)
+{
+ if (idstr != NULL)
+ {
+ struct id id;
+ err_t ugh = atoid(idstr, &id, FALSE);
+
+ if (ugh != NULL)
+ {
+ loglog(RC_BADID, "myid malformed: %s \"%s\"", ugh, idstr);
+ }
+ else
+ {
+ free_id_content(&myids[s]);
+ unshare_id_content(&id);
+ myids[s] = id;
+ if (s == MYID_SPECIFIED)
+ myid_state = MYID_SPECIFIED;
+
+ calc_myid_str(s);
+ }
+ }
+}
+
+void
+set_myFQDN(void)
+{
+ char FQDN[HOST_NAME_MAX + 1];
+ int r = gethostname(FQDN, sizeof(FQDN));
+
+ free_id_content(&myids[MYID_HOSTNAME]);
+ myids[MYID_HOSTNAME] = empty_id;
+ if (r != 0)
+ {
+ log_errno((e, "gethostname() failed in set_myFQDN"));
+ }
+ else
+ {
+ FQDN[sizeof(FQDN) - 1] = '\0'; /* insurance */
+
+ {
+ size_t len = strlen(FQDN);
+
+ if (len > 0 && FQDN[len-1] == '.')
+ {
+ /* nuke trailing . */
+ FQDN[len-1]='\0';
+ }
+ }
+
+ if (!strcaseeq(FQDN, "localhost.localdomain"))
+ {
+ clonetochunk(myids[MYID_HOSTNAME].name, FQDN, strlen(FQDN), "my FQDN");
+ myids[MYID_HOSTNAME].kind = ID_FQDN;
+ calc_myid_str(MYID_HOSTNAME);
+ }
+ }
+}
+
+void
+show_myid_status(void)
+{
+ char idstr[BUF_LEN];
+
+ (void)idtoa(&myids[myid_state], idstr, sizeof(idstr));
+ whack_log(RC_COMMENT, "%%myid = %s", idstr);
+}
+
+/* Convert textual form of id into a (temporary) struct id.
+ * Note that if the id is to be kept, unshare_id_content will be necessary.
+ */
+err_t
+atoid(char *src, struct id *id, bool myid_ok)
+{
+ err_t ugh = NULL;
+
+ *id = empty_id;
+
+ if (myid_ok && streq("%myid", src))
+ {
+ id->kind = ID_MYID;
+ }
+ else if (strchr(src, '=') != NULL)
+ {
+ /* we interpret this as an ASCII X.501 ID_DER_ASN1_DN */
+ id->kind = ID_DER_ASN1_DN;
+ id->name.ptr = temporary_cyclic_buffer(); /* assign temporary buffer */
+ id->name.len = 0;
+ /* convert from LDAP style or openssl x509 -subject style to ASN.1 DN
+ * discard optional @ character in front of DN
+ */
+ ugh = atodn((*src == '@')?src+1:src, &id->name);
+ }
+ else if (strchr(src, '@') == NULL)
+ {
+ if (streq(src, "%any") || streq(src, "0.0.0.0"))
+ {
+ /* any ID will be accepted */
+ id->kind = ID_NONE;
+ }
+ else
+ {
+ /* !!! this test is not sufficient for distinguishing address families.
+ * We need a notation to specify that a FQDN is to be resolved to IPv6.
+ */
+ const struct af_info *afi = strchr(src, ':') == NULL
+ ? &af_inet4_info: &af_inet6_info;
+
+ id->kind = afi->id_addr;
+ ugh = ttoaddr(src, 0, afi->af, &id->ip_addr);
+ }
+ }
+ else
+ {
+ if (*src == '@')
+ {
+ if (*(src+1) == '#')
+ {
+ /* if there is a second specifier (#) on the line
+ * we interprete this as ID_KEY_ID
+ */
+ id->kind = ID_KEY_ID;
+ id->name.ptr = src;
+ /* discard @~, convert from hex to bin */
+ ugh = ttodata(src+2, 0, 16, id->name.ptr, strlen(src), &id->name.len);
+ }
+ else if (*(src+1) == '~')
+ {
+ /* if there is a second specifier (~) on the line
+ * we interprete this as a binary ID_DER_ASN1_DN
+ */
+ id->kind = ID_DER_ASN1_DN;
+ id->name.ptr = src;
+ /* discard @~, convert from hex to bin */
+ ugh = ttodata(src+2, 0, 16, id->name.ptr, strlen(src), &id->name.len);
+ }
+ else
+ {
+ id->kind = ID_FQDN;
+ id->name.ptr = src+1; /* discard @ */
+ id->name.len = strlen(src)-1;
+ }
+ }
+ else
+ {
+ /* We leave in @, as per DOI 4.6.2.4
+ * (but DNS wants . instead).
+ */
+ id->kind = ID_USER_FQDN;
+ id->name.ptr = src;
+ id->name.len = strlen(src);
+ }
+ }
+ return ugh;
+}
+
+
+/*
+ * Converts a binary key ID into hexadecimal format
+ */
+int
+keyidtoa(char *dst, size_t dstlen, chunk_t keyid)
+{
+ int n = datatot(keyid.ptr, keyid.len, 'x', dst, dstlen);
+ return (((size_t)n < dstlen)? n : dstlen) - 1;
+}
+
+void
+iptoid(const ip_address *ip, struct id *id)
+{
+ *id = empty_id;
+
+ switch (addrtypeof(ip))
+ {
+ case AF_INET:
+ id->kind = ID_IPV4_ADDR;
+ break;
+ case AF_INET6:
+ id->kind = ID_IPV6_ADDR;
+ break;
+ default:
+ bad_case(addrtypeof(ip));
+ }
+ id->ip_addr = *ip;
+}
+
+int
+idtoa(const struct id *id, char *dst, size_t dstlen)
+{
+ int n;
+
+ id = resolve_myid(id);
+ switch (id->kind)
+ {
+ case ID_NONE:
+ n = snprintf(dst, dstlen, "(none)");
+ break;
+ case ID_IPV4_ADDR:
+ case ID_IPV6_ADDR:
+ n = (int)addrtot(&id->ip_addr, 0, dst, dstlen) - 1;
+ break;
+ case ID_FQDN:
+ n = snprintf(dst, dstlen, "@%.*s", (int)id->name.len, id->name.ptr);
+ break;
+ case ID_USER_FQDN:
+ n = snprintf(dst, dstlen, "%.*s", (int)id->name.len, id->name.ptr);
+ break;
+ case ID_DER_ASN1_DN:
+ n = dntoa(dst, dstlen, id->name);
+ break;
+ case ID_KEY_ID:
+ n = keyidtoa(dst, dstlen, id->name);
+ break;
+ default:
+ n = snprintf(dst, dstlen, "unknown id kind %d", id->kind);
+ break;
+ }
+
+ /* "Sanitize" string so that log isn't endangered:
+ * replace unprintable characters with '?'.
+ */
+ if (n > 0)
+ {
+ for ( ; *dst != '\0'; dst++)
+ if (!isprint(*dst))
+ *dst = '?';
+ }
+
+ return n;
+}
+
+/* Replace the shell metacharacters ', \, ", `, and $ in a character string
+ * by escape sequences consisting of their octal values
+ */
+void
+escape_metachar(const char *src, char *dst, size_t dstlen)
+{
+ while (*src != '\0' && dstlen > 4)
+ {
+ switch (*src)
+ {
+ case '\'':
+ case '\\':
+ case '"':
+ case '`':
+ case '$':
+ sprintf(dst,"\\%s%o", (*src < 64)?"0":"", *src);
+ dst += 4;
+ dstlen -= 4;
+ break;
+ default:
+ *dst++ = *src;
+ dstlen--;
+ }
+ src++;
+ }
+ *dst = '\0';
+}
+
+
+/* Make private copy of string in struct id.
+ * This is needed if the result of atoid is to be kept.
+ */
+void
+unshare_id_content(struct id *id)
+{
+ switch (id->kind)
+ {
+ case ID_FQDN:
+ case ID_USER_FQDN:
+ case ID_DER_ASN1_DN:
+ case ID_KEY_ID:
+ id->name.ptr = clone_bytes(id->name.ptr, id->name.len, "keep id name");
+ break;
+ case ID_MYID:
+ case ID_NONE:
+ case ID_IPV4_ADDR:
+ case ID_IPV6_ADDR:
+ break;
+ default:
+ bad_case(id->kind);
+ }
+}
+
+void
+free_id_content(struct id *id)
+{
+ switch (id->kind)
+ {
+ case ID_FQDN:
+ case ID_USER_FQDN:
+ case ID_DER_ASN1_DN:
+ case ID_KEY_ID:
+ freeanychunk(id->name);
+ break;
+ case ID_MYID:
+ case ID_NONE:
+ case ID_IPV4_ADDR:
+ case ID_IPV6_ADDR:
+ break;
+ default:
+ bad_case(id->kind);
+ }
+}
+
+/* compare two struct id values */
+bool
+same_id(const struct id *a, const struct id *b)
+{
+ a = resolve_myid(a);
+ b = resolve_myid(b);
+ if (a->kind != b->kind)
+ return FALSE;
+ switch (a->kind)
+ {
+ case ID_NONE:
+ return TRUE; /* kind of vacuous */
+
+ case ID_IPV4_ADDR:
+ case ID_IPV6_ADDR:
+ return sameaddr(&a->ip_addr, &b->ip_addr);
+
+ case ID_FQDN:
+ case ID_USER_FQDN:
+ /* assumptions:
+ * - case should be ignored
+ * - trailing "." should be ignored (even if the only character?)
+ */
+ {
+ size_t al = a->name.len
+ , bl = b->name.len;
+
+ while (al > 0 && a->name.ptr[al - 1] == '.')
+ al--;
+ while (bl > 0 && b->name.ptr[bl - 1] == '.')
+ bl--;
+ return al == bl
+ && strncasecmp(a->name.ptr, b->name.ptr, al) == 0;
+ }
+
+ case ID_DER_ASN1_DN:
+ return same_dn(a->name, b->name);
+
+ case ID_KEY_ID:
+ return a->name.len == b->name.len
+ && memcmp(a->name.ptr, b->name.ptr, a->name.len) == 0;
+
+ default:
+ bad_case(a->kind);
+ }
+ return FALSE;
+}
+
+/* compare two struct id values, DNs can contain wildcards */
+bool
+match_id(const struct id *a, const struct id *b, int *wildcards)
+{
+ if (b->kind == ID_NONE)
+ {
+ *wildcards = MAX_WILDCARDS;
+ return TRUE;
+ }
+ if (a->kind != b->kind)
+ return FALSE;
+ if (a->kind == ID_DER_ASN1_DN)
+ return match_dn(a->name, b->name, wildcards);
+ else
+ {
+ *wildcards = 0;
+ return same_id(a, b);
+ }
+}
+
+/* count the numer of wildcards in an id */
+int
+id_count_wildcards(const struct id *id)
+{
+ switch (id->kind)
+ {
+ case ID_NONE:
+ return MAX_WILDCARDS;
+ case ID_DER_ASN1_DN:
+ return dn_count_wildcards(id->name);
+ default:
+ return 0;
+ }
+}
+
+/* build an ID payload
+ * Note: no memory is allocated for the body of the payload (tl->ptr).
+ * We assume it will end up being a pointer into a sufficiently
+ * stable datastructure. It only needs to last a short time.
+ */
+void
+build_id_payload(struct isakmp_ipsec_id *hd, chunk_t *tl, struct end *end)
+{
+ const struct id *id = resolve_myid(&end->id);
+
+ zero(hd);
+ hd->isaiid_idtype = id->kind;
+ switch (id->kind)
+ {
+ case ID_NONE:
+ hd->isaiid_idtype = aftoinfo(addrtypeof(&end->host_addr))->id_addr;
+ tl->len = addrbytesptr(&end->host_addr
+ , (const unsigned char **)&tl->ptr); /* sets tl->ptr too */
+ break;
+ case ID_FQDN:
+ case ID_USER_FQDN:
+ case ID_DER_ASN1_DN:
+ case ID_KEY_ID:
+ *tl = id->name;
+ break;
+ case ID_IPV4_ADDR:
+ case ID_IPV6_ADDR:
+ tl->len = addrbytesptr(&id->ip_addr
+ , (const unsigned char **)&tl->ptr); /* sets tl->ptr too */
+ break;
+ default:
+ bad_case(id->kind);
+ }
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset:4
+ * c-style: pluto
+ * End:
+ */
diff --git a/src/pluto/id.h b/src/pluto/id.h
new file mode 100644
index 000000000..4fe9ef227
--- /dev/null
+++ b/src/pluto/id.h
@@ -0,0 +1,67 @@
+/* identity representation, as in IKE ID Payloads (RFC 2407 DOI 4.6.2.1)
+ * Copyright (C) 1999-2001 D. Hugh Redelmeier
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: id.h,v 1.5 2005/08/15 20:07:08 as Exp $
+ */
+
+#ifndef _ID_H
+#define _ID_H
+
+#include "defs.h"
+
+struct id {
+ int kind; /* ID_* value */
+ ip_address ip_addr; /* ID_IPV4_ADDR, ID_IPV6_ADDR */
+ chunk_t name; /* ID_FQDN, ID_USER_FQDN (with @) */
+ /* ID_KEY_ID, ID_DER_ASN_DN */
+};
+
+extern void init_id(void);
+
+extern const struct id empty_id; /* ID_NONE */
+
+enum myid_state {
+ MYID_UNKNOWN, /* not yet figured out */
+ MYID_HOSTNAME, /* our current hostname */
+ MYID_IP, /* our default IP address */
+ MYID_SPECIFIED /* as specified by ipsec.conf */
+};
+
+extern enum myid_state myid_state;
+extern struct id myids[MYID_SPECIFIED+1]; /* %myid */
+extern char *myid_str[MYID_SPECIFIED+1]; /* strings */
+extern void set_myid(enum myid_state s, char *);
+extern void show_myid_status(void);
+#define resolve_myid(id) ((id)->kind == ID_MYID? &myids[myid_state] : (id))
+extern void set_myFQDN(void);
+
+extern err_t atoid(char *src, struct id *id, bool myid_ok);
+extern int keyidtoa(char *dst, size_t dstlen, chunk_t keyid);
+extern void iptoid(const ip_address *ip, struct id *id);
+extern int idtoa(const struct id *id, char *dst, size_t dstlen);
+#define IDTOA_BUF 512
+extern void escape_metachar(const char *src, char *dst, size_t dstlen);
+struct end; /* forward declaration of tag (defined in connections.h) */
+extern void unshare_id_content(struct id *id);
+extern void free_id_content(struct id *id);
+extern bool same_id(const struct id *a, const struct id *b);
+#define MAX_WILDCARDS 15
+extern bool match_id(const struct id *a, const struct id *b, int *wildcards);
+extern int id_count_wildcards(const struct id *id);
+#define id_is_ipaddr(id) ((id)->kind == ID_IPV4_ADDR || (id)->kind == ID_IPV6_ADDR)
+
+struct isakmp_ipsec_id; /* forward declaration of tag (defined in packet.h) */
+extern void
+ build_id_payload(struct isakmp_ipsec_id *hd, chunk_t *tl, struct end *end);
+
+#endif /* _ID_H */
diff --git a/src/pluto/ike_alg.c b/src/pluto/ike_alg.c
new file mode 100644
index 000000000..1c6514b4b
--- /dev/null
+++ b/src/pluto/ike_alg.c
@@ -0,0 +1,592 @@
+/* IKE modular algorithm handling interface
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: ike_alg.c,v 1.6 2004/09/17 21:29:50 as Exp $
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/queue.h>
+
+#include <freeswan.h>
+#include <ipsec_policy.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "sha1.h"
+#include "md5.h"
+#include "crypto.h"
+
+#include "state.h"
+#include "packet.h"
+#include "log.h"
+#include "whack.h"
+#include "spdb.h"
+#include "alg_info.h"
+#include "ike_alg.h"
+#include "db_ops.h"
+#include "connections.h"
+#include "kernel.h"
+
+#define return_on(var, val) do { var=val;goto return_out; } while(0);
+
+/*
+ * IKE algorithm list handling - registration and lookup
+ */
+
+/* Modular IKE algorithm storage structure */
+
+static struct ike_alg *ike_alg_base[IKE_ALG_MAX+1] = {NULL, NULL};
+
+/*
+ * return ike_algo object by {type, id}
+ */
+static struct ike_alg *
+ike_alg_find(u_int algo_type, u_int algo_id, u_int keysize __attribute__((unused)))
+{
+ struct ike_alg *e = ike_alg_base[algo_type];
+
+ while (e != NULL && algo_id > e->algo_id)
+ {
+ e = e->algo_next;
+ }
+ return (e != NULL && e->algo_id == algo_id) ? e : NULL;
+}
+
+/*
+ * "raw" ike_alg list adding function
+ */
+int
+ike_alg_add(struct ike_alg* a)
+{
+ if (a->algo_type > IKE_ALG_MAX)
+ {
+ plog("ike_alg: Not added, invalid algorithm type");
+ return -EINVAL;
+ }
+
+ if (ike_alg_find(a->algo_type, a->algo_id, 0) != NULL)
+ {
+ plog("ike_alg: Not added, algorithm already exists");
+ return -EEXIST;
+ }
+
+ {
+ struct ike_alg **ep = &ike_alg_base[a->algo_type];
+ struct ike_alg *e = *ep;
+
+ while (e != NULL && a->algo_id > e->algo_id)
+ {
+ ep = &e->algo_next;
+ e = *ep;
+ }
+ *ep = a;
+ a->algo_next = e;
+ return 0;
+ }
+}
+
+/*
+ * get IKE hash algorithm
+ */
+struct hash_desc *ike_alg_get_hasher(u_int alg)
+{
+ return (struct hash_desc *) ike_alg_find(IKE_ALG_HASH, alg, 0);
+}
+
+/*
+ * get IKE encryption algorithm
+ */
+struct encrypt_desc *ike_alg_get_encrypter(u_int alg)
+{
+ return (struct encrypt_desc *) ike_alg_find(IKE_ALG_ENCRYPT, alg, 0);
+}
+
+/*
+ * check if IKE hash algorithm is present
+ */
+bool
+ike_alg_hash_present(u_int halg)
+{
+ return ike_alg_get_hasher(halg) != NULL;
+}
+
+/*
+ * check if IKE encryption algorithm is present
+ */
+bool
+ike_alg_enc_present(u_int ealg)
+{
+ return ike_alg_get_encrypter(ealg) != NULL;
+}
+
+/*
+ * Validate and register IKE hash algorithm object
+ */
+int
+ike_alg_register_hash(struct hash_desc *hash_desc)
+{
+ const char *alg_name = NULL;
+ int ret = 0;
+
+ if (hash_desc->algo_id > OAKLEY_HASH_MAX)
+ {
+ plog ("ike_alg: hash alg=%d > max=%d"
+ , hash_desc->algo_id, OAKLEY_HASH_MAX);
+ return_on(ret,-EINVAL);
+ }
+
+ if (hash_desc->hash_ctx_size > sizeof (union hash_ctx))
+ {
+ plog ("ike_alg: hash alg=%d has ctx_size=%d > hash_ctx=%d"
+ , hash_desc->algo_id
+ , (int)hash_desc->hash_ctx_size
+ , (int)sizeof (union hash_ctx));
+ return_on(ret,-EOVERFLOW);
+ }
+
+ if (!(hash_desc->hash_init && hash_desc->hash_update && hash_desc->hash_final))
+ {
+ plog ("ike_alg: hash alg=%d needs hash_init(), hash_update() and hash_final()"
+ , hash_desc->algo_id);
+ return_on(ret,-EINVAL);
+ }
+
+ alg_name = enum_name(&oakley_hash_names, hash_desc->algo_id);
+ if (!alg_name)
+ {
+ plog ("ike_alg: hash alg=%d not found in constants.c:oakley_hash_names"
+ , hash_desc->algo_id);
+ alg_name = "<NULL>";
+ }
+
+return_out:
+ if (ret == 0)
+ ret = ike_alg_add((struct ike_alg *)hash_desc);
+
+ plog("ike_alg: Activating %s hash: %s"
+ ,alg_name, ret == 0 ? "Ok" : "FAILED");
+
+ return ret;
+}
+
+/*
+ * Validate and register IKE encryption algorithm object
+ */
+int
+ike_alg_register_enc(struct encrypt_desc *enc_desc)
+{
+ int ret = ike_alg_add((struct ike_alg *)enc_desc);
+
+ const char *alg_name = enum_name(&oakley_enc_names, enc_desc->algo_id);
+
+ char alg_number[20];
+
+ /* algorithm is not listed in oakley_enc_names */
+ if (alg_name == NULL)
+ {
+ snprintf(alg_number, sizeof(alg_number), "OAKLEY_ID_%d"
+ , enc_desc->algo_id);
+ alg_name = alg_number;
+ }
+
+ plog("ike_alg: Activating %s encryption: %s"
+ , alg_name, ret == 0 ? "Ok" : "FAILED");
+
+ return ret;
+}
+
+/*
+ * Get pfsgroup for this connection
+ */
+const struct oakley_group_desc *
+ike_alg_pfsgroup(struct connection *c, lset_t policy)
+{
+ const struct oakley_group_desc * ret = NULL;
+
+ if ((policy & POLICY_PFS)
+ && c->alg_info_esp
+ && c->alg_info_esp->esp_pfsgroup)
+ ret = lookup_group(c->alg_info_esp->esp_pfsgroup);
+ return ret;
+}
+
+/*
+ * Create an OAKLEY proposal based on alg_info and policy
+ */
+struct db_context *
+ike_alg_db_new(struct alg_info_ike *ai , lset_t policy)
+{
+ struct db_context *db_ctx = NULL;
+ struct ike_info *ike_info;
+ struct encrypt_desc *enc_desc;
+ u_int ealg, halg, modp, eklen = 0;
+ int i;
+
+ bool is_xauth_server = (policy & POLICY_XAUTH_SERVER) != LEMPTY;
+
+ if (!ai)
+ {
+ whack_log(RC_LOG_SERIOUS, "no IKE algorithms "
+ "for this connection "
+ "(check ike algorithm string)");
+ goto fail;
+ }
+ policy &= POLICY_ID_AUTH_MASK;
+ db_ctx = db_prop_new(PROTO_ISAKMP, 8, 8 * 5);
+
+ /* for each group */
+ ALG_INFO_IKE_FOREACH(ai, ike_info, i)
+ {
+ ealg = ike_info->ike_ealg;
+ halg = ike_info->ike_halg;
+ modp = ike_info->ike_modp;
+ eklen= ike_info->ike_eklen;
+
+ if (!ike_alg_enc_present(ealg))
+ {
+ DBG_log("ike_alg: ike enc ealg=%d not present"
+ , ealg);
+ continue;
+ }
+
+ if (!ike_alg_hash_present(halg))
+ {
+ DBG_log("ike_alg: ike hash halg=%d not present"
+ , halg);
+ continue;
+ }
+
+ enc_desc = ike_alg_get_encrypter(ealg);
+ passert(enc_desc != NULL);
+
+ if (eklen
+ && (eklen < enc_desc->keyminlen || eklen > enc_desc->keymaxlen))
+ {
+ DBG_log("ike_alg: ealg=%d (specified) keylen:%d, not valid min=%d, max=%d"
+ , ealg
+ , eklen
+ , enc_desc->keyminlen
+ , enc_desc->keymaxlen
+ );
+ continue;
+ }
+
+ if (policy & POLICY_RSASIG)
+ {
+ db_trans_add(db_ctx, KEY_IKE);
+ db_attr_add_values(db_ctx, OAKLEY_ENCRYPTION_ALGORITHM, ealg);
+ db_attr_add_values(db_ctx, OAKLEY_HASH_ALGORITHM, halg);
+ if (eklen)
+ db_attr_add_values(db_ctx, OAKLEY_KEY_LENGTH, eklen);
+ db_attr_add_values(db_ctx, OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_SIG);
+ db_attr_add_values(db_ctx, OAKLEY_GROUP_DESCRIPTION, modp);
+ }
+
+ if (policy & POLICY_PSK)
+ {
+ db_trans_add(db_ctx, KEY_IKE);
+ db_attr_add_values(db_ctx, OAKLEY_ENCRYPTION_ALGORITHM, ealg);
+ db_attr_add_values(db_ctx, OAKLEY_HASH_ALGORITHM, halg);
+ if (eklen)
+ db_attr_add_values(db_ctx, OAKLEY_KEY_LENGTH, eklen);
+ db_attr_add_values(db_ctx, OAKLEY_AUTHENTICATION_METHOD, OAKLEY_PRESHARED_KEY);
+ db_attr_add_values(db_ctx, OAKLEY_GROUP_DESCRIPTION, modp);
+ }
+
+ if (policy & POLICY_XAUTH_RSASIG)
+ {
+ db_trans_add(db_ctx, KEY_IKE);
+ db_attr_add_values(db_ctx, OAKLEY_ENCRYPTION_ALGORITHM, ealg);
+ db_attr_add_values(db_ctx, OAKLEY_HASH_ALGORITHM, halg);
+ if (eklen)
+ db_attr_add_values(db_ctx, OAKLEY_KEY_LENGTH, eklen);
+ db_attr_add_values(db_ctx, OAKLEY_AUTHENTICATION_METHOD
+ , is_xauth_server ? XAUTHRespRSA : XAUTHInitRSA);
+ db_attr_add_values(db_ctx, OAKLEY_GROUP_DESCRIPTION, modp);
+ }
+
+ if (policy & POLICY_XAUTH_PSK)
+ {
+ db_trans_add(db_ctx, KEY_IKE);
+ db_attr_add_values(db_ctx, OAKLEY_ENCRYPTION_ALGORITHM, ealg);
+ db_attr_add_values(db_ctx, OAKLEY_HASH_ALGORITHM, halg);
+ if (eklen)
+ db_attr_add_values(db_ctx, OAKLEY_KEY_LENGTH, eklen);
+ db_attr_add_values(db_ctx, OAKLEY_AUTHENTICATION_METHOD
+ , is_xauth_server ? XAUTHRespPreShared : XAUTHInitPreShared);
+ db_attr_add_values(db_ctx, OAKLEY_GROUP_DESCRIPTION, modp);
+ }
+ }
+fail:
+ return db_ctx;
+}
+
+/*
+ * Show registered IKE algorithms
+ */
+void
+ike_alg_list(void)
+{
+ u_int i;
+ struct ike_alg *a;
+
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of registered IKE Encryption Algorithms:");
+ whack_log(RC_COMMENT, " ");
+
+ for (a = ike_alg_base[IKE_ALG_ENCRYPT]; a != NULL; a = a->algo_next)
+ {
+ struct encrypt_desc *desc = (struct encrypt_desc*)a;
+
+ whack_log(RC_COMMENT, "#%-5d %s, blocksize: %d, keylen: %d-%d-%d"
+ , a->algo_id
+ , enum_name(&oakley_enc_names, a->algo_id)
+ , (int)desc->enc_blocksize*BITS_PER_BYTE
+ , desc->keyminlen
+ , desc->keydeflen
+ , desc->keymaxlen
+ );
+ }
+
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of registered IKE Hash Algorithms:");
+ whack_log(RC_COMMENT, " ");
+
+ for (a = ike_alg_base[IKE_ALG_HASH]; a != NULL; a = a->algo_next)
+ {
+ whack_log(RC_COMMENT, "#%-5d %s, hashsize: %d"
+ , a->algo_id
+ , enum_name(&oakley_hash_names, a->algo_id)
+ , (int)((struct hash_desc *)a)->hash_digest_size*BITS_PER_BYTE
+ );
+ }
+
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of registered IKE DH Groups:");
+ whack_log(RC_COMMENT, " ");
+
+ for (i = 0; i < elemsof(oakley_group); i++)
+ {
+ const struct oakley_group_desc *gdesc=oakley_group + i;
+
+ whack_log(RC_COMMENT, "#%-5d %s, groupsize: %d"
+ , gdesc->group
+ , enum_name(&oakley_group_names, gdesc->group)
+ , (int)gdesc->bytes*BITS_PER_BYTE
+ );
+ }
+}
+
+/* Show IKE algorithms for
+ * - this connection (result from ike= string)
+ * - newest SA
+ */
+void
+ike_alg_show_connection(struct connection *c, const char *instance)
+{
+ char buf[256];
+ struct state *st;
+
+ if (c->alg_info_ike)
+ {
+ alg_info_snprint(buf, sizeof(buf)-1, (struct alg_info *)c->alg_info_ike);
+ whack_log(RC_COMMENT
+ , "\"%s\"%s: IKE algorithms wanted: %s"
+ , c->name
+ , instance
+ , buf
+ );
+
+ alg_info_snprint_ike(buf, sizeof(buf)-1, c->alg_info_ike);
+ whack_log(RC_COMMENT
+ , "\"%s\"%s: IKE algorithms found: %s"
+ , c->name
+ , instance
+ , buf
+ );
+ }
+
+ st = state_with_serialno(c->newest_isakmp_sa);
+ if (st)
+ whack_log(RC_COMMENT
+ , "\"%s\"%s: IKE algorithm newest: %s_%d-%s-%s"
+ , c->name
+ , instance
+ , enum_show(&oakley_enc_names, st->st_oakley.encrypt)
+ +7 /* strlen("OAKLEY_") */
+ /* , st->st_oakley.encrypter->keydeflen */
+ , st->st_oakley.enckeylen
+ , enum_show(&oakley_hash_names, st->st_oakley.hash)
+ +7 /* strlen("OAKLEY_") */
+ , enum_show(&oakley_group_names, st->st_oakley.group->group)
+ +13 /* strlen("OAKLEY_GROUP_") */
+ );
+}
+
+/*
+ * Apply a suite of testvectors to a hash algorithm
+ */
+static bool
+ike_hash_test(const struct hash_desc *desc)
+{
+ bool hash_results = TRUE;
+ bool hmac_results = TRUE;
+
+ if (desc->hash_testvectors == NULL)
+ {
+ plog(" %s hash self-test not available", enum_name(&oakley_hash_names, desc->algo_id));
+ }
+ else
+ {
+ int i;
+
+ for (i = 0; desc->hash_testvectors[i].msg_digest != NULL; i++)
+ {
+ u_char digest[MAX_DIGEST_LEN];
+ bool result;
+
+ union hash_ctx ctx;
+
+ desc->hash_init(&ctx);
+ desc->hash_update(&ctx, desc->hash_testvectors[i].msg
+ ,desc->hash_testvectors[i].msg_size);
+ desc->hash_final(digest, &ctx);
+ result = memcmp(digest, desc->hash_testvectors[i].msg_digest
+ , desc->hash_digest_size) == 0;
+ DBG(DBG_CRYPT,
+ DBG_log(" hash testvector %d: %s", i, result ? "ok":"failed")
+ )
+ hash_results &= result;
+ }
+ plog(" %s hash self-test %s", enum_name(&oakley_hash_names, desc->algo_id)
+ , hash_results ? "passed":"failed");
+ }
+
+ if (desc->hmac_testvectors == NULL)
+ {
+ plog(" %s hmac self-test not available", enum_name(&oakley_hash_names, desc->algo_id));
+ }
+ else
+ {
+ int i;
+
+ for (i = 0; desc->hmac_testvectors[i].hmac != NULL; i++)
+ {
+ u_char digest[MAX_DIGEST_LEN];
+ bool result;
+
+ struct hmac_ctx ctx;
+
+ hmac_init(&ctx, desc, desc->hmac_testvectors[i].key
+ , desc->hmac_testvectors[i].key_size);
+ hmac_update(&ctx, desc->hmac_testvectors[i].msg
+ ,desc->hmac_testvectors[i].msg_size);
+ hmac_final(digest, &ctx);
+ result = memcmp(digest, desc->hmac_testvectors[i].hmac
+ , desc->hash_digest_size) == 0;
+ DBG(DBG_CRYPT,
+ DBG_log(" hmac testvector %d: %s", i, result ? "ok":"failed")
+ )
+ hmac_results &= result;
+ }
+ plog(" %s hmac self-test %s", enum_name(&oakley_hash_names, desc->algo_id)
+ , hmac_results ? "passed":"failed");
+ }
+ return hash_results && hmac_results;
+}
+
+/*
+ * Apply test vectors to registered encryption and hash algorithms
+ */
+bool
+ike_alg_test(void)
+{
+ bool all_results = TRUE;
+ struct ike_alg *a;
+
+ plog("Testing registered IKE encryption algorithms:");
+
+ for (a = ike_alg_base[IKE_ALG_ENCRYPT]; a != NULL; a = a->algo_next)
+ {
+
+ struct encrypt_desc *desc = (struct encrypt_desc*)a;
+
+ plog(" %s self-test not available", enum_name(&oakley_enc_names, a->algo_id));
+ }
+
+ plog("Testing registered IKE hash algorithms:");
+
+ for (a = ike_alg_base[IKE_ALG_HASH]; a != NULL; a = a->algo_next)
+ {
+ struct hash_desc *desc = (struct hash_desc*)a;
+
+ all_results &= ike_hash_test(desc);
+ }
+
+ if (all_results)
+ plog("All crypto self-tests passed");
+ else
+ plog("Some crypto self-tests failed");
+ return all_results;
+}
+
+/*
+ * ML: make F_STRICT logic consider enc,hash/auth,modp algorithms
+ */
+bool
+ike_alg_ok_final(u_int ealg, u_int key_len, u_int aalg, u_int group
+, struct alg_info_ike *alg_info_ike)
+{
+ /*
+ * simple test to discard low key_len, will accept it only
+ * if specified in "esp" string
+ */
+ bool ealg_insecure = (key_len < 128);
+
+ if (ealg_insecure
+ || (alg_info_ike && alg_info_ike->alg_info_flags & ALG_INFO_F_STRICT))
+ {
+ int i;
+ struct ike_info *ike_info;
+
+ if (alg_info_ike)
+ {
+ ALG_INFO_IKE_FOREACH(alg_info_ike, ike_info, i)
+ {
+ if (ike_info->ike_ealg == ealg
+ && (ike_info->ike_eklen == 0 || key_len == 0 || ike_info->ike_eklen == key_len)
+ && ike_info->ike_halg == aalg
+ && ike_info->ike_modp == group)
+ {
+ if (ealg_insecure)
+ loglog(RC_LOG_SERIOUS, "You should NOT use insecure IKE algorithms (%s)!"
+ , enum_name(&oakley_enc_names, ealg));
+ return TRUE;
+ }
+ }
+ }
+ plog("Oakley Transform [%s (%d), %s, %s] refused due to %s"
+ , enum_name(&oakley_enc_names, ealg), key_len
+ , enum_name(&oakley_hash_names, aalg)
+ , enum_name(&oakley_group_names, group)
+ , ealg_insecure ?
+ "insecure key_len and enc. alg. not listed in \"ike\" string" : "strict flag"
+ );
+ return FALSE;
+ }
+ return TRUE;
+}
+
diff --git a/src/pluto/ike_alg.h b/src/pluto/ike_alg.h
new file mode 100644
index 000000000..19e2e591c
--- /dev/null
+++ b/src/pluto/ike_alg.h
@@ -0,0 +1,94 @@
+/* IKE modular algorithm handling interface
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: ike_alg.h,v 1.3 2004/09/16 23:22:22 as Exp $
+ */
+
+#ifndef _IKE_ALG_H
+#define _IKE_ALG_H
+
+#include "connections.h"
+
+struct ike_alg {
+ u_int16_t algo_type;
+ u_int16_t algo_id;
+ struct ike_alg *algo_next;
+};
+
+struct encrypt_desc {
+ u_int16_t algo_type;
+ u_int16_t algo_id;
+ struct ike_alg *algo_next;
+
+ size_t enc_ctxsize;
+ size_t enc_blocksize;
+ u_int keydeflen;
+ u_int keymaxlen;
+ u_int keyminlen;
+ void (*do_crypt)(u_int8_t *dat, size_t datasize, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc);
+};
+
+typedef struct hash_testvector hash_testvector_t;
+
+struct hash_testvector {
+ const size_t msg_size;
+ const u_char *msg;
+ const u_char *msg_digest;
+};
+
+typedef struct hmac_testvector hmac_testvector_t;
+
+struct hmac_testvector {
+ const size_t key_size;
+ const u_char *key;
+ const size_t msg_size;
+ const u_char *msg;
+ const u_char *hmac;
+};
+struct hash_desc {
+ u_int16_t algo_type;
+ u_int16_t algo_id;
+ struct ike_alg *algo_next;
+
+ size_t hash_ctx_size;
+ size_t hash_block_size;
+ size_t hash_digest_size;
+ const hash_testvector_t *hash_testvectors;
+ const hmac_testvector_t *hmac_testvectors;
+ void (*hash_init)(void *ctx);
+ void (*hash_update)(void *ctx, const u_int8_t *in, size_t datasize);
+ void (*hash_final)(u_int8_t *out, void *ctx);
+};
+
+#define IKE_ALG_ENCRYPT 0
+#define IKE_ALG_HASH 1
+#define IKE_ALG_MAX IKE_ALG_HASH
+
+extern int ike_alg_add(struct ike_alg *a);
+extern struct hash_desc *ike_alg_get_hasher(u_int alg);
+extern struct encrypt_desc *ike_alg_get_encrypter(u_int alg);
+extern bool ike_alg_enc_present(u_int ealg);
+extern bool ike_alg_hash_present(u_int halg);
+extern int ike_alg_register_hash(struct hash_desc *a);
+extern int ike_alg_register_enc(struct encrypt_desc *e);
+extern const struct oakley_group_desc* ike_alg_pfsgroup(struct connection *c
+ , lset_t policy);
+extern struct db_context * ike_alg_db_new(struct alg_info_ike *ai, lset_t policy);
+extern void ike_alg_list(void);
+extern void ike_alg_show_connection(struct connection *c, const char *instance);
+extern bool ike_alg_test(void);
+extern bool ike_alg_ok_final(u_int ealg, u_int key_len, u_int aalg, u_int group
+ , struct alg_info_ike *alg_info_ike);
+extern int ike_alg_init(void);
+
+#endif /* _IKE_ALG_H */
diff --git a/src/pluto/ipsec.secrets.5 b/src/pluto/ipsec.secrets.5
new file mode 100644
index 000000000..3cce4d3f8
--- /dev/null
+++ b/src/pluto/ipsec.secrets.5
@@ -0,0 +1,175 @@
+.TH IPSEC.SECRETS 5 "28 March 1999"
+.SH NAME
+ipsec.secrets \- secrets for IKE/IPsec authentication
+.SH DESCRIPTION
+The file \fIipsec.secrets\fP holds a table of secrets.
+These secrets are used by \fIipsec_pluto\fP(8), the FreeS/WAN Internet Key
+Exchange daemon, to authenticate other hosts.
+Currently there are two kinds of secrets: preshared secrets and
+.\" the private part of DSS keys.
+RSA private keys.
+.LP
+It is vital that these secrets be protected. The file should be owned
+by the super-user,
+and its permissions should be set to block all access by others.
+.LP
+The file is a sequence of entries and include directives.
+Here is an example. Each entry or directive must start at the
+left margin, but if it continues beyond a single line, each continuation
+line must be indented.
+.LP
+.RS
+.nf
+# sample /etc/ipsec.secrets file for 10.1.0.1
+10.1.0.1 10.2.0.1: PSK "secret shared by two hosts"
+
+# an entry may be split across lines,
+# but indentation matters
+www.xs4all.nl @www.kremvax.ru
+\ \ \ \ 10.6.0.1 10.7.0.1 1.8.0.1: PSK "secret shared by 5"
+
+.\" # Private part of our DSS key, in base 64,
+.\" # as generated by BIND 8.2.1's dnskeygen.
+.\" # Since this is the default key for this host,
+.\" # there is no need to specify indices.
+.\" : DSS 0siMs0N/hfRoCBMXA6plPtuv58/+c=
+# an RSA private key.
+# note that the lines are too wide for a
+# man page, so ... has been substituted for
+# the truncated part
+@my.com: rsa {
+\ \ \ \ Modulus:\ 0syXpo/6waam+ZhSs8Lt6jnBzu3C4grtt...
+\ \ \ \ PublicExponent:\ 0sAw==
+\ \ \ \ PrivateExponent:\ 0shlGbVR1m8Z+7rhzSyenCaBN...
+\ \ \ \ Prime1:\ 0s8njV7WTxzVzRz7AP+0OraDxmEAt1BL5l...
+\ \ \ \ Prime2:\ 0s1LgR7/oUMo9BvfU8yRFNos1s211KX5K0...
+\ \ \ \ Exponent1:\ 0soaXj85ihM5M2inVf/NfHmtLutVz4r...
+\ \ \ \ Exponent2:\ 0sjdAL9VFizF+BKU4ohguJFzOd55OG6...
+\ \ \ \ Coefficient:\ 0sK1LWwgnNrNFGZsS/2GuMBg9nYVZ...
+\ \ \ \ }
+
+include ipsec.*.secrets # get secrets from other files
+.fi
+.RE
+.LP
+Each entry in the file is a list of indices, followed by a secret.
+The two parts are separated by a colon (\fB:\fP) that is
+followed by whitespace or a newline. For compatability
+with the previous form of this file, if the key part is just a
+double-quoted string the colon may be left out.
+.LP
+An index is an IP address, or a Fully Qualified Domain Name, user@FQDN,
+\fB%any\fP or \fB%any6\fP (other kinds may come). An IP address may be written
+in the familiar dotted quad form or as a domain name to be looked up
+when the file is loaded
+(or in any of the forms supported by the FreeS/WAN \fIipsec_ttoaddr\fP(3)
+routine). In many cases it is a bad idea to use domain names because
+the name server may not be running or may be insecure. To denote a
+Fully Qualified Domain Name (as opposed to an IP address denoted by
+its domain name), precede the name with an at sign (\fB@\fP).
+.LP
+Matching IDs with indices is fairly straightforward: they have to be
+equal. In the case of a ``Road Warrior'' connection, if an equal
+match is not found for the Peer's ID, and it is in the form of an IP
+address, an index of \fB%any\fP will match the peer's IP address if IPV4
+and \fB%any6\fP will match a the peer's IP address if IPV6.
+Currently, the obsolete notation \fB0.0.0.0\fP may be used in place of
+\fB%any\fP.
+.LP
+An additional complexity
+arises in the case of authentication by preshared secret: the
+responder will need to look up the secret before the Peer's ID payload has
+been decoded, so the ID used will be the IP address.
+.LP
+To authenticate a connection between two hosts, the entry that most
+specifically matches the host and peer IDs is used. An entry with no
+index will match any host and peer. More specifically, an entry with one index will
+match a host and peer if the index matches the host's ID (the peer isn't
+considered). Still more specifically, an entry with multiple indices will match a host and
+peer if the host ID and peer ID each match one of the indices. If the key
+is for an asymmetric authentication technique (i.e. a public key
+system such as RSA), an entry with multiple indices will match a host
+and peer even if only the host ID matches an index (it is presumed that the
+multiple indices are all identities of the host).
+It is acceptable for two entries to be the best match as
+long as they agree about the secret or private key.
+.LP
+Authentication by preshared secret requires that both systems find the
+identical secret (the secret is not actually transmitted by the IKE
+protocol). If both the host and peer appear in the index list, the
+same entry will be suitable for both systems so verbatim copying
+between systems can be used. This naturally extends to larger groups
+sharing the same secret. Thus multiple-index entries are best for PSK
+authentication.
+.LP
+Authentication by RSA Signatures requires that each host have its own private
+key. A host could reasonably use a different private keys
+for different interfaces and for different peers. But it would not
+be normal to share entries between systems. Thus thus no-index and
+one-index forms of entry often make sense for RSA Signature authentication.
+.LP
+The key part of an entry may start with a token indicating the kind of
+key. ``RSA'' signifies RSA private key and ``PSK'' signifies
+PreShared Key (case is ignored). For compatability with previous
+forms of this file, PSK is the default.
+.LP
+A preshared secret is most conveniently represented as a sequence of
+characters, delimited by the double-quote
+character (\fB"\fP). The sequence cannot contain a newline or
+double-quote. Strictly speaking, the secret is actually the sequence
+of bytes that is used in the file to represent the sequence of
+characters (excluding the delimiters).
+A preshared secret may also be represented, without quotes, in any form supported by
+\fIipsec_ttodata\fP(3).
+.LP
+An RSA private key is a composite of eight generally large numbers. The notation
+used is a brace-enclosed list of field name and value pairs (see the example above).
+A suitable key, in a suitable format, may be generated by \fIipsec_rsasigkey\fP(8).
+The structure is very similar to that used by BIND 8.2.2 or later, but note that
+the numbers must have a ``0s'' prefix if they are in base 64. The order of
+the fields is fixed.
+.LP
+The first token an entry must start in
+the first column of its line. Subsequent tokens must be
+separated by whitespace,
+except for a colon token, which only needs to be followed by whitespace.
+A newline is taken as whitespace, but every
+line of an entry after the first must be indented.
+.LP
+Whitespace at the end of a line is ignored (except in the 0t
+notation for a key). At the start of line or
+after whitespace, \fB#\fP and the following text up to the end of the
+line is treated as a comment. Within entries, all lines must be
+indented (except for lines with no tokens).
+Outside entries, no line may be indented (this is to make sure that
+the file layout reflects its structure).
+.LP
+An include directive causes the contents of the named file to be processed
+before continuing with the current file. The filename is subject to
+``globbing'' as in \fIsh\fP(1), so every file with a matching name
+is processed. Includes may be nested to a modest
+depth (10, currently). If the filename doesn't start with a \fB/\fP, the
+directory containing the current file is prepended to the name. The
+include directive is a line that starts with the word \fBinclude\fP,
+followed by whitespace, followed by the filename (which must not contain
+whitespace).
+.SH FILES
+/etc/ipsec.secrets
+.SH SEE ALSO
+The rest of the FreeS/WAN distribution, in particular
+\fIipsec.conf\fP(5),
+\fIipsec\fP(8),
+\fIipsec_newhostkey\fP(8),
+\fIipsec_rsasigkey\fP(8),
+\fIipsec_showhostkey\fP(8),
+\fIipsec_auto\fP(8) \fB\-\-rereadsecrets\fP,
+and \fIipsec_pluto\fP(8) \fB\-\-listen\fP,.
+.br
+BIND 8.2.2 or later, ftp://ftp.isc.org/isc/bind/src/
+.SH HISTORY
+Designed for the FreeS/WAN project
+<http://www.freeswan.org>
+by D. Hugh Redelmeier.
+.SH BUGS
+If an ID is \fB0.0.0.0\fP, it will match \fB%any\fP;
+if it is \fB0::0\fP, it will match \fB%any6\fP.
diff --git a/src/pluto/ipsec_doi.c b/src/pluto/ipsec_doi.c
new file mode 100644
index 000000000..1c22b299b
--- /dev/null
+++ b/src/pluto/ipsec_doi.c
@@ -0,0 +1,5630 @@
+/* IPsec DOI and Oakley resolution routines
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: ipsec_doi.c,v 1.39 2006/04/22 21:59:20 as Exp $
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */
+#include <sys/queue.h>
+#include <sys/time.h> /* for gettimeofday */
+
+#include <freeswan.h>
+#include <ipsec_policy.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "mp_defs.h"
+#include "state.h"
+#include "id.h"
+#include "x509.h"
+#include "crl.h"
+#include "ca.h"
+#include "certs.h"
+#include "smartcard.h"
+#include "connections.h"
+#include "keys.h"
+#include "packet.h"
+#include "demux.h" /* needs packet.h */
+#include "adns.h" /* needs <resolv.h> */
+#include "dnskey.h" /* needs keys.h and adns.h */
+#include "kernel.h"
+#include "log.h"
+#include "cookie.h"
+#include "server.h"
+#include "spdb.h"
+#include "timer.h"
+#include "rnd.h"
+#include "ipsec_doi.h" /* needs demux.h and state.h */
+#include "whack.h"
+#include "fetch.h"
+#include "pkcs7.h"
+#include "asn1.h"
+
+#include "sha1.h"
+#include "md5.h"
+#include "crypto.h" /* requires sha1.h and md5.h */
+#include "vendor.h"
+#include "alg_info.h"
+#include "ike_alg.h"
+#include "kernel_alg.h"
+#include "nat_traversal.h"
+#include "virtual.h"
+
+/*
+ * are we sending Pluto's Vendor ID?
+ */
+#ifdef VENDORID
+#define SEND_PLUTO_VID 1
+#else /* !VENDORID */
+#define SEND_PLUTO_VID 0
+#endif /* !VENDORID */
+
+/*
+ * are we sending a Cisco Unity VID?
+ */
+#ifdef CISCO_QUIRKS
+#define SEND_CISCO_UNITY_VID 1
+#else /* !CISCO_QUIRKS */
+#define SEND_CISCO_UNITY_VID 0
+#endif /* !CISCO_QUIRKS */
+
+/* MAGIC: perform f, a function that returns notification_t
+ * and return from the ENCLOSING stf_status returning function if it fails.
+ */
+#define RETURN_STF_FAILURE(f) \
+ { int r = (f); if (r != NOTHING_WRONG) return STF_FAIL + r; }
+
+/* create output HDR as replica of input HDR */
+void
+echo_hdr(struct msg_digest *md, bool enc, u_int8_t np)
+{
+ struct isakmp_hdr r_hdr = md->hdr; /* mostly same as incoming header */
+
+ r_hdr.isa_flags &= ~ISAKMP_FLAG_COMMIT; /* we won't ever turn on this bit */
+ if (enc)
+ r_hdr.isa_flags |= ISAKMP_FLAG_ENCRYPTION;
+ /* some day, we may have to set r_hdr.isa_version */
+ r_hdr.isa_np = np;
+ if (!out_struct(&r_hdr, &isakmp_hdr_desc, &md->reply, &md->rbody))
+ impossible(); /* surely must have room and be well-formed */
+}
+
+/* Compute DH shared secret from our local secret and the peer's public value.
+ * We make the leap that the length should be that of the group
+ * (see quoted passage at start of ACCEPT_KE).
+ */
+static void
+compute_dh_shared(struct state *st, const chunk_t g
+, const struct oakley_group_desc *group)
+{
+ MP_INT mp_g, mp_shared;
+ struct timeval tv0, tv1;
+ unsigned long tv_diff;
+
+ gettimeofday(&tv0, NULL);
+ passert(st->st_sec_in_use);
+ n_to_mpz(&mp_g, g.ptr, g.len);
+ mpz_init(&mp_shared);
+ mpz_powm(&mp_shared, &mp_g, &st->st_sec, group->modulus);
+ mpz_clear(&mp_g);
+ freeanychunk(st->st_shared); /* happens in odd error cases */
+ st->st_shared = mpz_to_n(&mp_shared, group->bytes);
+ mpz_clear(&mp_shared);
+ gettimeofday(&tv1, NULL);
+ tv_diff=(tv1.tv_sec - tv0.tv_sec) * 1000000 + (tv1.tv_usec - tv0.tv_usec);
+ DBG(DBG_CRYPT,
+ DBG_log("compute_dh_shared(): time elapsed (%s): %ld usec"
+ , enum_show(&oakley_group_names, st->st_oakley.group->group)
+ , tv_diff);
+ );
+ /* if took more than 200 msec ... */
+ if (tv_diff > 200000) {
+ loglog(RC_LOG_SERIOUS, "WARNING: compute_dh_shared(): for %s took "
+ "%ld usec"
+ , enum_show(&oakley_group_names, st->st_oakley.group->group)
+ , tv_diff);
+ }
+
+ DBG_cond_dump_chunk(DBG_CRYPT, "DH shared secret:\n", st->st_shared);
+}
+
+/* if we haven't already done so, compute a local DH secret (st->st_sec) and
+ * the corresponding public value (g). This is emitted as a KE payload.
+ */
+static bool
+build_and_ship_KE(struct state *st, chunk_t *g
+, const struct oakley_group_desc *group, pb_stream *outs, u_int8_t np)
+{
+ if (!st->st_sec_in_use)
+ {
+ u_char tmp[LOCALSECRETSIZE];
+ MP_INT mp_g;
+
+ get_rnd_bytes(tmp, LOCALSECRETSIZE);
+ st->st_sec_in_use = TRUE;
+ n_to_mpz(&st->st_sec, tmp, LOCALSECRETSIZE);
+
+ mpz_init(&mp_g);
+ mpz_powm(&mp_g, &groupgenerator, &st->st_sec, group->modulus);
+ freeanychunk(*g); /* happens in odd error cases */
+ *g = mpz_to_n(&mp_g, group->bytes);
+ mpz_clear(&mp_g);
+ DBG(DBG_CRYPT,
+ DBG_dump("Local DH secret:\n", tmp, LOCALSECRETSIZE);
+ DBG_dump_chunk("Public DH value sent:\n", *g));
+ }
+ return out_generic_chunk(np, &isakmp_keyex_desc, outs, *g, "keyex value");
+}
+
+/* accept_ke
+ *
+ * Check and accept DH public value (Gi or Gr) from peer's message.
+ * According to RFC2409 "The Internet key exchange (IKE)" 5:
+ * The Diffie-Hellman public value passed in a KE payload, in either
+ * a phase 1 or phase 2 exchange, MUST be the length of the negotiated
+ * Diffie-Hellman group enforced, if necessary, by pre-pending the
+ * value with zeros.
+ */
+static notification_t
+accept_KE(chunk_t *dest, const char *val_name
+, const struct oakley_group_desc *gr
+, pb_stream *pbs)
+{
+ if (pbs_left(pbs) != gr->bytes)
+ {
+ loglog(RC_LOG_SERIOUS, "KE has %u byte DH public value; %u required"
+ , (unsigned) pbs_left(pbs), (unsigned) gr->bytes);
+ /* XXX Could send notification back */
+ return INVALID_KEY_INFORMATION;
+ }
+ clonereplacechunk(*dest, pbs->cur, pbs_left(pbs), val_name);
+ DBG_cond_dump_chunk(DBG_CRYPT, "DH public value received:\n", *dest);
+ return NOTHING_WRONG;
+}
+
+/* accept_PFS_KE
+ *
+ * Check and accept optional Quick Mode KE payload for PFS.
+ * Extends ACCEPT_PFS to check whether KE is allowed or required.
+ */
+static notification_t
+accept_PFS_KE(struct msg_digest *md, chunk_t *dest
+, const char *val_name, const char *msg_name)
+{
+ struct state *st = md->st;
+ struct payload_digest *const ke_pd = md->chain[ISAKMP_NEXT_KE];
+
+ if (ke_pd == NULL)
+ {
+ if (st->st_pfs_group != NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "missing KE payload in %s message", msg_name);
+ return INVALID_KEY_INFORMATION;
+ }
+ }
+ else
+ {
+ if (st->st_pfs_group == NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "%s message KE payload requires a GROUP_DESCRIPTION attribute in SA"
+ , msg_name);
+ return INVALID_KEY_INFORMATION;
+ }
+ if (ke_pd->next != NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "%s message contains several KE payloads; we accept at most one", msg_name);
+ return INVALID_KEY_INFORMATION; /* ??? */
+ }
+ return accept_KE(dest, val_name, st->st_pfs_group, &ke_pd->pbs);
+ }
+ return NOTHING_WRONG;
+}
+
+static bool
+build_and_ship_nonce(chunk_t *n, pb_stream *outs, u_int8_t np
+, const char *name)
+{
+ freeanychunk(*n);
+ setchunk(*n, alloc_bytes(DEFAULT_NONCE_SIZE, name), DEFAULT_NONCE_SIZE);
+ get_rnd_bytes(n->ptr, DEFAULT_NONCE_SIZE);
+ return out_generic_chunk(np, &isakmp_nonce_desc, outs, *n, name);
+}
+
+static bool
+collect_rw_ca_candidates(struct msg_digest *md, generalName_t **top)
+{
+ struct connection *d = find_host_connection(&md->iface->addr
+ , pluto_port, (ip_address*)NULL, md->sender_port, LEMPTY);
+
+ for (; d != NULL; d = d->hp_next)
+ {
+ /* must be a road warrior connection */
+ if (d->kind == CK_TEMPLATE && !(d->policy & POLICY_OPPO)
+ && d->spd.that.ca.ptr != NULL)
+ {
+ generalName_t *gn;
+ bool new_entry = TRUE;
+
+ for (gn = *top; gn != NULL; gn = gn->next)
+ {
+ if (same_dn(gn->name, d->spd.that.ca))
+ {
+ new_entry = FALSE;
+ break;
+ }
+ }
+ if (new_entry)
+ {
+ gn = alloc_thing(generalName_t, "generalName");
+ gn->kind = GN_DIRECTORY_NAME;
+ gn->name = d->spd.that.ca;
+ gn->next = *top;
+ *top = gn;
+ }
+ }
+ }
+ return *top != NULL;
+}
+
+static bool
+build_and_ship_CR(u_int8_t type, chunk_t ca, pb_stream *outs, u_int8_t np)
+{
+ pb_stream cr_pbs;
+ struct isakmp_cr cr_hd;
+ cr_hd.isacr_np = np;
+ cr_hd.isacr_type = type;
+
+ /* build CR header */
+ if (!out_struct(&cr_hd, &isakmp_ipsec_cert_req_desc, outs, &cr_pbs))
+ return FALSE;
+
+ if (ca.ptr != NULL)
+ {
+ /* build CR body containing the distinguished name of the CA */
+ if (!out_chunk(ca, &cr_pbs, "CA"))
+ return FALSE;
+ }
+ close_output_pbs(&cr_pbs);
+ return TRUE;
+}
+
+/* Send a notification to the peer. We could decide
+ * whether to send the notification, based on the type and the
+ * destination, if we care to.
+ */
+static void
+send_notification(struct state *sndst, u_int16_t type, struct state *encst,
+ msgid_t msgid, u_char *icookie, u_char *rcookie,
+ u_char *spi, size_t spisize, u_char protoid)
+{
+ u_char buffer[1024];
+ pb_stream pbs, r_hdr_pbs;
+ u_char *r_hashval = NULL; /* where in reply to jam hash value */
+ u_char *r_hash_start = NULL; /* start of what is to be hashed */
+
+ passert((sndst) && (sndst->st_connection));
+
+ plog("sending %snotification %s to %s:%u"
+ , encst ? "encrypted " : ""
+ , enum_name(&notification_names, type)
+ , ip_str(&sndst->st_connection->spd.that.host_addr)
+ , (unsigned)sndst->st_connection->spd.that.host_port);
+
+ memset(buffer, 0, sizeof(buffer));
+ init_pbs(&pbs, buffer, sizeof(buffer), "ISAKMP notify");
+
+ /* HDR* */
+ {
+ struct isakmp_hdr hdr;
+
+ hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION;
+ hdr.isa_np = encst ? ISAKMP_NEXT_HASH : ISAKMP_NEXT_N;
+ hdr.isa_xchg = ISAKMP_XCHG_INFO;
+ hdr.isa_msgid = msgid;
+ hdr.isa_flags = encst ? ISAKMP_FLAG_ENCRYPTION : 0;
+ if (icookie)
+ memcpy(hdr.isa_icookie, icookie, COOKIE_SIZE);
+ if (rcookie)
+ memcpy(hdr.isa_rcookie, rcookie, COOKIE_SIZE);
+ if (!out_struct(&hdr, &isakmp_hdr_desc, &pbs, &r_hdr_pbs))
+ impossible();
+ }
+
+ /* HASH -- value to be filled later */
+ if (encst)
+ {
+ pb_stream hash_pbs;
+ if (!out_generic(ISAKMP_NEXT_N, &isakmp_hash_desc, &r_hdr_pbs,
+ &hash_pbs))
+ impossible();
+ r_hashval = hash_pbs.cur; /* remember where to plant value */
+ if (!out_zero(
+ encst->st_oakley.hasher->hash_digest_size, &hash_pbs, "HASH"))
+ impossible();
+ close_output_pbs(&hash_pbs);
+ r_hash_start = r_hdr_pbs.cur; /* hash from after HASH */
+ }
+
+ /* Notification Payload */
+ {
+ pb_stream not_pbs;
+ struct isakmp_notification isan;
+
+ isan.isan_doi = ISAKMP_DOI_IPSEC;
+ isan.isan_np = ISAKMP_NEXT_NONE;
+ isan.isan_type = type;
+ isan.isan_spisize = spisize;
+ isan.isan_protoid = protoid;
+
+ if (!out_struct(&isan, &isakmp_notification_desc, &r_hdr_pbs, &not_pbs)
+ || !out_raw(spi, spisize, &not_pbs, "spi"))
+ impossible();
+ close_output_pbs(&not_pbs);
+ }
+
+ /* calculate hash value and patch into Hash Payload */
+ if (encst)
+ {
+ struct hmac_ctx ctx;
+ hmac_init_chunk(&ctx, encst->st_oakley.hasher, encst->st_skeyid_a);
+ hmac_update(&ctx, (u_char *) &msgid, sizeof(msgid_t));
+ hmac_update(&ctx, r_hash_start, r_hdr_pbs.cur-r_hash_start);
+ hmac_final(r_hashval, &ctx);
+
+ DBG(DBG_CRYPT,
+ DBG_log("HASH computed:");
+ DBG_dump("", r_hashval, ctx.hmac_digest_size);
+ )
+ }
+
+ /* Encrypt message (preserve st_iv and st_new_iv) */
+ if (encst)
+ {
+ u_char old_iv[MAX_DIGEST_LEN];
+ u_char new_iv[MAX_DIGEST_LEN];
+
+ u_int old_iv_len = encst->st_iv_len;
+ u_int new_iv_len = encst->st_new_iv_len;
+
+ if (old_iv_len > MAX_DIGEST_LEN || new_iv_len > MAX_DIGEST_LEN)
+ impossible();
+
+ memcpy(old_iv, encst->st_iv, old_iv_len);
+ memcpy(new_iv, encst->st_new_iv, new_iv_len);
+
+ if (!IS_ISAKMP_SA_ESTABLISHED(encst->st_state))
+ {
+ memcpy(encst->st_ph1_iv, encst->st_new_iv, encst->st_new_iv_len);
+ encst->st_ph1_iv_len = encst->st_new_iv_len;
+ }
+ init_phase2_iv(encst, &msgid);
+ if (!encrypt_message(&r_hdr_pbs, encst))
+ impossible();
+
+ /* restore preserved st_iv and st_new_iv */
+ memcpy(encst->st_iv, old_iv, old_iv_len);
+ memcpy(encst->st_new_iv, new_iv, new_iv_len);
+ encst->st_iv_len = old_iv_len;
+ encst->st_new_iv_len = new_iv_len;
+ }
+ else
+ {
+ close_output_pbs(&r_hdr_pbs);
+ }
+
+ /* Send packet (preserve st_tpacket) */
+ {
+ chunk_t saved_tpacket = sndst->st_tpacket;
+
+ setchunk(sndst->st_tpacket, pbs.start, pbs_offset(&pbs));
+ send_packet(sndst, "ISAKMP notify");
+ sndst->st_tpacket = saved_tpacket;
+ }
+}
+
+void
+send_notification_from_state(struct state *st, enum state_kind state,
+ u_int16_t type)
+{
+ struct state *p1st;
+
+ passert(st);
+
+ if (state == STATE_UNDEFINED)
+ state = st->st_state;
+
+ if (IS_QUICK(state))
+ {
+ p1st = find_phase1_state(st->st_connection, ISAKMP_SA_ESTABLISHED_STATES);
+ if ((p1st == NULL) || (!IS_ISAKMP_SA_ESTABLISHED(p1st->st_state)))
+ {
+ loglog(RC_LOG_SERIOUS,
+ "no Phase1 state for Quick mode notification");
+ return;
+ }
+ send_notification(st, type, p1st, generate_msgid(p1st),
+ st->st_icookie, st->st_rcookie, NULL, 0, PROTO_ISAKMP);
+ }
+ else if (IS_ISAKMP_ENCRYPTED(state) && st->st_enc_key.ptr != NULL)
+ {
+ send_notification(st, type, st, generate_msgid(st),
+ st->st_icookie, st->st_rcookie, NULL, 0, PROTO_ISAKMP);
+ }
+ else
+ {
+ /* no ISAKMP SA established - don't encrypt notification */
+ send_notification(st, type, NULL, 0,
+ st->st_icookie, st->st_rcookie, NULL, 0, PROTO_ISAKMP);
+ }
+}
+
+void
+send_notification_from_md(struct msg_digest *md, u_int16_t type)
+{
+ /**
+ * Create a dummy state to be able to use send_packet in
+ * send_notification
+ *
+ * we need to set:
+ * st_connection->that.host_addr
+ * st_connection->that.host_port
+ * st_connection->interface
+ */
+ struct state st;
+ struct connection cnx;
+
+ passert(md);
+
+ memset(&st, 0, sizeof(st));
+ memset(&cnx, 0, sizeof(cnx));
+ st.st_connection = &cnx;
+ cnx.spd.that.host_addr = md->sender;
+ cnx.spd.that.host_port = md->sender_port;
+ cnx.interface = md->iface;
+
+ send_notification(&st, type, NULL, 0,
+ md->hdr.isa_icookie, md->hdr.isa_rcookie, NULL, 0, PROTO_ISAKMP);
+}
+
+/* Send a Delete Notification to announce deletion of ISAKMP SA or
+ * inbound IPSEC SAs. Does nothing if no such SAs are being deleted.
+ * Delete Notifications cannot announce deletion of outbound IPSEC/ISAKMP SAs.
+ */
+void
+send_delete(struct state *st)
+{
+ pb_stream reply_pbs;
+ pb_stream r_hdr_pbs;
+ msgid_t msgid;
+ u_char buffer[8192];
+ struct state *p1st;
+ ip_said said[EM_MAXRELSPIS];
+ ip_said *ns = said;
+ u_char
+ *r_hashval, /* where in reply to jam hash value */
+ *r_hash_start; /* start of what is to be hashed */
+ bool isakmp_sa = FALSE;
+
+ if (IS_IPSEC_SA_ESTABLISHED(st->st_state))
+ {
+ p1st = find_phase1_state(st->st_connection, ISAKMP_SA_ESTABLISHED_STATES);
+ if (p1st == NULL)
+ {
+ DBG(DBG_CONTROL, DBG_log("no Phase 1 state for Delete"));
+ return;
+ }
+
+ if (st->st_ah.present)
+ {
+ ns->spi = st->st_ah.our_spi;
+ ns->dst = st->st_connection->spd.this.host_addr;
+ ns->proto = PROTO_IPSEC_AH;
+ ns++;
+ }
+ if (st->st_esp.present)
+ {
+ ns->spi = st->st_esp.our_spi;
+ ns->dst = st->st_connection->spd.this.host_addr;
+ ns->proto = PROTO_IPSEC_ESP;
+ ns++;
+ }
+
+ passert(ns != said); /* there must be some SAs to delete */
+ }
+ else if (IS_ISAKMP_SA_ESTABLISHED(st->st_state))
+ {
+ p1st = st;
+ isakmp_sa = TRUE;
+ }
+ else
+ {
+ return; /* nothing to do */
+ }
+
+ msgid = generate_msgid(p1st);
+
+ zero(buffer);
+ init_pbs(&reply_pbs, buffer, sizeof(buffer), "delete msg");
+
+ /* HDR* */
+ {
+ struct isakmp_hdr hdr;
+
+ hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION;
+ hdr.isa_np = ISAKMP_NEXT_HASH;
+ hdr.isa_xchg = ISAKMP_XCHG_INFO;
+ hdr.isa_msgid = msgid;
+ hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION;
+ memcpy(hdr.isa_icookie, p1st->st_icookie, COOKIE_SIZE);
+ memcpy(hdr.isa_rcookie, p1st->st_rcookie, COOKIE_SIZE);
+ if (!out_struct(&hdr, &isakmp_hdr_desc, &reply_pbs, &r_hdr_pbs))
+ impossible();
+ }
+
+ /* HASH -- value to be filled later */
+ {
+ pb_stream hash_pbs;
+
+ if (!out_generic(ISAKMP_NEXT_D, &isakmp_hash_desc, &r_hdr_pbs, &hash_pbs))
+ impossible();
+ r_hashval = hash_pbs.cur; /* remember where to plant value */
+ if (!out_zero(p1st->st_oakley.hasher->hash_digest_size, &hash_pbs, "HASH(1)"))
+ impossible();
+ close_output_pbs(&hash_pbs);
+ r_hash_start = r_hdr_pbs.cur; /* hash from after HASH(1) */
+ }
+
+ /* Delete Payloads */
+ if (isakmp_sa)
+ {
+ pb_stream del_pbs;
+ struct isakmp_delete isad;
+ u_char isakmp_spi[2*COOKIE_SIZE];
+
+ isad.isad_doi = ISAKMP_DOI_IPSEC;
+ isad.isad_np = ISAKMP_NEXT_NONE;
+ isad.isad_spisize = (2 * COOKIE_SIZE);
+ isad.isad_protoid = PROTO_ISAKMP;
+ isad.isad_nospi = 1;
+
+ memcpy(isakmp_spi, st->st_icookie, COOKIE_SIZE);
+ memcpy(isakmp_spi+COOKIE_SIZE, st->st_rcookie, COOKIE_SIZE);
+
+ if (!out_struct(&isad, &isakmp_delete_desc, &r_hdr_pbs, &del_pbs)
+ || !out_raw(&isakmp_spi, (2*COOKIE_SIZE), &del_pbs, "delete payload"))
+ impossible();
+ close_output_pbs(&del_pbs);
+ }
+ else
+ {
+ while (ns != said)
+ {
+
+ pb_stream del_pbs;
+ struct isakmp_delete isad;
+
+ ns--;
+ isad.isad_doi = ISAKMP_DOI_IPSEC;
+ isad.isad_np = ns == said? ISAKMP_NEXT_NONE : ISAKMP_NEXT_D;
+ isad.isad_spisize = sizeof(ipsec_spi_t);
+ isad.isad_protoid = ns->proto;
+
+ isad.isad_nospi = 1;
+ if (!out_struct(&isad, &isakmp_delete_desc, &r_hdr_pbs, &del_pbs)
+ || !out_raw(&ns->spi, sizeof(ipsec_spi_t), &del_pbs, "delete payload"))
+ impossible();
+ close_output_pbs(&del_pbs);
+ }
+ }
+
+ /* calculate hash value and patch into Hash Payload */
+ {
+ struct hmac_ctx ctx;
+ hmac_init_chunk(&ctx, p1st->st_oakley.hasher, p1st->st_skeyid_a);
+ hmac_update(&ctx, (u_char *) &msgid, sizeof(msgid_t));
+ hmac_update(&ctx, r_hash_start, r_hdr_pbs.cur-r_hash_start);
+ hmac_final(r_hashval, &ctx);
+
+ DBG(DBG_CRYPT,
+ DBG_log("HASH(1) computed:");
+ DBG_dump("", r_hashval, ctx.hmac_digest_size);
+ )
+ }
+
+ /* Do a dance to avoid needing a new state object.
+ * We use the Phase 1 State. This is the one with right
+ * IV, for one thing.
+ * The tricky bits are:
+ * - we need to preserve (save/restore) st_iv (but not st_iv_new)
+ * - we need to preserve (save/restore) st_tpacket.
+ */
+ {
+ u_char old_iv[MAX_DIGEST_LEN];
+ chunk_t saved_tpacket = p1st->st_tpacket;
+
+ memcpy(old_iv, p1st->st_iv, p1st->st_iv_len);
+ init_phase2_iv(p1st, &msgid);
+
+ if (!encrypt_message(&r_hdr_pbs, p1st))
+ impossible();
+
+ setchunk(p1st->st_tpacket, reply_pbs.start, pbs_offset(&reply_pbs));
+ send_packet(p1st, "delete notify");
+ p1st->st_tpacket = saved_tpacket;
+
+ /* get back old IV for this state */
+ memcpy(p1st->st_iv, old_iv, p1st->st_iv_len);
+ }
+}
+
+void
+accept_delete(struct state *st, struct msg_digest *md, struct payload_digest *p)
+{
+ struct isakmp_delete *d = &(p->payload.delete);
+ size_t sizespi;
+ int i;
+
+ if (!md->encrypted)
+ {
+ loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: not encrypted");
+ return;
+ }
+
+ if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state))
+ {
+ /* can't happen (if msg is encrypt), but just to be sure */
+ loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: "
+ "ISAKMP SA not established");
+ return;
+ }
+
+ if (d->isad_nospi == 0)
+ {
+ loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: no SPI");
+ return;
+ }
+
+ switch (d->isad_protoid)
+ {
+ case PROTO_ISAKMP:
+ sizespi = 2 * COOKIE_SIZE;
+ break;
+ case PROTO_IPSEC_AH:
+ case PROTO_IPSEC_ESP:
+ sizespi = sizeof(ipsec_spi_t);
+ break;
+ case PROTO_IPCOMP:
+ /* nothing interesting to delete */
+ return;
+ default:
+ loglog(RC_LOG_SERIOUS
+ , "ignoring Delete SA payload: unknown Protocol ID (%s)"
+ , enum_show(&protocol_names, d->isad_protoid));
+ return;
+ }
+
+ if (d->isad_spisize != sizespi)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "ignoring Delete SA payload: bad SPI size (%d) for %s"
+ , d->isad_spisize, enum_show(&protocol_names, d->isad_protoid));
+ return;
+ }
+
+ if (pbs_left(&p->pbs) != d->isad_nospi * sizespi)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "ignoring Delete SA payload: invalid payload size");
+ return;
+ }
+
+ for (i = 0; i < d->isad_nospi; i++)
+ {
+ u_char *spi = p->pbs.cur + (i * sizespi);
+
+ if (d->isad_protoid == PROTO_ISAKMP)
+ {
+ /**
+ * ISAKMP
+ */
+ struct state *dst = find_state(spi /*iCookie*/
+ , spi+COOKIE_SIZE /*rCookie*/
+ , &st->st_connection->spd.that.host_addr
+ , MAINMODE_MSGID);
+
+ if (dst == NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: "
+ "ISAKMP SA not found (maybe expired)");
+ }
+ else if (!same_peer_ids(st->st_connection, dst->st_connection, NULL))
+ {
+ /* we've not authenticated the relevant identities */
+ loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: "
+ "ISAKMP SA used to convey Delete has different IDs from ISAKMP SA it deletes");
+ }
+ else
+ {
+ struct connection *oldc;
+
+ oldc = cur_connection;
+ set_cur_connection(dst->st_connection);
+
+ if (nat_traversal_enabled)
+ nat_traversal_change_port_lookup(md, dst);
+
+ loglog(RC_LOG_SERIOUS, "received Delete SA payload: "
+ "deleting ISAKMP State #%lu", dst->st_serialno);
+ delete_state(dst);
+ set_cur_connection(oldc);
+ }
+ }
+ else
+ {
+ /**
+ * IPSEC (ESP/AH)
+ */
+ bool bogus;
+ struct state *dst = find_phase2_state_to_delete(st
+ , d->isad_protoid
+ , *(ipsec_spi_t *)spi /* network order */
+ , &bogus);
+
+ if (dst == NULL)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "ignoring Delete SA payload: %s SA(0x%08lx) not found (%s)"
+ , enum_show(&protocol_names, d->isad_protoid)
+ , (unsigned long)ntohl((unsigned long)*(ipsec_spi_t *)spi)
+ , bogus ? "our SPI - bogus implementation" : "maybe expired");
+ }
+ else
+ {
+ struct connection *rc = dst->st_connection;
+ struct connection *oldc;
+
+ oldc = cur_connection;
+ set_cur_connection(rc);
+
+ if (nat_traversal_enabled)
+ nat_traversal_change_port_lookup(md, dst);
+
+ if (rc->newest_ipsec_sa == dst->st_serialno
+ && (rc->policy & POLICY_UP))
+ {
+ /* Last IPSec SA for a permanent connection that we
+ * have initiated. Replace it in a few seconds.
+ *
+ * Useful if the other peer is rebooting.
+ */
+#define DELETE_SA_DELAY EVENT_RETRANSMIT_DELAY_0
+ if (dst->st_event != NULL
+ && dst->st_event->ev_type == EVENT_SA_REPLACE
+ && dst->st_event->ev_time <= DELETE_SA_DELAY + now())
+ {
+ /* Patch from Angus Lees to ignore retransmited
+ * Delete SA.
+ */
+ loglog(RC_LOG_SERIOUS, "received Delete SA payload: "
+ "already replacing IPSEC State #%lu in %d seconds"
+ , dst->st_serialno, (int)(dst->st_event->ev_time - now()));
+ }
+ else
+ {
+ loglog(RC_LOG_SERIOUS, "received Delete SA payload: "
+ "replace IPSEC State #%lu in %d seconds"
+ , dst->st_serialno, DELETE_SA_DELAY);
+ dst->st_margin = DELETE_SA_DELAY;
+ delete_event(dst);
+ event_schedule(EVENT_SA_REPLACE, DELETE_SA_DELAY, dst);
+ }
+ }
+ else
+ {
+ loglog(RC_LOG_SERIOUS, "received Delete SA(0x%08lx) payload: "
+ "deleting IPSEC State #%lu"
+ , (unsigned long)ntohl((unsigned long)*(ipsec_spi_t *)spi)
+ , dst->st_serialno);
+ delete_state(dst);
+ }
+
+ /* reset connection */
+ set_cur_connection(oldc);
+ }
+ }
+ }
+}
+
+/* The whole message must be a multiple of 4 octets.
+ * I'm not sure where this is spelled out, but look at
+ * rfc2408 3.6 Transform Payload.
+ * Note: it talks about 4 BYTE boundaries!
+ */
+void
+close_message(pb_stream *pbs)
+{
+ size_t padding = pad_up(pbs_offset(pbs), 4);
+
+ if (padding != 0)
+ (void) out_zero(padding, pbs, "message padding");
+ close_output_pbs(pbs);
+}
+
+/* Initiate an Oakley Main Mode exchange.
+ * --> HDR;SA
+ * Note: this is not called from demux.c
+ */
+static stf_status
+main_outI1(int whack_sock, struct connection *c, struct state *predecessor
+ , lset_t policy, unsigned long try)
+{
+ struct state *st = new_state();
+ pb_stream reply; /* not actually a reply, but you know what I mean */
+ pb_stream rbody;
+
+ int vids_to_send = 0;
+
+ /* set up new state */
+ st->st_connection = c;
+ set_cur_state(st); /* we must reset before exit */
+ st->st_policy = policy & ~POLICY_IPSEC_MASK;
+ st->st_whack_sock = whack_sock;
+ st->st_try = try;
+ st->st_state = STATE_MAIN_I1;
+
+ /* determine how many Vendor ID payloads we will be sending */
+ if (SEND_PLUTO_VID)
+ vids_to_send++;
+ if (SEND_CISCO_UNITY_VID)
+ vids_to_send++;
+ if (c->spd.this.cert.type == CERT_PGP)
+ vids_to_send++;
+ /* always send XAUTH Vendor ID */
+ vids_to_send++;
+ /* always send DPD Vendor ID */
+ vids_to_send++;
+ if (nat_traversal_enabled)
+ vids_to_send++;
+
+ get_cookie(TRUE, st->st_icookie, COOKIE_SIZE, &c->spd.that.host_addr);
+
+ insert_state(st); /* needs cookies, connection, and msgid (0) */
+
+ if (HAS_IPSEC_POLICY(policy))
+ add_pending(dup_any(whack_sock), st, c, policy, 1
+ , predecessor == NULL? SOS_NOBODY : predecessor->st_serialno);
+
+ if (predecessor == NULL)
+ plog("initiating Main Mode");
+ else
+ plog("initiating Main Mode to replace #%lu", predecessor->st_serialno);
+
+ /* set up reply */
+ init_pbs(&reply, reply_buffer, sizeof(reply_buffer), "reply packet");
+
+ /* HDR out */
+ {
+ struct isakmp_hdr hdr;
+
+ zero(&hdr); /* default to 0 */
+ hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION;
+ hdr.isa_np = ISAKMP_NEXT_SA;
+ hdr.isa_xchg = ISAKMP_XCHG_IDPROT;
+ memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE);
+ /* R-cookie, flags and MessageID are left zero */
+
+ if (!out_struct(&hdr, &isakmp_hdr_desc, &reply, &rbody))
+ {
+ reset_cur_state();
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+ /* SA out */
+ {
+ u_char *sa_start = rbody.cur;
+ lset_t auth_policy = policy & POLICY_ID_AUTH_MASK;
+
+ if (!out_sa(&rbody, &oakley_sadb, st, TRUE
+ , vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE))
+ {
+ reset_cur_state();
+ return STF_INTERNAL_ERROR;
+ }
+
+ /* save initiator SA for later HASH */
+ passert(st->st_p1isa.ptr == NULL); /* no leak! (MUST be first time) */
+ clonetochunk(st->st_p1isa, sa_start, rbody.cur - sa_start
+ , "sa in main_outI1");
+ }
+
+ /* if enabled send Pluto Vendor ID */
+ if (SEND_PLUTO_VID)
+ {
+ if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE
+ , &rbody, VID_STRONGSWAN))
+ {
+ reset_cur_state();
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+ /* if enabled send Cisco Unity Vendor ID */
+ if (SEND_CISCO_UNITY_VID)
+ {
+ if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE
+ , &rbody, VID_CISCO_UNITY))
+ {
+ reset_cur_state();
+ return STF_INTERNAL_ERROR;
+ }
+ }
+ /* if we have an OpenPGP certificate we assume an
+ * OpenPGP peer and have to send the Vendor ID
+ */
+ if (c->spd.this.cert.type == CERT_PGP)
+ {
+ if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE
+ , &rbody, VID_OPENPGP))
+ {
+ reset_cur_state();
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+ /* Announce our ability to do eXtended AUTHentication to the peer */
+ if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE
+ , &rbody, VID_MISC_XAUTH))
+ {
+ reset_cur_state();
+ return STF_INTERNAL_ERROR;
+ }
+
+ /* Announce our ability to do Dead Peer Detection to the peer */
+ {
+ if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE
+ , &rbody, VID_MISC_DPD))
+ {
+ reset_cur_state();
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+ if (nat_traversal_enabled)
+ {
+ /* Add supported NAT-Traversal VID */
+ if (!nat_traversal_add_vid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE
+ , &rbody))
+ {
+ reset_cur_state();
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+ close_message(&rbody);
+ close_output_pbs(&reply);
+
+ clonetochunk(st->st_tpacket, reply.start, pbs_offset(&reply)
+ , "reply packet for main_outI1");
+
+ /* Transmit */
+
+ send_packet(st, "main_outI1");
+
+ /* Set up a retransmission event, half a minute henceforth */
+ delete_event(st);
+ event_schedule(EVENT_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0, st);
+
+ if (predecessor != NULL)
+ {
+ update_pending(predecessor, st);
+ whack_log(RC_NEW_STATE + STATE_MAIN_I1
+ , "%s: initiate, replacing #%lu"
+ , enum_name(&state_names, st->st_state)
+ , predecessor->st_serialno);
+ }
+ else
+ {
+ whack_log(RC_NEW_STATE + STATE_MAIN_I1
+ , "%s: initiate", enum_name(&state_names, st->st_state));
+ }
+ reset_cur_state();
+ return STF_OK;
+}
+
+void
+ipsecdoi_initiate(int whack_sock
+, struct connection *c
+, lset_t policy
+, unsigned long try
+, so_serial_t replacing)
+{
+ /* If there's already an ISAKMP SA established, use that and
+ * go directly to Quick Mode. We are even willing to use one
+ * that is still being negotiated, but only if we are the Initiator
+ * (thus we can be sure that the IDs are not going to change;
+ * other issues around intent might matter).
+ * Note: there is no way to initiate with a Road Warrior.
+ */
+ struct state *st = find_phase1_state(c
+ , ISAKMP_SA_ESTABLISHED_STATES | PHASE1_INITIATOR_STATES);
+
+ if (st == NULL)
+ {
+ (void) main_outI1(whack_sock, c, NULL, policy, try);
+ }
+ else if (HAS_IPSEC_POLICY(policy))
+ {
+ if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state))
+ {
+ /* leave our Phase 2 negotiation pending */
+ add_pending(whack_sock, st, c, policy, try, replacing);
+ }
+ else
+ {
+ /* ??? we assume that peer_nexthop_sin isn't important:
+ * we already have it from when we negotiated the ISAKMP SA!
+ * It isn't clear what to do with the error return.
+ */
+ (void) quick_outI1(whack_sock, st, c, policy, try, replacing);
+ }
+ }
+ else
+ {
+ close_any(whack_sock);
+ }
+}
+
+/* Replace SA with a fresh one that is similar
+ *
+ * Shares some logic with ipsecdoi_initiate, but not the same!
+ * - we must not reuse the ISAKMP SA if we are trying to replace it!
+ * - if trying to replace IPSEC SA, use ipsecdoi_initiate to build
+ * ISAKMP SA if needed.
+ * - duplicate whack fd, if live.
+ * Does not delete the old state -- someone else will do that.
+ */
+void
+ipsecdoi_replace(struct state *st, unsigned long try)
+{
+ int whack_sock = dup_any(st->st_whack_sock);
+ lset_t policy = st->st_policy;
+
+ if (IS_PHASE1(st->st_state))
+ {
+ passert(!HAS_IPSEC_POLICY(policy));
+ (void) main_outI1(whack_sock, st->st_connection, st, policy, try);
+ }
+ else
+ {
+ /* Add features of actual old state to policy. This ensures
+ * that rekeying doesn't downgrade security. I admit that
+ * this doesn't capture everything.
+ */
+ if (st->st_pfs_group != NULL)
+ policy |= POLICY_PFS;
+ if (st->st_ah.present)
+ {
+ policy |= POLICY_AUTHENTICATE;
+ if (st->st_ah.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL)
+ policy |= POLICY_TUNNEL;
+ }
+ if (st->st_esp.present && st->st_esp.attrs.transid != ESP_NULL)
+ {
+ policy |= POLICY_ENCRYPT;
+ if (st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL)
+ policy |= POLICY_TUNNEL;
+ }
+ if (st->st_ipcomp.present)
+ {
+ policy |= POLICY_COMPRESS;
+ if (st->st_ipcomp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL)
+ policy |= POLICY_TUNNEL;
+ }
+ passert(HAS_IPSEC_POLICY(policy));
+ ipsecdoi_initiate(whack_sock, st->st_connection, policy, try
+ , st->st_serialno);
+ }
+}
+
+/* SKEYID for preshared keys.
+ * See draft-ietf-ipsec-ike-01.txt 4.1
+ */
+static bool
+skeyid_preshared(struct state *st)
+{
+ const chunk_t *pss = get_preshared_secret(st->st_connection);
+
+ if (pss == NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "preshared secret disappeared!");
+ return FALSE;
+ }
+ else
+ {
+ struct hmac_ctx ctx;
+
+ hmac_init_chunk(&ctx, st->st_oakley.hasher, *pss);
+ hmac_update_chunk(&ctx, st->st_ni);
+ hmac_update_chunk(&ctx, st->st_nr);
+ hmac_final_chunk(st->st_skeyid, "st_skeyid in skeyid_preshared()", &ctx);
+ return TRUE;
+ }
+}
+
+static bool
+skeyid_digisig(struct state *st)
+{
+ struct hmac_ctx ctx;
+ chunk_t nir;
+
+ /* We need to hmac_init with the concatenation of Ni_b and Nr_b,
+ * so we have to build a temporary concatentation.
+ */
+ nir.len = st->st_ni.len + st->st_nr.len;
+ nir.ptr = alloc_bytes(nir.len, "Ni + Nr in skeyid_digisig");
+ memcpy(nir.ptr, st->st_ni.ptr, st->st_ni.len);
+ memcpy(nir.ptr+st->st_ni.len, st->st_nr.ptr, st->st_nr.len);
+ hmac_init_chunk(&ctx, st->st_oakley.hasher, nir);
+ pfree(nir.ptr);
+
+ hmac_update_chunk(&ctx, st->st_shared);
+ hmac_final_chunk(st->st_skeyid, "st_skeyid in skeyid_digisig()", &ctx);
+ return TRUE;
+}
+
+/* Generate the SKEYID_* and new IV
+ * See draft-ietf-ipsec-ike-01.txt 4.1
+ */
+static bool
+generate_skeyids_iv(struct state *st)
+{
+ /* Generate the SKEYID */
+ switch (st->st_oakley.auth)
+ {
+ case OAKLEY_PRESHARED_KEY:
+ case XAUTHInitPreShared:
+ case XAUTHRespPreShared:
+ if (!skeyid_preshared(st))
+ return FALSE;
+ break;
+
+ case OAKLEY_RSA_SIG:
+ case XAUTHInitRSA:
+ case XAUTHRespRSA:
+ if (!skeyid_digisig(st))
+ return FALSE;
+ break;
+
+ case OAKLEY_DSS_SIG:
+ /* XXX */
+
+ case OAKLEY_RSA_ENC:
+ case OAKLEY_RSA_ENC_REV:
+ case OAKLEY_ELGAMAL_ENC:
+ case OAKLEY_ELGAMAL_ENC_REV:
+ /* XXX */
+
+ default:
+ bad_case(st->st_oakley.auth);
+ }
+
+ /* generate SKEYID_* from SKEYID */
+ {
+ struct hmac_ctx ctx;
+
+ hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid);
+
+ /* SKEYID_D */
+ hmac_update_chunk(&ctx, st->st_shared);
+ hmac_update(&ctx, st->st_icookie, COOKIE_SIZE);
+ hmac_update(&ctx, st->st_rcookie, COOKIE_SIZE);
+ hmac_update(&ctx, "\0", 1);
+ hmac_final_chunk(st->st_skeyid_d, "st_skeyid_d in generate_skeyids_iv()", &ctx);
+
+ /* SKEYID_A */
+ hmac_reinit(&ctx);
+ hmac_update_chunk(&ctx, st->st_skeyid_d);
+ hmac_update_chunk(&ctx, st->st_shared);
+ hmac_update(&ctx, st->st_icookie, COOKIE_SIZE);
+ hmac_update(&ctx, st->st_rcookie, COOKIE_SIZE);
+ hmac_update(&ctx, "\1", 1);
+ hmac_final_chunk(st->st_skeyid_a, "st_skeyid_a in generate_skeyids_iv()", &ctx);
+
+ /* SKEYID_E */
+ hmac_reinit(&ctx);
+ hmac_update_chunk(&ctx, st->st_skeyid_a);
+ hmac_update_chunk(&ctx, st->st_shared);
+ hmac_update(&ctx, st->st_icookie, COOKIE_SIZE);
+ hmac_update(&ctx, st->st_rcookie, COOKIE_SIZE);
+ hmac_update(&ctx, "\2", 1);
+ hmac_final_chunk(st->st_skeyid_e, "st_skeyid_e in generate_skeyids_iv()", &ctx);
+ }
+
+ /* generate IV */
+ {
+ union hash_ctx hash_ctx;
+ const struct hash_desc *h = st->st_oakley.hasher;
+
+ st->st_new_iv_len = h->hash_digest_size;
+ passert(st->st_new_iv_len <= sizeof(st->st_new_iv));
+
+ DBG(DBG_CRYPT,
+ DBG_dump_chunk("DH_i:", st->st_gi);
+ DBG_dump_chunk("DH_r:", st->st_gr);
+ );
+ h->hash_init(&hash_ctx);
+ h->hash_update(&hash_ctx, st->st_gi.ptr, st->st_gi.len);
+ h->hash_update(&hash_ctx, st->st_gr.ptr, st->st_gr.len);
+ h->hash_final(st->st_new_iv, &hash_ctx);
+ }
+
+ /* Oakley Keying Material
+ * Derived from Skeyid_e: if it is not big enough, generate more
+ * using the PRF.
+ * See RFC 2409 "IKE" Appendix B
+ */
+ {
+ /* const size_t keysize = st->st_oakley.encrypter->keydeflen/BITS_PER_BYTE; */
+ const size_t keysize = st->st_oakley.enckeylen/BITS_PER_BYTE;
+ u_char keytemp[MAX_OAKLEY_KEY_LEN + MAX_DIGEST_LEN];
+ u_char *k = st->st_skeyid_e.ptr;
+
+ if (keysize > st->st_skeyid_e.len)
+ {
+ struct hmac_ctx ctx;
+ size_t i = 0;
+
+ hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid_e);
+ hmac_update(&ctx, "\0", 1);
+ for (;;)
+ {
+ hmac_final(&keytemp[i], &ctx);
+ i += ctx.hmac_digest_size;
+ if (i >= keysize)
+ break;
+ hmac_reinit(&ctx);
+ hmac_update(&ctx, &keytemp[i - ctx.hmac_digest_size], ctx.hmac_digest_size);
+ }
+ k = keytemp;
+ }
+ clonereplacechunk(st->st_enc_key, k, keysize, "st_enc_key");
+ }
+
+ DBG(DBG_CRYPT,
+ DBG_dump_chunk("Skeyid: ", st->st_skeyid);
+ DBG_dump_chunk("Skeyid_d:", st->st_skeyid_d);
+ DBG_dump_chunk("Skeyid_a:", st->st_skeyid_a);
+ DBG_dump_chunk("Skeyid_e:", st->st_skeyid_e);
+ DBG_dump_chunk("enc key:", st->st_enc_key);
+ DBG_dump("IV:", st->st_new_iv, st->st_new_iv_len));
+ return TRUE;
+}
+
+/* Generate HASH_I or HASH_R for ISAKMP Phase I.
+ * This will *not* generate other hash payloads (eg. Phase II or Quick Mode,
+ * New Group Mode, or ISAKMP Informational Exchanges).
+ * If the hashi argument is TRUE, generate HASH_I; if FALSE generate HASH_R.
+ * If hashus argument is TRUE, we're generating a hash for our end.
+ * See RFC2409 IKE 5.
+ *
+ * Generating the SIG_I and SIG_R for DSS is an odd perversion of this:
+ * Most of the logic is the same, but SHA-1 is used in place of HMAC-whatever.
+ * The extensive common logic is embodied in main_mode_hash_body().
+ * See draft-ietf-ipsec-ike-01.txt 4.1 and 6.1.1.2
+ */
+
+typedef void (*hash_update_t)(union hash_ctx *, const u_char *, size_t) ;
+static void
+main_mode_hash_body(struct state *st
+, bool hashi /* Initiator? */
+, const pb_stream *idpl /* ID payload, as PBS */
+, union hash_ctx *ctx
+, void (*hash_update_void)(void *, const u_char *input, size_t))
+{
+#define HASH_UPDATE_T (union hash_ctx *, const u_char *input, unsigned int len)
+ hash_update_t hash_update=(hash_update_t) hash_update_void;
+#if 0 /* if desperate to debug hashing */
+# define hash_update(ctx, input, len) { \
+ DBG_dump("hash input", input, len); \
+ (hash_update)(ctx, input, len); \
+ }
+#endif
+
+# define hash_update_chunk(ctx, ch) hash_update((ctx), (ch).ptr, (ch).len)
+
+ if (hashi)
+ {
+ hash_update_chunk(ctx, st->st_gi);
+ hash_update_chunk(ctx, st->st_gr);
+ hash_update(ctx, st->st_icookie, COOKIE_SIZE);
+ hash_update(ctx, st->st_rcookie, COOKIE_SIZE);
+ }
+ else
+ {
+ hash_update_chunk(ctx, st->st_gr);
+ hash_update_chunk(ctx, st->st_gi);
+ hash_update(ctx, st->st_rcookie, COOKIE_SIZE);
+ hash_update(ctx, st->st_icookie, COOKIE_SIZE);
+ }
+
+ DBG(DBG_CRYPT, DBG_log("hashing %lu bytes of SA"
+ , (unsigned long) (st->st_p1isa.len - sizeof(struct isakmp_generic))));
+
+ /* SA_b */
+ hash_update(ctx, st->st_p1isa.ptr + sizeof(struct isakmp_generic)
+ , st->st_p1isa.len - sizeof(struct isakmp_generic));
+
+ /* Hash identification payload, without generic payload header.
+ * We used to reconstruct ID Payload for this purpose, but now
+ * we use the bytes as they appear on the wire to avoid
+ * "spelling problems".
+ */
+ hash_update(ctx
+ , idpl->start + sizeof(struct isakmp_generic)
+ , pbs_offset(idpl) - sizeof(struct isakmp_generic));
+
+# undef hash_update_chunk
+# undef hash_update
+}
+
+static size_t /* length of hash */
+main_mode_hash(struct state *st
+, u_char *hash_val /* resulting bytes */
+, bool hashi /* Initiator? */
+, const pb_stream *idpl) /* ID payload, as PBS; cur must be at end */
+{
+ struct hmac_ctx ctx;
+
+ hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid);
+ main_mode_hash_body(st, hashi, idpl, &ctx.hash_ctx, ctx.h->hash_update);
+ hmac_final(hash_val, &ctx);
+ return ctx.hmac_digest_size;
+}
+
+#if 0 /* only needed for DSS */
+static void
+main_mode_sha1(struct state *st
+, u_char *hash_val /* resulting bytes */
+, size_t *hash_len /* length of hash */
+, bool hashi /* Initiator? */
+, const pb_stream *idpl) /* ID payload, as PBS */
+{
+ union hash_ctx ctx;
+
+ SHA1Init(&ctx.ctx_sha1);
+ SHA1Update(&ctx.ctx_sha1, st->st_skeyid.ptr, st->st_skeyid.len);
+ *hash_len = SHA1_DIGEST_SIZE;
+ main_mode_hash_body(st, hashi, idpl, &ctx
+ , (void (*)(union hash_ctx *, const u_char *, unsigned int))&SHA1Update);
+ SHA1Final(hash_val, &ctx.ctx_sha1);
+}
+#endif
+
+/* Create an RSA signature of a hash.
+ * Poorly specified in draft-ietf-ipsec-ike-01.txt 6.1.1.2.
+ * Use PKCS#1 version 1.5 encryption of hash (called
+ * RSAES-PKCS1-V1_5) in PKCS#2.
+ */
+static size_t
+RSA_sign_hash(struct connection *c
+, u_char sig_val[RSA_MAX_OCTETS]
+, const u_char *hash_val, size_t hash_len)
+{
+ size_t sz = 0;
+ smartcard_t *sc = c->spd.this.sc;
+
+ if (sc == NULL) /* no smartcard */
+ {
+ const struct RSA_private_key *k = get_RSA_private_key(c);
+
+ if (k == NULL)
+ return 0; /* failure: no key to use */
+
+ sz = k->pub.k;
+ passert(RSA_MIN_OCTETS <= sz && 4 + hash_len < sz && sz <= RSA_MAX_OCTETS);
+ sign_hash(k, hash_val, hash_len, sig_val, sz);
+ }
+ else if (sc->valid) /* if valid pin then sign hash on the smartcard */
+ {
+ lock_certs_and_keys("RSA_sign_hash");
+ if (!scx_establish_context(sc) || !scx_login(sc))
+ {
+ scx_release_context(sc);
+ unlock_certs_and_keys("RSA_sign_hash");
+ return 0;
+ }
+
+ sz = scx_get_keylength(sc);
+ if (sz == 0)
+ {
+ plog("failed to get keylength from smartcard");
+ scx_release_context(sc);
+ unlock_certs_and_keys("RSA_sign_hash");
+ return 0;
+ }
+
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ DBG_log("signing hash with RSA key from smartcard (slot: %d, id: %s)"
+ , (int)sc->slot, sc->id)
+ )
+ sz = scx_sign_hash(sc, hash_val, hash_len, sig_val, sz) ? sz : 0;
+ if (!pkcs11_keep_state)
+ scx_release_context(sc);
+ unlock_certs_and_keys("RSA_sign_hash");
+ }
+ return sz;
+}
+
+/* Check a Main Mode RSA Signature against computed hash using RSA public key k.
+ *
+ * As a side effect, on success, the public key is copied into the
+ * state object to record the authenticator.
+ *
+ * Can fail because wrong public key is used or because hash disagrees.
+ * We distinguish because diagnostics should also.
+ *
+ * The result is NULL if the Signature checked out.
+ * Otherwise, the first character of the result indicates
+ * how far along failure occurred. A greater character signifies
+ * greater progress.
+ *
+ * Classes:
+ * 0 reserved for caller
+ * 1 SIG length doesn't match key length -- wrong key
+ * 2-8 malformed ECB after decryption -- probably wrong key
+ * 9 decrypted hash != computed hash -- probably correct key
+ *
+ * Although the math should be the same for generating and checking signatures,
+ * it is not: the knowledge of the private key allows more efficient (i.e.
+ * different) computation for encryption.
+ */
+static err_t
+try_RSA_signature(const u_char hash_val[MAX_DIGEST_LEN], size_t hash_len
+, const pb_stream *sig_pbs, pubkey_t *kr
+, struct state *st)
+{
+ const u_char *sig_val = sig_pbs->cur;
+ size_t sig_len = pbs_left(sig_pbs);
+ u_char s[RSA_MAX_OCTETS]; /* for decrypted sig_val */
+ u_char *hash_in_s = &s[sig_len - hash_len];
+ const struct RSA_public_key *k = &kr->u.rsa;
+
+ /* decrypt the signature -- reversing RSA_sign_hash */
+ if (sig_len != k->k)
+ {
+ /* XXX notification: INVALID_KEY_INFORMATION */
+ return "1" "SIG length does not match public key length";
+ }
+
+ /* actual exponentiation; see PKCS#1 v2.0 5.1 */
+ {
+ chunk_t temp_s;
+ mpz_t c;
+
+ n_to_mpz(c, sig_val, sig_len);
+ mpz_powm(c, c, &k->e, &k->n);
+
+ temp_s = mpz_to_n(c, sig_len); /* back to octets */
+ memcpy(s, temp_s.ptr, sig_len);
+ pfree(temp_s.ptr);
+ mpz_clear(c);
+ }
+
+ /* sanity check on signature: see if it matches
+ * PKCS#1 v1.5 8.1 encryption-block formatting
+ */
+ {
+ err_t ugh = NULL;
+
+ if (s[0] != 0x00)
+ ugh = "2" "no leading 00";
+ else if (hash_in_s[-1] != 0x00)
+ ugh = "3" "00 separator not present";
+ else if (s[1] == 0x01)
+ {
+ const u_char *p;
+
+ for (p = &s[2]; p != hash_in_s - 1; p++)
+ {
+ if (*p != 0xFF)
+ {
+ ugh = "4" "invalid Padding String";
+ break;
+ }
+ }
+ }
+ else if (s[1] == 0x02)
+ {
+ const u_char *p;
+
+ for (p = &s[2]; p != hash_in_s - 1; p++)
+ {
+ if (*p == 0x00)
+ {
+ ugh = "5" "invalid Padding String";
+ break;
+ }
+ }
+ }
+ else
+ ugh = "6" "Block Type not 01 or 02";
+
+ if (ugh != NULL)
+ {
+ /* note: it might be a good idea to make sure that
+ * an observer cannot tell what kind of failure happened.
+ * I don't know what this means in practice.
+ */
+ /* We probably selected the wrong public key for peer:
+ * SIG Payload decrypted into malformed ECB
+ */
+ /* XXX notification: INVALID_KEY_INFORMATION */
+ return ugh;
+ }
+ }
+
+ /* We have the decoded hash: see if it matches. */
+ if (memcmp(hash_val, hash_in_s, hash_len) != 0)
+ {
+ /* good: header, hash, signature, and other payloads well-formed
+ * good: we could find an RSA Sig key for the peer.
+ * bad: hash doesn't match
+ * Guess: sides disagree about key to be used.
+ */
+ DBG_cond_dump(DBG_CRYPT, "decrypted SIG", s, sig_len);
+ DBG_cond_dump(DBG_CRYPT, "computed HASH", hash_val, hash_len);
+ /* XXX notification: INVALID_HASH_INFORMATION */
+ return "9" "authentication failure: received SIG does not match computed HASH, but message is well-formed";
+ }
+
+ /* Success: copy successful key into state.
+ * There might be an old one if we previously aborted this
+ * state transition.
+ */
+ unreference_key(&st->st_peer_pubkey);
+ st->st_peer_pubkey = reference_key(kr);
+
+ return NULL; /* happy happy */
+}
+
+/* Check signature against all RSA public keys we can find.
+ * If we need keys from DNS KEY records, and they haven't been fetched,
+ * return STF_SUSPEND to ask for asynch DNS lookup.
+ *
+ * Note: parameter keys_from_dns contains results of DNS lookup for key
+ * or is NULL indicating lookup not yet tried.
+ *
+ * take_a_crack is a helper function. Mostly forensic.
+ * If only we had coroutines.
+ */
+struct tac_state {
+ /* RSA_check_signature's args that take_a_crack needs */
+ struct state *st;
+ const u_char *hash_val;
+ size_t hash_len;
+ const pb_stream *sig_pbs;
+
+ /* state carried between calls */
+ err_t best_ugh; /* most successful failure */
+ int tried_cnt; /* number of keys tried */
+ char tried[50]; /* keyids of tried public keys */
+ char *tn; /* roof of tried[] */
+};
+
+static bool
+take_a_crack(struct tac_state *s
+, pubkey_t *kr
+, const char *story USED_BY_DEBUG)
+{
+ err_t ugh = try_RSA_signature(s->hash_val, s->hash_len, s->sig_pbs
+ , kr, s->st);
+ const struct RSA_public_key *k = &kr->u.rsa;
+
+ s->tried_cnt++;
+ if (ugh == NULL)
+ {
+ DBG(DBG_CRYPT | DBG_CONTROL
+ , DBG_log("an RSA Sig check passed with *%s [%s]"
+ , k->keyid, story));
+ return TRUE;
+ }
+ else
+ {
+ DBG(DBG_CRYPT
+ , DBG_log("an RSA Sig check failure %s with *%s [%s]"
+ , ugh + 1, k->keyid, story));
+ if (s->best_ugh == NULL || s->best_ugh[0] < ugh[0])
+ s->best_ugh = ugh;
+ if (ugh[0] > '0'
+ && s->tn - s->tried + KEYID_BUF + 2 < (ptrdiff_t)sizeof(s->tried))
+ {
+ strcpy(s->tn, " *");
+ strcpy(s->tn + 2, k->keyid);
+ s->tn += strlen(s->tn);
+ }
+ return FALSE;
+ }
+}
+
+static stf_status
+RSA_check_signature(const struct id* peer
+, struct state *st
+, const u_char hash_val[MAX_DIGEST_LEN]
+, size_t hash_len
+, const pb_stream *sig_pbs
+#ifdef USE_KEYRR
+, const pubkey_list_t *keys_from_dns
+#endif /* USE_KEYRR */
+, const struct gw_info *gateways_from_dns
+)
+{
+ const struct connection *c = st->st_connection;
+ struct tac_state s;
+ err_t dns_ugh = NULL;
+
+ s.st = st;
+ s.hash_val = hash_val;
+ s.hash_len = hash_len;
+ s.sig_pbs = sig_pbs;
+
+ s.best_ugh = NULL;
+ s.tried_cnt = 0;
+ s.tn = s.tried;
+
+ /* try all gateway records hung off c */
+ if (c->policy & POLICY_OPPO)
+ {
+ struct gw_info *gw;
+
+ for (gw = c->gw_info; gw != NULL; gw = gw->next)
+ {
+ /* only consider entries that have a key and are for our peer */
+ if (gw->gw_key_present
+ && same_id(&gw->gw_id, &c->spd.that.id)
+ && take_a_crack(&s, gw->key, "key saved from DNS TXT"))
+ return STF_OK;
+ }
+ }
+
+ /* try all appropriate Public keys */
+ {
+ pubkey_list_t *p, **pp;
+
+ pp = &pubkeys;
+
+ for (p = pubkeys; p != NULL; p = *pp)
+ {
+ pubkey_t *key = p->key;
+
+ if (key->alg == PUBKEY_ALG_RSA && same_id(peer, &key->id))
+ {
+ time_t now = time(NULL);
+
+ /* check if found public key has expired */
+ if (key->until_time != UNDEFINED_TIME && key->until_time < now)
+ {
+ loglog(RC_LOG_SERIOUS,
+ "cached RSA public key has expired and has been deleted");
+ *pp = free_public_keyentry(p);
+ continue; /* continue with next public key */
+ }
+
+ if (take_a_crack(&s, key, "preloaded key"))
+ return STF_OK;
+ }
+ pp = &p->next;
+ }
+ }
+
+ /* if no key was found (evidenced by best_ugh == NULL)
+ * and that side of connection is key_from_DNS_on_demand
+ * then go search DNS for keys for peer.
+ */
+ if (s.best_ugh == NULL && c->spd.that.key_from_DNS_on_demand)
+ {
+ if (gateways_from_dns != NULL)
+ {
+ /* TXT keys */
+ const struct gw_info *gwp;
+
+ for (gwp = gateways_from_dns; gwp != NULL; gwp = gwp->next)
+ if (gwp->gw_key_present
+ && take_a_crack(&s, gwp->key, "key from DNS TXT"))
+ return STF_OK;
+ }
+#ifdef USE_KEYRR
+ else if (keys_from_dns != NULL)
+ {
+ /* KEY keys */
+ const pubkey_list_t *kr;
+
+ for (kr = keys_from_dns; kr != NULL; kr = kr->next)
+ if (kr->key->alg == PUBKEY_ALG_RSA
+ && take_a_crack(&s, kr->key, "key from DNS KEY"))
+ return STF_OK;
+ }
+#endif /* USE_KEYRR */
+ else
+ {
+ /* nothing yet: ask for asynch DNS lookup */
+ return STF_SUSPEND;
+ }
+ }
+
+ /* no acceptable key was found: diagnose */
+ {
+ char id_buf[BUF_LEN]; /* arbitrary limit on length of ID reported */
+
+ (void) idtoa(peer, id_buf, sizeof(id_buf));
+
+ if (s.best_ugh == NULL)
+ {
+ if (dns_ugh == NULL)
+ loglog(RC_LOG_SERIOUS, "no RSA public key known for '%s'"
+ , id_buf);
+ else
+ loglog(RC_LOG_SERIOUS, "no RSA public key known for '%s'"
+ "; DNS search for KEY failed (%s)"
+ , id_buf, dns_ugh);
+
+ /* ??? is this the best code there is? */
+ return STF_FAIL + INVALID_KEY_INFORMATION;
+ }
+
+ if (s.best_ugh[0] == '9')
+ {
+ loglog(RC_LOG_SERIOUS, "%s", s.best_ugh + 1);
+ /* XXX Could send notification back */
+ return STF_FAIL + INVALID_HASH_INFORMATION;
+ }
+ else
+ {
+ if (s.tried_cnt == 1)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "Signature check (on %s) failed (wrong key?); tried%s"
+ , id_buf, s.tried);
+ DBG(DBG_CONTROL,
+ DBG_log("public key for %s failed:"
+ " decrypted SIG payload into a malformed ECB (%s)"
+ , id_buf, s.best_ugh + 1));
+ }
+ else
+ {
+ loglog(RC_LOG_SERIOUS
+ , "Signature check (on %s) failed:"
+ " tried%s keys but none worked."
+ , id_buf, s.tried);
+ DBG(DBG_CONTROL,
+ DBG_log("all %d public keys for %s failed:"
+ " best decrypted SIG payload into a malformed ECB (%s)"
+ , s.tried_cnt, id_buf, s.best_ugh + 1));
+ }
+ return STF_FAIL + INVALID_KEY_INFORMATION;
+ }
+ }
+}
+
+static notification_t
+accept_nonce(struct msg_digest *md, chunk_t *dest, const char *name)
+{
+ pb_stream *nonce_pbs = &md->chain[ISAKMP_NEXT_NONCE]->pbs;
+ size_t len = pbs_left(nonce_pbs);
+
+ if (len < MINIMUM_NONCE_SIZE || MAXIMUM_NONCE_SIZE < len)
+ {
+ loglog(RC_LOG_SERIOUS, "%s length not between %d and %d"
+ , name , MINIMUM_NONCE_SIZE, MAXIMUM_NONCE_SIZE);
+ return PAYLOAD_MALFORMED; /* ??? */
+ }
+ clonereplacechunk(*dest, nonce_pbs->cur, len, "nonce");
+ return NOTHING_WRONG;
+}
+
+/* encrypt message, sans fixed part of header
+ * IV is fetched from st->st_new_iv and stored into st->st_iv.
+ * The theory is that there will be no "backing out", so we commit to IV.
+ * We also close the pbs.
+ */
+bool
+encrypt_message(pb_stream *pbs, struct state *st)
+{
+ const struct encrypt_desc *e = st->st_oakley.encrypter;
+ u_int8_t *enc_start = pbs->start + sizeof(struct isakmp_hdr);
+ size_t enc_len = pbs_offset(pbs) - sizeof(struct isakmp_hdr);
+
+ DBG_cond_dump(DBG_CRYPT | DBG_RAW, "encrypting:\n", enc_start, enc_len);
+
+ /* Pad up to multiple of encryption blocksize.
+ * See the description associated with the definition of
+ * struct isakmp_hdr in packet.h.
+ */
+ {
+ size_t padding = pad_up(enc_len, e->enc_blocksize);
+
+ if (padding != 0)
+ {
+ if (!out_zero(padding, pbs, "encryption padding"))
+ return FALSE;
+ enc_len += padding;
+ }
+ }
+
+ DBG(DBG_CRYPT, DBG_log("encrypting using %s", enum_show(&oakley_enc_names, st->st_oakley.encrypt)));
+
+ /* e->crypt(TRUE, enc_start, enc_len, st); */
+ crypto_cbc_encrypt(e, TRUE, enc_start, enc_len, st);
+
+ update_iv(st);
+ DBG_cond_dump(DBG_CRYPT, "next IV:", st->st_iv, st->st_iv_len);
+ close_message(pbs);
+ return TRUE;
+}
+
+/* Compute HASH(1), HASH(2) of Quick Mode.
+ * HASH(1) is part of Quick I1 message.
+ * HASH(2) is part of Quick R1 message.
+ * Used by: quick_outI1, quick_inI1_outR1 (twice), quick_inR1_outI2
+ * (see RFC 2409 "IKE" 5.5, pg. 18 or draft-ietf-ipsec-ike-01.txt 6.2 pg 25)
+ */
+static size_t
+quick_mode_hash12(u_char *dest, const u_char *start, const u_char *roof
+, const struct state *st, const msgid_t *msgid, bool hash2)
+{
+ struct hmac_ctx ctx;
+
+#if 0 /* if desperate to debug hashing */
+# define hmac_update(ctx, ptr, len) { \
+ DBG_dump("hash input", (ptr), (len)); \
+ (hmac_update)((ctx), (ptr), (len)); \
+ }
+ DBG_dump("hash key", st->st_skeyid_a.ptr, st->st_skeyid_a.len);
+#endif
+ hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid_a);
+ hmac_update(&ctx, (const void *) msgid, sizeof(msgid_t));
+ if (hash2)
+ hmac_update_chunk(&ctx, st->st_ni); /* include Ni_b in the hash */
+ hmac_update(&ctx, start, roof-start);
+ hmac_final(dest, &ctx);
+
+ DBG(DBG_CRYPT,
+ DBG_log("HASH(%d) computed:", hash2 + 1);
+ DBG_dump("", dest, ctx.hmac_digest_size));
+ return ctx.hmac_digest_size;
+# undef hmac_update
+}
+
+/* Compute HASH(3) in Quick Mode (part of Quick I2 message).
+ * Used by: quick_inR1_outI2, quick_inI2
+ * See RFC2409 "The Internet Key Exchange (IKE)" 5.5.
+ * NOTE: this hash (unlike HASH(1) and HASH(2)) ONLY covers the
+ * Message ID and Nonces. This is a mistake.
+ */
+static size_t
+quick_mode_hash3(u_char *dest, struct state *st)
+{
+ struct hmac_ctx ctx;
+
+ hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid_a);
+ hmac_update(&ctx, "\0", 1);
+ hmac_update(&ctx, (u_char *) &st->st_msgid, sizeof(st->st_msgid));
+ hmac_update_chunk(&ctx, st->st_ni);
+ hmac_update_chunk(&ctx, st->st_nr);
+ hmac_final(dest, &ctx);
+ DBG_cond_dump(DBG_CRYPT, "HASH(3) computed:", dest, ctx.hmac_digest_size);
+ return ctx.hmac_digest_size;
+}
+
+/* Compute Phase 2 IV.
+ * Uses Phase 1 IV from st_iv; puts result in st_new_iv.
+ */
+void
+init_phase2_iv(struct state *st, const msgid_t *msgid)
+{
+ const struct hash_desc *h = st->st_oakley.hasher;
+ union hash_ctx ctx;
+
+ DBG_cond_dump(DBG_CRYPT, "last Phase 1 IV:"
+ , st->st_ph1_iv, st->st_ph1_iv_len);
+
+ st->st_new_iv_len = h->hash_digest_size;
+ passert(st->st_new_iv_len <= sizeof(st->st_new_iv));
+
+ h->hash_init(&ctx);
+ h->hash_update(&ctx, st->st_ph1_iv, st->st_ph1_iv_len);
+ passert(*msgid != 0);
+ h->hash_update(&ctx, (const u_char *)msgid, sizeof(*msgid));
+ h->hash_final(st->st_new_iv, &ctx);
+
+ DBG_cond_dump(DBG_CRYPT, "computed Phase 2 IV:"
+ , st->st_new_iv, st->st_new_iv_len);
+}
+
+/* Initiate quick mode.
+ * --> HDR*, HASH(1), SA, Nr [, KE ] [, IDci, IDcr ]
+ * (see RFC 2409 "IKE" 5.5)
+ * Note: this is not called from demux.c
+ */
+
+static bool
+emit_subnet_id(ip_subnet *net
+, u_int8_t np, u_int8_t protoid, u_int16_t port, pb_stream *outs)
+{
+ struct isakmp_ipsec_id id;
+ pb_stream id_pbs;
+ ip_address ta;
+ const unsigned char *tbp;
+ size_t tal;
+
+ id.isaiid_np = np;
+ id.isaiid_idtype = subnetishost(net)
+ ? aftoinfo(subnettypeof(net))->id_addr
+ : aftoinfo(subnettypeof(net))->id_subnet;
+ id.isaiid_protoid = protoid;
+ id.isaiid_port = port;
+
+ if (!out_struct(&id, &isakmp_ipsec_identification_desc, outs, &id_pbs))
+ return FALSE;
+
+ networkof(net, &ta);
+ tal = addrbytesptr(&ta, &tbp);
+ if (!out_raw(tbp, tal, &id_pbs, "client network"))
+ return FALSE;
+
+ if (!subnetishost(net))
+ {
+ maskof(net, &ta);
+ tal = addrbytesptr(&ta, &tbp);
+ if (!out_raw(tbp, tal, &id_pbs, "client mask"))
+ return FALSE;
+ }
+
+ close_output_pbs(&id_pbs);
+ return TRUE;
+}
+
+stf_status
+quick_outI1(int whack_sock
+, struct state *isakmp_sa
+, struct connection *c
+, lset_t policy
+, unsigned long try
+, so_serial_t replacing)
+{
+ struct state *st = duplicate_state(isakmp_sa);
+ pb_stream reply; /* not really a reply */
+ pb_stream rbody;
+ u_char /* set by START_HASH_PAYLOAD: */
+ *r_hashval, /* where in reply to jam hash value */
+ *r_hash_start; /* start of what is to be hashed */
+ bool has_client = c->spd.this.has_client || c->spd.that.has_client ||
+ c->spd.this.protocol || c->spd.that.protocol ||
+ c->spd.this.port || c->spd.that.port;
+
+ bool send_natoa = FALSE;
+ u_int8_t np = ISAKMP_NEXT_NONE;
+
+ st->st_whack_sock = whack_sock;
+ st->st_connection = c;
+ set_cur_state(st); /* we must reset before exit */
+ st->st_policy = policy;
+ st->st_try = try;
+
+ st->st_myuserprotoid = c->spd.this.protocol;
+ st->st_peeruserprotoid = c->spd.that.protocol;
+ st->st_myuserport = c->spd.this.port;
+ st->st_peeruserport = c->spd.that.port;
+
+ st->st_msgid = generate_msgid(isakmp_sa);
+ st->st_state = STATE_QUICK_I1;
+
+ insert_state(st); /* needs cookies, connection, and msgid */
+
+ if (replacing == SOS_NOBODY)
+ plog("initiating Quick Mode %s {using isakmp#%lu}"
+ , prettypolicy(policy)
+ , isakmp_sa->st_serialno);
+ else
+ plog("initiating Quick Mode %s to replace #%lu {using isakmp#%lu}"
+ , prettypolicy(policy)
+ , replacing
+ , isakmp_sa->st_serialno);
+
+ if (isakmp_sa->nat_traversal & NAT_T_DETECTED)
+ {
+ /* Duplicate nat_traversal status in new state */
+ st->nat_traversal = isakmp_sa->nat_traversal;
+
+ if (isakmp_sa->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME))
+ has_client = TRUE;
+
+ nat_traversal_change_port_lookup(NULL, st);
+ }
+ else
+ st->nat_traversal = 0;
+
+ /* are we going to send a NAT-OA payload? */
+ if ((st->nat_traversal & NAT_T_WITH_NATOA)
+ && !(st->st_policy & POLICY_TUNNEL)
+ && (st->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME)))
+ {
+ send_natoa = TRUE;
+ np = (st->nat_traversal & NAT_T_WITH_RFC_VALUES) ?
+ ISAKMP_NEXT_NATOA_RFC : ISAKMP_NEXT_NATOA_DRAFTS;
+ }
+
+ /* set up reply */
+ init_pbs(&reply, reply_buffer, sizeof(reply_buffer), "reply packet");
+
+ /* HDR* out */
+ {
+ struct isakmp_hdr hdr;
+
+ hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION;
+ hdr.isa_np = ISAKMP_NEXT_HASH;
+ hdr.isa_xchg = ISAKMP_XCHG_QUICK;
+ hdr.isa_msgid = st->st_msgid;
+ hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION;
+ memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE);
+ memcpy(hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE);
+ if (!out_struct(&hdr, &isakmp_hdr_desc, &reply, &rbody))
+ {
+ reset_cur_state();
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+ /* HASH(1) -- create and note space to be filled later */
+ START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_SA);
+
+ /* SA out */
+
+ /*
+ * See if pfs_group has been specified for this conn,
+ * if not, fallback to old use-same-as-P1 behaviour
+ */
+#ifndef NO_IKE_ALG
+ if (st->st_connection)
+ st->st_pfs_group = ike_alg_pfsgroup(st->st_connection, policy);
+ if (!st->st_pfs_group)
+#endif
+ /* If PFS specified, use the same group as during Phase 1:
+ * since no negotiation is possible, we pick one that is
+ * very likely supported.
+ */
+ st->st_pfs_group = policy & POLICY_PFS? isakmp_sa->st_oakley.group : NULL;
+
+ /* Emit SA payload based on a subset of the policy bits.
+ * POLICY_COMPRESS is considered iff we can do IPcomp.
+ */
+ {
+ lset_t pm = POLICY_ENCRYPT | POLICY_AUTHENTICATE;
+
+ if (can_do_IPcomp)
+ pm |= POLICY_COMPRESS;
+
+ if (!out_sa(&rbody
+ , &ipsec_sadb[(st->st_policy & pm) >> POLICY_IPSEC_SHIFT]
+ , st, FALSE, ISAKMP_NEXT_NONCE))
+ {
+ reset_cur_state();
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+ /* Ni out */
+ if (!build_and_ship_nonce(&st->st_ni, &rbody
+ , policy & POLICY_PFS? ISAKMP_NEXT_KE : has_client? ISAKMP_NEXT_ID : np
+ , "Ni"))
+ {
+ reset_cur_state();
+ return STF_INTERNAL_ERROR;
+ }
+
+ /* [ KE ] out (for PFS) */
+
+ if (st->st_pfs_group != NULL)
+ {
+ if (!build_and_ship_KE(st, &st->st_gi, st->st_pfs_group
+ , &rbody, has_client? ISAKMP_NEXT_ID : np))
+ {
+ reset_cur_state();
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+ /* [ IDci, IDcr ] out */
+ if (has_client)
+ {
+ /* IDci (we are initiator), then IDcr (peer is responder) */
+ if (!emit_subnet_id(&c->spd.this.client
+ , ISAKMP_NEXT_ID, st->st_myuserprotoid, st->st_myuserport, &rbody)
+ || !emit_subnet_id(&c->spd.that.client
+ , np, st->st_peeruserprotoid, st->st_peeruserport, &rbody))
+ {
+ reset_cur_state();
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+ /* Send NAT-OA if our address is NATed */
+ if (send_natoa)
+ {
+ if (!nat_traversal_add_natoa(ISAKMP_NEXT_NONE, &rbody, st))
+ {
+ reset_cur_state();
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+ /* finish computing HASH(1), inserting it in output */
+ (void) quick_mode_hash12(r_hashval, r_hash_start, rbody.cur
+ , st, &st->st_msgid, FALSE);
+
+ /* encrypt message, except for fixed part of header */
+
+ init_phase2_iv(isakmp_sa, &st->st_msgid);
+ st->st_new_iv_len = isakmp_sa->st_new_iv_len;
+ memcpy(st->st_new_iv, isakmp_sa->st_new_iv, st->st_new_iv_len);
+
+ if (!encrypt_message(&rbody, st))
+ {
+ reset_cur_state();
+ return STF_INTERNAL_ERROR;
+ }
+
+ /* save packet, now that we know its size */
+ clonetochunk(st->st_tpacket, reply.start, pbs_offset(&reply)
+ , "reply packet from quick_outI1");
+
+ /* send the packet */
+
+ send_packet(st, "quick_outI1");
+
+ delete_event(st);
+ event_schedule(EVENT_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0, st);
+
+ if (replacing == SOS_NOBODY)
+ whack_log(RC_NEW_STATE + STATE_QUICK_I1
+ , "%s: initiate"
+ , enum_name(&state_names, st->st_state));
+ else
+ whack_log(RC_NEW_STATE + STATE_QUICK_I1
+ , "%s: initiate to replace #%lu"
+ , enum_name(&state_names, st->st_state)
+ , replacing);
+ reset_cur_state();
+ return STF_OK;
+}
+
+
+/*
+ * Decode the CERT payload of Phase 1.
+ */
+static void
+decode_cert(struct msg_digest *md)
+{
+ struct payload_digest *p;
+
+ for (p = md->chain[ISAKMP_NEXT_CERT]; p != NULL; p = p->next)
+ {
+ struct isakmp_cert *const cert = &p->payload.cert;
+ chunk_t blob;
+ time_t valid_until;
+ blob.ptr = p->pbs.cur;
+ blob.len = pbs_left(&p->pbs);
+ if (cert->isacert_type == CERT_X509_SIGNATURE)
+ {
+ x509cert_t cert = empty_x509cert;
+ if (parse_x509cert(blob, 0, &cert))
+ {
+ if (verify_x509cert(&cert, strict_crl_policy, &valid_until))
+ {
+ DBG(DBG_PARSING,
+ DBG_log("Public key validated")
+ )
+ add_x509_public_key(&cert, valid_until, DAL_SIGNED);
+ }
+ else
+ {
+ plog("X.509 certificate rejected");
+ }
+ free_generalNames(cert.subjectAltName, FALSE);
+ free_generalNames(cert.crlDistributionPoints, FALSE);
+ }
+ else
+ plog("Syntax error in X.509 certificate");
+ }
+ else if (cert->isacert_type == CERT_PKCS7_WRAPPED_X509)
+ {
+ x509cert_t *cert = NULL;
+
+ if (pkcs7_parse_signedData(blob, NULL, &cert, NULL, NULL))
+ store_x509certs(&cert, strict_crl_policy);
+ else
+ plog("Syntax error in PKCS#7 wrapped X.509 certificates");
+ }
+ else
+ {
+ loglog(RC_LOG_SERIOUS, "ignoring %s certificate payload",
+ enum_show(&cert_type_names, cert->isacert_type));
+ DBG_cond_dump_chunk(DBG_PARSING, "CERT:\n", blob);
+ }
+ }
+}
+
+/*
+ * Decode the CR payload of Phase 1.
+ */
+static void
+decode_cr(struct msg_digest *md, struct connection *c)
+{
+ struct payload_digest *p;
+
+ for (p = md->chain[ISAKMP_NEXT_CR]; p != NULL; p = p->next)
+ {
+ struct isakmp_cr *const cr = &p->payload.cr;
+ chunk_t ca_name;
+
+ ca_name.len = pbs_left(&p->pbs);
+ ca_name.ptr = (ca_name.len > 0)? p->pbs.cur : NULL;
+
+ DBG_cond_dump_chunk(DBG_PARSING, "CR", ca_name);
+
+ if (cr->isacr_type == CERT_X509_SIGNATURE)
+ {
+ char buf[BUF_LEN];
+
+ if (ca_name.len > 0)
+ {
+ generalName_t *gn;
+
+ if (!is_asn1(ca_name))
+ continue;
+
+ gn = alloc_thing(generalName_t, "generalName");
+ clonetochunk(ca_name, ca_name.ptr,ca_name.len, "ca name");
+ gn->kind = GN_DIRECTORY_NAME;
+ gn->name = ca_name;
+ gn->next = c->requested_ca;
+ c->requested_ca = gn;
+ }
+ c->got_certrequest = TRUE;
+
+ DBG(DBG_PARSING | DBG_CONTROL,
+ dntoa_or_null(buf, BUF_LEN, ca_name, "%any");
+ DBG_log("requested CA: '%s'", buf);
+ )
+ }
+ else
+ loglog(RC_LOG_SERIOUS, "ignoring %s certificate request payload",
+ enum_show(&cert_type_names, cr->isacr_type));
+ }
+}
+
+/* Decode the ID payload of Phase 1 (main_inI3_outR3 and main_inR3)
+ * Note: we may change connections as a result.
+ * We must be called before SIG or HASH are decoded since we
+ * may change the peer's RSA key or ID.
+ */
+static bool
+decode_peer_id(struct msg_digest *md, struct id *peer)
+{
+ struct state *const st = md->st;
+ struct payload_digest *const id_pld = md->chain[ISAKMP_NEXT_ID];
+ const pb_stream *const id_pbs = &id_pld->pbs;
+ struct isakmp_id *const id = &id_pld->payload.id;
+
+ /* I think that RFC2407 (IPSEC DOI) 4.6.2 is confused.
+ * It talks about the protocol ID and Port fields of the ID
+ * Payload, but they don't exist as such in Phase 1.
+ * We use more appropriate names.
+ * isaid_doi_specific_a is in place of Protocol ID.
+ * isaid_doi_specific_b is in place of Port.
+ * Besides, there is no good reason for allowing these to be
+ * other than 0 in Phase 1.
+ */
+ if ((st->nat_traversal & NAT_T_WITH_PORT_FLOATING)
+ && id->isaid_doi_specific_a == IPPROTO_UDP
+ && (id->isaid_doi_specific_b == 0 || id->isaid_doi_specific_b == NAT_T_IKE_FLOAT_PORT))
+ {
+ DBG_log("protocol/port in Phase 1 ID Payload is %d/%d. "
+ "accepted with port_floating NAT-T",
+ id->isaid_doi_specific_a, id->isaid_doi_specific_b);
+ }
+ else if (!(id->isaid_doi_specific_a == 0 && id->isaid_doi_specific_b == 0)
+ && !(id->isaid_doi_specific_a == IPPROTO_UDP && id->isaid_doi_specific_b == IKE_UDP_PORT))
+ {
+ loglog(RC_LOG_SERIOUS, "protocol/port in Phase 1 ID Payload must be 0/0 or %d/%d"
+ " but are %d/%d"
+ , IPPROTO_UDP, IKE_UDP_PORT
+ , id->isaid_doi_specific_a, id->isaid_doi_specific_b);
+ return FALSE;
+ }
+
+ peer->kind = id->isaid_idtype;
+
+ switch (peer->kind)
+ {
+ case ID_IPV4_ADDR:
+ case ID_IPV6_ADDR:
+ /* failure mode for initaddr is probably inappropriate address length */
+ {
+ err_t ugh = initaddr(id_pbs->cur, pbs_left(id_pbs)
+ , peer->kind == ID_IPV4_ADDR? AF_INET : AF_INET6
+ , &peer->ip_addr);
+
+ if (ugh != NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "improper %s identification payload: %s"
+ , enum_show(&ident_names, peer->kind), ugh);
+ /* XXX Could send notification back */
+ return FALSE;
+ }
+ }
+ break;
+
+ case ID_USER_FQDN:
+ if (memchr(id_pbs->cur, '@', pbs_left(id_pbs)) == NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "peer's ID_USER_FQDN contains no @");
+ return FALSE;
+ }
+ /* FALLTHROUGH */
+ case ID_FQDN:
+ if (memchr(id_pbs->cur, '\0', pbs_left(id_pbs)) != NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "Phase 1 ID Payload of type %s contains a NUL"
+ , enum_show(&ident_names, peer->kind));
+ return FALSE;
+ }
+
+ /* ??? ought to do some more sanity check, but what? */
+
+ setchunk(peer->name, id_pbs->cur, pbs_left(id_pbs));
+ break;
+
+ case ID_KEY_ID:
+ setchunk(peer->name, id_pbs->cur, pbs_left(id_pbs));
+ DBG(DBG_PARSING,
+ DBG_dump_chunk("KEY ID:", peer->name));
+ break;
+
+ case ID_DER_ASN1_DN:
+ setchunk(peer->name, id_pbs->cur, pbs_left(id_pbs));
+ DBG(DBG_PARSING,
+ DBG_dump_chunk("DER ASN1 DN:", peer->name));
+ break;
+
+ default:
+ /* XXX Could send notification back */
+ loglog(RC_LOG_SERIOUS, "Unacceptable identity type (%s) in Phase 1 ID Payload"
+ , enum_show(&ident_names, peer->kind));
+ return FALSE;
+ }
+
+ {
+ char buf[BUF_LEN];
+
+ idtoa(peer, buf, sizeof(buf));
+ plog("Peer ID is %s: '%s'",
+ enum_show(&ident_names, id->isaid_idtype), buf);
+ }
+
+ /* check for certificates */
+ decode_cert(md);
+ return TRUE;
+}
+
+/* Now that we've decoded the ID payload, let's see if we
+ * need to switch connections.
+ * We must not switch horses if we initiated:
+ * - if the initiation was explicit, we'd be ignoring user's intent
+ * - if opportunistic, we'll lose our HOLD info
+ */
+static bool
+switch_connection(struct msg_digest *md, struct id *peer, bool initiator)
+{
+ struct state *const st = md->st;
+ struct connection *c = st->st_connection;
+
+ chunk_t peer_ca = (st->st_peer_pubkey != NULL)
+ ? st->st_peer_pubkey->issuer : empty_chunk;
+
+ DBG(DBG_CONTROL,
+ char buf[BUF_LEN];
+
+ dntoa_or_null(buf, BUF_LEN, peer_ca, "%none");
+ DBG_log("peer CA: '%s'", buf);
+ )
+
+ if (initiator)
+ {
+ int pathlen;
+
+ if (!same_id(&c->spd.that.id, peer))
+ {
+ char expect[BUF_LEN]
+ , found[BUF_LEN];
+
+ idtoa(&c->spd.that.id, expect, sizeof(expect));
+ idtoa(peer, found, sizeof(found));
+ loglog(RC_LOG_SERIOUS
+ , "we require peer to have ID '%s', but peer declares '%s'"
+ , expect, found);
+ return FALSE;
+ }
+
+ DBG(DBG_CONTROL,
+ char buf[BUF_LEN];
+
+ dntoa_or_null(buf, BUF_LEN, c->spd.this.ca, "%none");
+ DBG_log("required CA: '%s'", buf);
+ )
+
+ if (!trusted_ca(peer_ca, c->spd.that.ca, &pathlen))
+ {
+ loglog(RC_LOG_SERIOUS
+ , "we don't accept the peer's CA");
+ return FALSE;
+ }
+ }
+ else
+ {
+ struct connection *r;
+
+ /* check for certificate requests */
+ decode_cr(md, c);
+
+ r = refine_host_connection(st, peer, peer_ca);
+
+ /* delete the collected certificate requests */
+ free_generalNames(c->requested_ca, TRUE);
+ c->requested_ca = NULL;
+
+ if (r == NULL)
+ {
+ char buf[BUF_LEN];
+
+ idtoa(peer, buf, sizeof(buf));
+ loglog(RC_LOG_SERIOUS, "no suitable connection for peer '%s'", buf);
+ return FALSE;
+ }
+
+ DBG(DBG_CONTROL,
+ char buf[BUF_LEN];
+
+ dntoa_or_null(buf, BUF_LEN, r->spd.this.ca, "%none");
+ DBG_log("offered CA: '%s'", buf);
+ )
+
+ if (r != c)
+ {
+ /* apparently, r is an improvement on c -- replace */
+
+ DBG(DBG_CONTROL
+ , DBG_log("switched from \"%s\" to \"%s\"", c->name, r->name));
+ if (r->kind == CK_TEMPLATE)
+ {
+ /* instantiate it, filling in peer's ID */
+ r = rw_instantiate(r, &c->spd.that.host_addr
+ , c->spd.that.host_port, NULL, peer);
+ }
+
+ /* copy certificate request info */
+ r->got_certrequest = c->got_certrequest;
+
+ st->st_connection = r; /* kill reference to c */
+ set_cur_connection(r);
+ connection_discard(c);
+ }
+ else if (c->spd.that.has_id_wildcards)
+ {
+ free_id_content(&c->spd.that.id);
+ c->spd.that.id = *peer;
+ c->spd.that.has_id_wildcards = FALSE;
+ unshare_id_content(&c->spd.that.id);
+ }
+ }
+ return TRUE;
+}
+
+/* Decode the variable part of an ID packet (during Quick Mode).
+ * This is designed for packets that identify clients, not peers.
+ * Rejects 0.0.0.0/32 or IPv6 equivalent because
+ * (1) it is wrong and (2) we use this value for inband signalling.
+ */
+static bool
+decode_net_id(struct isakmp_ipsec_id *id
+, pb_stream *id_pbs
+, ip_subnet *net
+, const char *which)
+{
+ const struct af_info *afi = NULL;
+
+ /* Note: the following may be a pointer into static memory
+ * that may be recycled, but only if the type is not known.
+ * That case is disposed of very early -- in the first switch.
+ */
+ const char *idtypename = enum_show(&ident_names, id->isaiid_idtype);
+
+ switch (id->isaiid_idtype)
+ {
+ case ID_IPV4_ADDR:
+ case ID_IPV4_ADDR_SUBNET:
+ case ID_IPV4_ADDR_RANGE:
+ afi = &af_inet4_info;
+ break;
+ case ID_IPV6_ADDR:
+ case ID_IPV6_ADDR_SUBNET:
+ case ID_IPV6_ADDR_RANGE:
+ afi = &af_inet6_info;
+ break;
+ case ID_FQDN:
+ return TRUE;
+ default:
+ /* XXX support more */
+ loglog(RC_LOG_SERIOUS, "unsupported ID type %s"
+ , idtypename);
+ /* XXX Could send notification back */
+ return FALSE;
+ }
+
+ switch (id->isaiid_idtype)
+ {
+ case ID_IPV4_ADDR:
+ case ID_IPV6_ADDR:
+ {
+ ip_address temp_address;
+ err_t ugh;
+
+ ugh = initaddr(id_pbs->cur, pbs_left(id_pbs), afi->af, &temp_address);
+
+ if (ugh != NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "%s ID payload %s has wrong length in Quick I1 (%s)"
+ , which, idtypename, ugh);
+ /* XXX Could send notification back */
+ return FALSE;
+ }
+ if (isanyaddr(&temp_address))
+ {
+ loglog(RC_LOG_SERIOUS, "%s ID payload %s is invalid (%s) in Quick I1"
+ , which, idtypename, ip_str(&temp_address));
+ /* XXX Could send notification back */
+ return FALSE;
+ }
+ happy(addrtosubnet(&temp_address, net));
+ DBG(DBG_PARSING | DBG_CONTROL
+ , DBG_log("%s is %s", which, ip_str(&temp_address)));
+ break;
+ }
+
+ case ID_IPV4_ADDR_SUBNET:
+ case ID_IPV6_ADDR_SUBNET:
+ {
+ ip_address temp_address, temp_mask;
+ err_t ugh;
+
+ if (pbs_left(id_pbs) != 2 * afi->ia_sz)
+ {
+ loglog(RC_LOG_SERIOUS, "%s ID payload %s wrong length in Quick I1"
+ , which, idtypename);
+ /* XXX Could send notification back */
+ return FALSE;
+ }
+ ugh = initaddr(id_pbs->cur
+ , afi->ia_sz, afi->af, &temp_address);
+ if (ugh == NULL)
+ ugh = initaddr(id_pbs->cur + afi->ia_sz
+ , afi->ia_sz, afi->af, &temp_mask);
+ if (ugh == NULL)
+ ugh = initsubnet(&temp_address, masktocount(&temp_mask)
+ , '0', net);
+ if (ugh == NULL && subnetisnone(net))
+ ugh = "contains only anyaddr";
+ if (ugh != NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "%s ID payload %s bad subnet in Quick I1 (%s)"
+ , which, idtypename, ugh);
+ /* XXX Could send notification back */
+ return FALSE;
+ }
+ DBG(DBG_PARSING | DBG_CONTROL,
+ {
+ char temp_buff[SUBNETTOT_BUF];
+
+ subnettot(net, 0, temp_buff, sizeof(temp_buff));
+ DBG_log("%s is subnet %s", which, temp_buff);
+ });
+ break;
+ }
+
+ case ID_IPV4_ADDR_RANGE:
+ case ID_IPV6_ADDR_RANGE:
+ {
+ ip_address temp_address_from, temp_address_to;
+ err_t ugh;
+
+ if (pbs_left(id_pbs) != 2 * afi->ia_sz)
+ {
+ loglog(RC_LOG_SERIOUS, "%s ID payload %s wrong length in Quick I1"
+ , which, idtypename);
+ /* XXX Could send notification back */
+ return FALSE;
+ }
+ ugh = initaddr(id_pbs->cur, afi->ia_sz, afi->af, &temp_address_from);
+ if (ugh == NULL)
+ ugh = initaddr(id_pbs->cur + afi->ia_sz
+ , afi->ia_sz, afi->af, &temp_address_to);
+ if (ugh != NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "%s ID payload %s malformed (%s) in Quick I1"
+ , which, idtypename, ugh);
+ /* XXX Could send notification back */
+ return FALSE;
+ }
+
+ ugh = rangetosubnet(&temp_address_from, &temp_address_to, net);
+ if (ugh == NULL && subnetisnone(net))
+ ugh = "contains only anyaddr";
+ if (ugh != NULL)
+ {
+ char temp_buff1[ADDRTOT_BUF], temp_buff2[ADDRTOT_BUF];
+
+ addrtot(&temp_address_from, 0, temp_buff1, sizeof(temp_buff1));
+ addrtot(&temp_address_to, 0, temp_buff2, sizeof(temp_buff2));
+ loglog(RC_LOG_SERIOUS, "%s ID payload in Quick I1, %s"
+ " %s - %s unacceptable: %s"
+ , which, idtypename, temp_buff1, temp_buff2, ugh);
+ return FALSE;
+ }
+ DBG(DBG_PARSING | DBG_CONTROL,
+ {
+ char temp_buff[SUBNETTOT_BUF];
+
+ subnettot(net, 0, temp_buff, sizeof(temp_buff));
+ DBG_log("%s is subnet %s (received as range)"
+ , which, temp_buff);
+ });
+ break;
+ }
+ }
+
+ /* set the port selector */
+ setportof(htons(id->isaiid_port), &net->addr);
+
+ DBG(DBG_PARSING | DBG_CONTROL,
+ DBG_log("%s protocol/port is %d/%d", which, id->isaiid_protoid, id->isaiid_port)
+ )
+
+ return TRUE;
+}
+
+/* like decode, but checks that what is received matches what was sent */
+static bool
+
+check_net_id(struct isakmp_ipsec_id *id
+, pb_stream *id_pbs
+, u_int8_t *protoid
+, u_int16_t *port
+, ip_subnet *net
+, const char *which)
+{
+ ip_subnet net_temp;
+
+ if (!decode_net_id(id, id_pbs, &net_temp, which))
+ return FALSE;
+
+ if (!samesubnet(net, &net_temp)
+ || *protoid != id->isaiid_protoid || *port != id->isaiid_port)
+ {
+ loglog(RC_LOG_SERIOUS, "%s ID returned doesn't match my proposal", which);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ * look for the existence of a non-expiring preloaded public key
+ */
+static bool
+has_preloaded_public_key(struct state *st)
+{
+ struct connection *c = st->st_connection;
+
+ /* do not consider rw connections since
+ * the peer's identity must be known
+ */
+ if (c->kind == CK_PERMANENT)
+ {
+ pubkey_list_t *p;
+
+ /* look for a matching RSA public key */
+ for (p = pubkeys; p != NULL; p = p->next)
+ {
+ pubkey_t *key = p->key;
+
+ if (key->alg == PUBKEY_ALG_RSA &&
+ same_id(&c->spd.that.id, &key->id) &&
+ key->until_time == UNDEFINED_TIME)
+ {
+ /* found a preloaded public key */
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * Produce the new key material of Quick Mode.
+ * RFC 2409 "IKE" section 5.5
+ * specifies how this is to be done.
+ */
+static void
+compute_proto_keymat(struct state *st
+, u_int8_t protoid
+, struct ipsec_proto_info *pi)
+{
+ size_t needed_len; /* bytes of keying material needed */
+
+ /* Add up the requirements for keying material
+ * (It probably doesn't matter if we produce too much!)
+ */
+ switch (protoid)
+ {
+ case PROTO_IPSEC_ESP:
+ switch (pi->attrs.transid)
+ {
+ case ESP_NULL:
+ needed_len = 0;
+ break;
+ case ESP_DES:
+ needed_len = DES_CBC_BLOCK_SIZE;
+ break;
+ case ESP_3DES:
+ needed_len = DES_CBC_BLOCK_SIZE * 3;
+ break;
+ default:
+#ifndef NO_KERNEL_ALG
+ if((needed_len=kernel_alg_esp_enc_keylen(pi->attrs.transid))>0) {
+ /* XXX: check key_len "coupling with kernel.c's */
+ if (pi->attrs.key_len) {
+ needed_len=pi->attrs.key_len/8;
+ DBG(DBG_PARSING, DBG_log("compute_proto_keymat:"
+ "key_len=%d from peer",
+ (int)needed_len));
+ }
+ break;
+ }
+#endif
+ bad_case(pi->attrs.transid);
+ }
+
+#ifndef NO_KERNEL_ALG
+ DBG(DBG_PARSING, DBG_log("compute_proto_keymat:"
+ "needed_len (after ESP enc)=%d",
+ (int)needed_len));
+ if (kernel_alg_esp_auth_ok(pi->attrs.auth, NULL)) {
+ needed_len += kernel_alg_esp_auth_keylen(pi->attrs.auth);
+ } else
+#endif
+ switch (pi->attrs.auth)
+ {
+ case AUTH_ALGORITHM_NONE:
+ break;
+ case AUTH_ALGORITHM_HMAC_MD5:
+ needed_len += HMAC_MD5_KEY_LEN;
+ break;
+ case AUTH_ALGORITHM_HMAC_SHA1:
+ needed_len += HMAC_SHA1_KEY_LEN;
+ break;
+ case AUTH_ALGORITHM_DES_MAC:
+ default:
+ bad_case(pi->attrs.auth);
+ }
+ DBG(DBG_PARSING, DBG_log("compute_proto_keymat:"
+ "needed_len (after ESP auth)=%d",
+ (int)needed_len));
+ break;
+
+ case PROTO_IPSEC_AH:
+ switch (pi->attrs.transid)
+ {
+ case AH_MD5:
+ needed_len = HMAC_MD5_KEY_LEN;
+ break;
+ case AH_SHA:
+ needed_len = HMAC_SHA1_KEY_LEN;
+ break;
+ default:
+ bad_case(pi->attrs.transid);
+ }
+ break;
+
+ default:
+ bad_case(protoid);
+ }
+
+ pi->keymat_len = needed_len;
+
+ /* Allocate space for the keying material.
+ * Although only needed_len bytes are desired, we
+ * must round up to a multiple of ctx.hmac_digest_size
+ * so that our buffer isn't overrun.
+ */
+ {
+ struct hmac_ctx ctx_me, ctx_peer;
+ size_t needed_space; /* space needed for keying material (rounded up) */
+ size_t i;
+
+ hmac_init_chunk(&ctx_me, st->st_oakley.hasher, st->st_skeyid_d);
+ ctx_peer = ctx_me; /* duplicate initial conditions */
+
+ needed_space = needed_len + pad_up(needed_len, ctx_me.hmac_digest_size);
+ replace(pi->our_keymat, alloc_bytes(needed_space, "keymat in compute_keymat()"));
+ replace(pi->peer_keymat, alloc_bytes(needed_space, "peer_keymat in quick_inI1_outR1()"));
+
+ for (i = 0;; )
+ {
+ if (st->st_shared.ptr != NULL)
+ {
+ /* PFS: include the g^xy */
+ hmac_update_chunk(&ctx_me, st->st_shared);
+ hmac_update_chunk(&ctx_peer, st->st_shared);
+ }
+ hmac_update(&ctx_me, &protoid, sizeof(protoid));
+ hmac_update(&ctx_peer, &protoid, sizeof(protoid));
+
+ hmac_update(&ctx_me, (u_char *)&pi->our_spi, sizeof(pi->our_spi));
+ hmac_update(&ctx_peer, (u_char *)&pi->attrs.spi, sizeof(pi->attrs.spi));
+
+ hmac_update_chunk(&ctx_me, st->st_ni);
+ hmac_update_chunk(&ctx_peer, st->st_ni);
+
+ hmac_update_chunk(&ctx_me, st->st_nr);
+ hmac_update_chunk(&ctx_peer, st->st_nr);
+
+ hmac_final(pi->our_keymat + i, &ctx_me);
+ hmac_final(pi->peer_keymat + i, &ctx_peer);
+
+ i += ctx_me.hmac_digest_size;
+ if (i >= needed_space)
+ break;
+
+ /* more keying material needed: prepare to go around again */
+
+ hmac_reinit(&ctx_me);
+ hmac_reinit(&ctx_peer);
+
+ hmac_update(&ctx_me, pi->our_keymat + i - ctx_me.hmac_digest_size
+ , ctx_me.hmac_digest_size);
+ hmac_update(&ctx_peer, pi->peer_keymat + i - ctx_peer.hmac_digest_size
+ , ctx_peer.hmac_digest_size);
+ }
+ }
+
+ DBG(DBG_CRYPT,
+ DBG_dump("KEYMAT computed:\n", pi->our_keymat, pi->keymat_len);
+ DBG_dump("Peer KEYMAT computed:\n", pi->peer_keymat, pi->keymat_len));
+}
+
+static void
+compute_keymats(struct state *st)
+{
+ if (st->st_ah.present)
+ compute_proto_keymat(st, PROTO_IPSEC_AH, &st->st_ah);
+ if (st->st_esp.present)
+ compute_proto_keymat(st, PROTO_IPSEC_ESP, &st->st_esp);
+}
+
+/* State Transition Functions.
+ *
+ * The definition of state_microcode_table in demux.c is a good
+ * overview of these routines.
+ *
+ * - Called from process_packet; result handled by complete_state_transition
+ * - struct state_microcode member "processor" points to these
+ * - these routine definitionss are in state order
+ * - these routines must be restartable from any point of error return:
+ * beware of memory allocated before any error.
+ * - output HDR is usually emitted by process_packet (if state_microcode
+ * member first_out_payload isn't ISAKMP_NEXT_NONE).
+ *
+ * The transition functions' functions include:
+ * - process and judge payloads
+ * - update st_iv (result of decryption is in st_new_iv)
+ * - build reply packet
+ */
+
+/* Handle a Main Mode Oakley first packet (responder side).
+ * HDR;SA --> HDR;SA
+ */
+stf_status
+main_inI1_outR1(struct msg_digest *md)
+{
+ struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_SA];
+ struct state *st;
+ struct connection *c;
+ struct isakmp_proposal proposal;
+ pb_stream proposal_pbs;
+ pb_stream r_sa_pbs;
+ u_int32_t ipsecdoisit;
+ lset_t policy = LEMPTY;
+ int vids_to_send = 0;
+
+ /* We preparse the peer's proposal in order to determine
+ * the requested authentication policy (RSA or PSK)
+ */
+ RETURN_STF_FAILURE(preparse_isakmp_sa_body(&sa_pd->payload.sa
+ , &sa_pd->pbs, &ipsecdoisit, &proposal_pbs, &proposal));
+
+ backup_pbs(&proposal_pbs);
+ RETURN_STF_FAILURE(parse_isakmp_policy(&proposal_pbs
+ , proposal.isap_notrans, &policy));
+ restore_pbs(&proposal_pbs);
+
+ /* We are only considering candidate connections that match
+ * the requested authentication policy (RSA or PSK)
+ */
+ c = find_host_connection(&md->iface->addr, pluto_port
+ , &md->sender, md->sender_port, policy);
+
+ if (c == NULL && md->iface->ike_float)
+ {
+ c = find_host_connection(&md->iface->addr, NAT_T_IKE_FLOAT_PORT
+ , &md->sender, md->sender_port, policy);
+ }
+
+ if (c == NULL)
+ {
+ /* See if a wildcarded connection can be found.
+ * We cannot pick the right connection, so we're making a guess.
+ * All Road Warrior connections are fair game:
+ * we pick the first we come across (if any).
+ * If we don't find any, we pick the first opportunistic
+ * with the smallest subnet that includes the peer.
+ * There is, of course, no necessary relationship between
+ * an Initiator's address and that of its client,
+ * but Food Groups kind of assumes one.
+ */
+ {
+ struct connection *d;
+
+ d = find_host_connection(&md->iface->addr
+ , pluto_port, (ip_address*)NULL, md->sender_port, policy);
+
+ for (; d != NULL; d = d->hp_next)
+ {
+ if (d->kind == CK_GROUP)
+ {
+ /* ignore */
+ }
+ else
+ {
+ if (d->kind == CK_TEMPLATE && !(d->policy & POLICY_OPPO))
+ {
+ /* must be Road Warrior: we have a winner */
+ c = d;
+ break;
+ }
+
+ /* Opportunistic or Shunt: pick tightest match */
+ if (addrinsubnet(&md->sender, &d->spd.that.client)
+ && (c == NULL || !subnetinsubnet(&c->spd.that.client, &d->spd.that.client)))
+ c = d;
+ }
+ }
+ }
+
+ if (c == NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "initial Main Mode message received on %s:%u"
+ " but no connection has been authorized%s%s"
+ , ip_str(&md->iface->addr), ntohs(portof(&md->iface->addr))
+ , (policy != LEMPTY) ? " with policy=" : ""
+ , (policy != LEMPTY) ? bitnamesof(sa_policy_bit_names, policy) : "");
+ /* XXX notification is in order! */
+ return STF_IGNORE;
+ }
+ else if (c->kind != CK_TEMPLATE)
+ {
+ loglog(RC_LOG_SERIOUS, "initial Main Mode message received on %s:%u"
+ " but \"%s\" forbids connection"
+ , ip_str(&md->iface->addr), pluto_port, c->name);
+ /* XXX notification is in order! */
+ return STF_IGNORE;
+ }
+ else
+ {
+ /* Create a temporary connection that is a copy of this one.
+ * His ID isn't declared yet.
+ */
+ c = rw_instantiate(c, &md->sender, md->sender_port, NULL, NULL);
+ }
+ }
+ else if (c->kind == CK_TEMPLATE)
+ {
+ /* Create an instance
+ * This is a rare case: wildcard peer ID but static peer IP address
+ */
+ c = rw_instantiate(c, &md->sender, md->sender_port, NULL, &c->spd.that.id);
+ }
+
+ /* Set up state */
+ md->st = st = new_state();
+ st->st_connection = c;
+ set_cur_state(st); /* (caller will reset cur_state) */
+ st->st_try = 0; /* not our job to try again from start */
+ st->st_policy = c->policy & ~POLICY_IPSEC_MASK; /* only as accurate as connection */
+
+ memcpy(st->st_icookie, md->hdr.isa_icookie, COOKIE_SIZE);
+ get_cookie(FALSE, st->st_rcookie, COOKIE_SIZE, &md->sender);
+
+ insert_state(st); /* needs cookies, connection, and msgid (0) */
+
+ st->st_doi = ISAKMP_DOI_IPSEC;
+ st->st_situation = SIT_IDENTITY_ONLY; /* We only support this */
+
+ if ((c->kind == CK_INSTANCE) && (c->spd.that.host_port != pluto_port))
+ {
+ plog("responding to Main Mode from unknown peer %s:%u"
+ , ip_str(&c->spd.that.host_addr), c->spd.that.host_port);
+ }
+ else if (c->kind == CK_INSTANCE)
+ {
+ plog("responding to Main Mode from unknown peer %s"
+ , ip_str(&c->spd.that.host_addr));
+ }
+ else
+ {
+ plog("responding to Main Mode");
+ }
+
+ /* parse_isakmp_sa also spits out a winning SA into our reply,
+ * so we have to build our md->reply and emit HDR before calling it.
+ */
+
+ /* determine how many Vendor ID payloads we will be sending */
+ if (SEND_PLUTO_VID)
+ vids_to_send++;
+ if (SEND_CISCO_UNITY_VID)
+ vids_to_send++;
+ if (md->openpgp)
+ vids_to_send++;
+ /* always send XAUTH Vendor ID */
+ vids_to_send++;
+ /* always send DPD Vendor ID */
+ vids_to_send++;
+ if (md->nat_traversal_vid && nat_traversal_enabled)
+ vids_to_send++;
+
+ /* HDR out.
+ * We can't leave this to comm_handle() because we must
+ * fill in the cookie.
+ */
+ {
+ struct isakmp_hdr r_hdr = md->hdr;
+
+ r_hdr.isa_flags &= ~ISAKMP_FLAG_COMMIT; /* we won't ever turn on this bit */
+ memcpy(r_hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE);
+ r_hdr.isa_np = ISAKMP_NEXT_SA;
+ if (!out_struct(&r_hdr, &isakmp_hdr_desc, &md->reply, &md->rbody))
+ return STF_INTERNAL_ERROR;
+ }
+
+ /* start of SA out */
+ {
+ struct isakmp_sa r_sa = sa_pd->payload.sa;
+
+ r_sa.isasa_np = vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE;
+
+ if (!out_struct(&r_sa, &isakmp_sa_desc, &md->rbody, &r_sa_pbs))
+ return STF_INTERNAL_ERROR;
+ }
+
+ /* SA body in and out */
+ RETURN_STF_FAILURE(parse_isakmp_sa_body(ipsecdoisit, &proposal_pbs
+ ,&proposal, &r_sa_pbs, st, FALSE));
+
+ /* if enabled send Pluto Vendor ID */
+ if (SEND_PLUTO_VID)
+ {
+ if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE
+ , &md->rbody, VID_STRONGSWAN))
+ {
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+ /* if enabled send Cisco Unity Vendor ID */
+ if (SEND_CISCO_UNITY_VID)
+ {
+ if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE
+ , &md->rbody, VID_CISCO_UNITY))
+ {
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+ /*
+ * if the peer sent an OpenPGP Vendor ID we offer the same capability
+ */
+ if (md->openpgp)
+ {
+ if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE
+ , &md->rbody, VID_OPENPGP))
+ {
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+ /* Announce our ability to do eXtended AUTHentication to the peer */
+ if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE
+ , &md->rbody, VID_MISC_XAUTH))
+ {
+ return STF_INTERNAL_ERROR;
+ }
+
+ /* Announce our ability to do Dead Peer Detection to the peer */
+ if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE
+ , &md->rbody, VID_MISC_DPD))
+ {
+ return STF_INTERNAL_ERROR;
+ }
+
+ if (md->nat_traversal_vid && nat_traversal_enabled)
+ {
+ /* reply if NAT-Traversal draft is supported */
+ st->nat_traversal = nat_traversal_vid_to_method(md->nat_traversal_vid);
+
+ if (st->nat_traversal
+ && !out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE
+ , &md->rbody, md->nat_traversal_vid))
+ {
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+ close_message(&md->rbody);
+
+ /* save initiator SA for HASH */
+ clonereplacechunk(st->st_p1isa, sa_pd->pbs.start, pbs_room(&sa_pd->pbs), "sa in main_inI1_outR1()");
+
+ return STF_OK;
+}
+
+/* STATE_MAIN_I1: HDR, SA --> auth dependent
+ * PSK_AUTH, DS_AUTH: --> HDR, KE, Ni
+ *
+ * The following are not yet implemented:
+ * PKE_AUTH: --> HDR, KE, [ HASH(1), ] <IDi1_b>PubKey_r, <Ni_b>PubKey_r
+ * RPKE_AUTH: --> HDR, [ HASH(1), ] <Ni_b>Pubkey_r, <KE_b>Ke_i,
+ * <IDi1_b>Ke_i [,<<Cert-I_b>Ke_i]
+ *
+ * We must verify that the proposal received matches one we sent.
+ */
+stf_status
+main_inR1_outI2(struct msg_digest *md)
+{
+ struct state *const st = md->st;
+
+ u_int8_t np = ISAKMP_NEXT_NONE;
+
+ /* verify echoed SA */
+ {
+ u_int32_t ipsecdoisit;
+ pb_stream proposal_pbs;
+ struct isakmp_proposal proposal;
+ struct payload_digest *const sapd = md->chain[ISAKMP_NEXT_SA];
+
+ RETURN_STF_FAILURE(preparse_isakmp_sa_body(&sapd->payload.sa
+ ,&sapd->pbs, &ipsecdoisit, &proposal_pbs, &proposal));
+ if (proposal.isap_notrans != 1)
+ {
+ loglog(RC_LOG_SERIOUS, "a single Transform is required in a selecting Oakley Proposal; found %u"
+ , (unsigned)proposal.isap_notrans);
+ RETURN_STF_FAILURE(BAD_PROPOSAL_SYNTAX);
+ }
+ RETURN_STF_FAILURE(parse_isakmp_sa_body(ipsecdoisit
+ , &proposal_pbs, &proposal, NULL, st, TRUE));
+ }
+
+ if (nat_traversal_enabled && md->nat_traversal_vid)
+ {
+ st->nat_traversal = nat_traversal_vid_to_method(md->nat_traversal_vid);
+ plog("enabling possible NAT-traversal with method %s"
+ , bitnamesof(natt_type_bitnames, st->nat_traversal));
+ }
+ if (st->nat_traversal & NAT_T_WITH_NATD)
+ {
+ np = (st->nat_traversal & NAT_T_WITH_RFC_VALUES) ?
+ ISAKMP_NEXT_NATD_RFC : ISAKMP_NEXT_NATD_DRAFTS;
+ }
+
+ /**************** build output packet HDR;KE;Ni ****************/
+
+ /* HDR out.
+ * We can't leave this to comm_handle() because the isa_np
+ * depends on the type of Auth (eventually).
+ */
+ echo_hdr(md, FALSE, ISAKMP_NEXT_KE);
+
+ /* KE out */
+ if (!build_and_ship_KE(st, &st->st_gi, st->st_oakley.group
+ , &md->rbody, ISAKMP_NEXT_NONCE))
+ return STF_INTERNAL_ERROR;
+
+#ifdef DEBUG
+ /* Ni out */
+ if (!build_and_ship_nonce(&st->st_ni, &md->rbody
+ , (cur_debugging & IMPAIR_BUST_MI2)? ISAKMP_NEXT_VID : np, "Ni"))
+ return STF_INTERNAL_ERROR;
+
+ if (cur_debugging & IMPAIR_BUST_MI2)
+ {
+ /* generate a pointless large VID payload to push message over MTU */
+ pb_stream vid_pbs;
+
+ if (!out_generic(np, &isakmp_vendor_id_desc, &md->rbody, &vid_pbs))
+ return STF_INTERNAL_ERROR;
+ if (!out_zero(1500 /*MTU?*/, &vid_pbs, "Filler VID"))
+ return STF_INTERNAL_ERROR;
+ close_output_pbs(&vid_pbs);
+ }
+#else
+ /* Ni out */
+ if (!build_and_ship_nonce(&st->st_ni, &md->rbody, np, "Ni"))
+ return STF_INTERNAL_ERROR;
+#endif
+
+ if (st->nat_traversal & NAT_T_WITH_NATD)
+ {
+ if (!nat_traversal_add_natd(ISAKMP_NEXT_NONE, &md->rbody, md))
+ return STF_INTERNAL_ERROR;
+ }
+
+ /* finish message */
+ close_message(&md->rbody);
+
+ /* Reinsert the state, using the responder cookie we just received */
+ unhash_state(st);
+ memcpy(st->st_rcookie, md->hdr.isa_rcookie, COOKIE_SIZE);
+ insert_state(st); /* needs cookies, connection, and msgid (0) */
+
+ return STF_OK;
+}
+
+/* STATE_MAIN_R1:
+ * PSK_AUTH, DS_AUTH: HDR, KE, Ni --> HDR, KE, Nr
+ *
+ * The following are not yet implemented:
+ * PKE_AUTH: HDR, KE, [ HASH(1), ] <IDi1_b>PubKey_r, <Ni_b>PubKey_r
+ * --> HDR, KE, <IDr1_b>PubKey_i, <Nr_b>PubKey_i
+ * RPKE_AUTH:
+ * HDR, [ HASH(1), ] <Ni_b>Pubkey_r, <KE_b>Ke_i, <IDi1_b>Ke_i [,<<Cert-I_b>Ke_i]
+ * --> HDR, <Nr_b>PubKey_i, <KE_b>Ke_r, <IDr1_b>Ke_r
+ */
+stf_status
+main_inI2_outR2(struct msg_digest *md)
+{
+ struct state *const st = md->st;
+ pb_stream *keyex_pbs = &md->chain[ISAKMP_NEXT_KE]->pbs;
+
+ /* send CR if auth is RSA and no preloaded RSA public key exists*/
+ bool RSA_auth = st->st_oakley.auth == OAKLEY_RSA_SIG
+ || st->st_oakley.auth == XAUTHInitRSA
+ || st->st_oakley.auth == XAUTHRespRSA;
+ bool send_cr = !no_cr_send && RSA_auth && !has_preloaded_public_key(st);
+
+ u_int8_t np = ISAKMP_NEXT_NONE;
+
+ /* KE in */
+ RETURN_STF_FAILURE(accept_KE(&st->st_gi, "Gi", st->st_oakley.group, keyex_pbs));
+
+ /* Ni in */
+ RETURN_STF_FAILURE(accept_nonce(md, &st->st_ni, "Ni"));
+
+ if (st->nat_traversal & NAT_T_WITH_NATD)
+ {
+ nat_traversal_natd_lookup(md);
+
+ np = (st->nat_traversal & NAT_T_WITH_RFC_VALUES) ?
+ ISAKMP_NEXT_NATD_RFC : ISAKMP_NEXT_NATD_DRAFTS;
+ }
+ if (st->nat_traversal)
+ {
+ nat_traversal_show_result(st->nat_traversal, md->sender_port);
+ }
+ if (st->nat_traversal & NAT_T_WITH_KA)
+ {
+ nat_traversal_new_ka_event();
+ }
+
+ /* decode certificate requests */
+ st->st_connection->got_certrequest = FALSE;
+ decode_cr(md, st->st_connection);
+
+ /**************** build output packet HDR;KE;Nr ****************/
+
+ /* HDR out done */
+
+ /* KE out */
+ if (!build_and_ship_KE(st, &st->st_gr, st->st_oakley.group
+ , &md->rbody, ISAKMP_NEXT_NONCE))
+ return STF_INTERNAL_ERROR;
+
+#ifdef DEBUG
+ /* Nr out */
+ if (!build_and_ship_nonce(&st->st_nr, &md->rbody
+ , (cur_debugging & IMPAIR_BUST_MR2)? ISAKMP_NEXT_VID
+ : (send_cr? ISAKMP_NEXT_CR : np), "Nr"))
+ return STF_INTERNAL_ERROR;
+
+ if (cur_debugging & IMPAIR_BUST_MR2)
+ {
+ /* generate a pointless large VID payload to push message over MTU */
+ pb_stream vid_pbs;
+
+ if (!out_generic((send_cr)? ISAKMP_NEXT_CR : np,
+ &isakmp_vendor_id_desc, &md->rbody, &vid_pbs))
+ return STF_INTERNAL_ERROR;
+ if (!out_zero(1500 /*MTU?*/, &vid_pbs, "Filler VID"))
+ return STF_INTERNAL_ERROR;
+ close_output_pbs(&vid_pbs);
+ }
+#else
+ /* Nr out */
+ if (!build_and_ship_nonce(&st->st_nr, &md->rbody,
+ (send_cr)? ISAKMP_NEXT_CR : np, "Nr"))
+ return STF_INTERNAL_ERROR;
+#endif
+
+ /* CR out */
+ if (send_cr)
+ {
+ if (st->st_connection->kind == CK_PERMANENT)
+ {
+ if (!build_and_ship_CR(CERT_X509_SIGNATURE
+ , st->st_connection->spd.that.ca
+ , &md->rbody, np))
+ return STF_INTERNAL_ERROR;
+ }
+ else
+ {
+ generalName_t *ca = NULL;
+
+ if (collect_rw_ca_candidates(md, &ca))
+ {
+ generalName_t *gn;
+
+ for (gn = ca; gn != NULL; gn = gn->next)
+ {
+ if (!build_and_ship_CR(CERT_X509_SIGNATURE, gn->name
+ , &md->rbody
+ , gn->next == NULL ? np : ISAKMP_NEXT_CR))
+ return STF_INTERNAL_ERROR;
+ }
+ free_generalNames(ca, FALSE);
+ }
+ else
+ {
+ if (!build_and_ship_CR(CERT_X509_SIGNATURE, empty_chunk
+ , &md->rbody, np))
+ return STF_INTERNAL_ERROR;
+ }
+ }
+ }
+
+ if (st->nat_traversal & NAT_T_WITH_NATD)
+ {
+ if (!nat_traversal_add_natd(ISAKMP_NEXT_NONE, &md->rbody, md))
+ return STF_INTERNAL_ERROR;
+ }
+
+ /* finish message */
+ close_message(&md->rbody);
+
+ /* next message will be encrypted, but not this one.
+ * We could defer this calculation.
+ */
+ compute_dh_shared(st, st->st_gi, st->st_oakley.group);
+ if (!generate_skeyids_iv(st))
+ return STF_FAIL + AUTHENTICATION_FAILED;
+ update_iv(st);
+
+ return STF_OK;
+}
+
+/* STATE_MAIN_I2:
+ * SMF_PSK_AUTH: HDR, KE, Nr --> HDR*, IDi1, HASH_I
+ * SMF_DS_AUTH: HDR, KE, Nr --> HDR*, IDi1, [ CERT, ] SIG_I
+ *
+ * The following are not yet implemented.
+ * SMF_PKE_AUTH: HDR, KE, <IDr1_b>PubKey_i, <Nr_b>PubKey_i
+ * --> HDR*, HASH_I
+ * SMF_RPKE_AUTH: HDR, <Nr_b>PubKey_i, <KE_b>Ke_r, <IDr1_b>Ke_r
+ * --> HDR*, HASH_I
+ */
+stf_status
+main_inR2_outI3(struct msg_digest *md)
+{
+ struct state *const st = md->st;
+ pb_stream *const keyex_pbs = &md->chain[ISAKMP_NEXT_KE]->pbs;
+ pb_stream id_pbs; /* ID Payload; also used for hash calculation */
+
+ certpolicy_t cert_policy = st->st_connection->spd.this.sendcert;
+ cert_t mycert = st->st_connection->spd.this.cert;
+ bool requested, send_cert, send_cr;
+
+ bool RSA_auth = st->st_oakley.auth == OAKLEY_RSA_SIG
+ || st->st_oakley.auth == XAUTHInitRSA
+ || st->st_oakley.auth == XAUTHRespRSA;
+
+ int auth_payload = RSA_auth ? ISAKMP_NEXT_SIG : ISAKMP_NEXT_HASH;
+
+ /* KE in */
+ RETURN_STF_FAILURE(accept_KE(&st->st_gr, "Gr", st->st_oakley.group, keyex_pbs));
+
+ /* Nr in */
+ RETURN_STF_FAILURE(accept_nonce(md, &st->st_nr, "Nr"));
+
+ /* decode certificate requests */
+ st->st_connection->got_certrequest = FALSE;
+ decode_cr(md, st->st_connection);
+
+ /* free collected certificate requests since as initiator
+ * we don't heed them anyway
+ */
+ free_generalNames(st->st_connection->requested_ca, TRUE);
+ st->st_connection->requested_ca = NULL;
+
+ /* send certificate if auth is RSA, we have one and we want
+ * or are requested to send it
+ */
+ requested = cert_policy == CERT_SEND_IF_ASKED
+ && st->st_connection->got_certrequest;
+ send_cert = RSA_auth && mycert.type != CERT_NONE
+ && (cert_policy == CERT_ALWAYS_SEND || requested);
+
+ /* send certificate request if we don't have a preloaded RSA public key */
+ send_cr = !no_cr_send && send_cert && !has_preloaded_public_key(st);
+
+ /* done parsing; initialize crypto */
+ compute_dh_shared(st, st->st_gr, st->st_oakley.group);
+ if (!generate_skeyids_iv(st))
+ return STF_FAIL + AUTHENTICATION_FAILED;
+
+ if (st->nat_traversal & NAT_T_WITH_NATD)
+ {
+ nat_traversal_natd_lookup(md);
+ }
+ if (st->nat_traversal)
+ {
+ nat_traversal_show_result(st->nat_traversal, md->sender_port);
+ }
+ if (st->nat_traversal & NAT_T_WITH_KA)
+ {
+ nat_traversal_new_ka_event();
+ }
+
+ /*************** build output packet HDR*;IDii;HASH/SIG_I ***************/
+ /* ??? NOTE: this is almost the same as main_inI3_outR3's code */
+
+ /* HDR* out done */
+
+ /* IDii out */
+ {
+ struct isakmp_ipsec_id id_hd;
+ chunk_t id_b;
+
+ build_id_payload(&id_hd, &id_b, &st->st_connection->spd.this);
+ id_hd.isaiid_np = (send_cert)? ISAKMP_NEXT_CERT : auth_payload;
+ if (!out_struct(&id_hd, &isakmp_ipsec_identification_desc, &md->rbody, &id_pbs)
+ || !out_chunk(id_b, &id_pbs, "my identity"))
+ return STF_INTERNAL_ERROR;
+ close_output_pbs(&id_pbs);
+ }
+
+ /* CERT out */
+ if (RSA_auth)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("our certificate policy is %s"
+ , enum_name(&cert_policy_names, cert_policy))
+ )
+ if (mycert.type != CERT_NONE)
+ {
+ const char *request_text = "";
+
+ if (cert_policy == CERT_SEND_IF_ASKED)
+ request_text = (send_cert)? "upon request":"without request";
+ plog("we have a cert %s sending it %s"
+ , send_cert? "and are":"but are not", request_text);
+ }
+ else
+ {
+ plog("we don't have a cert");
+ }
+ }
+ if (send_cert)
+ {
+ pb_stream cert_pbs;
+
+ struct isakmp_cert cert_hd;
+ cert_hd.isacert_np = (send_cr)? ISAKMP_NEXT_CR : ISAKMP_NEXT_SIG;
+ cert_hd.isacert_type = mycert.type;
+
+ if (!out_struct(&cert_hd, &isakmp_ipsec_certificate_desc, &md->rbody, &cert_pbs))
+ return STF_INTERNAL_ERROR;
+ if (!out_chunk(get_mycert(mycert), &cert_pbs, "CERT"))
+ return STF_INTERNAL_ERROR;
+ close_output_pbs(&cert_pbs);
+ }
+
+ /* CR out */
+ if (send_cr)
+ {
+ if (!build_and_ship_CR(mycert.type, st->st_connection->spd.that.ca
+ , &md->rbody, ISAKMP_NEXT_SIG))
+ return STF_INTERNAL_ERROR;
+ }
+
+ /* HASH_I or SIG_I out */
+ {
+ u_char hash_val[MAX_DIGEST_LEN];
+ size_t hash_len = main_mode_hash(st, hash_val, TRUE, &id_pbs);
+
+ if (auth_payload == ISAKMP_NEXT_HASH)
+ {
+ /* HASH_I out */
+ if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_hash_desc, &md->rbody
+ , hash_val, hash_len, "HASH_I"))
+ return STF_INTERNAL_ERROR;
+ }
+ else
+ {
+ /* SIG_I out */
+ u_char sig_val[RSA_MAX_OCTETS];
+ size_t sig_len = RSA_sign_hash(st->st_connection
+ , sig_val, hash_val, hash_len);
+
+ if (sig_len == 0)
+ {
+ loglog(RC_LOG_SERIOUS, "unable to locate my private key for RSA Signature");
+ return STF_FAIL + AUTHENTICATION_FAILED;
+ }
+
+ if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_signature_desc
+ , &md->rbody, sig_val, sig_len, "SIG_I"))
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+ /* encrypt message, except for fixed part of header */
+
+ /* st_new_iv was computed by generate_skeyids_iv */
+ if (!encrypt_message(&md->rbody, st))
+ return STF_INTERNAL_ERROR; /* ??? we may be partly committed */
+
+ return STF_OK;
+}
+
+/* Shared logic for asynchronous lookup of DNS KEY records.
+ * Used for STATE_MAIN_R2 and STATE_MAIN_I3.
+ */
+
+enum key_oppo_step {
+ kos_null,
+ kos_his_txt
+#ifdef USE_KEYRR
+ , kos_his_key
+#endif
+};
+
+struct key_continuation {
+ struct adns_continuation ac; /* common prefix */
+ struct msg_digest *md;
+ enum key_oppo_step step;
+ bool failure_ok;
+ err_t last_ugh;
+};
+
+typedef stf_status (key_tail_fn)(struct msg_digest *md
+ , struct key_continuation *kc);
+static void
+report_key_dns_failure(struct id *id, err_t ugh)
+{
+ char id_buf[BUF_LEN]; /* arbitrary limit on length of ID reported */
+
+ (void) idtoa(id, id_buf, sizeof(id_buf));
+ loglog(RC_LOG_SERIOUS, "no RSA public key known for '%s'"
+ "; DNS search for KEY failed (%s)", id_buf, ugh);
+}
+
+
+/* Processs the Main Mode ID Payload and the Authenticator
+ * (Hash or Signature Payload).
+ * If a DNS query is still needed to get the other host's public key,
+ * the query is initiated and STF_SUSPEND is returned.
+ * Note: parameter kc is a continuation containing the results from
+ * the previous DNS query, or NULL indicating no query has been issued.
+ */
+static stf_status
+main_id_and_auth(struct msg_digest *md
+ , bool initiator /* are we the Initiator? */
+ , cont_fn_t cont_fn /* continuation function */
+ , const struct key_continuation *kc /* current state, can be NULL */
+)
+{
+ struct state *st = md->st;
+ u_char hash_val[MAX_DIGEST_LEN];
+ size_t hash_len;
+ struct id peer;
+ stf_status r = STF_OK;
+
+ /* ID Payload in */
+ if (!decode_peer_id(md, &peer))
+ return STF_FAIL + INVALID_ID_INFORMATION;
+
+ /* Hash the ID Payload.
+ * main_mode_hash requires idpl->cur to be at end of payload
+ * so we temporarily set if so.
+ */
+ {
+ pb_stream *idpl = &md->chain[ISAKMP_NEXT_ID]->pbs;
+ u_int8_t *old_cur = idpl->cur;
+
+ idpl->cur = idpl->roof;
+ hash_len = main_mode_hash(st, hash_val, !initiator, idpl);
+ idpl->cur = old_cur;
+ }
+
+ switch (st->st_oakley.auth)
+ {
+ case OAKLEY_PRESHARED_KEY:
+ case XAUTHInitPreShared:
+ case XAUTHRespPreShared:
+ {
+ pb_stream *const hash_pbs = &md->chain[ISAKMP_NEXT_HASH]->pbs;
+
+ if (pbs_left(hash_pbs) != hash_len
+ || memcmp(hash_pbs->cur, hash_val, hash_len) != 0)
+ {
+ DBG_cond_dump(DBG_CRYPT, "received HASH:"
+ , hash_pbs->cur, pbs_left(hash_pbs));
+ loglog(RC_LOG_SERIOUS, "received Hash Payload does not match computed value");
+ /* XXX Could send notification back */
+ r = STF_FAIL + INVALID_HASH_INFORMATION;
+ }
+ }
+ break;
+
+ case OAKLEY_RSA_SIG:
+ case XAUTHInitRSA:
+ case XAUTHRespRSA:
+ r = RSA_check_signature(&peer, st, hash_val, hash_len
+ , &md->chain[ISAKMP_NEXT_SIG]->pbs
+#ifdef USE_KEYRR
+ , kc == NULL? NULL : kc->ac.keys_from_dns
+#endif /* USE_KEYRR */
+ , kc == NULL? NULL : kc->ac.gateways_from_dns
+ );
+
+ if (r == STF_SUSPEND)
+ {
+ /* initiate/resume asynchronous DNS lookup for key */
+ struct key_continuation *nkc
+ = alloc_thing(struct key_continuation, "key continuation");
+ enum key_oppo_step step_done = kc == NULL? kos_null : kc->step;
+ err_t ugh;
+
+ /* Record that state is used by a suspended md */
+ passert(st->st_suspended_md == NULL);
+ st->st_suspended_md = md;
+
+ nkc->failure_ok = FALSE;
+ nkc->md = md;
+
+ switch (step_done)
+ {
+ case kos_null:
+ /* first try: look for the TXT records */
+ nkc->step = kos_his_txt;
+#ifdef USE_KEYRR
+ nkc->failure_ok = TRUE;
+#endif
+ ugh = start_adns_query(&peer
+ , &peer /* SG itself */
+ , T_TXT
+ , cont_fn
+ , &nkc->ac);
+ break;
+
+#ifdef USE_KEYRR
+ case kos_his_txt:
+ /* second try: look for the KEY records */
+ nkc->step = kos_his_key;
+ ugh = start_adns_query(&peer
+ , NULL /* no sgw for KEY */
+ , T_KEY
+ , cont_fn
+ , &nkc->ac);
+ break;
+#endif /* USE_KEYRR */
+
+ default:
+ bad_case(step_done);
+ }
+
+ if (ugh != NULL)
+ {
+ report_key_dns_failure(&peer, ugh);
+ st->st_suspended_md = NULL;
+ r = STF_FAIL + INVALID_KEY_INFORMATION;
+ }
+ }
+ break;
+
+ default:
+ bad_case(st->st_oakley.auth);
+ }
+ if (r != STF_OK)
+ return r;
+
+ DBG(DBG_CRYPT, DBG_log("authentication succeeded"));
+
+ /*
+ * With the peer ID known, let's see if we need to switch connections.
+ */
+ if (!switch_connection(md, &peer, initiator))
+ return STF_FAIL + INVALID_ID_INFORMATION;
+
+ return r;
+}
+
+/* This continuation is called as part of either
+ * the main_inI3_outR3 state or main_inR3 state.
+ *
+ * The "tail" function is the corresponding tail
+ * function main_inI3_outR3_tail | main_inR3_tail,
+ * either directly when the state is started, or via
+ * adns continuation.
+ *
+ * Basically, we go around in a circle:
+ * main_in?3* -> key_continue
+ * ^ \
+ * / V
+ * adns main_in?3*_tail
+ * ^ |
+ * \ V
+ * main_id_and_auth
+ *
+ * until such time as main_id_and_auth is able
+ * to find authentication, or we run out of things
+ * to try.
+ */
+static void
+key_continue(struct adns_continuation *cr
+, err_t ugh
+, key_tail_fn *tail)
+{
+ struct key_continuation *kc = (void *)cr;
+ struct state *st = kc->md->st;
+
+ passert(cur_state == NULL);
+
+ /* if st == NULL, our state has been deleted -- just clean up */
+ if (st != NULL)
+ {
+ stf_status r;
+
+ passert(st->st_suspended_md == kc->md);
+ st->st_suspended_md = NULL; /* no longer connected or suspended */
+ cur_state = st;
+
+ if (!kc->failure_ok && ugh != NULL)
+ {
+ report_key_dns_failure(&st->st_connection->spd.that.id, ugh);
+ r = STF_FAIL + INVALID_KEY_INFORMATION;
+ }
+ else
+ {
+
+#ifdef USE_KEYRR
+ passert(kc->step == kos_his_txt || kc->step == kos_his_key);
+#else
+ passert(kc->step == kos_his_txt);
+#endif
+ kc->last_ugh = ugh; /* record previous error in case we need it */
+ r = (*tail)(kc->md, kc);
+ }
+ complete_state_transition(&kc->md, r);
+ }
+ if (kc->md != NULL)
+ release_md(kc->md);
+ cur_state = NULL;
+}
+
+/* STATE_MAIN_R2:
+ * PSK_AUTH: HDR*, IDi1, HASH_I --> HDR*, IDr1, HASH_R
+ * DS_AUTH: HDR*, IDi1, [ CERT, ] SIG_I --> HDR*, IDr1, [ CERT, ] SIG_R
+ * PKE_AUTH, RPKE_AUTH: HDR*, HASH_I --> HDR*, HASH_R
+ *
+ * Broken into parts to allow asynchronous DNS lookup.
+ *
+ * - main_inI3_outR3 to start
+ * - main_inI3_outR3_tail to finish or suspend for DNS lookup
+ * - main_inI3_outR3_continue to start main_inI3_outR3_tail again
+ */
+static key_tail_fn main_inI3_outR3_tail; /* forward */
+
+stf_status
+main_inI3_outR3(struct msg_digest *md)
+{
+ return main_inI3_outR3_tail(md, NULL);
+}
+
+static void
+main_inI3_outR3_continue(struct adns_continuation *cr, err_t ugh)
+{
+ key_continue(cr, ugh, main_inI3_outR3_tail);
+}
+
+static stf_status
+main_inI3_outR3_tail(struct msg_digest *md
+, struct key_continuation *kc)
+{
+ struct state *const st = md->st;
+ u_int8_t auth_payload;
+ pb_stream r_id_pbs; /* ID Payload; also used for hash calculation */
+ certpolicy_t cert_policy;
+ cert_t mycert;
+ bool RSA_auth;
+ bool send_cert;
+ bool requested;
+
+ /* ID and HASH_I or SIG_I in
+ * Note: this may switch the connection being used!
+ */
+ {
+ stf_status r = main_id_and_auth(md, FALSE
+ , main_inI3_outR3_continue
+ , kc);
+
+ if (r != STF_OK)
+ return r;
+ }
+
+ /* send certificate if auth is RSA, we have one and we want
+ * or are requested to send it
+ */
+ cert_policy = st->st_connection->spd.this.sendcert;
+ mycert = st->st_connection->spd.this.cert;
+ requested = cert_policy == CERT_SEND_IF_ASKED
+ && st->st_connection->got_certrequest;
+ RSA_auth = st->st_oakley.auth == OAKLEY_RSA_SIG
+ || st->st_oakley.auth == XAUTHInitRSA
+ || st->st_oakley.auth == XAUTHRespRSA;
+ send_cert = RSA_auth
+ && mycert.type != CERT_NONE
+ && (cert_policy == CERT_ALWAYS_SEND || requested);
+
+ /*************** build output packet HDR*;IDir;HASH/SIG_R ***************/
+ /* proccess_packet() would automatically generate the HDR*
+ * payload if smc->first_out_payload is not ISAKMP_NEXT_NONE.
+ * We don't do this because we wish there to be no partially
+ * built output packet if we need to suspend for asynch DNS.
+ */
+ /* ??? NOTE: this is almost the same as main_inR2_outI3's code */
+
+ /* HDR* out
+ * If auth were PKE_AUTH or RPKE_AUTH, ISAKMP_NEXT_HASH would
+ * be first payload.
+ */
+ echo_hdr(md, TRUE, ISAKMP_NEXT_ID);
+
+ auth_payload = RSA_auth ? ISAKMP_NEXT_SIG : ISAKMP_NEXT_HASH;
+
+ /* IDir out */
+ {
+ /* id_hd should be struct isakmp_id, but struct isakmp_ipsec_id
+ * allows build_id_payload() to work for both phases.
+ */
+ struct isakmp_ipsec_id id_hd;
+ chunk_t id_b;
+
+ build_id_payload(&id_hd, &id_b, &st->st_connection->spd.this);
+ id_hd.isaiid_np = (send_cert)? ISAKMP_NEXT_CERT : auth_payload;
+ if (!out_struct(&id_hd, &isakmp_ipsec_identification_desc, &md->rbody, &r_id_pbs)
+ || !out_chunk(id_b, &r_id_pbs, "my identity"))
+ return STF_INTERNAL_ERROR;
+ close_output_pbs(&r_id_pbs);
+ }
+
+ /* CERT out */
+ if (RSA_auth)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("our certificate policy is %s"
+ , enum_name(&cert_policy_names, cert_policy))
+ )
+ if (mycert.type != CERT_NONE)
+ {
+ const char *request_text = "";
+
+ if (cert_policy == CERT_SEND_IF_ASKED)
+ request_text = (send_cert)? "upon request":"without request";
+ plog("we have a cert %s sending it %s"
+ , send_cert? "and are":"but are not", request_text);
+ }
+ else
+ {
+ plog("we don't have a cert");
+ }
+ }
+ if (send_cert)
+ {
+ pb_stream cert_pbs;
+
+ struct isakmp_cert cert_hd;
+ cert_hd.isacert_np = ISAKMP_NEXT_SIG;
+ cert_hd.isacert_type = mycert.type;
+
+ if (!out_struct(&cert_hd, &isakmp_ipsec_certificate_desc, &md->rbody, &cert_pbs))
+ return STF_INTERNAL_ERROR;
+ if (!out_chunk(get_mycert(mycert), &cert_pbs, "CERT"))
+ return STF_INTERNAL_ERROR;
+ close_output_pbs(&cert_pbs);
+ }
+
+ /* HASH_R or SIG_R out */
+ {
+ u_char hash_val[MAX_DIGEST_LEN];
+ size_t hash_len = main_mode_hash(st, hash_val, FALSE, &r_id_pbs);
+
+ if (auth_payload == ISAKMP_NEXT_HASH)
+ {
+ /* HASH_R out */
+ if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_hash_desc, &md->rbody
+ , hash_val, hash_len, "HASH_R"))
+ return STF_INTERNAL_ERROR;
+ }
+ else
+ {
+ /* SIG_R out */
+ u_char sig_val[RSA_MAX_OCTETS];
+ size_t sig_len = RSA_sign_hash(st->st_connection
+ , sig_val, hash_val, hash_len);
+
+ if (sig_len == 0)
+ {
+ loglog(RC_LOG_SERIOUS, "unable to locate my private key for RSA Signature");
+ return STF_FAIL + AUTHENTICATION_FAILED;
+ }
+
+ if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_signature_desc
+ , &md->rbody, sig_val, sig_len, "SIG_R"))
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+ /* encrypt message, sans fixed part of header */
+
+ if (!encrypt_message(&md->rbody, st))
+ return STF_INTERNAL_ERROR; /* ??? we may be partly committed */
+
+ /* Last block of Phase 1 (R3), kept for Phase 2 IV generation */
+ DBG_cond_dump(DBG_CRYPT, "last encrypted block of Phase 1:"
+ , st->st_new_iv, st->st_new_iv_len);
+
+ ISAKMP_SA_established(st->st_connection, st->st_serialno);
+
+ /* Save Phase 1 IV */
+ st->st_ph1_iv_len = st->st_new_iv_len;
+ set_ph1_iv(st, st->st_new_iv);
+
+ return STF_OK;
+}
+
+/* STATE_MAIN_I3:
+ * Handle HDR*;IDir;HASH/SIG_R from responder.
+ *
+ * Broken into parts to allow asynchronous DNS for KEY records.
+ *
+ * - main_inR3 to start
+ * - main_inR3_tail to finish or suspend for DNS lookup
+ * - main_inR3_continue to start main_inR3_tail again
+ */
+
+static key_tail_fn main_inR3_tail; /* forward */
+
+stf_status
+main_inR3(struct msg_digest *md)
+{
+ return main_inR3_tail(md, NULL);
+}
+
+static void
+main_inR3_continue(struct adns_continuation *cr, err_t ugh)
+{
+ key_continue(cr, ugh, main_inR3_tail);
+}
+
+static stf_status
+main_inR3_tail(struct msg_digest *md
+, struct key_continuation *kc)
+{
+ struct state *const st = md->st;
+
+ /* ID and HASH_R or SIG_R in
+ * Note: this may switch the connection being used!
+ */
+ {
+ stf_status r = main_id_and_auth(md, TRUE, main_inR3_continue, kc);
+
+ if (r != STF_OK)
+ return r;
+ }
+
+ /**************** done input ****************/
+
+ ISAKMP_SA_established(st->st_connection, st->st_serialno);
+
+ /* Save Phase 1 IV */
+ st->st_ph1_iv_len = st->st_new_iv_len;
+ set_ph1_iv(st, st->st_new_iv);
+
+
+ update_iv(st); /* finalize our Phase 1 IV */
+
+ return STF_OK;
+}
+
+/* Handle first message of Phase 2 -- Quick Mode.
+ * HDR*, HASH(1), SA, Ni [, KE ] [, IDci, IDcr ] -->
+ * HDR*, HASH(2), SA, Nr [, KE ] [, IDci, IDcr ]
+ * (see RFC 2409 "IKE" 5.5)
+ * Installs inbound IPsec SAs.
+ * Although this seems early, we know enough to do so, and
+ * this way we know that it is soon enough to catch all
+ * packets that other side could send using this IPsec SA.
+ *
+ * Broken into parts to allow asynchronous DNS for TXT records:
+ *
+ * - quick_inI1_outR1 starts the ball rolling.
+ * It checks and parses enough to learn the Phase 2 IDs
+ *
+ * - quick_inI1_outR1_tail does the rest of the job
+ * unless DNS must be consulted. In that case,
+ * it starts a DNS query, salts away what is needed
+ * to continue, and suspends. Calls
+ * + quick_inI1_outR1_start_query
+ * + quick_inI1_outR1_process_answer
+ *
+ * - quick_inI1_outR1_continue will restart quick_inI1_outR1_tail
+ * when DNS comes back with an answer.
+ *
+ * A big chunk of quick_inI1_outR1_tail is executed twice.
+ * This is necessary because the set of connections
+ * might change while we are awaiting DNS.
+ * When first called, gateways_from_dns == NULL. If DNS is
+ * consulted asynchronously, gateways_from_dns != NULL the second time.
+ * Remember that our state object might disappear too!
+ *
+ *
+ * If the connection is opportunistic, we must verify delegation.
+ *
+ * 1. Check that we are authorized to be SG for
+ * our client. We look for the TXT record that
+ * delegates us. We also check that the public
+ * key (if present) matches the private key we used.
+ * Eventually, we should probably require DNSsec
+ * authentication for our side.
+ *
+ * 2. If our client TXT record did not include a
+ * public key, check the KEY record indicated
+ * by the identity in the TXT record.
+ *
+ * 3. If the peer's client is the peer itself, we
+ * consider it authenticated. Otherwise, we check
+ * the TXT record for the client to see that
+ * the identity of the SG matches the peer and
+ * that some public key (if present in the TXT)
+ * matches. We need not check the public key if
+ * it isn't in the TXT record.
+ *
+ * Since p isn't yet instantiated, we need to look
+ * in c for description of peer.
+ *
+ * We cannot afford to block waiting for a DNS query.
+ * The code here is structured as two halves:
+ * - process the result of just completed
+ * DNS query (if any)
+ * - if another query is needed, initiate the next
+ * DNS query and suspend
+ */
+
+enum verify_oppo_step {
+ vos_fail,
+ vos_start,
+ vos_our_client,
+ vos_our_txt,
+#ifdef USE_KEYRR
+ vos_our_key,
+#endif /* USE_KEYRR */
+ vos_his_client,
+ vos_done
+};
+
+static const char *const verify_step_name[] = {
+ "vos_fail",
+ "vos_start",
+ "vos_our_client",
+ "vos_our_txt",
+#ifdef USE_KEYRR
+ "vos_our_key",
+#endif /* USE_KEYRR */
+ "vos_his_client",
+ "vos_done"
+};
+
+/* hold anything we can handle of a Phase 2 ID */
+struct p2id {
+ ip_subnet net;
+ u_int8_t proto;
+ u_int16_t port;
+};
+
+struct verify_oppo_bundle {
+ enum verify_oppo_step step;
+ bool failure_ok; /* if true, quick_inI1_outR1_continue will try
+ * other things on DNS failure */
+ struct msg_digest *md;
+ struct p2id my, his;
+ unsigned int new_iv_len; /* p1st's might change */
+ u_char new_iv[MAX_DIGEST_LEN];
+ /* int whackfd; */ /* not needed because we are Responder */
+};
+
+struct verify_oppo_continuation {
+ struct adns_continuation ac; /* common prefix */
+ struct verify_oppo_bundle b;
+};
+
+static stf_status quick_inI1_outR1_tail(struct verify_oppo_bundle *b
+ , struct adns_continuation *ac);
+
+stf_status
+quick_inI1_outR1(struct msg_digest *md)
+{
+ const struct state *const p1st = md->st;
+ struct connection *c = p1st->st_connection;
+ struct payload_digest *const id_pd = md->chain[ISAKMP_NEXT_ID];
+ struct verify_oppo_bundle b;
+
+ /* HASH(1) in */
+ CHECK_QUICK_HASH(md
+ , quick_mode_hash12(hash_val, hash_pbs->roof, md->message_pbs.roof
+ , p1st, &md->hdr.isa_msgid, FALSE)
+ , "HASH(1)", "Quick I1");
+
+ /* [ IDci, IDcr ] in
+ * We do this now (probably out of physical order) because
+ * we wish to select the correct connection before we consult
+ * it for policy.
+ */
+
+ if (id_pd != NULL)
+ {
+ /* ??? we are assuming IPSEC_DOI */
+
+ /* IDci (initiator is peer) */
+
+ if (!decode_net_id(&id_pd->payload.ipsec_id, &id_pd->pbs
+ , &b.his.net, "peer client"))
+ return STF_FAIL + INVALID_ID_INFORMATION;
+
+ /* Hack for MS 818043 NAT-T Update */
+
+ if (id_pd->payload.ipsec_id.isaiid_idtype == ID_FQDN)
+ happy(addrtosubnet(&c->spd.that.host_addr, &b.his.net));
+
+ /* End Hack for MS 818043 NAT-T Update */
+
+ b.his.proto = id_pd->payload.ipsec_id.isaiid_protoid;
+ b.his.port = id_pd->payload.ipsec_id.isaiid_port;
+ b.his.net.addr.u.v4.sin_port = htons(b.his.port);
+
+ /* IDcr (we are responder) */
+
+ if (!decode_net_id(&id_pd->next->payload.ipsec_id, &id_pd->next->pbs
+ , &b.my.net, "our client"))
+ return STF_FAIL + INVALID_ID_INFORMATION;
+
+ b.my.proto = id_pd->next->payload.ipsec_id.isaiid_protoid;
+ b.my.port = id_pd->next->payload.ipsec_id.isaiid_port;
+ b.my.net.addr.u.v4.sin_port = htons(b.my.port);
+ }
+ else
+ {
+ /* implicit IDci and IDcr: peer and self */
+ if (!sameaddrtype(&c->spd.this.host_addr, &c->spd.that.host_addr))
+ return STF_FAIL;
+
+ happy(addrtosubnet(&c->spd.this.host_addr, &b.my.net));
+ happy(addrtosubnet(&c->spd.that.host_addr, &b.his.net));
+ b.his.proto = b.my.proto = 0;
+ b.his.port = b.my.port = 0;
+ }
+ b.step = vos_start;
+ b.md = md;
+ b.new_iv_len = p1st->st_new_iv_len;
+ memcpy(b.new_iv, p1st->st_new_iv, p1st->st_new_iv_len);
+ return quick_inI1_outR1_tail(&b, NULL);
+}
+
+static void
+report_verify_failure(struct verify_oppo_bundle *b, err_t ugh)
+{
+ struct state *st = b->md->st;
+ char fgwb[ADDRTOT_BUF]
+ , cb[ADDRTOT_BUF];
+ ip_address client;
+ err_t which;
+
+ switch (b->step)
+ {
+ case vos_our_client:
+ case vos_our_txt:
+#ifdef USE_KEYRR
+ case vos_our_key:
+#endif /* USE_KEYRR */
+ which = "our";
+ networkof(&b->my.net, &client);
+ break;
+
+ case vos_his_client:
+ which = "his";
+ networkof(&b->his.net, &client);
+ break;
+
+ case vos_start:
+ case vos_done:
+ case vos_fail:
+ default:
+ bad_case(b->step);
+ }
+
+ addrtot(&st->st_connection->spd.that.host_addr, 0, fgwb, sizeof(fgwb));
+ addrtot(&client, 0, cb, sizeof(cb));
+ loglog(RC_OPPOFAILURE
+ , "gateway %s wants connection with %s as %s client, but DNS fails to confirm delegation: %s"
+ , fgwb, cb, which, ugh);
+}
+
+static void
+quick_inI1_outR1_continue(struct adns_continuation *cr, err_t ugh)
+{
+ stf_status r;
+ struct verify_oppo_continuation *vc = (void *)cr;
+ struct verify_oppo_bundle *b = &vc->b;
+ struct state *st = b->md->st;
+
+ passert(cur_state == NULL);
+ /* if st == NULL, our state has been deleted -- just clean up */
+ if (st != NULL)
+ {
+ passert(st->st_suspended_md == b->md);
+ st->st_suspended_md = NULL; /* no longer connected or suspended */
+ cur_state = st;
+ if (!b->failure_ok && ugh != NULL)
+ {
+ report_verify_failure(b, ugh);
+ r = STF_FAIL + INVALID_ID_INFORMATION;
+ }
+ else
+ {
+ r = quick_inI1_outR1_tail(b, cr);
+ }
+ complete_state_transition(&b->md, r);
+ }
+ if (b->md != NULL)
+ release_md(b->md);
+ cur_state = NULL;
+}
+
+static stf_status
+quick_inI1_outR1_start_query(struct verify_oppo_bundle *b
+, enum verify_oppo_step next_step)
+{
+ struct msg_digest *md = b->md;
+ struct state *p1st = md->st;
+ struct connection *c = p1st->st_connection;
+ struct verify_oppo_continuation *vc
+ = alloc_thing(struct verify_oppo_continuation, "verify continuation");
+ struct id id /* subject of query */
+ , *our_id /* needed for myid playing */
+ , our_id_space; /* ephemeral: no need for unshare_id_content */
+ ip_address client;
+ err_t ugh;
+
+ /* Record that state is used by a suspended md */
+ b->step = next_step; /* not just vc->b.step */
+ vc->b = *b;
+ passert(p1st->st_suspended_md == NULL);
+ p1st->st_suspended_md = b->md;
+
+ DBG(DBG_CONTROL,
+ {
+ char ours[SUBNETTOT_BUF];
+ char his[SUBNETTOT_BUF];
+
+ subnettot(&c->spd.this.client, 0, ours, sizeof(ours));
+ subnettot(&c->spd.that.client, 0, his, sizeof(his));
+
+ DBG_log("responding with DNS query - from %s to %s new state: %s"
+ , ours, his, verify_step_name[b->step]);
+ });
+
+ /* Resolve %myid in a cheesy way.
+ * We have to do the resolution because start_adns_query
+ * et al have insufficient information to do so.
+ * If %myid is already known, we'll use that value
+ * (XXX this may be a mistake: it could be stale).
+ * If %myid is unknown, we should check to see if
+ * there are credentials for the IP address or the FQDN.
+ * Instead, we'll just assume the IP address since we are
+ * acting as the responder and only the IP address would
+ * have gotten it to us.
+ * We don't even try to do this for the other side:
+ * %myid makes no sense for the other side (but it is syntactically
+ * legal).
+ */
+ our_id = resolve_myid(&c->spd.this.id);
+ if (our_id->kind == ID_NONE)
+ {
+ iptoid(&c->spd.this.host_addr, &our_id_space);
+ our_id = &our_id_space;
+ }
+
+ switch (next_step)
+ {
+ case vos_our_client:
+ networkof(&b->my.net, &client);
+ iptoid(&client, &id);
+ vc->b.failure_ok = b->failure_ok = FALSE;
+ ugh = start_adns_query(&id
+ , our_id
+ , T_TXT
+ , quick_inI1_outR1_continue
+ , &vc->ac);
+ break;
+
+ case vos_our_txt:
+ vc->b.failure_ok = b->failure_ok = TRUE;
+ ugh = start_adns_query(our_id
+ , our_id /* self as SG */
+ , T_TXT
+ , quick_inI1_outR1_continue
+ , &vc->ac);
+ break;
+
+#ifdef USE_KEYRR
+ case vos_our_key:
+ vc->b.failure_ok = b->failure_ok = FALSE;
+ ugh = start_adns_query(our_id
+ , NULL
+ , T_KEY
+ , quick_inI1_outR1_continue
+ , &vc->ac);
+ break;
+#endif
+
+ case vos_his_client:
+ networkof(&b->his.net, &client);
+ iptoid(&client, &id);
+ vc->b.failure_ok = b->failure_ok = FALSE;
+ ugh = start_adns_query(&id
+ , &c->spd.that.id
+ , T_TXT
+ , quick_inI1_outR1_continue
+ , &vc->ac);
+ break;
+
+ default:
+ bad_case(next_step);
+ }
+
+ if (ugh != NULL)
+ {
+ /* note: we'd like to use vc->b but vc has been freed
+ * so we have to use b. This is why we plunked next_state
+ * into b, not just vc->b.
+ */
+ report_verify_failure(b, ugh);
+ p1st->st_suspended_md = NULL;
+ return STF_FAIL + INVALID_ID_INFORMATION;
+ }
+ else
+ {
+ return STF_SUSPEND;
+ }
+}
+
+static enum verify_oppo_step
+quick_inI1_outR1_process_answer(struct verify_oppo_bundle *b
+, struct adns_continuation *ac
+, struct state *p1st)
+{
+ struct connection *c = p1st->st_connection;
+ enum verify_oppo_step next_step;
+ err_t ugh = NULL;
+
+ DBG(DBG_CONTROL,
+ {
+ char ours[SUBNETTOT_BUF];
+ char his[SUBNETTOT_BUF];
+
+ subnettot(&c->spd.this.client, 0, ours, sizeof(ours));
+ subnettot(&c->spd.that.client, 0, his, sizeof(his));
+ DBG_log("responding on demand from %s to %s state: %s"
+ , ours, his, verify_step_name[b->step]);
+ });
+
+ /* process just completed DNS query (if any) */
+ switch (b->step)
+ {
+ case vos_start:
+ /* no query to digest */
+ next_step = vos_our_client;
+ break;
+
+ case vos_our_client:
+ next_step = vos_his_client;
+ {
+ const struct RSA_private_key *pri = get_RSA_private_key(c);
+ struct gw_info *gwp;
+
+ if (pri == NULL)
+ {
+ ugh = "we don't know our own key";
+ break;
+ }
+ ugh = "our client does not delegate us as its Security Gateway";
+ for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next)
+ {
+ ugh = "our client delegates us as its Security Gateway but with the wrong public key";
+ /* If there is no key in the TXT record,
+ * we count it as a win, but we will have
+ * to separately fetch and check the KEY record.
+ * If there is a key from the TXT record,
+ * we count it as a win if we match the key.
+ */
+ if (!gwp->gw_key_present)
+ {
+ next_step = vos_our_txt;
+ ugh = NULL; /* good! */
+ break;
+ }
+ else if (same_RSA_public_key(&pri->pub, &gwp->key->u.rsa))
+ {
+ ugh = NULL; /* good! */
+ break;
+ }
+ }
+ }
+ break;
+
+ case vos_our_txt:
+ next_step = vos_his_client;
+ {
+ const struct RSA_private_key *pri = get_RSA_private_key(c);
+
+ if (pri == NULL)
+ {
+ ugh = "we don't know our own key";
+ break;
+ }
+ {
+ struct gw_info *gwp;
+
+ for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next)
+ {
+#ifdef USE_KEYRR
+ /* not an error yet, because we have to check KEY RR as well */
+ ugh = NULL;
+#else
+ ugh = "our client delegation depends on our " RRNAME " record, but it has the wrong public key";
+#endif
+ if (gwp->gw_key_present
+ && same_RSA_public_key(&pri->pub, &gwp->key->u.rsa))
+ {
+ ugh = NULL; /* good! */
+ break;
+ }
+#ifdef USE_KEYRR
+ next_step = vos_our_key;
+#endif
+ }
+ }
+ }
+ break;
+
+#ifdef USE_KEYRR
+ case vos_our_key:
+ next_step = vos_his_client;
+ {
+ const struct RSA_private_key *pri = get_RSA_private_key(c);
+
+ if (pri == NULL)
+ {
+ ugh = "we don't know our own key";
+ break;
+ }
+ {
+ pubkey_list_t *kp;
+
+ ugh = "our client delegation depends on our missing " RRNAME " record";
+ for (kp = ac->keys_from_dns; kp != NULL; kp = kp->next)
+ {
+ ugh = "our client delegation depends on our " RRNAME " record, but it has the wrong public key";
+ if (same_RSA_public_key(&pri->pub, &kp->key->u.rsa))
+ {
+ /* do this only once a day */
+ if (!logged_txt_warning)
+ {
+ loglog(RC_LOG_SERIOUS, "found KEY RR but not TXT RR. See http://www.freeswan.org/err/txt-change.html.");
+ logged_txt_warning = TRUE;
+ }
+ ugh = NULL; /* good! */
+ break;
+ }
+ }
+ }
+ }
+ break;
+#endif /* USE_KEYRR */
+
+ case vos_his_client:
+ next_step = vos_done;
+ {
+ struct gw_info *gwp;
+
+ /* check that the public key that authenticated
+ * the ISAKMP SA (p1st) will do for this gateway.
+ */
+
+ ugh = "peer's client does not delegate to peer";
+ for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next)
+ {
+ ugh = "peer and its client disagree about public key";
+ /* If there is a key from the TXT record,
+ * we count it as a win if we match the key.
+ * If there was no key, we claim a match since
+ * it implies fetching a KEY from the same
+ * place we must have gotten it.
+ */
+ if (!gwp->gw_key_present
+ || same_RSA_public_key(&p1st->st_peer_pubkey->u.rsa
+ , &gwp->key->u.rsa))
+ {
+ ugh = NULL; /* good! */
+ break;
+ }
+ }
+ }
+ break;
+
+ default:
+ bad_case(b->step);
+ }
+
+ if (ugh != NULL)
+ {
+ report_verify_failure(b, ugh);
+ next_step = vos_fail;
+ }
+ return next_step;
+}
+
+static stf_status
+quick_inI1_outR1_tail(struct verify_oppo_bundle *b
+, struct adns_continuation *ac)
+{
+ struct msg_digest *md = b->md;
+ struct state *const p1st = md->st;
+ struct connection *c = p1st->st_connection;
+ struct payload_digest *const id_pd = md->chain[ISAKMP_NEXT_ID];
+ ip_subnet *our_net = &b->my.net
+ , *his_net = &b->his.net;
+
+ u_char /* set by START_HASH_PAYLOAD: */
+ *r_hashval, /* where in reply to jam hash value */
+ *r_hash_start; /* from where to start hashing */
+
+ /* Now that we have identities of client subnets, we must look for
+ * a suitable connection (our current one only matches for hosts).
+ */
+ {
+ struct connection *p = find_client_connection(c
+ , our_net, his_net, b->my.proto, b->my.port, b->his.proto, b->his.port);
+
+ if (p == NULL)
+ {
+ /* This message occurs in very puzzling circumstances
+ * so we must add as much information and beauty as we can.
+ */
+ struct end
+ me = c->spd.this,
+ he = c->spd.that;
+ char buf[2*SUBNETTOT_BUF + 2*ADDRTOT_BUF + 2*BUF_LEN + 2*ADDRTOT_BUF + 12]; /* + 12 for separating */
+ size_t l;
+
+ me.client = *our_net;
+ me.has_client = !subnetisaddr(our_net, &me.host_addr);
+ me.protocol = b->my.proto;
+ me.port = b->my.port;
+
+ he.client = *his_net;
+ he.has_client = !subnetisaddr(his_net, &he.host_addr);
+ he.protocol = b->his.proto;
+ he.port = b->his.port;
+
+ l = format_end(buf, sizeof(buf), &me, NULL, TRUE, LEMPTY);
+ l += snprintf(buf + l, sizeof(buf) - l, "...");
+ (void)format_end(buf + l, sizeof(buf) - l, &he, NULL, FALSE, LEMPTY);
+ plog("cannot respond to IPsec SA request"
+ " because no connection is known for %s"
+ , buf);
+ return STF_FAIL + INVALID_ID_INFORMATION;
+ }
+ else if (p != c)
+ {
+ /* We've got a better connection: it can support the
+ * specified clients. But it may need instantiation.
+ */
+ if (p->kind == CK_TEMPLATE)
+ {
+ /* Yup, it needs instantiation. How much?
+ * Is it a Road Warrior connection (simple)
+ * or is it an Opportunistic connection (needing gw validation)?
+ */
+ if (p->policy & POLICY_OPPO)
+ {
+ /* Opportunistic case: delegation must be verified.
+ * Here be dragons.
+ */
+ enum verify_oppo_step next_step;
+ ip_address our_client, his_client;
+
+ passert(subnetishost(our_net) && subnetishost(his_net));
+ networkof(our_net, &our_client);
+ networkof(his_net, &his_client);
+
+ next_step = quick_inI1_outR1_process_answer(b, ac, p1st);
+ if (next_step == vos_fail)
+ return STF_FAIL + INVALID_ID_INFORMATION;
+
+ /* short circuit: if peer's client is self,
+ * accept that we've verified delegation in Phase 1
+ */
+ if (next_step == vos_his_client
+ && sameaddr(&c->spd.that.host_addr, &his_client))
+ next_step = vos_done;
+
+ /* the second chunk: initiate the next DNS query (if any) */
+ DBG(DBG_CONTROL,
+ {
+ char ours[SUBNETTOT_BUF];
+ char his[SUBNETTOT_BUF];
+
+ subnettot(&c->spd.this.client, 0, ours, sizeof(ours));
+ subnettot(&c->spd.that.client, 0, his, sizeof(his));
+
+ DBG_log("responding on demand from %s to %s new state: %s"
+ , ours, his, verify_step_name[next_step]);
+ });
+
+ /* start next DNS query and suspend (if necessary) */
+ if (next_step != vos_done)
+ return quick_inI1_outR1_start_query(b, next_step);
+
+ /* Instantiate inbound Opportunistic connection,
+ * carrying over authenticated peer ID
+ * and filling in a few more details.
+ * We used to include gateways_from_dns, but that
+ * seems pointless at this stage of negotiation.
+ * We should record DNS sec use, if any -- belongs in
+ * state during perhaps.
+ */
+ p = oppo_instantiate(p, &c->spd.that.host_addr, &c->spd.that.id
+ , NULL, &our_client, &his_client);
+ }
+ else
+ {
+ /* Plain Road Warrior:
+ * instantiate, carrying over authenticated peer ID
+ */
+ p = rw_instantiate(p, &c->spd.that.host_addr, md->sender_port
+ , his_net, &c->spd.that.id);
+ }
+ }
+#ifdef DEBUG
+ /* temporarily bump up cur_debugging to get "using..." message
+ * printed if we'd want it with new connection.
+ */
+ {
+ lset_t old_cur_debugging = cur_debugging;
+
+ cur_debugging |= p->extra_debugging;
+ DBG(DBG_CONTROL, DBG_log("using connection \"%s\"", p->name));
+ cur_debugging = old_cur_debugging;
+ }
+#endif
+ c = p;
+ }
+ /* fill in the client's true ip address/subnet */
+ if (p->spd.that.has_client_wildcard)
+ {
+ p->spd.that.client = *his_net;
+ p->spd.that.has_client_wildcard = FALSE;
+ }
+ else if (is_virtual_connection(c))
+ {
+ c->spd.that.client = *his_net;
+ c->spd.that.virt = NULL;
+ if (subnetishost(his_net) && addrinsubnet(&c->spd.that.host_addr, his_net))
+ c->spd.that.has_client = FALSE;
+ }
+
+ /* fill in the client's true port */
+ if (p->spd.that.has_port_wildcard)
+ {
+ int port = htons(b->his.port);
+
+ setportof(port, &p->spd.that.host_addr);
+ setportof(port, &p->spd.that.client.addr);
+
+ p->spd.that.port = b->his.port;
+ p->spd.that.has_port_wildcard = FALSE;
+ }
+ }
+
+ /* now that we are sure of our connection, create our new state */
+ {
+ struct state *const st = duplicate_state(p1st);
+
+ /* first: fill in missing bits of our new state object
+ * note: we don't copy over st_peer_pubkey, the public key
+ * that authenticated the ISAKMP SA. We only need it in this
+ * routine, so we can "reach back" to p1st to get it.
+ */
+
+ if (st->st_connection != c)
+ {
+ struct connection *t = st->st_connection;
+
+ st->st_connection = c;
+ set_cur_connection(c);
+ connection_discard(t);
+ }
+
+ st->st_try = 0; /* not our job to try again from start */
+
+ st->st_msgid = md->hdr.isa_msgid;
+
+ st->st_new_iv_len = b->new_iv_len;
+ memcpy(st->st_new_iv, b->new_iv, b->new_iv_len);
+
+ set_cur_state(st); /* (caller will reset) */
+ md->st = st; /* feed back new state */
+
+ st->st_peeruserprotoid = b->his.proto;
+ st->st_peeruserport = b->his.port;
+ st->st_myuserprotoid = b->my.proto;
+ st->st_myuserport = b->my.port;
+
+ insert_state(st); /* needs cookies, connection, and msgid */
+
+ /* copy the connection's
+ * IPSEC policy into our state. The ISAKMP policy is water under
+ * the bridge, I think. It will reflect the ISAKMP SA that we
+ * are using.
+ */
+ st->st_policy = (p1st->st_policy & POLICY_ISAKMP_MASK)
+ | (c->policy & ~POLICY_ISAKMP_MASK);
+
+ if (p1st->nat_traversal & NAT_T_DETECTED)
+ {
+ st->nat_traversal = p1st->nat_traversal;
+ nat_traversal_change_port_lookup(md, md->st);
+ }
+ else
+ {
+ st->nat_traversal = 0;
+ }
+ if ((st->nat_traversal & NAT_T_DETECTED)
+ && (st->nat_traversal & NAT_T_WITH_NATOA))
+ {
+ nat_traversal_natoa_lookup(md);
+ }
+
+ /* Start the output packet.
+ *
+ * proccess_packet() would automatically generate the HDR*
+ * payload if smc->first_out_payload is not ISAKMP_NEXT_NONE.
+ * We don't do this because we wish there to be no partially
+ * built output packet if we need to suspend for asynch DNS.
+ *
+ * We build the reply packet as we parse the message since
+ * the parse_ipsec_sa_body emits the reply SA
+ */
+
+ /* HDR* out */
+ echo_hdr(md, TRUE, ISAKMP_NEXT_HASH);
+
+ /* HASH(2) out -- first pass */
+ START_HASH_PAYLOAD(md->rbody, ISAKMP_NEXT_SA);
+
+ /* process SA (in and out) */
+ {
+ struct payload_digest *const sapd = md->chain[ISAKMP_NEXT_SA];
+ pb_stream r_sa_pbs;
+ struct isakmp_sa sa = sapd->payload.sa;
+
+ /* sa header is unchanged -- except for np */
+ sa.isasa_np = ISAKMP_NEXT_NONCE;
+ if (!out_struct(&sa, &isakmp_sa_desc, &md->rbody, &r_sa_pbs))
+ return STF_INTERNAL_ERROR;
+
+ /* parse and accept body */
+ st->st_pfs_group = &unset_group;
+ RETURN_STF_FAILURE(parse_ipsec_sa_body(&sapd->pbs
+ , &sapd->payload.sa, &r_sa_pbs, FALSE, st));
+ }
+
+ passert(st->st_pfs_group != &unset_group);
+
+ if ((st->st_policy & POLICY_PFS) && st->st_pfs_group == NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "we require PFS but Quick I1 SA specifies no GROUP_DESCRIPTION");
+ return STF_FAIL + NO_PROPOSAL_CHOSEN; /* ??? */
+ }
+
+ /* Ni in */
+ RETURN_STF_FAILURE(accept_nonce(md, &st->st_ni, "Ni"));
+
+ /* [ KE ] in (for PFS) */
+ RETURN_STF_FAILURE(accept_PFS_KE(md, &st->st_gi, "Gi", "Quick Mode I1"));
+
+ plog("responding to Quick Mode");
+
+ /**** finish reply packet: Nr [, KE ] [, IDci, IDcr ] ****/
+
+ /* Nr out */
+ if (!build_and_ship_nonce(&st->st_nr, &md->rbody
+ , st->st_pfs_group != NULL? ISAKMP_NEXT_KE : id_pd != NULL? ISAKMP_NEXT_ID : ISAKMP_NEXT_NONE
+ , "Nr"))
+ return STF_INTERNAL_ERROR;
+
+ /* [ KE ] out (for PFS) */
+
+ if (st->st_pfs_group != NULL)
+ {
+ if (!build_and_ship_KE(st, &st->st_gr, st->st_pfs_group
+ , &md->rbody, id_pd != NULL? ISAKMP_NEXT_ID : ISAKMP_NEXT_NONE))
+ return STF_INTERNAL_ERROR;
+
+ /* MPZ-Operations might be done after sending the packet... */
+ compute_dh_shared(st, st->st_gi, st->st_pfs_group);
+ }
+
+ /* [ IDci, IDcr ] out */
+ if (id_pd != NULL)
+ {
+ struct isakmp_ipsec_id *p = (void *)md->rbody.cur; /* UGH! */
+
+ if (!out_raw(id_pd->pbs.start, pbs_room(&id_pd->pbs), &md->rbody, "IDci"))
+ return STF_INTERNAL_ERROR;
+ p->isaiid_np = ISAKMP_NEXT_ID;
+
+ p = (void *)md->rbody.cur; /* UGH! */
+
+ if (!out_raw(id_pd->next->pbs.start, pbs_room(&id_pd->next->pbs), &md->rbody, "IDcr"))
+ return STF_INTERNAL_ERROR;
+ p->isaiid_np = ISAKMP_NEXT_NONE;
+ }
+
+ if ((st->nat_traversal & NAT_T_WITH_NATOA)
+ && (st->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME))
+ && (st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TRANSPORT))
+ {
+ /** Send NAT-OA if our address is NATed and if we use Transport Mode */
+ if (!nat_traversal_add_natoa(ISAKMP_NEXT_NONE, &md->rbody, md->st))
+ {
+ return STF_INTERNAL_ERROR;
+ }
+ }
+ if ((st->nat_traversal & NAT_T_DETECTED)
+ && (st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TRANSPORT)
+ && (c->spd.that.has_client))
+ {
+ /** Remove client **/
+ addrtosubnet(&c->spd.that.host_addr, &c->spd.that.client);
+ c->spd.that.has_client = FALSE;
+ }
+
+ /* Compute reply HASH(2) and insert in output */
+ (void)quick_mode_hash12(r_hashval, r_hash_start, md->rbody.cur
+ , st, &st->st_msgid, TRUE);
+
+ /* Derive new keying material */
+ compute_keymats(st);
+
+ /* Tell the kernel to establish the new inbound SA
+ * (unless the commit bit is set -- which we don't support).
+ * We do this before any state updating so that
+ * failure won't look like success.
+ */
+ if (!install_inbound_ipsec_sa(st))
+ return STF_INTERNAL_ERROR; /* ??? we may be partly committed */
+
+ /* encrypt message, except for fixed part of header */
+
+ if (!encrypt_message(&md->rbody, st))
+ return STF_INTERNAL_ERROR; /* ??? we may be partly committed */
+
+ return STF_OK;
+ }
+}
+
+/*
+ * Initialize RFC 3706 Dead Peer Detection
+ */
+static void
+dpd_init(struct state *st)
+{
+ struct state *p1st = find_state(st->st_icookie, st->st_rcookie
+ , &st->st_connection->spd.that.host_addr, 0);
+
+ if (p1st == NULL)
+ loglog(RC_LOG_SERIOUS, "could not find phase 1 state for DPD");
+ else if (p1st->st_dpd)
+ {
+ plog("Dead Peer Detection (RFC 3706) enabled");
+ /* randomize the first DPD event */
+
+ event_schedule(EVENT_DPD
+ , (0.5 + rand()/(RAND_MAX + 1.E0)) * st->st_connection->dpd_delay
+ , st);
+ }
+}
+
+/* Handle (the single) message from Responder in Quick Mode.
+ * HDR*, HASH(2), SA, Nr [, KE ] [, IDci, IDcr ] -->
+ * HDR*, HASH(3)
+ * (see RFC 2409 "IKE" 5.5)
+ * Installs inbound and outbound IPsec SAs, routing, etc.
+ */
+stf_status
+quick_inR1_outI2(struct msg_digest *md)
+{
+ struct state *const st = md->st;
+ const struct connection *c = st->st_connection;
+
+ /* HASH(2) in */
+ CHECK_QUICK_HASH(md
+ , quick_mode_hash12(hash_val, hash_pbs->roof, md->message_pbs.roof
+ , st, &st->st_msgid, TRUE)
+ , "HASH(2)", "Quick R1");
+
+ /* SA in */
+ {
+ struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_SA];
+
+ RETURN_STF_FAILURE(parse_ipsec_sa_body(&sa_pd->pbs
+ , &sa_pd->payload.sa, NULL, TRUE, st));
+ }
+
+ /* Nr in */
+ RETURN_STF_FAILURE(accept_nonce(md, &st->st_nr, "Nr"));
+
+ /* [ KE ] in (for PFS) */
+ RETURN_STF_FAILURE(accept_PFS_KE(md, &st->st_gr, "Gr", "Quick Mode R1"));
+
+ if (st->st_pfs_group != NULL)
+ compute_dh_shared(st, st->st_gr, st->st_pfs_group);
+
+ /* [ IDci, IDcr ] in; these must match what we sent */
+
+ {
+ struct payload_digest *const id_pd = md->chain[ISAKMP_NEXT_ID];
+
+ if (id_pd != NULL)
+ {
+ /* ??? we are assuming IPSEC_DOI */
+
+ /* IDci (we are initiator) */
+
+ if (!check_net_id(&id_pd->payload.ipsec_id, &id_pd->pbs
+ , &st->st_myuserprotoid, &st->st_myuserport
+ , &st->st_connection->spd.this.client
+ , "our client"))
+ return STF_FAIL + INVALID_ID_INFORMATION;
+
+ /* IDcr (responder is peer) */
+
+ if (!check_net_id(&id_pd->next->payload.ipsec_id, &id_pd->next->pbs
+ , &st->st_peeruserprotoid, &st->st_peeruserport
+ , &st->st_connection->spd.that.client
+ , "peer client"))
+ return STF_FAIL + INVALID_ID_INFORMATION;
+ }
+ else
+ {
+ /* no IDci, IDcr: we must check that the defaults match our proposal */
+ if (!subnetisaddr(&c->spd.this.client, &c->spd.this.host_addr)
+ || !subnetisaddr(&c->spd.that.client, &c->spd.that.host_addr))
+ {
+ loglog(RC_LOG_SERIOUS, "IDci, IDcr payloads missing in message"
+ " but default does not match proposal");
+ return STF_FAIL + INVALID_ID_INFORMATION;
+ }
+ }
+ }
+
+ /* check the peer's group attributes */
+
+ {
+ const ietfAttrList_t *peer_list = NULL;
+
+ get_peer_ca_and_groups(st->st_connection, &peer_list);
+
+ if (!group_membership(peer_list, st->st_connection->name
+ , st->st_connection->spd.that.groups))
+ {
+ char buf[BUF_LEN];
+
+ format_groups(st->st_connection->spd.that.groups, buf, BUF_LEN);
+ loglog(RC_LOG_SERIOUS, "peer is not member of one of the groups: %s"
+ , buf);
+ return STF_FAIL + INVALID_ID_INFORMATION;
+ }
+ }
+
+ if ((st->nat_traversal & NAT_T_DETECTED)
+ && (st->nat_traversal & NAT_T_WITH_NATOA))
+ {
+ nat_traversal_natoa_lookup(md);
+ }
+
+ /* ??? We used to copy the accepted proposal into the state, but it was
+ * never used. From sa_pd->pbs.start, length pbs_room(&sa_pd->pbs).
+ */
+
+ /**************** build reply packet HDR*, HASH(3) ****************/
+
+ /* HDR* out done */
+
+ /* HASH(3) out -- since this is the only content, no passes needed */
+ {
+ u_char /* set by START_HASH_PAYLOAD: */
+ *r_hashval, /* where in reply to jam hash value */
+ *r_hash_start; /* start of what is to be hashed */
+
+ START_HASH_PAYLOAD(md->rbody, ISAKMP_NEXT_NONE);
+ (void)quick_mode_hash3(r_hashval, st);
+ }
+
+ /* Derive new keying material */
+ compute_keymats(st);
+
+ /* Tell the kernel to establish the inbound, outbound, and routing part
+ * of the new SA (unless the commit bit is set -- which we don't support).
+ * We do this before any state updating so that
+ * failure won't look like success.
+ */
+ if (!install_ipsec_sa(st, TRUE))
+ return STF_INTERNAL_ERROR;
+
+ /* encrypt message, except for fixed part of header */
+
+ if (!encrypt_message(&md->rbody, st))
+ return STF_INTERNAL_ERROR; /* ??? we may be partly committed */
+
+ {
+ DBG(DBG_CONTROLMORE, DBG_log("inR1_outI2: instance %s[%ld], setting newest_ipsec_sa to #%ld (was #%ld) (spd.eroute=#%ld)"
+ , st->st_connection->name
+ , st->st_connection->instance_serial
+ , st->st_serialno
+ , st->st_connection->newest_ipsec_sa
+ , st->st_connection->spd.eroute_owner));
+ }
+
+ st->st_connection->newest_ipsec_sa = st->st_serialno;
+
+ /* note (presumed) success */
+ if (c->gw_info != NULL)
+ c->gw_info->key->last_worked_time = now();
+
+ /* If we want DPD on this connection then initialize it */
+ if (st->st_connection->dpd_action != DPD_ACTION_NONE)
+ dpd_init(st);
+
+ return STF_OK;
+}
+
+/* Handle last message of Quick Mode.
+ * HDR*, HASH(3) -> done
+ * (see RFC 2409 "IKE" 5.5)
+ * Installs outbound IPsec SAs, routing, etc.
+ */
+stf_status
+quick_inI2(struct msg_digest *md)
+{
+ struct state *const st = md->st;
+
+ /* HASH(3) in */
+ CHECK_QUICK_HASH(md, quick_mode_hash3(hash_val, st)
+ , "HASH(3)", "Quick I2");
+
+ /* Tell the kernel to establish the outbound and routing part of the new SA
+ * (the previous state established inbound)
+ * (unless the commit bit is set -- which we don't support).
+ * We do this before any state updating so that
+ * failure won't look like success.
+ */
+ if (!install_ipsec_sa(st, FALSE))
+ return STF_INTERNAL_ERROR;
+
+ {
+ DBG(DBG_CONTROLMORE, DBG_log("inI2: instance %s[%ld], setting newest_ipsec_sa to #%ld (was #%ld) (spd.eroute=#%ld)"
+ , st->st_connection->name
+ , st->st_connection->instance_serial
+ , st->st_serialno
+ , st->st_connection->newest_ipsec_sa
+ , st->st_connection->spd.eroute_owner));
+ }
+
+ st->st_connection->newest_ipsec_sa = st->st_serialno;
+
+ update_iv(st); /* not actually used, but tidy */
+
+ /* note (presumed) success */
+ {
+ struct gw_info *gw = st->st_connection->gw_info;
+
+ if (gw != NULL)
+ gw->key->last_worked_time = now();
+ }
+
+ /* If we want DPD on this connection then initialize it */
+ if (st->st_connection->dpd_action != DPD_ACTION_NONE)
+ dpd_init(st);
+
+ return STF_OK;
+}
+
+static stf_status
+send_isakmp_notification(struct state *st, u_int16_t type
+ , const void *data, size_t len)
+{
+ msgid_t msgid;
+ pb_stream reply;
+ pb_stream rbody;
+ u_char
+ *r_hashval, /* where in reply to jam hash value */
+ *r_hash_start; /* start of what is to be hashed */
+
+ msgid = generate_msgid(st);
+
+ init_pbs(&reply, reply_buffer, sizeof(reply_buffer), "ISAKMP notify");
+
+ /* HDR* */
+ {
+ struct isakmp_hdr hdr;
+
+ hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION;
+ hdr.isa_np = ISAKMP_NEXT_HASH;
+ hdr.isa_xchg = ISAKMP_XCHG_INFO;
+ hdr.isa_msgid = msgid;
+ hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION;
+ memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE);
+ memcpy(hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE);
+ if (!out_struct(&hdr, &isakmp_hdr_desc, &reply, &rbody))
+ impossible();
+ }
+ /* HASH -- create and note space to be filled later */
+ START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_N);
+
+ /* NOTIFY */
+ {
+ pb_stream notify_pbs;
+ struct isakmp_notification isan;
+
+ isan.isan_np = ISAKMP_NEXT_NONE;
+ isan.isan_doi = ISAKMP_DOI_IPSEC;
+ isan.isan_protoid = PROTO_ISAKMP;
+ isan.isan_spisize = COOKIE_SIZE * 2;
+ isan.isan_type = type;
+ if (!out_struct(&isan, &isakmp_notification_desc, &rbody, &notify_pbs))
+ return STF_INTERNAL_ERROR;
+ if (!out_raw(st->st_icookie, COOKIE_SIZE, &notify_pbs, "notify icookie"))
+ return STF_INTERNAL_ERROR;
+ if (!out_raw(st->st_rcookie, COOKIE_SIZE, &notify_pbs, "notify rcookie"))
+ return STF_INTERNAL_ERROR;
+ if (data != NULL && len > 0)
+ if (!out_raw(data, len, &notify_pbs, "notify data"))
+ return STF_INTERNAL_ERROR;
+ close_output_pbs(&notify_pbs);
+ }
+
+ {
+ /* finish computing HASH */
+ struct hmac_ctx ctx;
+ hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid_a);
+ hmac_update(&ctx, (const u_char *) &msgid, sizeof(msgid_t));
+ hmac_update(&ctx, r_hash_start, rbody.cur-r_hash_start);
+ hmac_final(r_hashval, &ctx);
+
+ DBG(DBG_CRYPT,
+ DBG_log("HASH computed:");
+ DBG_dump("", r_hashval, ctx.hmac_digest_size));
+ }
+
+ /* Encrypt message (preserve st_iv and st_new_iv) */
+ {
+ u_char old_iv[MAX_DIGEST_LEN];
+ u_char new_iv[MAX_DIGEST_LEN];
+
+ u_int old_iv_len = st->st_iv_len;
+ u_int new_iv_len = st->st_new_iv_len;
+
+ if (old_iv_len > MAX_DIGEST_LEN || new_iv_len > MAX_DIGEST_LEN)
+ return STF_INTERNAL_ERROR;
+
+ memcpy(old_iv, st->st_iv, old_iv_len);
+ memcpy(new_iv, st->st_new_iv, new_iv_len);
+
+ init_phase2_iv(st, &msgid);
+ if (!encrypt_message(&rbody, st))
+ return STF_INTERNAL_ERROR;
+
+ /* restore preserved st_iv and st_new_iv */
+ memcpy(st->st_iv, old_iv, old_iv_len);
+ memcpy(st->st_new_iv, new_iv, new_iv_len);
+ st->st_iv_len = old_iv_len;
+ st->st_new_iv_len = new_iv_len;
+ }
+
+ /* Send packet (preserve st_tpacket) */
+ {
+ chunk_t saved_tpacket = st->st_tpacket;
+
+ setchunk(st->st_tpacket, reply.start, pbs_offset(&reply));
+ send_packet(st, "ISAKMP notify");
+ st->st_tpacket = saved_tpacket;
+ }
+
+ return STF_IGNORE;
+}
+
+/*
+ * DPD Out Initiator
+ */
+void
+dpd_outI(struct state *p2st)
+{
+ struct state *st;
+ u_int32_t seqno;
+ time_t tm;
+ time_t idle_time;
+ time_t delay = p2st->st_connection->dpd_delay;
+ time_t timeout = p2st->st_connection->dpd_timeout;
+
+ /* find the newest related Phase 1 state */
+ st = find_phase1_state(p2st->st_connection, ISAKMP_SA_ESTABLISHED_STATES);
+
+ if (st == NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "DPD: Could not find newest phase 1 state");
+ return;
+ }
+
+ /* If no DPD, then get out of here */
+ if (!st->st_dpd)
+ return;
+
+ /* schedule the next periodic DPD event */
+ event_schedule(EVENT_DPD, delay, p2st);
+
+ /* Current time */
+ tm = now();
+
+ /* Make sure we really need to invoke DPD */
+ if (!was_eroute_idle(p2st, delay, &idle_time))
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("recent eroute activity %u seconds ago, "
+ "no need to send DPD notification"
+ , (int)idle_time)
+ )
+ st->st_last_dpd = tm;
+ delete_dpd_event(st);
+ return;
+ }
+
+ /* If an R_U_THERE has been sent or received recently, or if a
+ * companion Phase 2 SA has shown eroute activity,
+ * then we don't need to invoke DPD.
+ */
+ if (tm < st->st_last_dpd + delay)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("recent DPD activity %u seconds ago, "
+ "no need to send DPD notification"
+ , (int)(tm - st->st_last_dpd))
+ )
+ return;
+ }
+
+ if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state))
+ return;
+
+ if (!st->st_dpd_seqno)
+ {
+ /* Get a non-zero random value that has room to grow */
+ get_rnd_bytes((u_char *)&st->st_dpd_seqno, sizeof(st->st_dpd_seqno));
+ st->st_dpd_seqno &= 0x7fff;
+ st->st_dpd_seqno++;
+ }
+ seqno = htonl(st->st_dpd_seqno);
+
+ if (send_isakmp_notification(st, R_U_THERE, &seqno, sizeof(seqno)) != STF_IGNORE)
+ {
+ loglog(RC_LOG_SERIOUS, "DPD: Could not send R_U_THERE");
+ return;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("sent DPD notification R_U_THERE with seqno = %u", st->st_dpd_seqno)
+ )
+ st->st_dpd_expectseqno = st->st_dpd_seqno++;
+ st->st_last_dpd = tm;
+ /* Only schedule a new timeout if there isn't one currently,
+ * or if it would be sooner than the current timeout. */
+ if (st->st_dpd_event == NULL
+ || st->st_dpd_event->ev_time > tm + timeout)
+ {
+ delete_dpd_event(st);
+ event_schedule(EVENT_DPD_TIMEOUT, timeout, st);
+ }
+}
+
+/*
+ * DPD in Initiator, out Responder
+ */
+stf_status
+dpd_inI_outR(struct state *st, struct isakmp_notification *const n, pb_stream *pbs)
+{
+ time_t tm = now();
+ u_int32_t seqno;
+
+ if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state))
+ {
+ loglog(RC_LOG_SERIOUS, "DPD: Received R_U_THERE for unestablished ISKAMP SA");
+ return STF_IGNORE;
+ }
+ if (n->isan_spisize != COOKIE_SIZE * 2 || pbs_left(pbs) < COOKIE_SIZE * 2)
+ {
+ loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE has invalid SPI length (%d)", n->isan_spisize);
+ return STF_FAIL + PAYLOAD_MALFORMED;
+ }
+
+ if (memcmp(pbs->cur, st->st_icookie, COOKIE_SIZE) != 0)
+ {
+#ifdef APPLY_CRISCO
+ /* Ignore it, cisco sends odd icookies */
+#else
+ loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE has invalid icookie (broken Cisco?)");
+ return STF_FAIL + INVALID_COOKIE;
+#endif
+ }
+ pbs->cur += COOKIE_SIZE;
+
+ if (memcmp(pbs->cur, st->st_rcookie, COOKIE_SIZE) != 0)
+ {
+ loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE has invalid rcookie (broken Cisco?)");
+ return STF_FAIL + INVALID_COOKIE;
+ }
+ pbs->cur += COOKIE_SIZE;
+
+ if (pbs_left(pbs) != sizeof(seqno))
+ {
+ loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE has invalid data length (%d)"
+ , (int) pbs_left(pbs));
+ return STF_FAIL + PAYLOAD_MALFORMED;
+ }
+
+ seqno = ntohl(*(u_int32_t *)pbs->cur);
+ DBG(DBG_CONTROL,
+ DBG_log("received DPD notification R_U_THERE with seqno = %u", seqno)
+ )
+
+ if (st->st_dpd_peerseqno && seqno <= st->st_dpd_peerseqno) {
+ loglog(RC_LOG_SERIOUS, "DPD: Received old or duplicate R_U_THERE");
+ return STF_IGNORE;
+ }
+
+ st->st_dpd_peerseqno = seqno;
+ delete_dpd_event(st);
+
+ if (send_isakmp_notification(st, R_U_THERE_ACK, pbs->cur, pbs_left(pbs)) != STF_IGNORE)
+ {
+ loglog(RC_LOG_SERIOUS, "DPD Info: could not send R_U_THERE_ACK");
+ return STF_IGNORE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("sent DPD notification R_U_THERE_ACK with seqno = %u", seqno)
+ )
+
+ st->st_last_dpd = tm;
+ return STF_IGNORE;
+}
+
+/*
+ * DPD out Responder
+ */
+stf_status
+dpd_inR(struct state *st, struct isakmp_notification *const n, pb_stream *pbs)
+{
+ u_int32_t seqno;
+
+ if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state))
+ {
+ loglog(RC_LOG_SERIOUS
+ , "DPD: Received R_U_THERE_ACK for unestablished ISKAMP SA");
+ return STF_FAIL;
+ }
+
+ if (n->isan_spisize != COOKIE_SIZE * 2 || pbs_left(pbs) < COOKIE_SIZE * 2)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "DPD: R_U_THERE_ACK has invalid SPI length (%d)"
+ , n->isan_spisize);
+ return STF_FAIL + PAYLOAD_MALFORMED;
+ }
+
+ if (memcmp(pbs->cur, st->st_icookie, COOKIE_SIZE) != 0)
+ {
+#ifdef APPLY_CRISCO
+ /* Ignore it, cisco sends odd icookies */
+#else
+ loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE_ACK has invalid icookie");
+ return STF_FAIL + INVALID_COOKIE;
+#endif
+ }
+ pbs->cur += COOKIE_SIZE;
+
+ if (memcmp(pbs->cur, st->st_rcookie, COOKIE_SIZE) != 0)
+ {
+#ifdef APPLY_CRISCO
+ /* Ignore it, cisco sends odd icookies */
+#else
+ loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE_ACK has invalid rcookie");
+ return STF_FAIL + INVALID_COOKIE;
+#endif
+ }
+ pbs->cur += COOKIE_SIZE;
+
+ if (pbs_left(pbs) != sizeof(seqno))
+ {
+ loglog(RC_LOG_SERIOUS
+ , " DPD: R_U_THERE_ACK has invalid data length (%d)"
+ , (int) pbs_left(pbs));
+ return STF_FAIL + PAYLOAD_MALFORMED;
+ }
+
+ seqno = ntohl(*(u_int32_t *)pbs->cur);
+ DBG(DBG_CONTROL,
+ DBG_log("received DPD notification R_U_THERE_ACK with seqno = %u"
+ , seqno)
+ )
+
+ if (!st->st_dpd_expectseqno && seqno != st->st_dpd_expectseqno)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "DPD: R_U_THERE_ACK has unexpected sequence number");
+ return STF_FAIL + PAYLOAD_MALFORMED;
+ }
+
+ st->st_dpd_expectseqno = 0;
+ delete_dpd_event(st);
+ return STF_IGNORE;
+}
+
+/*
+ * DPD Timeout Function
+ *
+ * This function is called when a timeout DPD_EVENT occurs. We set clear/trap
+ * both the SA and the eroutes, depending on what the connection definition
+ * tells us (either 'hold' or 'clear')
+ */
+void
+dpd_timeout(struct state *st)
+{
+ struct state *newest_phase1_st;
+ struct connection *c = st->st_connection;
+ int action = st->st_connection->dpd_action;
+
+ passert(action == DPD_ACTION_HOLD
+ || action == DPD_ACTION_CLEAR
+ || DPD_ACTION_RESTART);
+
+ /* is there a newer phase1_state? */
+ newest_phase1_st = find_phase1_state(c, ISAKMP_SA_ESTABLISHED_STATES);
+ if (newest_phase1_st != NULL && newest_phase1_st != st)
+ {
+ plog("DPD: Phase1 state #%ld has been superseded by #%ld"
+ " - timeout ignored"
+ , st->st_serialno, newest_phase1_st->st_serialno);
+ return;
+ }
+
+ loglog(RC_LOG_SERIOUS, "DPD: No response from peer - declaring peer dead");
+
+ /* delete the state, which is probably in phase 2 */
+ set_cur_connection(c);
+ plog("DPD: Terminating all SAs using this connection");
+ delete_states_by_connection(c, TRUE);
+ reset_cur_connection();
+
+ switch (action)
+ {
+ case DPD_ACTION_HOLD:
+ /* dpdaction=hold - Wipe the SA's but %trap the eroute so we don't
+ * leak traffic. Also, being in %trap means new packets will
+ * force an initiation of the conn again.
+ */
+ loglog(RC_LOG_SERIOUS, "DPD: Putting connection into %%trap");
+ break;
+ case DPD_ACTION_CLEAR:
+ /* dpdaction=clear - Wipe the SA & eroute - everything */
+ loglog(RC_LOG_SERIOUS, "DPD: Clearing connection");
+ unroute_connection(c);
+ break;
+ case DPD_ACTION_RESTART:
+ /* dpdaction=restart - Restart connection,
+ * except if roadwarrior connection
+ */
+ loglog(RC_LOG_SERIOUS, "DPD: Restarting connection");
+ unroute_connection(c);
+ initiate_connection(c->name, NULL_FD);
+ break;
+ default:
+ loglog(RC_LOG_SERIOUS, "DPD: unknown action");
+ }
+}
+
diff --git a/src/pluto/ipsec_doi.h b/src/pluto/ipsec_doi.h
new file mode 100644
index 000000000..80b12c31d
--- /dev/null
+++ b/src/pluto/ipsec_doi.h
@@ -0,0 +1,104 @@
+/* IPsec DOI and Oakley resolution routines
+ * Copyright (C) 1998-2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: ipsec_doi.h,v 1.3 2005/01/06 22:10:44 as Exp $
+ */
+
+extern void echo_hdr(struct msg_digest *md, bool enc, u_int8_t np);
+
+extern void ipsecdoi_initiate(int whack_sock, struct connection *c
+ , lset_t policy, unsigned long try, so_serial_t replacing);
+
+extern void ipsecdoi_replace(struct state *st, unsigned long try);
+
+extern void init_phase2_iv(struct state *st, const msgid_t *msgid);
+
+extern stf_status quick_outI1(int whack_sock
+ , struct state *isakmp_sa
+ , struct connection *c
+ , lset_t policy
+ , unsigned long try
+ , so_serial_t replacing);
+
+extern state_transition_fn
+ main_inI1_outR1,
+ main_inR1_outI2,
+ main_inI2_outR2,
+ main_inR2_outI3,
+ main_inI3_outR3,
+ main_inR3,
+ quick_inI1_outR1,
+ quick_inR1_outI2,
+ quick_inI2;
+
+extern void send_delete(struct state *st);
+extern void accept_delete(struct state *st, struct msg_digest *md
+ , struct payload_digest *p);
+extern void close_message(pb_stream *pbs);
+extern bool encrypt_message(pb_stream *pbs, struct state *st);
+
+
+extern void send_notification_from_state(struct state *st,
+ enum state_kind state, u_int16_t type);
+extern void send_notification_from_md(struct msg_digest *md, u_int16_t type);
+
+extern const char *init_pluto_vendorid(void);
+
+extern void dpd_outI(struct state *st);
+extern stf_status dpd_inI_outR(struct state *st
+ , struct isakmp_notification *const n, pb_stream *n_pbs);
+extern stf_status dpd_inR(struct state *st
+ , struct isakmp_notification *const n, pb_stream *n_pbs);
+extern void dpd_timeout(struct state *st);
+
+/* START_HASH_PAYLOAD
+ *
+ * Emit a to-be-filled-in hash payload, noting the field start (r_hashval)
+ * and the start of the part of the message to be hashed (r_hash_start).
+ * This macro is magic.
+ * - it can cause the caller to return
+ * - it references variables local to the caller (r_hashval, r_hash_start, st)
+ */
+#define START_HASH_PAYLOAD(rbody, np) { \
+ pb_stream hash_pbs; \
+ if (!out_generic(np, &isakmp_hash_desc, &(rbody), &hash_pbs)) \
+ return STF_INTERNAL_ERROR; \
+ r_hashval = hash_pbs.cur; /* remember where to plant value */ \
+ if (!out_zero(st->st_oakley.hasher->hash_digest_size, &hash_pbs, "HASH")) \
+ return STF_INTERNAL_ERROR; \
+ close_output_pbs(&hash_pbs); \
+ r_hash_start = (rbody).cur; /* hash from after HASH payload */ \
+}
+
+/* CHECK_QUICK_HASH
+ *
+ * This macro is magic -- it cannot be expressed as a function.
+ * - it causes the caller to return!
+ * - it declares local variables and expects the "do_hash" argument
+ * expression to reference them (hash_val, hash_pbs)
+ */
+#define CHECK_QUICK_HASH(md, do_hash, hash_name, msg_name) { \
+ pb_stream *const hash_pbs = &md->chain[ISAKMP_NEXT_HASH]->pbs; \
+ u_char hash_val[MAX_DIGEST_LEN]; \
+ size_t hash_len = do_hash; \
+ if (pbs_left(hash_pbs) != hash_len \
+ || memcmp(hash_pbs->cur, hash_val, hash_len) != 0) \
+ { \
+ DBG_cond_dump(DBG_CRYPT, "received " hash_name ":", hash_pbs->cur, pbs_left(hash_pbs)); \
+ loglog(RC_LOG_SERIOUS, "received " hash_name " does not match computed value in " msg_name); \
+ /* XXX Could send notification back */ \
+ return STF_FAIL + INVALID_HASH_INFORMATION; \
+ } \
+ }
+
+
diff --git a/src/pluto/kameipsec.h b/src/pluto/kameipsec.h
new file mode 100644
index 000000000..5f08c7d38
--- /dev/null
+++ b/src/pluto/kameipsec.h
@@ -0,0 +1,47 @@
+#ifndef __IPSEC_H
+#define __IPSEC_H 1
+
+/* The definitions, required to talk to KAME racoon IKE. */
+
+#define IPSEC_PORT_ANY 0
+#define IPSEC_ULPROTO_ANY 255
+#define IPSEC_PROTO_ANY 255
+
+enum {
+ IPSEC_MODE_ANY = 0, /* We do not support this for SA */
+ IPSEC_MODE_TRANSPORT = 1,
+ IPSEC_MODE_TUNNEL = 2
+};
+
+enum {
+ IPSEC_DIR_ANY = 0,
+ IPSEC_DIR_INBOUND = 1,
+ IPSEC_DIR_OUTBOUND = 2,
+ IPSEC_DIR_FWD = 3, /* It is our own */
+ IPSEC_DIR_MAX = 4,
+ IPSEC_DIR_INVALID = 5
+};
+
+enum {
+ IPSEC_POLICY_DISCARD = 0,
+ IPSEC_POLICY_NONE = 1,
+ IPSEC_POLICY_IPSEC = 2,
+ IPSEC_POLICY_ENTRUST = 3,
+ IPSEC_POLICY_BYPASS = 4
+};
+
+enum {
+ IPSEC_LEVEL_DEFAULT = 0,
+ IPSEC_LEVEL_USE = 1,
+ IPSEC_LEVEL_REQUIRE = 2,
+ IPSEC_LEVEL_UNIQUE = 3
+};
+
+#define IPSEC_MANUAL_REQID_MAX 0x3fff
+
+#define IPSEC_REPLAYWSIZE 32
+
+#define IP_IPSEC_POLICY 16
+#define IPV6_IPSEC_POLICY 34
+
+#endif /* __IPSEC_H */
diff --git a/src/pluto/kernel.c b/src/pluto/kernel.c
new file mode 100644
index 000000000..663fa7230
--- /dev/null
+++ b/src/pluto/kernel.c
@@ -0,0 +1,2995 @@
+/* routines that interface with the kernel's IPsec mechanism
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: kernel.c,v 1.26 2006/04/29 18:16:02 as Exp $
+ */
+
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <wait.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/queue.h>
+
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <freeswan.h>
+#include <ipsec_policy.h>
+
+#ifdef KLIPS
+#include <signal.h>
+#include <sys/time.h> /* for select(2) */
+#include <sys/types.h> /* for select(2) */
+#include <pfkeyv2.h>
+#include <pfkey.h>
+#include "kameipsec.h"
+#endif /* KLIPS */
+
+#include "constants.h"
+#include "defs.h"
+#include "rnd.h"
+#include "id.h"
+#include "connections.h"
+#include "state.h"
+#include "timer.h"
+#include "kernel.h"
+#include "kernel_netlink.h"
+#include "kernel_pfkey.h"
+#include "kernel_noklips.h"
+#include "log.h"
+#include "ca.h"
+#include "server.h"
+#include "whack.h" /* for RC_LOG_SERIOUS */
+#include "keys.h"
+#include "nat_traversal.h"
+#include "alg_info.h"
+#include "kernel_alg.h"
+
+
+bool can_do_IPcomp = TRUE; /* can system actually perform IPCOMP? */
+
+/* How far can IPsec messages arrive out of order before the anti-replay
+ * logic loses track and swats them? 64 is the best KLIPS can do.
+ * And 32 is the best XFRM can do...
+ */
+#define REPLAY_WINDOW 64
+#define REPLAY_WINDOW_XFRM 32
+
+/* test if the routes required for two different connections agree
+ * It is assumed that the destination subnets agree; we are only
+ * testing that the interfaces and nexthops match.
+ */
+#define routes_agree(c, d) ((c)->interface == (d)->interface \
+ && sameaddr(&(c)->spd.this.host_nexthop, &(d)->spd.this.host_nexthop))
+
+#ifndef KLIPS
+
+bool no_klips = TRUE; /* don't actually use KLIPS */
+
+#else /* !KLIPS */
+
+/* bare (connectionless) shunt (eroute) table
+ *
+ * Bare shunts are those that don't "belong" to a connection.
+ * This happens because some %trapped traffic hasn't yet or cannot be
+ * assigned to a connection. The usual reason is that we cannot discover
+ * the peer SG. Another is that even when the peer has been discovered,
+ * it may be that no connection matches all the particulars.
+ * We record them so that, with scanning, we can discover
+ * which %holds are news and which others should expire.
+ */
+
+#define SHUNT_SCAN_INTERVAL (60 * 2) /* time between scans of eroutes */
+
+/* SHUNT_PATIENCE only has resolution down to a multiple of the sample rate,
+ * SHUNT_SCAN_INTERVAL.
+ * By making SHUNT_PATIENCE an odd multiple of half of SHUNT_SCAN_INTERVAL,
+ * we minimize the effects of jitter.
+ */
+#define SHUNT_PATIENCE (SHUNT_SCAN_INTERVAL * 15 / 2) /* inactivity timeout */
+
+struct bare_shunt {
+ policy_prio_t policy_prio;
+ ip_subnet ours;
+ ip_subnet his;
+ ip_said said;
+ int transport_proto;
+ unsigned long count;
+ time_t last_activity;
+ char *why;
+ struct bare_shunt *next;
+};
+
+static struct bare_shunt *bare_shunts = NULL;
+
+#ifdef DEBUG
+static void
+DBG_bare_shunt(const char *op, const struct bare_shunt *bs)
+{
+ DBG(DBG_KLIPS,
+ {
+ int ourport = ntohs(portof(&(bs)->ours.addr));
+ int hisport = ntohs(portof(&(bs)->his.addr));
+ char ourst[SUBNETTOT_BUF];
+ char hist[SUBNETTOT_BUF];
+ char sat[SATOT_BUF];
+ char prio[POLICY_PRIO_BUF];
+
+ subnettot(&(bs)->ours, 0, ourst, sizeof(ourst));
+ subnettot(&(bs)->his, 0, hist, sizeof(hist));
+ satot(&(bs)->said, 0, sat, sizeof(sat));
+ fmt_policy_prio(bs->policy_prio, prio);
+ DBG_log("%s bare shunt %p %s:%d -> %s:%d => %s:%d %s %s"
+ , op, (const void *)(bs), ourst, ourport, hist, hisport
+ , sat, (bs)->transport_proto, prio, (bs)->why);
+ });
+}
+#else /* !DEBUG */
+#define DBG_bare_shunt(op, bs) {}
+#endif /* !DEBUG */
+
+/* The orphaned_holds table records %holds for which we
+ * scan_proc_shunts found no representation of in any connection.
+ * The corresponding ACQUIRE message might have been lost.
+ */
+struct eroute_info *orphaned_holds = NULL;
+
+/* forward declaration */
+static bool shunt_eroute(struct connection *c
+ , struct spd_route *sr
+ , enum routing_t rt_kind
+ , unsigned int op, const char *opname);
+static void set_text_said(char *text_said
+ , const ip_address *dst
+ , ipsec_spi_t spi
+ , int proto);
+
+bool no_klips = FALSE; /* don't actually use KLIPS */
+
+static const struct pfkey_proto_info null_proto_info[2] = {
+ {
+ proto: IPPROTO_ESP,
+ encapsulation: ENCAPSULATION_MODE_TRANSPORT,
+ reqid: 0
+ },
+ {
+ proto: 0,
+ encapsulation: 0,
+ reqid: 0
+ }
+};
+
+void
+record_and_initiate_opportunistic(const ip_subnet *ours
+ , const ip_subnet *his
+ , int transport_proto
+ , const char *why)
+{
+ passert(samesubnettype(ours, his));
+
+ /* Add to bare shunt list.
+ * We need to do this because the shunt was installed by KLIPS
+ * which can't do this itself.
+ */
+ {
+ struct bare_shunt *bs = alloc_thing(struct bare_shunt, "bare shunt");
+
+ bs->why = clone_str(why, "story for bare shunt");
+ bs->ours = *ours;
+ bs->his = *his;
+ bs->transport_proto = transport_proto;
+ bs->policy_prio = BOTTOM_PRIO;
+
+ bs->said.proto = SA_INT;
+ bs->said.spi = htonl(SPI_HOLD);
+ bs->said.dst = *aftoinfo(subnettypeof(ours))->any;
+
+ bs->count = 0;
+ bs->last_activity = now();
+
+ bs->next = bare_shunts;
+ bare_shunts = bs;
+ DBG_bare_shunt("add", bs);
+ }
+
+ /* actually initiate opportunism */
+ {
+ ip_address src, dst;
+
+ networkof(ours, &src);
+ networkof(his, &dst);
+ initiate_opportunistic(&src, &dst, transport_proto, TRUE, NULL_FD);
+ }
+
+ /* if present, remove from orphaned_holds list.
+ * NOTE: we do this last in case ours or his is a pointer into a member.
+ */
+ {
+ struct eroute_info **pp, *p;
+
+ for (pp = &orphaned_holds; (p = *pp) != NULL; pp = &p->next)
+ {
+ if (samesubnet(ours, &p->ours)
+ && samesubnet(his, &p->his)
+ && transport_proto == p->transport_proto
+ && portof(&ours->addr) == portof(&p->ours.addr)
+ && portof(&his->addr) == portof(&p->his.addr))
+ {
+ *pp = p->next;
+ pfree(p);
+ break;
+ }
+ }
+ }
+}
+
+#endif /* KLIPS */
+
+static unsigned get_proto_reqid(unsigned base, int proto)
+{
+ switch (proto)
+ {
+ default:
+ case IPPROTO_COMP:
+ base++;
+ /* fall through */
+ case IPPROTO_ESP:
+ base++;
+ /* fall through */
+ case IPPROTO_AH:
+ break;
+ }
+
+ return base;
+}
+
+/* Generate Unique SPI numbers.
+ *
+ * The specs say that the number must not be less than IPSEC_DOI_SPI_MIN.
+ * Pluto generates numbers not less than IPSEC_DOI_SPI_OUR_MIN,
+ * reserving numbers in between for manual keying (but we cannot so
+ * restrict numbers generated by our peer).
+ * XXX This should be replaced by a call to the kernel when
+ * XXX we get an API.
+ * The returned SPI is in network byte order.
+ * We use a random number as the initial SPI so that there is
+ * a good chance that different Pluto instances will choose
+ * different SPIs. This is good for two reasons.
+ * - the keying material for the initiator and responder only
+ * differs if the SPIs differ.
+ * - if Pluto is restarted, it would otherwise recycle the SPI
+ * numbers and confuse everything. When the kernel generates
+ * SPIs, this will no longer matter.
+ * We then allocate numbers sequentially. Thus we don't have to
+ * check if the number was previously used (assuming that no
+ * SPI lives longer than 4G of its successors).
+ */
+ipsec_spi_t
+get_ipsec_spi(ipsec_spi_t avoid, int proto, struct spd_route *sr, bool tunnel)
+{
+ static ipsec_spi_t spi = 0; /* host order, so not returned directly! */
+ char text_said[SATOT_BUF];
+
+ set_text_said(text_said, &sr->this.host_addr, 0, proto);
+
+ if (kernel_ops->get_spi)
+ return kernel_ops->get_spi(&sr->that.host_addr
+ , &sr->this.host_addr, proto, tunnel
+ , get_proto_reqid(sr->reqid, proto)
+ , IPSEC_DOI_SPI_OUR_MIN, 0xffffffff
+ , text_said);
+
+ spi++;
+ while (spi < IPSEC_DOI_SPI_OUR_MIN || spi == ntohl(avoid))
+ get_rnd_bytes((u_char *)&spi, sizeof(spi));
+
+ DBG(DBG_CONTROL,
+ {
+ ipsec_spi_t spi_net = htonl(spi);
+
+ DBG_dump("generate SPI:", (u_char *)&spi_net, sizeof(spi_net));
+ });
+
+ return htonl(spi);
+}
+
+/* Generate Unique CPI numbers.
+ * The result is returned as an SPI (4 bytes) in network order!
+ * The real bits are in the nework-low-order 2 bytes.
+ * Modelled on get_ipsec_spi, but range is more limited:
+ * 256-61439.
+ * If we can't find one easily, return 0 (a bad SPI,
+ * no matter what order) indicating failure.
+ */
+ipsec_spi_t
+get_my_cpi(struct spd_route *sr, bool tunnel)
+{
+ static cpi_t
+ first_busy_cpi = 0,
+ latest_cpi;
+ char text_said[SATOT_BUF];
+
+ set_text_said(text_said, &sr->this.host_addr, 0, IPPROTO_COMP);
+
+ if (kernel_ops->get_spi)
+ return kernel_ops->get_spi(&sr->that.host_addr
+ , &sr->this.host_addr, IPPROTO_COMP, tunnel
+ , get_proto_reqid(sr->reqid, IPPROTO_COMP)
+ , IPCOMP_FIRST_NEGOTIATED, IPCOMP_LAST_NEGOTIATED
+ , text_said);
+
+ while (!(IPCOMP_FIRST_NEGOTIATED <= first_busy_cpi && first_busy_cpi < IPCOMP_LAST_NEGOTIATED))
+ {
+ get_rnd_bytes((u_char *)&first_busy_cpi, sizeof(first_busy_cpi));
+ latest_cpi = first_busy_cpi;
+ }
+
+ latest_cpi++;
+
+ if (latest_cpi == first_busy_cpi)
+ find_my_cpi_gap(&latest_cpi, &first_busy_cpi);
+
+ if (latest_cpi > IPCOMP_LAST_NEGOTIATED)
+ latest_cpi = IPCOMP_FIRST_NEGOTIATED;
+
+ return htonl((ipsec_spi_t)latest_cpi);
+}
+
+/* invoke the updown script to do the routing and firewall commands required
+ *
+ * The user-specified updown script is run. Parameters are fed to it in
+ * the form of environment variables. All such environment variables
+ * have names starting with "PLUTO_".
+ *
+ * The operation to be performed is specified by PLUTO_VERB. This
+ * verb has a suffix "-host" if the client on this end is just the
+ * host; otherwise the suffix is "-client". If the address family
+ * of the host is IPv6, an extra suffix of "-v6" is added.
+ *
+ * "prepare-host" and "prepare-client" are used to delete a route
+ * that may exist (due to forces outside of Pluto). It is used to
+ * prepare for pluto creating a route.
+ *
+ * "route-host" and "route-client" are used to install a route.
+ * Since routing is based only on destination, the PLUTO_MY_CLIENT_*
+ * values are probably of no use (using them may signify a bug).
+ *
+ * "unroute-host" and "unroute-client" are used to delete a route.
+ * Since routing is based only on destination, the PLUTO_MY_CLIENT_*
+ * values are probably of no use (using them may signify a bug).
+ *
+ * "up-host" and "up-client" are run when an eroute is added (not replaced).
+ * They are useful for adjusting a firewall: usually for adding a rule
+ * to let processed packets flow between clients. Note that only
+ * one eroute may exist for a pair of client subnets but inbound
+ * IPsec SAs may persist without an eroute.
+ *
+ * "down-host" and "down-client" are run when an eroute is deleted.
+ * They are useful for adjusting a firewall.
+ */
+
+#ifndef DEFAULT_UPDOWN
+# define DEFAULT_UPDOWN "ipsec _updown"
+#endif
+
+static bool
+do_command(struct connection *c, struct spd_route *sr, const char *verb)
+{
+ char cmd[1536]; /* arbitrary limit on shell command length */
+ const char *verb_suffix;
+
+ /* figure out which verb suffix applies */
+ {
+ const char *hs, *cs;
+
+ switch (addrtypeof(&sr->this.host_addr))
+ {
+ case AF_INET:
+ hs = "-host";
+ cs = "-client";
+ break;
+ case AF_INET6:
+ hs = "-host-v6";
+ cs = "-client-v6";
+ break;
+ default:
+ loglog(RC_LOG_SERIOUS, "unknown address family");
+ return FALSE;
+ }
+ verb_suffix = subnetisaddr(&sr->this.client, &sr->this.host_addr)
+ ? hs : cs;
+ }
+
+ /* form the command string */
+ {
+ char
+ nexthop_str[sizeof("PLUTO_NEXT_HOP='' ") +ADDRTOT_BUF] = "",
+ srcip_str[sizeof("PLUTO_MY_SOURCEIP='' ")+ADDRTOT_BUF] = "",
+ me_str[ADDRTOT_BUF],
+ myid_str[BUF_LEN],
+ myclient_str[SUBNETTOT_BUF],
+ myclientnet_str[ADDRTOT_BUF],
+ myclientmask_str[ADDRTOT_BUF],
+ peer_str[ADDRTOT_BUF],
+ peerid_str[BUF_LEN],
+ peerclient_str[SUBNETTOT_BUF],
+ peerclientnet_str[ADDRTOT_BUF],
+ peerclientmask_str[ADDRTOT_BUF],
+ peerca_str[BUF_LEN],
+ secure_myid_str[BUF_LEN] = "",
+ secure_peerid_str[BUF_LEN] = "",
+ secure_peerca_str[BUF_LEN] = "";
+ ip_address ta;
+ pubkey_list_t *p;
+
+ if (addrbytesptr(&sr->this.host_nexthop, NULL)
+ && !isanyaddr(&sr->this.host_nexthop))
+ {
+ char *n;
+
+ strcpy(nexthop_str, "PLUTO_NEXT_HOP='");
+ n = nexthop_str + strlen(nexthop_str);
+
+ addrtot(&sr->this.host_nexthop, 0
+ ,n , sizeof(nexthop_str)-strlen(nexthop_str));
+ strncat(nexthop_str, "' ", sizeof(nexthop_str));
+ }
+
+ if (addrbytesptr(&sr->this.host_srcip, NULL)
+ && !isanyaddr(&sr->this.host_srcip))
+ {
+ char *n;
+
+ strcpy(srcip_str, "PLUTO_MY_SOURCEIP='");
+ n = srcip_str + strlen(srcip_str);
+
+ addrtot(&sr->this.host_srcip, 0
+ ,n , sizeof(srcip_str)-strlen(srcip_str));
+ strncat(srcip_str, "' ", sizeof(srcip_str));
+ }
+
+ addrtot(&sr->this.host_addr, 0, me_str, sizeof(me_str));
+ idtoa(&sr->this.id, myid_str, sizeof(myid_str));
+ escape_metachar(myid_str, secure_myid_str, sizeof(secure_myid_str));
+ subnettot(&sr->this.client, 0, myclient_str, sizeof(myclientnet_str));
+ networkof(&sr->this.client, &ta);
+ addrtot(&ta, 0, myclientnet_str, sizeof(myclientnet_str));
+ maskof(&sr->this.client, &ta);
+ addrtot(&ta, 0, myclientmask_str, sizeof(myclientmask_str));
+
+ addrtot(&sr->that.host_addr, 0, peer_str, sizeof(peer_str));
+ idtoa(&sr->that.id, peerid_str, sizeof(peerid_str));
+ escape_metachar(peerid_str, secure_peerid_str, sizeof(secure_peerid_str));
+ subnettot(&sr->that.client, 0, peerclient_str, sizeof(peerclientnet_str));
+ networkof(&sr->that.client, &ta);
+ addrtot(&ta, 0, peerclientnet_str, sizeof(peerclientnet_str));
+ maskof(&sr->that.client, &ta);
+ addrtot(&ta, 0, peerclientmask_str, sizeof(peerclientmask_str));
+
+ for (p = pubkeys; p != NULL; p = p->next)
+ {
+ pubkey_t *key = p->key;
+ int pathlen;
+
+ if (key->alg == PUBKEY_ALG_RSA && same_id(&sr->that.id, &key->id)
+ && trusted_ca(key->issuer, sr->that.ca, &pathlen))
+ {
+ dntoa_or_null(peerca_str, BUF_LEN, key->issuer, "");
+ escape_metachar(peerca_str, secure_peerca_str, sizeof(secure_peerca_str));
+ break;
+ }
+ }
+
+ if (-1 == snprintf(cmd, sizeof(cmd)
+ , "2>&1 " /* capture stderr along with stdout */
+ "PLUTO_VERSION='1.1' " /* change VERSION when interface spec changes */
+ "PLUTO_VERB='%s%s' "
+ "PLUTO_CONNECTION='%s' "
+ "%s" /* optional PLUTO_NEXT_HOP */
+ "PLUTO_INTERFACE='%s' "
+ "%s" /* optional PLUTO_HOST_ACCESS */
+ "PLUTO_REQID='%u' "
+ "PLUTO_ME='%s' "
+ "PLUTO_MY_ID='%s' "
+ "PLUTO_MY_CLIENT='%s' "
+ "PLUTO_MY_CLIENT_NET='%s' "
+ "PLUTO_MY_CLIENT_MASK='%s' "
+ "PLUTO_MY_PORT='%u' "
+ "PLUTO_MY_PROTOCOL='%u' "
+ "PLUTO_PEER='%s' "
+ "PLUTO_PEER_ID='%s' "
+ "PLUTO_PEER_CLIENT='%s' "
+ "PLUTO_PEER_CLIENT_NET='%s' "
+ "PLUTO_PEER_CLIENT_MASK='%s' "
+ "PLUTO_PEER_PORT='%u' "
+ "PLUTO_PEER_PROTOCOL='%u' "
+ "PLUTO_PEER_CA='%s' "
+ "%s" /* optional PLUTO_MY_SRCIP */
+ "%s" /* actual script */
+ , verb, verb_suffix
+ , c->name
+ , nexthop_str
+ , c->interface->vname
+ , sr->this.hostaccess? "PLUTO_HOST_ACCESS='1' " : ""
+ , sr->reqid + 1 /* ESP requid */
+ , me_str
+ , secure_myid_str
+ , myclient_str
+ , myclientnet_str
+ , myclientmask_str
+ , sr->this.port
+ , sr->this.protocol
+ , peer_str
+ , secure_peerid_str
+ , peerclient_str
+ , peerclientnet_str
+ , peerclientmask_str
+ , sr->that.port
+ , sr->that.protocol
+ , secure_peerca_str
+ , srcip_str
+ , sr->this.updown == NULL? DEFAULT_UPDOWN : sr->this.updown))
+ {
+ loglog(RC_LOG_SERIOUS, "%s%s command too long!", verb, verb_suffix);
+ return FALSE;
+ }
+ }
+
+ DBG(DBG_CONTROL, DBG_log("executing %s%s: %s"
+ , verb, verb_suffix, cmd));
+
+#ifdef KLIPS
+ if (!no_klips)
+ {
+ /* invoke the script, catching stderr and stdout
+ * It may be of concern that some file descriptors will
+ * be inherited. For the ones under our control, we
+ * have done fcntl(fd, F_SETFD, FD_CLOEXEC) to prevent this.
+ * Any used by library routines (perhaps the resolver or syslog)
+ * will remain.
+ */
+ FILE *f = popen(cmd, "r");
+
+ if (f == NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "unable to popen %s%s command", verb, verb_suffix);
+ return FALSE;
+ }
+
+ /* log any output */
+ for (;;)
+ {
+ /* if response doesn't fit in this buffer, it will be folded */
+ char resp[256];
+
+ if (fgets(resp, sizeof(resp), f) == NULL)
+ {
+ if (ferror(f))
+ {
+ log_errno((e, "fgets failed on output of %s%s command"
+ , verb, verb_suffix));
+ return FALSE;
+ }
+ else
+ {
+ passert(feof(f));
+ break;
+ }
+ }
+ else
+ {
+ char *e = resp + strlen(resp);
+
+ if (e > resp && e[-1] == '\n')
+ e[-1] = '\0'; /* trim trailing '\n' */
+ plog("%s%s output: %s", verb, verb_suffix, resp);
+ }
+ }
+
+ /* report on and react to return code */
+ {
+ int r = pclose(f);
+
+ if (r == -1)
+ {
+ log_errno((e, "pclose failed for %s%s command"
+ , verb, verb_suffix));
+ return FALSE;
+ }
+ else if (WIFEXITED(r))
+ {
+ if (WEXITSTATUS(r) != 0)
+ {
+ loglog(RC_LOG_SERIOUS, "%s%s command exited with status %d"
+ , verb, verb_suffix, WEXITSTATUS(r));
+ return FALSE;
+ }
+ }
+ else if (WIFSIGNALED(r))
+ {
+ loglog(RC_LOG_SERIOUS, "%s%s command exited with signal %d"
+ , verb, verb_suffix, WTERMSIG(r));
+ return FALSE;
+ }
+ else
+ {
+ loglog(RC_LOG_SERIOUS, "%s%s command exited with unknown status %d"
+ , verb, verb_suffix, r);
+ return FALSE;
+ }
+ }
+ }
+#endif /* KLIPS */
+ return TRUE;
+}
+
+/* Check that we can route (and eroute). Diagnose if we cannot. */
+
+enum routability {
+ route_impossible = 0,
+ route_easy = 1,
+ route_nearconflict = 2,
+ route_farconflict = 3
+};
+
+static enum routability
+could_route(struct connection *c)
+{
+ struct spd_route *esr, *rosr;
+ struct connection *ero /* who, if anyone, owns our eroute? */
+ , *ro = route_owner(c, &rosr, &ero, &esr); /* who owns our route? */
+
+ /* it makes no sense to route a connection that is ISAKMP-only */
+ if (!NEVER_NEGOTIATE(c->policy) && !HAS_IPSEC_POLICY(c->policy))
+ {
+ loglog(RC_ROUTE, "cannot route an ISAKMP-only connection");
+ return route_impossible;
+ }
+
+ /* if this is a Road Warrior template, we cannot route.
+ * Opportunistic template is OK.
+ */
+ if (c->kind == CK_TEMPLATE && !(c->policy & POLICY_OPPO))
+ {
+ loglog(RC_ROUTE, "cannot route Road Warrior template");
+ return route_impossible;
+ }
+
+ /* if we don't know nexthop, we cannot route */
+ if (isanyaddr(&c->spd.this.host_nexthop))
+ {
+ loglog(RC_ROUTE, "cannot route connection without knowing our nexthop");
+ return route_impossible;
+ }
+
+ /* if routing would affect IKE messages, reject */
+ if (!no_klips
+ && c->spd.this.host_port != NAT_T_IKE_FLOAT_PORT
+ && c->spd.this.host_port != IKE_UDP_PORT
+ && addrinsubnet(&c->spd.that.host_addr, &c->spd.that.client))
+ {
+ loglog(RC_LOG_SERIOUS, "cannot install route: peer is within its client");
+ return route_impossible;
+ }
+
+ /* If there is already a route for peer's client subnet
+ * and it disagrees about interface or nexthop, we cannot steal it.
+ * Note: if this connection is already routed (perhaps for another
+ * state object), the route will agree.
+ * This is as it should be -- it will arise during rekeying.
+ */
+ if (ro != NULL && !routes_agree(ro, c))
+ {
+ loglog(RC_LOG_SERIOUS, "cannot route -- route already in use for \"%s\""
+ , ro->name);
+ return route_impossible; /* another connection already
+ using the eroute */
+ }
+
+#ifdef KLIPS
+ /* if there is an eroute for another connection, there is a problem */
+ if (ero != NULL && ero != c)
+ {
+ struct connection *ero2, *ero_top;
+ struct connection *inside, *outside;
+
+ /*
+ * note, wavesec (PERMANENT) goes *outside* and
+ * OE goes *inside* (TEMPLATE)
+ */
+ inside = NULL;
+ outside= NULL;
+ if (ero->kind == CK_PERMANENT
+ && c->kind == CK_TEMPLATE)
+ {
+ outside = ero;
+ inside = c;
+ }
+ else if (c->kind == CK_PERMANENT
+ && ero->kind == CK_TEMPLATE)
+ {
+ outside = c;
+ inside = ero;
+ }
+
+ /* okay, check again, with correct order */
+ if (outside && outside->kind == CK_PERMANENT
+ && inside && inside->kind == CK_TEMPLATE)
+ {
+ char inst[CONN_INST_BUF];
+
+ /* this is a co-terminal attempt of the "near" kind. */
+ /* when chaining, we chain from inside to outside */
+
+ /* XXX permit multiple deep connections? */
+ passert(inside->policy_next == NULL);
+
+ inside->policy_next = outside;
+
+ /* since we are going to steal the eroute from the secondary
+ * policy, we need to make sure that it no longer thinks that
+ * it owns the eroute.
+ */
+ outside->spd.eroute_owner = SOS_NOBODY;
+ outside->spd.routing = RT_UNROUTED_KEYED;
+
+ /* set the priority of the new eroute owner to be higher
+ * than that of the current eroute owner
+ */
+ inside->prio = outside->prio + 1;
+
+ fmt_conn_instance(inside, inst);
+
+ loglog(RC_LOG_SERIOUS
+ , "conflict on eroute (%s), switching eroute to %s and linking %s"
+ , inst, inside->name, outside->name);
+
+ return route_nearconflict;
+ }
+
+ /* look along the chain of policies for one with the same name */
+ ero_top = ero;
+
+ for (ero2 = ero; ero2 != NULL; ero2 = ero->policy_next)
+ {
+ if (ero2->kind == CK_TEMPLATE
+ && streq(ero2->name, c->name))
+ break;
+ }
+
+ /* If we fell of the end of the list, then we found no TEMPLATE
+ * so there must be a conflict that we can't resolve.
+ * As the names are not equal, then we aren't replacing/rekeying.
+ */
+ if (ero2 == NULL)
+ {
+ char inst[CONN_INST_BUF];
+
+ fmt_conn_instance(ero, inst);
+
+ loglog(RC_LOG_SERIOUS
+ , "cannot install eroute -- it is in use for \"%s\"%s #%lu"
+ , ero->name, inst, esr->eroute_owner);
+ return FALSE; /* another connection already using the eroute */
+ }
+ }
+#endif /* KLIPS */
+ return route_easy;
+}
+
+bool
+trap_connection(struct connection *c)
+{
+ switch (could_route(c))
+ {
+ case route_impossible:
+ return FALSE;
+
+ case route_nearconflict:
+ case route_easy:
+ /* RT_ROUTED_TUNNEL is treated specially: we don't override
+ * because we don't want to lose track of the IPSEC_SAs etc.
+ */
+ if (c->spd.routing < RT_ROUTED_TUNNEL)
+ {
+ return route_and_eroute(c, &c->spd, NULL);
+ }
+ return TRUE;
+
+ case route_farconflict:
+ return FALSE;
+ }
+
+ return FALSE;
+}
+
+/* delete any eroute for a connection and unroute it if route isn't shared */
+void
+unroute_connection(struct connection *c)
+{
+ struct spd_route *sr;
+ enum routing_t cr;
+
+ for (sr = &c->spd; sr; sr = sr->next)
+ {
+ cr = sr->routing;
+
+ if (erouted(cr))
+ {
+ /* cannot handle a live one */
+ passert(sr->routing != RT_ROUTED_TUNNEL);
+#ifdef KLIPS
+ shunt_eroute(c, sr, RT_UNROUTED, ERO_DELETE, "delete");
+#endif
+ }
+
+ sr->routing = RT_UNROUTED; /* do now so route_owner won't find us */
+
+ /* only unroute if no other connection shares it */
+ if (routed(cr) && route_owner(c, NULL, NULL, NULL) == NULL)
+ (void) do_command(c, sr, "unroute");
+ }
+}
+
+
+#ifdef KLIPS
+
+static void
+set_text_said(char *text_said, const ip_address *dst, ipsec_spi_t spi, int proto)
+{
+ ip_said said;
+
+ initsaid(dst, spi, proto, &said);
+ satot(&said, 0, text_said, SATOT_BUF);
+}
+
+/* find an entry in the bare_shunt table.
+ * Trick: return a pointer to the pointer to the entry;
+ * this allows the entry to be deleted.
+ */
+static struct bare_shunt **
+bare_shunt_ptr(const ip_subnet *ours, const ip_subnet *his, int transport_proto)
+{
+ struct bare_shunt *p, **pp;
+
+ for (pp = &bare_shunts; (p = *pp) != NULL; pp = &p->next)
+ {
+ if (samesubnet(ours, &p->ours)
+ && samesubnet(his, &p->his)
+ && transport_proto == p->transport_proto
+ && portof(&ours->addr) == portof(&p->ours.addr)
+ && portof(&his->addr) == portof(&p->his.addr))
+ return pp;
+ }
+ return NULL;
+}
+
+/* free a bare_shunt entry, given a pointer to the pointer */
+static void
+free_bare_shunt(struct bare_shunt **pp)
+{
+ if (pp == NULL)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("delete bare shunt: null pointer")
+ )
+ }
+ else
+ {
+ struct bare_shunt *p = *pp;
+
+ *pp = p->next;
+ DBG_bare_shunt("delete", p);
+ pfree(p->why);
+ pfree(p);
+ }
+}
+
+void
+show_shunt_status(void)
+{
+ struct bare_shunt *bs;
+
+ for (bs = bare_shunts; bs != NULL; bs = bs->next)
+ {
+ /* Print interesting fields. Ignore count and last_active. */
+
+ int ourport = ntohs(portof(&bs->ours.addr));
+ int hisport = ntohs(portof(&bs->his.addr));
+ char ourst[SUBNETTOT_BUF];
+ char hist[SUBNETTOT_BUF];
+ char sat[SATOT_BUF];
+ char prio[POLICY_PRIO_BUF];
+
+ subnettot(&(bs)->ours, 0, ourst, sizeof(ourst));
+ subnettot(&(bs)->his, 0, hist, sizeof(hist));
+ satot(&(bs)->said, 0, sat, sizeof(sat));
+ fmt_policy_prio(bs->policy_prio, prio);
+
+ whack_log(RC_COMMENT, "%s:%d -> %s:%d => %s:%d %s %s"
+ , ourst, ourport, hist, hisport, sat, bs->transport_proto
+ , prio, bs->why);
+ }
+ if (bare_shunts != NULL)
+ whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */
+}
+
+/* Setup an IPsec route entry.
+ * op is one of the ERO_* operators.
+ */
+
+static bool
+raw_eroute(const ip_address *this_host
+ , const ip_subnet *this_client
+ , const ip_address *that_host
+ , const ip_subnet *that_client
+ , ipsec_spi_t spi
+ , unsigned int proto
+ , unsigned int satype
+ , unsigned int transport_proto
+ , const struct pfkey_proto_info *proto_info
+ , time_t use_lifetime
+ , unsigned int op
+ , const char *opname USED_BY_DEBUG)
+{
+ char text_said[SATOT_BUF];
+
+ set_text_said(text_said, that_host, spi, proto);
+
+ DBG(DBG_CONTROL | DBG_KLIPS,
+ {
+ int sport = ntohs(portof(&this_client->addr));
+ int dport = ntohs(portof(&that_client->addr));
+ char mybuf[SUBNETTOT_BUF];
+ char peerbuf[SUBNETTOT_BUF];
+
+ subnettot(this_client, 0, mybuf, sizeof(mybuf));
+ subnettot(that_client, 0, peerbuf, sizeof(peerbuf));
+ DBG_log("%s eroute %s:%d -> %s:%d => %s:%d"
+ , opname, mybuf, sport, peerbuf, dport
+ , text_said, transport_proto);
+ });
+
+ return kernel_ops->raw_eroute(this_host, this_client
+ , that_host, that_client, spi, satype, transport_proto, proto_info
+ , use_lifetime, op, text_said);
+}
+
+/* test to see if %hold remains */
+bool
+has_bare_hold(const ip_address *src, const ip_address *dst, int transport_proto)
+{
+ ip_subnet this_client, that_client;
+ struct bare_shunt **bspp;
+
+ passert(addrtypeof(src) == addrtypeof(dst));
+ happy(addrtosubnet(src, &this_client));
+ happy(addrtosubnet(dst, &that_client));
+ bspp = bare_shunt_ptr(&this_client, &that_client, transport_proto);
+ return bspp != NULL
+ && (*bspp)->said.proto == SA_INT && (*bspp)->said.spi == htonl(SPI_HOLD);
+}
+
+
+/* Replace (or delete) a shunt that is in the bare_shunts table.
+ * Issues the PF_KEY commands and updates the bare_shunts table.
+ */
+bool
+replace_bare_shunt(const ip_address *src, const ip_address *dst
+ , policy_prio_t policy_prio
+ , ipsec_spi_t shunt_spi /* in host order! */
+ , bool repl /* if TRUE, replace; if FALSE, delete */
+ , unsigned int transport_proto
+ , const char *why)
+{
+ ip_subnet this_client, that_client;
+ ip_subnet this_broad_client, that_broad_client;
+ const ip_address *null_host = aftoinfo(addrtypeof(src))->any;
+
+ passert(addrtypeof(src) == addrtypeof(dst));
+ happy(addrtosubnet(src, &this_client));
+ happy(addrtosubnet(dst, &that_client));
+ this_broad_client = this_client;
+ that_broad_client = that_client;
+ setportof(0, &this_broad_client.addr);
+ setportof(0, &that_broad_client.addr);
+
+ if (repl)
+ {
+ struct bare_shunt **bs_pp = bare_shunt_ptr(&this_broad_client
+ , &that_broad_client, 0);
+
+ /* is there already a broad host-to-host bare shunt? */
+ if (bs_pp == NULL)
+ {
+ if (raw_eroute(null_host, &this_broad_client, null_host, &that_broad_client
+ , htonl(shunt_spi), SA_INT, SADB_X_SATYPE_INT
+ , 0, null_proto_info
+ , SHUNT_PATIENCE, ERO_ADD, why))
+ {
+ struct bare_shunt *bs = alloc_thing(struct bare_shunt, "bare shunt");
+
+ bs->ours = this_broad_client;
+ bs->his = that_broad_client;
+ bs->transport_proto = 0;
+ bs->said.proto = SA_INT;
+ bs->why = clone_str(why, "bare shunt story");
+ bs->policy_prio = policy_prio;
+ bs->said.spi = htonl(shunt_spi);
+ bs->said.dst = *null_host;
+ bs->count = 0;
+ bs->last_activity = now();
+ bs->next = bare_shunts;
+ bare_shunts = bs;
+ DBG_bare_shunt("add", bs);
+ }
+ }
+ shunt_spi = SPI_HOLD;
+ }
+
+ if (raw_eroute(null_host, &this_client, null_host, &that_client
+ , htonl(shunt_spi), SA_INT, SADB_X_SATYPE_INT
+ , transport_proto, null_proto_info
+ , SHUNT_PATIENCE, ERO_DELETE, why))
+ {
+ struct bare_shunt **bs_pp = bare_shunt_ptr(&this_client, &that_client
+ , transport_proto);
+
+ /* delete bare eroute */
+ free_bare_shunt(bs_pp);
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+static bool
+eroute_connection(struct spd_route *sr
+, ipsec_spi_t spi, unsigned int proto, unsigned int satype
+, const struct pfkey_proto_info *proto_info
+, unsigned int op, const char *opname)
+{
+ const ip_address *peer = &sr->that.host_addr;
+ char buf2[256];
+
+ snprintf(buf2, sizeof(buf2)
+ , "eroute_connection %s", opname);
+
+ if (proto == SA_INT)
+ peer = aftoinfo(addrtypeof(peer))->any;
+
+ return raw_eroute(&sr->this.host_addr, &sr->this.client
+ , peer
+ , &sr->that.client
+ , spi, proto, satype
+ , sr->this.protocol, proto_info, 0, op, buf2);
+}
+
+/* assign a bare hold to a connection */
+
+bool
+assign_hold(struct connection *c USED_BY_DEBUG
+ , struct spd_route *sr
+ , int transport_proto
+ , const ip_address *src, const ip_address *dst)
+{
+ /* either the automatically installed %hold eroute is broad enough
+ * or we try to add a broader one and delete the automatic one.
+ * Beware: this %hold might be already handled, but still squeak
+ * through because of a race.
+ */
+ enum routing_t ro = sr->routing /* routing, old */
+ , rn = ro; /* routing, new */
+
+ passert(LHAS(LELEM(CK_PERMANENT) | LELEM(CK_INSTANCE), c->kind));
+ /* figure out what routing should become */
+ switch (ro)
+ {
+ case RT_UNROUTED:
+ rn = RT_UNROUTED_HOLD;
+ break;
+ case RT_ROUTED_PROSPECTIVE:
+ rn = RT_ROUTED_HOLD;
+ break;
+ default:
+ /* no change: this %hold is old news and should just be deleted */
+ break;
+ }
+
+ /* we need a broad %hold, not the narrow one.
+ * First we ensure that there is a broad %hold.
+ * There may already be one (race condition): no need to create one.
+ * There may already be a %trap: replace it.
+ * There may not be any broad eroute: add %hold.
+ * Once the broad %hold is in place, delete the narrow one.
+ */
+ if (rn != ro)
+ {
+ if (erouted(ro)
+ ? !eroute_connection(sr, htonl(SPI_HOLD), SA_INT, SADB_X_SATYPE_INT
+ , null_proto_info
+ , ERO_REPLACE, "replace %trap with broad %hold")
+ : !eroute_connection(sr, htonl(SPI_HOLD), SA_INT, SADB_X_SATYPE_INT
+ , null_proto_info
+ , ERO_ADD, "add broad %hold"))
+ {
+ return FALSE;
+ }
+ }
+ if (!replace_bare_shunt(src, dst, BOTTOM_PRIO, SPI_HOLD, FALSE
+ , transport_proto, "delete narrow %hold"))
+ {
+ return FALSE;
+ }
+ sr->routing = rn;
+ return TRUE;
+}
+
+/* install or remove eroute for SA Group */
+static bool
+sag_eroute(struct state *st, struct spd_route *sr
+ , unsigned op, const char *opname)
+{
+ u_int inner_proto = 0;
+ u_int inner_satype = 0;
+ ipsec_spi_t inner_spi = 0;
+ struct pfkey_proto_info proto_info[4];
+ int i;
+ bool tunnel;
+
+ /* figure out the SPI and protocol (in two forms)
+ * for the innermost transformation.
+ */
+
+ i = sizeof(proto_info) / sizeof(proto_info[0]) - 1;
+ proto_info[i].proto = 0;
+ tunnel = FALSE;
+
+ if (st->st_ah.present)
+ {
+ inner_spi = st->st_ah.attrs.spi;
+ inner_proto = SA_AH;
+ inner_satype = SADB_SATYPE_AH;
+
+ i--;
+ proto_info[i].proto = IPPROTO_AH;
+ proto_info[i].encapsulation = st->st_ah.attrs.encapsulation;
+ tunnel |= proto_info[i].encapsulation == ENCAPSULATION_MODE_TUNNEL;
+ proto_info[i].reqid = sr->reqid;
+ }
+
+ if (st->st_esp.present)
+ {
+ inner_spi = st->st_esp.attrs.spi;
+ inner_proto = SA_ESP;
+ inner_satype = SADB_SATYPE_ESP;
+
+ i--;
+ proto_info[i].proto = IPPROTO_ESP;
+ proto_info[i].encapsulation = st->st_esp.attrs.encapsulation;
+ tunnel |= proto_info[i].encapsulation == ENCAPSULATION_MODE_TUNNEL;
+ proto_info[i].reqid = sr->reqid + 1;
+ }
+
+ if (st->st_ipcomp.present)
+ {
+ inner_spi = st->st_ipcomp.attrs.spi;
+ inner_proto = SA_COMP;
+ inner_satype = SADB_X_SATYPE_COMP;
+
+ i--;
+ proto_info[i].proto = IPPROTO_COMP;
+ proto_info[i].encapsulation = st->st_ipcomp.attrs.encapsulation;
+ tunnel |= proto_info[i].encapsulation == ENCAPSULATION_MODE_TUNNEL;
+ proto_info[i].reqid = sr->reqid + 2;
+ }
+
+ if (i == sizeof(proto_info) / sizeof(proto_info[0]) - 1)
+ {
+ impossible(); /* no transform at all! */
+ }
+
+ if (tunnel)
+ {
+ int j;
+
+ inner_spi = st->st_tunnel_out_spi;
+ inner_proto = SA_IPIP;
+ inner_satype = SADB_X_SATYPE_IPIP;
+
+ proto_info[i].encapsulation = ENCAPSULATION_MODE_TUNNEL;
+ for (j = i + 1; proto_info[j].proto; j++)
+ {
+ proto_info[j].encapsulation = ENCAPSULATION_MODE_TRANSPORT;
+ }
+ }
+
+ return eroute_connection(sr
+ , inner_spi, inner_proto, inner_satype, proto_info + i
+ , op, opname);
+}
+
+/* compute a (host-order!) SPI to implement the policy in connection c */
+ipsec_spi_t
+shunt_policy_spi(struct connection *c, bool prospective)
+{
+ /* note: these are in host order :-( */
+ static const ipsec_spi_t shunt_spi[] =
+ {
+ SPI_TRAP, /* --initiateontraffic */
+ SPI_PASS, /* --pass */
+ SPI_DROP, /* --drop */
+ SPI_REJECT, /* --reject */
+ };
+
+ static const ipsec_spi_t fail_spi[] =
+ {
+ 0, /* --none*/
+ SPI_PASS, /* --failpass */
+ SPI_DROP, /* --faildrop */
+ SPI_REJECT, /* --failreject */
+ };
+
+ return prospective
+ ? shunt_spi[(c->policy & POLICY_SHUNT_MASK) >> POLICY_SHUNT_SHIFT]
+ : fail_spi[(c->policy & POLICY_FAIL_MASK) >> POLICY_FAIL_SHIFT];
+}
+
+/* Add/replace/delete a shunt eroute.
+ * Such an eroute determines the fate of packets without the use
+ * of any SAs. These are defaults, in effect.
+ * If a negotiation has not been attempted, use %trap.
+ * If negotiation has failed, the choice between %trap/%pass/%drop/%reject
+ * is specified in the policy of connection c.
+ */
+static bool
+shunt_eroute(struct connection *c
+, struct spd_route *sr
+, enum routing_t rt_kind
+, unsigned int op, const char *opname)
+{
+ /* We are constructing a special SAID for the eroute.
+ * The destination doesn't seem to matter, but the family does.
+ * The protocol is SA_INT -- mark this as shunt.
+ * The satype has no meaning, but is required for PF_KEY header!
+ * The SPI signifies the kind of shunt.
+ */
+ ipsec_spi_t spi = shunt_policy_spi(c, rt_kind == RT_ROUTED_PROSPECTIVE);
+ bool ok;
+
+ if (spi == 0)
+ {
+ /* we're supposed to end up with no eroute: rejig op and opname */
+ switch (op)
+ {
+ case ERO_REPLACE:
+ /* replace with nothing == delete */
+ op = ERO_DELETE;
+ opname = "delete";
+ break;
+ case ERO_ADD:
+ /* add nothing == do nothing */
+ return TRUE;
+ case ERO_DELETE:
+ /* delete remains delete */
+ break;
+ default:
+ bad_case(op);
+ }
+ }
+ if (sr->routing == RT_ROUTED_ECLIPSED && c->kind == CK_TEMPLATE)
+ {
+ /* We think that we have an eroute, but we don't.
+ * Adjust the request and account for eclipses.
+ */
+ passert(eclipsable(sr));
+ switch (op)
+ {
+ case ERO_REPLACE:
+ /* really an add */
+ op = ERO_ADD;
+ opname = "replace eclipsed";
+ eclipse_count--;
+ break;
+ case ERO_DELETE:
+ /* delete unnecessary: we don't actually have an eroute */
+ eclipse_count--;
+ return TRUE;
+ case ERO_ADD:
+ default:
+ bad_case(op);
+ }
+ }
+ else if (eclipse_count > 0 && op == ERO_DELETE && eclipsable(sr))
+ {
+ /* maybe we are uneclipsing something */
+ struct spd_route *esr;
+ struct connection *ue = eclipsed(c, &esr);
+
+ if (ue != NULL)
+ {
+ esr->routing = RT_ROUTED_PROSPECTIVE;
+ return shunt_eroute(ue, esr
+ , RT_ROUTED_PROSPECTIVE, ERO_REPLACE, "restoring eclipsed");
+ }
+ }
+
+ ok = TRUE;
+ if (kernel_ops->inbound_eroute)
+ {
+ ok = raw_eroute(&c->spd.that.host_addr, &c->spd.that.client
+ , &c->spd.this.host_addr, &c->spd.this.client
+ , htonl(spi), SA_INT, SADB_X_SATYPE_INT
+ , 0, null_proto_info, 0
+ , op | (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT), opname);
+ }
+ return eroute_connection(sr, htonl(spi), SA_INT, SADB_X_SATYPE_INT
+ , null_proto_info, op, opname) && ok;
+}
+
+
+/*
+ * This is only called when s is a likely SAID with trailing protocol i.e.
+ * it has the form :-
+ *
+ * %<keyword>:p
+ * <ip-proto><spi>@a.b.c.d:p
+ *
+ * The task here is to remove the ":p" part so that the rest can be read
+ * by another routine.
+ */
+static const char *
+read_proto(const char * s, size_t * len, int * transport_proto)
+{
+ const char * p;
+ const char * ugh;
+ unsigned long proto;
+ size_t l;
+
+ l = *len;
+ p = memchr(s, ':', l);
+ if (p == 0) {
+ *transport_proto = 0;
+ return 0;
+ }
+ ugh = ttoul(p+1, l-((p-s)+1), 10, &proto);
+ if (ugh != 0)
+ return ugh;
+ if (proto > 65535)
+ return "protocol number is too large, legal range is 0-65535";
+ *len = p-s;
+ *transport_proto = proto;
+ return 0;
+}
+
+
+/* scan /proc/net/ipsec_eroute every once in a while, looking for:
+ *
+ * - %hold shunts of which Pluto isn't aware. This situation could
+ * be caused by lost ACQUIRE messages. When found, they will
+ * added to orphan_holds. This in turn will lead to Opportunistic
+ * initiation.
+ *
+ * - other kinds of shunts that haven't been used recently. These will be
+ * deleted. They represent OE failures.
+ *
+ * - recording recent uses of tunnel eroutes so that rekeying decisions
+ * can be made for OE connections.
+ *
+ * Here are some sample lines:
+ * 10 10.3.2.1.0/24 -> 0.0.0.0/0 => %trap
+ * 259 10.3.2.1.115/32 -> 10.19.75.161/32 => tun0x1002@10.19.75.145
+ * 71 10.44.73.97/32 -> 0.0.0.0/0 => %trap
+ * 4119 10.44.73.97/32 -> 10.114.121.41/32 => %pass
+ * Newer versions of KLIPS start each line with a 32-bit packet count.
+ * If available, the count is used to detect whether a %pass shunt is in use.
+ *
+ * NOTE: execution time is quadratic in the number of eroutes since the
+ * searching for each is sequential. If this becomes a problem, faster
+ * searches could be implemented (hash or radix tree, for example).
+ */
+void
+scan_proc_shunts(void)
+{
+ static const char procname[] = "/proc/net/ipsec_eroute";
+ FILE *f;
+ time_t nw = now();
+ int lino;
+ struct eroute_info *expired = NULL;
+
+ event_schedule(EVENT_SHUNT_SCAN, SHUNT_SCAN_INTERVAL, NULL);
+
+ DBG(DBG_CONTROL,
+ DBG_log("scanning for shunt eroutes")
+ )
+
+ /* free any leftover entries: they will be refreshed if still current */
+ while (orphaned_holds != NULL)
+ {
+ struct eroute_info *p = orphaned_holds;
+
+ orphaned_holds = p->next;
+ pfree(orphaned_holds);
+ }
+
+ /* decode the /proc file. Don't do anything strenuous to it
+ * (certainly no PF_KEY stuff) to minimize the chance that it
+ * might change underfoot.
+ */
+
+ f = fopen(procname, "r");
+ if (f == NULL)
+ return;
+
+ /* for each line... */
+ for (lino = 1; ; lino++)
+ {
+ unsigned char buf[1024]; /* should be big enough */
+ chunk_t field[10]; /* 10 is loose upper bound */
+ chunk_t *ff = NULL; /* fixed fields (excluding optional count) */
+ int fi;
+ struct eroute_info eri;
+ char *cp;
+ err_t context = ""
+ , ugh = NULL;
+
+ cp = fgets(buf, sizeof(buf), f);
+ if (cp == NULL)
+ break;
+
+ /* break out each field
+ * Note: if there are too many fields, just stop;
+ * it will be diagnosed a little later.
+ */
+ for (fi = 0; fi < (int)elemsof(field); fi++)
+ {
+ static const char sep[] = " \t\n"; /* field-separating whitespace */
+ size_t w;
+
+ cp += strspn(cp, sep); /* find start of field */
+ w = strcspn(cp, sep); /* find width of field */
+ setchunk(field[fi], cp, w);
+ cp += w;
+ if (w == 0)
+ break;
+ }
+
+ /* This odd do-hickey is to share error reporting code.
+ * A break will get to that common code. The setting
+ * of "ugh" and "context" parameterize it.
+ */
+ do {
+ /* Old entries have no packet count; new ones do.
+ * check if things are as they should be.
+ */
+ if (fi == 5)
+ ff = &field[0]; /* old form, with no count */
+ else if (fi == 6)
+ ff = &field[1]; /* new form, with count */
+ else
+ {
+ ugh = "has wrong number of fields";
+ break;
+ }
+
+ if (ff[1].len != 2
+ || strncmp(ff[1].ptr, "->", 2) != 0
+ || ff[3].len != 2
+ || strncmp(ff[3].ptr, "=>", 2) != 0)
+ {
+ ugh = "is missing -> or =>";
+ break;
+ }
+
+ /* actually digest fields of interest */
+
+ /* packet count */
+
+ eri.count = 0;
+ if (ff != field)
+ {
+ context = "count field is malformed: ";
+ ugh = ttoul(field[0].ptr, field[0].len, 10, &eri.count);
+ if (ugh != NULL)
+ break;
+ }
+
+ /* our client */
+
+ context = "source subnet field malformed: ";
+ ugh = ttosubnet(ff[0].ptr, ff[0].len, AF_INET, &eri.ours);
+ if (ugh != NULL)
+ break;
+
+ /* his client */
+
+ context = "destination subnet field malformed: ";
+ ugh = ttosubnet(ff[2].ptr, ff[2].len, AF_INET, &eri.his);
+ if (ugh != NULL)
+ break;
+
+ /* SAID */
+
+ context = "SA ID field malformed: ";
+ ugh = read_proto(ff[4].ptr, &ff[4].len, &eri.transport_proto);
+ if (ugh != NULL)
+ break;
+ ugh = ttosa(ff[4].ptr, ff[4].len, &eri.said);
+ } while (FALSE);
+
+ if (ugh != NULL)
+ {
+ plog("INTERNAL ERROR: %s line %d %s%s"
+ , procname, lino, context, ugh);
+ continue; /* ignore rest of line */
+ }
+
+ /* Now we have decoded eroute, let's consider it.
+ * For shunt eroutes:
+ *
+ * %hold: if not known, add to orphaned_holds list for initiation
+ * because ACQUIRE might have been lost.
+ *
+ * %pass, %drop, %reject: determine if idle; if so, blast it away.
+ * Can occur bare (if DNS provided insufficient information)
+ * or with a connection (failure context).
+ * Could even be installed by ipsec manual.
+ *
+ * %trap: always welcome.
+ *
+ * For other eroutes: find state and record count change
+ */
+ if (eri.said.proto == SA_INT)
+ {
+ /* shunt eroute */
+ switch (ntohl(eri.said.spi))
+ {
+ case SPI_HOLD:
+ if (bare_shunt_ptr(&eri.ours, &eri.his, eri.transport_proto) == NULL
+ && shunt_owner(&eri.ours, &eri.his) == NULL)
+ {
+ int ourport = ntohs(portof(&eri.ours.addr));
+ int hisport = ntohs(portof(&eri.his.addr));
+ char ourst[SUBNETTOT_BUF];
+ char hist[SUBNETTOT_BUF];
+ char sat[SATOT_BUF];
+
+ subnettot(&eri.ours, 0, ourst, sizeof(ourst));
+ subnettot(&eri.his, 0, hist, sizeof(hist));
+ satot(&eri.said, 0, sat, sizeof(sat));
+
+ DBG(DBG_CONTROL,
+ DBG_log("add orphaned shunt %s:%d -> %s:%d => %s:%d"
+ , ourst, ourport, hist, hisport, sat, eri.transport_proto)
+ )
+ eri.next = orphaned_holds;
+ orphaned_holds = clone_thing(eri, "orphaned %hold");
+ }
+ break;
+
+ case SPI_PASS:
+ case SPI_DROP:
+ case SPI_REJECT:
+ /* nothing sensible to do if we don't have counts */
+ if (ff != field)
+ {
+ struct bare_shunt **bs_pp
+ = bare_shunt_ptr(&eri.ours, &eri.his, eri.transport_proto);
+
+ if (bs_pp != NULL)
+ {
+ struct bare_shunt *bs = *bs_pp;
+
+ if (eri.count != bs->count)
+ {
+ bs->count = eri.count;
+ bs->last_activity = nw;
+ }
+ else if (nw - bs->last_activity > SHUNT_PATIENCE)
+ {
+ eri.next = expired;
+ expired = clone_thing(eri, "expired %pass");
+ }
+ }
+ }
+ break;
+
+ case SPI_TRAP:
+ break;
+
+ default:
+ bad_case(ntohl(eri.said.spi));
+ }
+ }
+ else
+ {
+ /* regular (non-shunt) eroute */
+ state_eroute_usage(&eri.ours, &eri.his, eri.count, nw);
+ }
+ } /* for each line */
+ fclose(f);
+
+ /* Now that we've finished processing the /proc file,
+ * it is safe to delete the expired %pass shunts.
+ */
+ while (expired != NULL)
+ {
+ struct eroute_info *p = expired;
+ ip_address src, dst;
+
+ networkof(&p->ours, &src);
+ networkof(&p->his, &dst);
+ (void) replace_bare_shunt(&src, &dst
+ , BOTTOM_PRIO /* not used because we are deleting. This value is a filler */
+ , SPI_PASS /* not used because we are deleting. This value is a filler */
+ , FALSE, p->transport_proto, "delete expired bare shunts");
+ expired = p->next;
+ pfree(p);
+ }
+}
+
+static bool
+del_spi(ipsec_spi_t spi, int proto
+, const ip_address *src, const ip_address *dest)
+{
+ char text_said[SATOT_BUF];
+ struct kernel_sa sa;
+
+ set_text_said(text_said, dest, spi, proto);
+
+ DBG(DBG_KLIPS, DBG_log("delete %s", text_said));
+
+ memset(&sa, 0, sizeof(sa));
+ sa.spi = spi;
+ sa.proto = proto;
+ sa.src = src;
+ sa.dst = dest;
+ sa.text_said = text_said;
+
+ return kernel_ops->del_sa(&sa);
+}
+
+/* Setup a pair of SAs. Code taken from setsa.c and spigrp.c, in
+ * ipsec-0.5.
+ */
+
+static bool
+setup_half_ipsec_sa(struct state *st, bool inbound)
+{
+ /* Build an inbound or outbound SA */
+
+ struct connection *c = st->st_connection;
+ ip_subnet src, dst;
+ ip_subnet src_client, dst_client;
+ ipsec_spi_t inner_spi = 0;
+ u_int proto = 0;
+ u_int satype = SADB_SATYPE_UNSPEC;
+ bool replace;
+
+ /* SPIs, saved for spigrouping or undoing, if necessary */
+ struct kernel_sa
+ said[EM_MAXRELSPIS],
+ *said_next = said;
+
+ char text_said[SATOT_BUF];
+ int encapsulation;
+
+ replace = inbound && (kernel_ops->get_spi != NULL);
+
+ src.maskbits = 0;
+ dst.maskbits = 0;
+
+ if (inbound)
+ {
+ src.addr = c->spd.that.host_addr;
+ dst.addr = c->spd.this.host_addr;
+ src_client = c->spd.that.client;
+ dst_client = c->spd.this.client;
+ }
+ else
+ {
+ src.addr = c->spd.this.host_addr,
+ dst.addr = c->spd.that.host_addr;
+ src_client = c->spd.this.client;
+ dst_client = c->spd.that.client;
+ }
+
+ encapsulation = ENCAPSULATION_MODE_TRANSPORT;
+ if (st->st_ah.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL
+ || st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL
+ || st->st_ipcomp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL)
+ {
+ encapsulation = ENCAPSULATION_MODE_TUNNEL;
+ }
+
+ memset(said, 0, sizeof(said));
+
+ /* If we are tunnelling, set up IP in IP pseudo SA */
+
+ if (kernel_ops->inbound_eroute)
+ {
+ inner_spi = 256;
+ proto = SA_IPIP;
+ satype = SADB_SATYPE_UNSPEC;
+ }
+ else if (encapsulation == ENCAPSULATION_MODE_TUNNEL)
+ {
+ /* XXX hack alert -- we SHOULD NOT HAVE TO HAVE A DIFFERENT SPI
+ * XXX FOR IP-in-IP ENCAPSULATION!
+ */
+
+ ipsec_spi_t ipip_spi;
+
+ /* Allocate an SPI for the tunnel.
+ * Since our peer will never see this,
+ * and it comes from its own number space,
+ * it is purely a local implementation wart.
+ */
+ {
+ static ipsec_spi_t last_tunnel_spi = IPSEC_DOI_SPI_OUR_MIN;
+
+ ipip_spi = htonl(++last_tunnel_spi);
+ if (inbound)
+ st->st_tunnel_in_spi = ipip_spi;
+ else
+ st->st_tunnel_out_spi = ipip_spi;
+ }
+
+ set_text_said(text_said
+ , &c->spd.that.host_addr, ipip_spi, SA_IPIP);
+
+ said_next->src = &src.addr;
+ said_next->dst = &dst.addr;
+ said_next->src_client = &src_client;
+ said_next->dst_client = &dst_client;
+ said_next->spi = ipip_spi;
+ said_next->satype = SADB_X_SATYPE_IPIP;
+ said_next->text_said = text_said;
+
+ if (!kernel_ops->add_sa(said_next, replace))
+ goto fail;
+
+ said_next++;
+
+ inner_spi = ipip_spi;
+ proto = SA_IPIP;
+ satype = SADB_X_SATYPE_IPIP;
+ }
+
+ /* set up IPCOMP SA, if any */
+
+ if (st->st_ipcomp.present)
+ {
+ ipsec_spi_t ipcomp_spi = inbound? st->st_ipcomp.our_spi : st->st_ipcomp.attrs.spi;
+ unsigned compalg;
+
+ switch (st->st_ipcomp.attrs.transid)
+ {
+ case IPCOMP_DEFLATE:
+ compalg = SADB_X_CALG_DEFLATE;
+ break;
+
+ default:
+ loglog(RC_LOG_SERIOUS, "IPCOMP transform %s not implemented"
+ , enum_name(&ipcomp_transformid_names, st->st_ipcomp.attrs.transid));
+ goto fail;
+ }
+
+ set_text_said(text_said, &dst.addr, ipcomp_spi, SA_COMP);
+
+ said_next->src = &src.addr;
+ said_next->dst = &dst.addr;
+ said_next->src_client = &src_client;
+ said_next->dst_client = &dst_client;
+ said_next->spi = ipcomp_spi;
+ said_next->satype = SADB_X_SATYPE_COMP;
+ said_next->compalg = compalg;
+ said_next->encapsulation = encapsulation;
+ said_next->reqid = c->spd.reqid + 2;
+ said_next->text_said = text_said;
+
+ if (!kernel_ops->add_sa(said_next, replace))
+ goto fail;
+
+ said_next++;
+
+ encapsulation = ENCAPSULATION_MODE_TRANSPORT;
+ }
+
+ /* set up ESP SA, if any */
+
+ if (st->st_esp.present)
+ {
+ ipsec_spi_t esp_spi = inbound? st->st_esp.our_spi : st->st_esp.attrs.spi;
+ u_char *esp_dst_keymat = inbound? st->st_esp.our_keymat : st->st_esp.peer_keymat;
+ const struct esp_info *ei;
+ u_int16_t key_len;
+
+ static const struct esp_info esp_info[] = {
+ { ESP_NULL, AUTH_ALGORITHM_HMAC_MD5,
+ 0, HMAC_MD5_KEY_LEN,
+ SADB_EALG_NULL, SADB_AALG_MD5_HMAC },
+ { ESP_NULL, AUTH_ALGORITHM_HMAC_SHA1,
+ 0, HMAC_SHA1_KEY_LEN,
+ SADB_EALG_NULL, SADB_AALG_SHA1_HMAC },
+
+ { ESP_DES, AUTH_ALGORITHM_NONE,
+ DES_CBC_BLOCK_SIZE, 0,
+ SADB_EALG_DES_CBC, SADB_AALG_NONE },
+ { ESP_DES, AUTH_ALGORITHM_HMAC_MD5,
+ DES_CBC_BLOCK_SIZE, HMAC_MD5_KEY_LEN,
+ SADB_EALG_DES_CBC, SADB_AALG_MD5_HMAC },
+ { ESP_DES, AUTH_ALGORITHM_HMAC_SHA1,
+ DES_CBC_BLOCK_SIZE,
+ HMAC_SHA1_KEY_LEN, SADB_EALG_DES_CBC, SADB_AALG_SHA1_HMAC },
+
+ { ESP_3DES, AUTH_ALGORITHM_NONE,
+ DES_CBC_BLOCK_SIZE * 3, 0,
+ SADB_EALG_3DES_CBC, SADB_AALG_NONE },
+ { ESP_3DES, AUTH_ALGORITHM_HMAC_MD5,
+ DES_CBC_BLOCK_SIZE * 3, HMAC_MD5_KEY_LEN,
+ SADB_EALG_3DES_CBC, SADB_AALG_MD5_HMAC },
+ { ESP_3DES, AUTH_ALGORITHM_HMAC_SHA1,
+ DES_CBC_BLOCK_SIZE * 3, HMAC_SHA1_KEY_LEN,
+ SADB_EALG_3DES_CBC, SADB_AALG_SHA1_HMAC },
+ };
+
+ u_int8_t natt_type = 0;
+ u_int16_t natt_sport = 0;
+ u_int16_t natt_dport = 0;
+ ip_address natt_oa;
+
+ if (st->nat_traversal & NAT_T_DETECTED)
+ {
+ natt_type = (st->nat_traversal & NAT_T_WITH_PORT_FLOATING) ?
+ ESPINUDP_WITH_NON_ESP : ESPINUDP_WITH_NON_IKE;
+ natt_sport = inbound? c->spd.that.host_port : c->spd.this.host_port;
+ natt_dport = inbound? c->spd.this.host_port : c->spd.that.host_port;
+ natt_oa = st->nat_oa;
+ }
+
+ for (ei = esp_info; ; ei++)
+ {
+ if (ei == &esp_info[elemsof(esp_info)])
+ {
+ /* Check for additional kernel alg */
+#ifndef NO_KERNEL_ALG
+ if ((ei=kernel_alg_esp_info(st->st_esp.attrs.transid,
+ st->st_esp.attrs.auth))!=NULL) {
+ break;
+ }
+#endif
+
+ /* note: enum_show may use a static buffer, so two
+ * calls in one printf would be a mistake.
+ * enum_name does the same job, without a static buffer,
+ * assuming the name will be found.
+ */
+ loglog(RC_LOG_SERIOUS, "ESP transform %s / auth %s not implemented yet"
+ , enum_name(&esp_transformid_names, st->st_esp.attrs.transid)
+ , enum_name(&auth_alg_names, st->st_esp.attrs.auth));
+ goto fail;
+ }
+
+ if (st->st_esp.attrs.transid == ei->transid
+ && st->st_esp.attrs.auth == ei->auth)
+ break;
+ }
+
+ key_len = st->st_esp.attrs.key_len/8;
+ if (key_len)
+ {
+ /* XXX: must change to check valid _range_ key_len */
+ if (key_len > ei->enckeylen)
+ {
+ loglog(RC_LOG_SERIOUS, "ESP transform %s passed key_len=%d > %d",
+ enum_name(&esp_transformid_names, st->st_esp.attrs.transid),
+ (int)key_len, (int)ei->enckeylen);
+ goto fail;
+ }
+ }
+ else
+ {
+ key_len = ei->enckeylen;
+ }
+ /* Grrrrr.... f*cking 7 bits jurassic algos */
+
+ /* 168 bits in kernel, need 192 bits for keymat_len */
+ if (ei->transid == ESP_3DES && key_len == 21)
+ key_len = 24;
+
+ /* 56 bits in kernel, need 64 bits for keymat_len */
+ if (ei->transid == ESP_DES && key_len == 7)
+ key_len = 8;
+
+ /* divide up keying material */
+ /* passert(st->st_esp.keymat_len == ei->enckeylen + ei->authkeylen); */
+ DBG(DBG_KLIPS|DBG_CONTROL|DBG_PARSING,
+ if(st->st_esp.keymat_len != key_len + ei->authkeylen)
+ DBG_log("keymat_len=%d key_len=%d authkeylen=%d",
+ st->st_esp.keymat_len, (int)key_len, (int)ei->authkeylen);
+ )
+ passert(st->st_esp.keymat_len == key_len + ei->authkeylen);
+
+ set_text_said(text_said, &dst.addr, esp_spi, SA_ESP);
+
+ said_next->src = &src.addr;
+ said_next->dst = &dst.addr;
+ said_next->src_client = &src_client;
+ said_next->dst_client = &dst_client;
+ said_next->spi = esp_spi;
+ said_next->satype = SADB_SATYPE_ESP;
+ said_next->replay_window = (kernel_ops->type == KERNEL_TYPE_KLIPS) ? REPLAY_WINDOW : REPLAY_WINDOW_XFRM;
+ said_next->authalg = ei->authalg;
+ said_next->authkeylen = ei->authkeylen;
+ /* said_next->authkey = esp_dst_keymat + ei->enckeylen; */
+ said_next->authkey = esp_dst_keymat + key_len;
+ said_next->encalg = ei->encryptalg;
+ /* said_next->enckeylen = ei->enckeylen; */
+ said_next->enckeylen = key_len;
+ said_next->enckey = esp_dst_keymat;
+ said_next->encapsulation = encapsulation;
+ said_next->reqid = c->spd.reqid + 1;
+ said_next->natt_sport = natt_sport;
+ said_next->natt_dport = natt_dport;
+ said_next->transid = st->st_esp.attrs.transid;
+ said_next->natt_type = natt_type;
+ said_next->natt_oa = &natt_oa;
+ said_next->text_said = text_said;
+
+ if (!kernel_ops->add_sa(said_next, replace))
+ goto fail;
+
+ said_next++;
+
+ encapsulation = ENCAPSULATION_MODE_TRANSPORT;
+ }
+
+ /* set up AH SA, if any */
+
+ if (st->st_ah.present)
+ {
+ ipsec_spi_t ah_spi = inbound? st->st_ah.our_spi : st->st_ah.attrs.spi;
+ u_char *ah_dst_keymat = inbound? st->st_ah.our_keymat : st->st_ah.peer_keymat;
+
+ unsigned char authalg;
+
+ switch (st->st_ah.attrs.auth)
+ {
+ case AUTH_ALGORITHM_HMAC_MD5:
+ authalg = SADB_AALG_MD5_HMAC;
+ break;
+
+ case AUTH_ALGORITHM_HMAC_SHA1:
+ authalg = SADB_AALG_SHA1_HMAC;
+ break;
+
+ default:
+ loglog(RC_LOG_SERIOUS, "%s not implemented yet"
+ , enum_show(&auth_alg_names, st->st_ah.attrs.auth));
+ goto fail;
+ }
+
+ set_text_said(text_said, &dst.addr, ah_spi, SA_AH);
+
+ said_next->src = &src.addr;
+ said_next->dst = &dst.addr;
+ said_next->src_client = &src_client;
+ said_next->dst_client = &dst_client;
+ said_next->spi = ah_spi;
+ said_next->satype = SADB_SATYPE_AH;
+ said_next->replay_window = (kernel_ops->type == KERNEL_TYPE_KLIPS) ? REPLAY_WINDOW : REPLAY_WINDOW_XFRM;
+ said_next->authalg = authalg;
+ said_next->authkeylen = st->st_ah.keymat_len;
+ said_next->authkey = ah_dst_keymat;
+ said_next->encapsulation = encapsulation;
+ said_next->reqid = c->spd.reqid;
+ said_next->text_said = text_said;
+
+ if (!kernel_ops->add_sa(said_next, replace))
+ goto fail;
+
+ said_next++;
+
+ encapsulation = ENCAPSULATION_MODE_TRANSPORT;
+ }
+
+ if (st->st_ah.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL
+ || st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL
+ || st->st_ipcomp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL)
+ {
+ encapsulation = ENCAPSULATION_MODE_TUNNEL;
+ }
+
+ if (kernel_ops->inbound_eroute ? c->spd.eroute_owner == SOS_NOBODY
+ : encapsulation == ENCAPSULATION_MODE_TUNNEL)
+ {
+ /* If inbound, and policy does not specifie DISABLEARRIVALCHECK,
+ * tell KLIPS to enforce the IP addresses appropriate for this tunnel.
+ * Note reversed ends.
+ * Not much to be done on failure.
+ */
+ if (inbound && (c->policy & POLICY_DISABLEARRIVALCHECK) == 0)
+ {
+ struct pfkey_proto_info proto_info[4];
+ int i = 0;
+
+ if (st->st_ipcomp.present)
+ {
+ proto_info[i].proto = IPPROTO_COMP;
+ proto_info[i].encapsulation = st->st_ipcomp.attrs.encapsulation;
+ proto_info[i].reqid = c->spd.reqid + 2;
+ i++;
+ }
+
+ if (st->st_esp.present)
+ {
+ proto_info[i].proto = IPPROTO_ESP;
+ proto_info[i].encapsulation = st->st_esp.attrs.encapsulation;
+ proto_info[i].reqid = c->spd.reqid + 1;
+ i++;
+ }
+
+ if (st->st_ah.present)
+ {
+ proto_info[i].proto = IPPROTO_AH;
+ proto_info[i].encapsulation = st->st_ah.attrs.encapsulation;
+ proto_info[i].reqid = c->spd.reqid;
+ i++;
+ }
+
+ proto_info[i].proto = 0;
+
+ if (kernel_ops->inbound_eroute
+ && encapsulation == ENCAPSULATION_MODE_TUNNEL)
+ {
+ proto_info[0].encapsulation = ENCAPSULATION_MODE_TUNNEL;
+ for (i = 1; proto_info[i].proto; i++)
+ {
+ proto_info[i].encapsulation = ENCAPSULATION_MODE_TRANSPORT;
+ }
+ }
+
+ /* MCR - should be passed a spd_eroute structure here */
+ (void) raw_eroute(&c->spd.that.host_addr, &c->spd.that.client
+ , &c->spd.this.host_addr, &c->spd.this.client
+ , inner_spi, proto, satype, c->spd.this.protocol
+ , proto_info, 0
+ , ERO_ADD_INBOUND, "add inbound");
+ }
+ }
+
+ /* If there are multiple SPIs, group them. */
+
+ if (kernel_ops->grp_sa && said_next > &said[1])
+ {
+ struct kernel_sa *s;
+
+ /* group SAs, two at a time, inner to outer (backwards in said[])
+ * The grouping is by pairs. So if said[] contains ah esp ipip,
+ * the grouping would be ipip:esp, esp:ah.
+ */
+ for (s = said; s < said_next-1; s++)
+ {
+ char
+ text_said0[SATOT_BUF],
+ text_said1[SATOT_BUF];
+
+ /* group s[1] and s[0], in that order */
+
+ set_text_said(text_said0, s[0].dst, s[0].spi, s[0].proto);
+ set_text_said(text_said1, s[1].dst, s[1].spi, s[1].proto);
+
+ DBG(DBG_KLIPS, DBG_log("grouping %s and %s", text_said1, text_said0));
+
+ s[0].text_said = text_said0;
+ s[1].text_said = text_said1;
+
+ if (!kernel_ops->grp_sa(s + 1, s))
+ goto fail;
+ }
+ /* could update said, but it will not be used */
+ }
+
+ return TRUE;
+
+fail:
+ {
+ /* undo the done SPIs */
+ while (said_next-- != said)
+ (void) del_spi(said_next->spi, said_next->proto
+ , &src.addr, said_next->dst);
+ return FALSE;
+ }
+}
+
+/* teardown_ipsec_sa is a canibalized version of setup_ipsec_sa */
+
+static bool
+teardown_half_ipsec_sa(struct state *st, bool inbound)
+{
+ /* We need to delete AH, ESP, and IP in IP SPIs.
+ * But if there is more than one, they have been grouped
+ * so deleting any one will do. So we just delete the
+ * first one found. It may or may not be the only one.
+ */
+ struct connection *c = st->st_connection;
+ struct {
+ unsigned proto;
+ struct ipsec_proto_info *info;
+ } protos[4];
+ int i;
+ bool result;
+
+ i = 0;
+ if (kernel_ops->inbound_eroute && inbound
+ && c->spd.eroute_owner == SOS_NOBODY)
+ {
+ (void) raw_eroute(&c->spd.that.host_addr, &c->spd.that.client
+ , &c->spd.this.host_addr, &c->spd.this.client
+ , 256, IPSEC_PROTO_ANY, SADB_SATYPE_UNSPEC, c->spd.this.protocol
+ , null_proto_info, 0
+ , ERO_DEL_INBOUND, "delete inbound");
+ }
+
+ if (!kernel_ops->grp_sa)
+ {
+ if (st->st_ah.present)
+ {
+ protos[i].info = &st->st_ah;
+ protos[i].proto = SA_AH;
+ i++;
+ }
+
+ if (st->st_esp.present)
+ {
+ protos[i].info = &st->st_esp;
+ protos[i].proto = SA_ESP;
+ i++;
+ }
+
+ if (st->st_ipcomp.present)
+ {
+ protos[i].info = &st->st_ipcomp;
+ protos[i].proto = SA_COMP;
+ i++;
+ }
+ }
+ else if (st->st_ah.present)
+ {
+ protos[i].info = &st->st_ah;
+ protos[i].proto = SA_AH;
+ i++;
+ }
+ else if (st->st_esp.present)
+ {
+ protos[i].info = &st->st_esp;
+ protos[i].proto = SA_ESP;
+ i++;
+ }
+ else
+ {
+ impossible(); /* neither AH nor ESP in outbound SA bundle! */
+ }
+ protos[i].proto = 0;
+
+ result = TRUE;
+ for (i = 0; protos[i].proto; i++)
+ {
+ unsigned proto = protos[i].proto;
+ ipsec_spi_t spi;
+ const ip_address *src, *dst;
+
+ if (inbound)
+ {
+ spi = protos[i].info->our_spi;
+ src = &c->spd.that.host_addr;
+ dst = &c->spd.this.host_addr;
+ }
+ else
+ {
+ spi = protos[i].info->attrs.spi;
+ src = &c->spd.this.host_addr;
+ dst = &c->spd.that.host_addr;
+ }
+
+ result &= del_spi(spi, proto, src, dst);
+ }
+ return result;
+}
+
+/*
+ * get information about a given sa
+ */
+bool
+get_sa_info(struct state *st, bool inbound, u_int *bytes, time_t *use_time)
+{
+ char text_said[SATOT_BUF];
+ struct kernel_sa sa;
+ struct connection *c = st->st_connection;
+
+ *use_time = UNDEFINED_TIME;
+
+ if (kernel_ops->get_sa == NULL || !st->st_esp.present)
+ return FALSE;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.proto = SA_ESP;
+
+ if (inbound)
+ {
+ sa.src = &c->spd.that.host_addr;
+ sa.dst = &c->spd.this.host_addr;
+ sa.spi = st->st_esp.our_spi;
+ }
+ else
+ {
+ sa.src = &c->spd.this.host_addr;
+ sa.dst = &c->spd.that.host_addr;
+ sa.spi = st->st_esp.attrs.spi;
+ }
+ set_text_said(text_said, sa.dst, sa.spi, sa.proto);
+
+ sa.text_said = text_said;
+
+ DBG(DBG_KLIPS,
+ DBG_log("get %s", text_said)
+ )
+ if (!kernel_ops->get_sa(&sa, bytes))
+ return FALSE;
+ DBG(DBG_KLIPS,
+ DBG_log(" current: %d bytes", *bytes)
+ )
+
+ if (st->st_serialno == c->spd.eroute_owner)
+ {
+ DBG(DBG_KLIPS,
+ DBG_log("get %sbound policy with reqid %u"
+ , inbound? "in":"out", (u_int)c->spd.reqid + 1)
+ )
+ sa.transport_proto = c->spd.this.protocol;
+ sa.encapsulation = st->st_esp.attrs.encapsulation;
+
+ if (inbound)
+ {
+ sa.src_client = &c->spd.that.client;
+ sa.dst_client = &c->spd.this.client;
+ }
+ else
+ {
+ sa.src_client = &c->spd.this.client;
+ sa.dst_client = &c->spd.that.client;
+ }
+ if (!kernel_ops->get_policy(&sa, inbound, use_time))
+ return FALSE;
+ DBG(DBG_KLIPS,
+ DBG_log(" use_time: %s", timetoa(use_time, FALSE))
+ )
+ }
+ return TRUE;
+}
+
+const struct kernel_ops *kernel_ops;
+
+#endif /* KLIPS */
+
+void
+init_kernel(void)
+{
+#ifdef KLIPS
+
+ if (no_klips)
+ {
+ kernel_ops = &noklips_kernel_ops;
+ return;
+ }
+
+ init_pfkey();
+
+ kernel_ops = &klips_kernel_ops;
+
+#if defined(linux) && defined(KERNEL26_SUPPORT)
+ {
+ bool linux_ipsec = 0;
+ struct stat buf;
+
+ linux_ipsec = (stat("/proc/net/pfkey", &buf) == 0);
+ if (linux_ipsec)
+ {
+ plog("Using Linux 2.6 IPsec interface code");
+ kernel_ops = &linux_kernel_ops;
+ }
+ else
+ {
+ plog("Using KLIPS IPsec interface code");
+ }
+ }
+#endif
+
+ if (kernel_ops->init)
+ {
+ kernel_ops->init();
+ }
+
+ /* register SA types that we can negotiate */
+ can_do_IPcomp = FALSE; /* until we get a response from KLIPS */
+ kernel_ops->pfkey_register();
+
+ if (!kernel_ops->policy_lifetime)
+ {
+ event_schedule(EVENT_SHUNT_SCAN, SHUNT_SCAN_INTERVAL, NULL);
+ }
+#endif
+}
+
+/* Note: install_inbound_ipsec_sa is only used by the Responder.
+ * The Responder will subsequently use install_ipsec_sa for the outbound.
+ * The Initiator uses install_ipsec_sa to install both at once.
+ */
+bool
+install_inbound_ipsec_sa(struct state *st)
+{
+ struct connection *const c = st->st_connection;
+
+ /* If our peer has a fixed-address client, check if we already
+ * have a route for that client that conflicts. We will take this
+ * as proof that that route and the connections using it are
+ * obsolete and should be eliminated. Interestingly, this is
+ * the only case in which we can tell that a connection is obsolete.
+ */
+ passert(c->kind == CK_PERMANENT || c->kind == CK_INSTANCE);
+ if (c->spd.that.has_client)
+ {
+ for (;;)
+ {
+ struct spd_route *esr;
+ struct connection *o = route_owner(c, &esr, NULL, NULL);
+
+ if (o == NULL)
+ break; /* nobody has a route */
+
+ /* note: we ignore the client addresses at this end */
+ if (sameaddr(&o->spd.that.host_addr, &c->spd.that.host_addr)
+ && o->interface == c->interface)
+ break; /* existing route is compatible */
+
+ if (o->kind == CK_TEMPLATE && streq(o->name, c->name))
+ break; /* ??? is this good enough?? */
+
+ loglog(RC_LOG_SERIOUS, "route to peer's client conflicts with \"%s\" %s; releasing old connection to free the route"
+ , o->name, ip_str(&o->spd.that.host_addr));
+ release_connection(o, FALSE);
+ }
+ }
+
+ DBG(DBG_CONTROL, DBG_log("install_inbound_ipsec_sa() checking if we can route"));
+ /* check that we will be able to route and eroute */
+ switch (could_route(c))
+ {
+ case route_easy:
+ case route_nearconflict:
+ break;
+
+ default:
+ return FALSE;
+ }
+
+#ifdef KLIPS
+ /* (attempt to) actually set up the SAs */
+ return setup_half_ipsec_sa(st, TRUE);
+#else /* !KLIPS */
+ DBG(DBG_CONTROL, DBG_log("install_inbound_ipsec_sa()"));
+ return TRUE;
+#endif /* !KLIPS */
+}
+
+/* Install a route and then a prospective shunt eroute or an SA group eroute.
+ * Assumption: could_route gave a go-ahead.
+ * Any SA Group must have already been created.
+ * On failure, steps will be unwound.
+ */
+bool
+route_and_eroute(struct connection *c USED_BY_KLIPS
+ , struct spd_route *sr USED_BY_KLIPS
+ , struct state *st USED_BY_KLIPS)
+{
+#ifdef KLIPS
+ struct spd_route *esr;
+ struct spd_route *rosr;
+ struct connection *ero /* who, if anyone, owns our eroute? */
+ , *ro = route_owner(c, &rosr, &ero, &esr);
+ bool eroute_installed = FALSE
+ , firewall_notified = FALSE
+ , route_installed = FALSE;
+
+ struct connection *ero_top;
+ struct bare_shunt **bspp;
+
+ DBG(DBG_CONTROLMORE,
+ DBG_log("route_and_eroute with c: %s (next: %s) ero:%s esr:{%p} ro:%s rosr:{%p} and state: %lu"
+ , c->name
+ , (c->policy_next ? c->policy_next->name : "none")
+ , ero ? ero->name : "null"
+ , esr
+ , ro ? ro->name : "null"
+ , rosr
+ , st ? st->st_serialno : 0));
+
+ /* look along the chain of policies for one with the same name */
+ ero_top = ero;
+
+#if 0
+ /* XXX - mcr this made sense before, and likely will make sense
+ * again, so I'l leaving this to remind me what is up */
+ if (ero!= NULL && ero->routing == RT_UNROUTED_KEYED)
+ ero = NULL;
+
+ for (ero2 = ero; ero2 != NULL; ero2 = ero->policy_next)
+ if ((ero2->kind == CK_TEMPLATE || ero2->kind==CK_SECONDARY)
+ && streq(ero2->name, c->name))
+ break;
+#endif
+
+ bspp = (ero == NULL)
+ ? bare_shunt_ptr(&sr->this.client, &sr->that.client, sr->this.protocol)
+ : NULL;
+
+ /* install the eroute */
+
+ passert(bspp == NULL || ero == NULL); /* only one non-NULL */
+
+ if (bspp != NULL || ero != NULL)
+ {
+ /* We're replacing an eroute */
+
+ /* if no state provided, then install a shunt for later */
+ if (st == NULL)
+ eroute_installed = shunt_eroute(c, sr, RT_ROUTED_PROSPECTIVE
+ , ERO_REPLACE, "replace");
+ else
+ eroute_installed = sag_eroute(st, sr, ERO_REPLACE, "replace");
+
+#if 0
+ /* XXX - MCR. I previously felt that this was a bogus check */
+ if (ero != NULL && ero != c && esr != sr)
+ {
+ /* By elimination, we must be eclipsing ero. Check. */
+ passert(ero->kind == CK_TEMPLATE && streq(ero->name, c->name));
+ passert(LHAS(LELEM(RT_ROUTED_PROSPECTIVE) | LELEM(RT_ROUTED_ECLIPSED)
+ , esr->routing));
+ passert(samesubnet(&esr->this.client, &sr->this.client)
+ && samesubnet(&esr->that.client, &sr->that.client));
+ }
+#endif
+ /* remember to free bspp iff we make it out of here alive */
+ }
+ else
+ {
+ /* we're adding an eroute */
+
+ /* if no state provided, then install a shunt for later */
+ if (st == NULL)
+ eroute_installed = shunt_eroute(c, sr, RT_ROUTED_PROSPECTIVE
+ , ERO_ADD, "add");
+ else
+ eroute_installed = sag_eroute(st, sr, ERO_ADD, "add");
+ }
+
+ /* notify the firewall of a new tunnel */
+
+ if (eroute_installed)
+ {
+ /* do we have to notify the firewall? Yes, if we are installing
+ * a tunnel eroute and the firewall wasn't notified
+ * for a previous tunnel with the same clients. Any Previous
+ * tunnel would have to be for our connection, so the actual
+ * test is simple.
+ */
+ firewall_notified = st == NULL /* not a tunnel eroute */
+ || sr->eroute_owner != SOS_NOBODY /* already notified */
+ || do_command(c, sr, "up"); /* go ahead and notify */
+ }
+
+ /* install the route */
+
+ DBG(DBG_CONTROL,
+ DBG_log("route_and_eroute: firewall_notified: %s"
+ , firewall_notified ? "true" : "false"));
+ if (!firewall_notified)
+ {
+ /* we're in trouble -- don't do routing */
+ }
+ else if (ro == NULL)
+ {
+ /* a new route: no deletion required, but preparation is */
+ (void) do_command(c, sr, "prepare"); /* just in case; ignore failure */
+ route_installed = do_command(c, sr, "route");
+ }
+ else if (routed(sr->routing)
+ || routes_agree(ro, c))
+ {
+ route_installed = TRUE; /* nothing to be done */
+ }
+ else
+ {
+ /* Some other connection must own the route
+ * and the route must disagree. But since could_route
+ * must have allowed our stealing it, we'll do so.
+ *
+ * A feature of LINUX allows us to install the new route
+ * before deleting the old if the nexthops differ.
+ * This reduces the "window of vulnerability" when packets
+ * might flow in the clear.
+ */
+ if (sameaddr(&sr->this.host_nexthop, &esr->this.host_nexthop))
+ {
+ (void) do_command(ro, sr, "unroute");
+ route_installed = do_command(c, sr, "route");
+ }
+ else
+ {
+ route_installed = do_command(c, sr, "route");
+ (void) do_command(ro, sr, "unroute");
+ }
+
+ /* record unrouting */
+ if (route_installed)
+ {
+ do {
+ passert(!erouted(rosr->routing));
+ rosr->routing = RT_UNROUTED;
+
+ /* no need to keep old value */
+ ro = route_owner(c, &rosr, NULL, NULL);
+ } while (ro != NULL);
+ }
+ }
+
+ /* all done -- clean up */
+ if (route_installed)
+ {
+ /* Success! */
+
+ if (bspp != NULL)
+ {
+ free_bare_shunt(bspp);
+ }
+ else if (ero != NULL && ero != c)
+ {
+ /* check if ero is an ancestor of c. */
+ struct connection *ero2;
+
+ for (ero2 = c; ero2 != NULL && ero2 != c; ero2 = ero2->policy_next)
+ ;
+
+ if (ero2 == NULL)
+ {
+ /* By elimination, we must be eclipsing ero. Checked above. */
+ if (ero->spd.routing != RT_ROUTED_ECLIPSED)
+ {
+ ero->spd.routing = RT_ROUTED_ECLIPSED;
+ eclipse_count++;
+ }
+ }
+ }
+
+ if (st == NULL)
+ {
+ passert(sr->eroute_owner == SOS_NOBODY);
+ sr->routing = RT_ROUTED_PROSPECTIVE;
+ }
+ else
+ {
+ char cib[CONN_INST_BUF];
+ sr->routing = RT_ROUTED_TUNNEL;
+
+ DBG(DBG_CONTROL,
+ DBG_log("route_and_eroute: instance \"%s\"%s, setting eroute_owner {spd=%p,sr=%p} to #%ld (was #%ld) (newest_ipsec_sa=#%ld)"
+ , st->st_connection->name
+ , (fmt_conn_instance(st->st_connection, cib), cib)
+ , &st->st_connection->spd, sr
+ , st->st_serialno
+ , sr->eroute_owner
+ , st->st_connection->newest_ipsec_sa));
+ sr->eroute_owner = st->st_serialno;
+ }
+
+ return TRUE;
+ }
+ else
+ {
+ /* Failure! Unwind our work. */
+ if (firewall_notified && sr->eroute_owner == SOS_NOBODY)
+ (void) do_command(c, sr, "down");
+
+ if (eroute_installed)
+ {
+ /* Restore original eroute, if we can.
+ * Since there is nothing much to be done if the restoration
+ * fails, ignore success or failure.
+ */
+ if (bspp != NULL)
+ {
+ /* Restore old bare_shunt.
+ * I don't think that this case is very likely.
+ * Normally a bare shunt would have been assigned
+ * to a connection before we've gotten this far.
+ */
+ struct bare_shunt *bs = *bspp;
+
+ (void) raw_eroute(&bs->said.dst /* should be useless */
+ , &bs->ours
+ , &bs->said.dst /* should be useless */
+ , &bs->his
+ , bs->said.spi /* network order */
+ , SA_INT
+ , SADB_X_SATYPE_INT
+ , 0
+ , null_proto_info
+ , SHUNT_PATIENCE
+ , ERO_REPLACE, "restore");
+ }
+ else if (ero != NULL)
+ {
+ /* restore ero's former glory */
+ if (esr->eroute_owner == SOS_NOBODY)
+ {
+ /* note: normal or eclipse case */
+ (void) shunt_eroute(ero, esr
+ , esr->routing, ERO_REPLACE, "restore");
+ }
+ else
+ {
+ /* Try to find state that owned eroute.
+ * Don't do anything if it cannot be found.
+ * This case isn't likely since we don't run
+ * the updown script when replacing a SA group
+ * with its successor (for the same conn).
+ */
+ struct state *ost = state_with_serialno(esr->eroute_owner);
+
+ if (ost != NULL)
+ (void) sag_eroute(ost, esr, ERO_REPLACE, "restore");
+ }
+ }
+ else
+ {
+ /* there was no previous eroute: delete whatever we installed */
+ if (st == NULL)
+ (void) shunt_eroute(c, sr
+ , sr->routing, ERO_DELETE, "delete");
+ else
+ (void) sag_eroute(st, sr
+ , ERO_DELETE, "delete");
+ }
+ }
+
+ return FALSE;
+ }
+#else /* !KLIPS */
+ return TRUE;
+#endif /* !KLIPS */
+}
+
+bool
+install_ipsec_sa(struct state *st, bool inbound_also USED_BY_KLIPS)
+{
+#ifdef KLIPS
+ struct spd_route *sr;
+
+ DBG(DBG_CONTROL, DBG_log("install_ipsec_sa() for #%ld: %s"
+ , st->st_serialno
+ , inbound_also?
+ "inbound and outbound" : "outbound only"));
+
+ switch (could_route(st->st_connection))
+ {
+ case route_easy:
+ case route_nearconflict:
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ /* (attempt to) actually set up the SA group */
+ if ((inbound_also && !setup_half_ipsec_sa(st, TRUE))
+ || !setup_half_ipsec_sa(st, FALSE))
+ return FALSE;
+
+ for (sr = &st->st_connection->spd; sr != NULL; sr = sr->next)
+ {
+ DBG(DBG_CONTROL, DBG_log("sr for #%ld: %s"
+ , st->st_serialno
+ , enum_name(&routing_story, sr->routing)));
+
+ /*
+ * if the eroute owner is not us, then make it us.
+ * See test co-terminal-02, pluto-rekey-01, pluto-unit-02/oppo-twice
+ */
+ pexpect(sr->eroute_owner == SOS_NOBODY
+ || sr->routing >= RT_ROUTED_TUNNEL);
+
+ if (sr->eroute_owner != st->st_serialno
+ && sr->routing != RT_UNROUTED_KEYED)
+ {
+ if (!route_and_eroute(st->st_connection, sr, st))
+ {
+ delete_ipsec_sa(st, FALSE);
+ /* XXX go and unroute any SRs that were successfully
+ * routed already.
+ */
+ return FALSE;
+ }
+ }
+ }
+#else /* !KLIPS */
+ DBG(DBG_CONTROL, DBG_log("install_ipsec_sa() %s"
+ , inbound_also? "inbound and oubound" : "outbound only"));
+
+ switch (could_route(st->st_connection))
+ {
+ case route_easy:
+ case route_nearconflict:
+ break;
+
+ default:
+ return FALSE;
+ }
+
+
+#endif /* !KLIPS */
+
+ return TRUE;
+}
+
+/* delete an IPSEC SA.
+ * we may not succeed, but we bull ahead anyway because
+ * we cannot do anything better by recognizing failure
+ */
+void
+delete_ipsec_sa(struct state *st USED_BY_KLIPS, bool inbound_only USED_BY_KLIPS)
+{
+#ifdef KLIPS
+ if (!inbound_only)
+ {
+ /* If the state is the eroute owner, we must adjust
+ * the routing for the connection.
+ */
+ struct connection *c = st->st_connection;
+ struct spd_route *sr;
+
+ passert(st->st_connection);
+
+ for (sr = &c->spd; sr; sr = sr->next)
+ {
+ if (sr->eroute_owner == st->st_serialno
+ && sr->routing == RT_ROUTED_TUNNEL)
+ {
+ sr->eroute_owner = SOS_NOBODY;
+
+ /* Routing should become RT_ROUTED_FAILURE,
+ * but if POLICY_FAIL_NONE, then we just go
+ * right back to RT_ROUTED_PROSPECTIVE as if no
+ * failure happened.
+ */
+ sr->routing = (c->policy & POLICY_FAIL_MASK) == POLICY_FAIL_NONE
+ ? RT_ROUTED_PROSPECTIVE : RT_ROUTED_FAILURE;
+
+ (void) do_command(c, sr, "down");
+ if ((c->policy & POLICY_DONT_REKEY)
+ && c->kind == CK_INSTANCE)
+ {
+ /* in this special case, even if the connection
+ * is still alive (due to an ISAKMP SA),
+ * we get rid of routing.
+ * Even though there is still an eroute, the c->routing
+ * setting will convince unroute_connection to delete it.
+ * unroute_connection would be upset if c->routing == RT_ROUTED_TUNNEL
+ */
+ unroute_connection(c);
+ }
+ else
+ {
+ (void) shunt_eroute(c, sr, sr->routing, ERO_REPLACE, "replace with shunt");
+ }
+ }
+ }
+ (void) teardown_half_ipsec_sa(st, FALSE);
+ }
+ (void) teardown_half_ipsec_sa(st, TRUE);
+#else /* !KLIPS */
+ DBG(DBG_CONTROL, DBG_log("if I knew how, I'd eroute() and teardown_ipsec_sa()"));
+#endif /* !KLIPS */
+}
+
+#ifdef KLIPS
+static bool update_nat_t_ipsec_esp_sa (struct state *st, bool inbound)
+{
+ struct connection *c = st->st_connection;
+ char text_said[SATOT_BUF];
+ struct kernel_sa sa;
+ ip_address
+ src = inbound? c->spd.that.host_addr : c->spd.this.host_addr,
+ dst = inbound? c->spd.this.host_addr : c->spd.that.host_addr;
+
+ ipsec_spi_t esp_spi = inbound? st->st_esp.our_spi : st->st_esp.attrs.spi;
+
+ u_int16_t
+ natt_sport = inbound? c->spd.that.host_port : c->spd.this.host_port,
+ natt_dport = inbound? c->spd.this.host_port : c->spd.that.host_port;
+
+ set_text_said(text_said, &dst, esp_spi, SA_ESP);
+
+ memset(&sa, 0, sizeof(sa));
+ sa.spi = esp_spi;
+ sa.src = &src;
+ sa.dst = &dst;
+ sa.text_said = text_said;
+ sa.authalg = alg_info_esp_aa2sadb(st->st_esp.attrs.auth);
+ sa.natt_sport = natt_sport;
+ sa.natt_dport = natt_dport;
+ sa.transid = st->st_esp.attrs.transid;
+
+ return kernel_ops->add_sa(&sa, TRUE);
+}
+#endif
+
+bool update_ipsec_sa (struct state *st USED_BY_KLIPS)
+{
+#ifdef KLIPS
+ if (IS_IPSEC_SA_ESTABLISHED(st->st_state))
+ {
+ if (st->st_esp.present && (
+ (!update_nat_t_ipsec_esp_sa (st, TRUE)) ||
+ (!update_nat_t_ipsec_esp_sa (st, FALSE))))
+ {
+ return FALSE;
+ }
+ }
+ else if (IS_ONLY_INBOUND_IPSEC_SA_ESTABLISHED(st->st_state))
+ {
+ if (st->st_esp.present && !update_nat_t_ipsec_esp_sa (st, FALSE))
+ {
+ return FALSE;
+ }
+ }
+ else
+ {
+ DBG_log("assert failed at %s:%d st_state=%d", __FILE__, __LINE__, st->st_state);
+ return FALSE;
+ }
+ return TRUE;
+#else /* !KLIPS */
+ DBG(DBG_CONTROL, DBG_log("if I knew how, I'd update_ipsec_sa()"));
+ return TRUE;
+#endif /* !KLIPS */
+}
+
+/* Check if there was traffic on given SA during the last idle_max
+ * seconds. If TRUE, the SA was idle and DPD exchange should be performed.
+ * If FALSE, DPD is not necessary. We also return TRUE for errors, as they
+ * could mean that the SA is broken and needs to be replace anyway.
+ */
+bool
+was_eroute_idle(struct state *st, time_t idle_max, time_t *idle_time)
+{
+ static const char procname[] = "/proc/net/ipsec_spi";
+ FILE *f;
+ char buf[1024];
+ u_int bytes;
+ int ret = TRUE;
+
+ passert(st != NULL);
+
+ f = fopen(procname, "r");
+ if (f == NULL)
+ {
+ /* Can't open the file, perhaps were are on 26sec? */
+ time_t use_time;
+
+ if (get_sa_info(st, TRUE, &bytes, &use_time)
+ && use_time != UNDEFINED_TIME)
+ {
+ *idle_time = time(NULL) - use_time;
+ ret = *idle_time >= idle_max;
+ }
+ }
+ else
+ {
+ while (f != NULL)
+ {
+ char *line;
+ char text_said[SATOT_BUF];
+ u_int8_t proto = 0;
+ ip_address dst;
+ ip_said said;
+ ipsec_spi_t spi = 0;
+ static const char idle[] = "idle=";
+
+ dst = st->st_connection->spd.this.host_addr; /* inbound SA */
+ if (st->st_ah.present)
+ {
+ proto = SA_AH;
+ spi = st->st_ah.our_spi;
+ }
+ if (st->st_esp.present)
+ {
+ proto = SA_ESP;
+ spi = st->st_esp.our_spi;
+ }
+
+ if (proto == 0 && spi == 0)
+ {
+ ret = TRUE;
+ break;
+ }
+
+ initsaid(&dst, spi, proto, &said);
+ satot(&said, 'x', text_said, SATOT_BUF);
+
+ line = fgets(buf, sizeof(buf), f);
+ if (line == NULL)
+ {
+ /* Reached end of list */
+ ret = TRUE;
+ break;
+ }
+
+ if (strncmp(line, text_said, strlen(text_said)) == 0)
+ {
+ /* we found a match, now try to find idle= */
+ char *p = strstr(line, idle);
+
+ if (p == NULL)
+ {
+ /* SAs which haven't been used yet don't have it */
+ ret = TRUE; /* it didn't have traffic */
+ break;
+ }
+ p += sizeof(idle)-1;
+ if (*p == '\0')
+ {
+ ret = TRUE; /* be paranoid */
+ break;
+ }
+ if (sscanf(p, "%d", (int *) idle_time) <= 0)
+ {
+ ret = TRUE;
+ break;
+ }
+ if (*idle_time >= idle_max)
+ {
+ ret = TRUE;
+ break;
+ }
+ else
+ {
+ ret = FALSE;
+ break;
+ }
+ }
+ }
+ fclose(f);
+ }
+ return ret;
+}
diff --git a/src/pluto/kernel.h b/src/pluto/kernel.h
new file mode 100644
index 000000000..e7ff08c7b
--- /dev/null
+++ b/src/pluto/kernel.h
@@ -0,0 +1,198 @@
+/* declarations of routines that interface with the kernel's IPsec mechanism
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: kernel.h,v 1.10 2006/03/08 22:12:37 as Exp $
+ */
+
+#include "connections.h"
+
+extern bool no_klips; /* don't actually use KLIPS */
+extern bool can_do_IPcomp; /* can system actually perform IPCOMP? */
+
+#ifdef KLIPS
+/* Declare eroute things early enough for uses.
+ *
+ * Flags are encoded above the low-order byte of verbs.
+ * "real" eroutes are only outbound. Inbound eroutes don't exist,
+ * but an addflow with an INBOUND flag allows IPIP tunnels to be
+ * limited to appropriate source and destination addresses.
+ */
+
+#define ERO_MASK 0xFF
+#define ERO_FLAG_SHIFT 8
+
+#define ERO_DELETE SADB_X_DELFLOW
+#define ERO_ADD SADB_X_ADDFLOW
+#define ERO_REPLACE (SADB_X_ADDFLOW | (SADB_X_SAFLAGS_REPLACEFLOW << ERO_FLAG_SHIFT))
+#define ERO_ADD_INBOUND (SADB_X_ADDFLOW | (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT))
+#define ERO_DEL_INBOUND (SADB_X_DELFLOW | (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT))
+
+struct pfkey_proto_info {
+ int proto;
+ int encapsulation;
+ unsigned reqid;
+};
+struct sadb_msg;
+
+struct kernel_sa {
+ const ip_address *src;
+ const ip_address *dst;
+
+ const ip_subnet *src_client;
+ const ip_subnet *dst_client;
+
+ ipsec_spi_t spi;
+ unsigned proto;
+ unsigned satype;
+ unsigned transport_proto;
+ unsigned replay_window;
+ unsigned reqid;
+
+ unsigned authalg;
+ unsigned authkeylen;
+ char *authkey;
+
+ unsigned encalg;
+ unsigned enckeylen;
+ char *enckey;
+
+ unsigned compalg;
+
+ int encapsulation;
+
+ u_int16_t natt_sport, natt_dport;
+ u_int8_t transid, natt_type;
+ ip_address *natt_oa;
+
+ const char *text_said;
+};
+
+struct kernel_ops {
+ enum {
+ KERNEL_TYPE_NONE,
+ KERNEL_TYPE_KLIPS,
+ KERNEL_TYPE_LINUX,
+ } type;
+ bool inbound_eroute;
+ bool policy_lifetime;
+ int *async_fdp;
+
+ void (*init)(void);
+ void (*pfkey_register)(void);
+ void (*pfkey_register_response)(const struct sadb_msg *msg);
+ void (*process_queue)(void);
+ void (*process_msg)(void);
+ bool (*raw_eroute)(const ip_address *this_host,
+ const ip_subnet *this_client,
+ const ip_address *that_host,
+ const ip_subnet *that_client,
+ ipsec_spi_t spi,
+ unsigned int satype,
+ unsigned int transport_proto,
+ const struct pfkey_proto_info *proto_info,
+ time_t use_lifetime,
+ unsigned int op,
+ const char *text_said);
+ bool (*get_policy)(const struct kernel_sa *sa, bool inbound,
+ time_t *use_time);
+ bool (*add_sa)(const struct kernel_sa *sa, bool replace);
+ bool (*grp_sa)(const struct kernel_sa *sa_outer,
+ const struct kernel_sa *sa_inner);
+ bool (*del_sa)(const struct kernel_sa *sa);
+ bool (*get_sa)(const struct kernel_sa *sa, u_int *bytes);
+ ipsec_spi_t (*get_spi)(const ip_address *src,
+ const ip_address *dst,
+ int proto,
+ bool tunnel_mode,
+ unsigned reqid,
+ ipsec_spi_t min,
+ ipsec_spi_t max,
+ const char *text_said);
+};
+
+
+extern const struct kernel_ops *kernel_ops;
+
+/* information from /proc/net/ipsec_eroute */
+
+struct eroute_info {
+ unsigned long count;
+ ip_subnet ours;
+ ip_subnet his;
+ ip_address dst;
+ ip_said said;
+ int transport_proto;
+ struct eroute_info *next;
+};
+
+extern struct eroute_info *orphaned_holds;
+
+extern void show_shunt_status(void);
+#endif
+
+/* A netlink header defines EM_MAXRELSPIS, the max number of SAs in a group.
+ * Is there a PF_KEY equivalent?
+ */
+#ifndef EM_MAXRELSPIS
+# define EM_MAXRELSPIS 4 /* AH ESP IPCOMP IPIP */
+#endif
+
+extern void record_and_initiate_opportunistic(const ip_subnet *
+ , const ip_subnet *
+ , int transport_proto
+ , const char *why);
+
+extern void init_kernel(void);
+
+extern void scan_proc_shunts(void);
+
+extern bool trap_connection(struct connection *c);
+extern void unroute_connection(struct connection *c);
+
+extern bool has_bare_hold(const ip_address *src, const ip_address *dst
+ , int transport_proto);
+
+extern bool replace_bare_shunt(const ip_address *src, const ip_address *dst
+ , policy_prio_t policy_prio
+ , ipsec_spi_t shunt_spi /* in host order! */
+ , bool repl
+ , unsigned int transport_proto
+ , const char *why);
+
+extern bool assign_hold(struct connection *c
+ , struct spd_route *sr
+ , int transport_proto
+ , const ip_address *src, const ip_address *dst);
+
+extern ipsec_spi_t shunt_policy_spi(struct connection *c, bool prospective);
+
+
+struct state; /* forward declaration of tag */
+extern ipsec_spi_t get_ipsec_spi(ipsec_spi_t avoid
+ , int proto
+ , struct spd_route *sr
+ , bool tunnel_mode);
+extern ipsec_spi_t get_my_cpi(struct spd_route *sr, bool tunnel_mode);
+
+extern bool install_inbound_ipsec_sa(struct state *st);
+extern bool install_ipsec_sa(struct state *st, bool inbound_also);
+extern void delete_ipsec_sa(struct state *st, bool inbound_only);
+extern bool route_and_eroute(struct connection *c
+ , struct spd_route *sr
+ , struct state *st);
+extern bool was_eroute_idle(struct state *st, time_t idle_max
+ , time_t *idle_time);
+extern bool get_sa_info(struct state *st, bool inbound, u_int *bytes
+ , time_t *use_time);
+
+extern bool update_ipsec_sa(struct state *st);
diff --git a/src/pluto/kernel_alg.c b/src/pluto/kernel_alg.c
new file mode 100644
index 000000000..91dfaff59
--- /dev/null
+++ b/src/pluto/kernel_alg.c
@@ -0,0 +1,775 @@
+/* Kernel runtime algorithm handling interface
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: kernel_alg.c,v 1.9 2005/08/17 16:31:24 as Exp $
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <sys/queue.h>
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include <freeswan.h>
+#include <ipsec_policy.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "connections.h"
+#include "state.h"
+#include "packet.h"
+#include "spdb.h"
+#include "kernel.h"
+#include "kernel_alg.h"
+#include "alg_info.h"
+
+#ifndef NO_PLUTO
+#include "log.h"
+#include "whack.h"
+#include "db_ops.h"
+#else
+/*
+ * macros/functions for compilation without pluto (eg: spi for manual conns)
+ */
+extern int debug;
+#include <assert.h>
+#define passert(x) assert(x)
+#define DBG(cond, action) { if (debug) { action ; } }
+#define DBG_log(x, args...) fprintf(stderr, x "\n" , ##args);
+#define plog(x, args...) fprintf(stderr, x "\n" , ##args);
+#endif /* NO_PLUTO */
+/* ALG storage */
+static struct sadb_alg esp_aalg[SADB_AALG_MAX+1];
+static struct sadb_alg esp_ealg[SADB_EALG_MAX+1];
+static int esp_ealg_num = 0;
+static int esp_aalg_num = 0;
+
+#define ESP_EALG_PRESENT(algo) (((algo)<=SADB_EALG_MAX)&&(esp_ealg[(algo)].sadb_alg_id==(algo)))
+#define ESP_EALG_FOR_EACH_UPDOWN(algo) \
+ for (algo=SADB_EALG_MAX; algo >0 ; algo--) \
+ if (ESP_EALG_PRESENT(algo))
+#define ESP_AALG_PRESENT(algo) ((algo<=SADB_AALG_MAX)&&(esp_aalg[(algo)].sadb_alg_id==(algo)))
+#define ESP_AALG_FOR_EACH_UPDOWN(algo) \
+ for (algo=SADB_AALG_MAX; algo >0 ; algo--) \
+ if (ESP_AALG_PRESENT(algo))
+
+static struct sadb_alg*
+sadb_alg_ptr (int satype, int exttype, int alg_id, int rw)
+{
+ struct sadb_alg *alg_p = NULL;
+
+ switch (exttype)
+ {
+ case SADB_EXT_SUPPORTED_AUTH:
+ if (alg_id > SADB_AALG_MAX)
+ return NULL;
+ break;
+ case SADB_EXT_SUPPORTED_ENCRYPT:
+ if (alg_id > SADB_EALG_MAX)
+ return NULL;
+ break;
+ default:
+ return NULL;
+ }
+
+ switch (satype)
+ {
+ case SADB_SATYPE_ESP:
+ alg_p = (exttype == SADB_EXT_SUPPORTED_ENCRYPT)?
+ &esp_ealg[alg_id] : &esp_aalg[alg_id];
+ /* get for write: increment elem count */
+ if (rw)
+ {
+ (exttype == SADB_EXT_SUPPORTED_ENCRYPT)?
+ esp_ealg_num++ : esp_aalg_num++;
+ }
+ break;
+ case SADB_SATYPE_AH:
+ default:
+ return NULL;
+ }
+
+ return alg_p;
+}
+
+const struct sadb_alg *
+kernel_alg_sadb_alg_get(int satype, int exttype, int alg_id)
+{
+ return sadb_alg_ptr(satype, exttype, alg_id, 0);
+}
+
+/*
+ * Forget previous registration
+ */
+static void
+kernel_alg_init(void)
+{
+ DBG(DBG_KLIPS,
+ DBG_log("alg_init(): memset(%p, 0, %d) memset(%p, 0, %d)",
+ &esp_aalg, (int)sizeof (esp_aalg),
+ &esp_ealg, (int)sizeof (esp_ealg))
+ )
+ memset (&esp_aalg, 0, sizeof (esp_aalg));
+ memset (&esp_ealg, 0, sizeof (esp_ealg));
+ esp_ealg_num=esp_aalg_num = 0;
+}
+
+static int
+kernel_alg_add(int satype, int exttype, const struct sadb_alg *sadb_alg)
+{
+ struct sadb_alg *alg_p = NULL;
+ int alg_id = sadb_alg->sadb_alg_id;
+
+ DBG(DBG_KLIPS,
+ DBG_log("kernel_alg_add(): satype=%d, exttype=%d, alg_id=%d",
+ satype, exttype, sadb_alg->sadb_alg_id)
+ )
+ if (!(alg_p = sadb_alg_ptr(satype, exttype, alg_id, 1)))
+ return -1;
+
+ /* This logic "mimics" KLIPS: first algo implementation will be used */
+ if (alg_p->sadb_alg_id)
+ {
+ DBG(DBG_KLIPS,
+ DBG_log("kernel_alg_add(): discarding already setup "
+ "satype=%d, exttype=%d, alg_id=%d",
+ satype, exttype, sadb_alg->sadb_alg_id)
+ )
+ return 0;
+ }
+ *alg_p = *sadb_alg;
+ return 1;
+}
+
+bool
+kernel_alg_esp_enc_ok(u_int alg_id, u_int key_len,
+ struct alg_info_esp *alg_info __attribute__((unused)))
+{
+ struct sadb_alg *alg_p = NULL;
+
+ /*
+ * test #1: encrypt algo must be present
+ */
+ int ret = ESP_EALG_PRESENT(alg_id);
+ if (!ret) goto out;
+
+ alg_p = &esp_ealg[alg_id];
+
+ /*
+ * test #2: if key_len specified, it must be in range
+ */
+ if (key_len
+ && (key_len < alg_p->sadb_alg_minbits || key_len > alg_p->sadb_alg_maxbits))
+ {
+ plog("kernel_alg_db_add() key_len not in range: alg_id=%d, "
+ "key_len=%d, alg_minbits=%d, alg_maxbits=%d"
+ , alg_id, key_len
+ , alg_p->sadb_alg_minbits
+ , alg_p->sadb_alg_maxbits);
+ ret = FALSE;
+ }
+
+out:
+ if (ret)
+ {
+ DBG(DBG_KLIPS,
+ DBG_log("kernel_alg_esp_enc_ok(%d,%d): "
+ "alg_id=%d, "
+ "alg_ivlen=%d, alg_minbits=%d, alg_maxbits=%d, "
+ "res=%d, ret=%d"
+ , alg_id, key_len
+ , alg_p->sadb_alg_id
+ , alg_p->sadb_alg_ivlen
+ , alg_p->sadb_alg_minbits
+ , alg_p->sadb_alg_maxbits
+ , alg_p->sadb_alg_reserved
+ , ret);
+ )
+ }
+ else
+ {
+ DBG(DBG_KLIPS,
+ DBG_log("kernel_alg_esp_enc_ok(%d,%d): NO", alg_id, key_len);
+ )
+ }
+ return ret;
+}
+
+/*
+ * ML: make F_STRICT logic consider enc,auth algorithms
+ */
+#ifndef NO_PLUTO
+bool
+kernel_alg_esp_ok_final(u_int ealg, u_int key_len, u_int aalg, struct alg_info_esp *alg_info)
+{
+ int ealg_insecure;
+
+ /*
+ * key_len passed comes from esp_attrs read from peer
+ * For many older algoritms (eg 3DES) this key_len is fixed
+ * and get passed as 0.
+ * ... then get default key_len
+ */
+ if (key_len == 0)
+ key_len = kernel_alg_esp_enc_keylen(ealg) * BITS_PER_BYTE;
+
+ /*
+ * simple test to toss low key_len, will accept it only
+ * if specified in "esp" string
+ */
+ ealg_insecure = (key_len < 128) ;
+
+ if (ealg_insecure
+ || (alg_info && alg_info->alg_info_flags & ALG_INFO_F_STRICT))
+ {
+ int i;
+ struct esp_info *esp_info;
+
+ if (alg_info)
+ {
+ ALG_INFO_ESP_FOREACH(alg_info, esp_info, i)
+ {
+ if (esp_info->esp_ealg_id == ealg
+ && (esp_info->esp_ealg_keylen == 0 || key_len == 0
+ || esp_info->esp_ealg_keylen == key_len)
+ && esp_info->esp_aalg_id == aalg)
+ {
+ if (ealg_insecure)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "You should NOT use insecure ESP algorithms [%s (%d)]!"
+ , enum_name(&esp_transformid_names, ealg), key_len);
+ }
+ return TRUE;
+ }
+ }
+ }
+ plog("IPSec Transform [%s (%d), %s] refused due to %s",
+ enum_name(&esp_transformid_names, ealg), key_len,
+ enum_name(&auth_alg_names, aalg),
+ ealg_insecure ? "insecure key_len and enc. alg. not listed in \"esp\" string" : "strict flag");
+ return FALSE;
+ }
+ return TRUE;
+}
+#endif /* NO_PLUTO */
+
+/*
+ * Load kernel_alg arrays from /proc
+ * used in manual mode from klips/utils/spi.c
+ */
+int
+kernel_alg_proc_read(void)
+{
+ int satype;
+ int supp_exttype;
+ int alg_id, ivlen, minbits, maxbits;
+ struct sadb_alg sadb_alg;
+ int ret;
+ char buf[128];
+
+ FILE *fp=fopen("/proc/net/pf_key_supported", "r");
+
+ if (!fp)
+ return -1;
+
+ kernel_alg_init();
+
+ while (fgets(buf, sizeof(buf), fp))
+ {
+ if (buf[0] != ' ') /* skip titles */
+ continue;
+
+ sscanf(buf, "%d %d %d %d %d %d"
+ ,&satype, &supp_exttype
+ , &alg_id, &ivlen
+ , &minbits, &maxbits);
+
+ switch (satype)
+ {
+ case SADB_SATYPE_ESP:
+ switch(supp_exttype)
+ {
+ case SADB_EXT_SUPPORTED_AUTH:
+ case SADB_EXT_SUPPORTED_ENCRYPT:
+ sadb_alg.sadb_alg_id = alg_id;
+ sadb_alg.sadb_alg_ivlen = ivlen;
+ sadb_alg.sadb_alg_minbits = minbits;
+ sadb_alg.sadb_alg_maxbits = maxbits;
+ ret = kernel_alg_add(satype, supp_exttype, &sadb_alg);
+ DBG(DBG_CRYPT,
+ DBG_log("kernel_alg_proc_read() alg_id=%d, "
+ "alg_ivlen=%d, alg_minbits=%d, alg_maxbits=%d, "
+ "ret=%d"
+ , sadb_alg.sadb_alg_id
+ , sadb_alg.sadb_alg_ivlen
+ , sadb_alg.sadb_alg_minbits
+ , sadb_alg.sadb_alg_maxbits
+ , ret)
+ )
+ }
+ default:
+ continue;
+ }
+ }
+ fclose(fp);
+ return 0;
+}
+
+/*
+ * Load kernel_alg arrays pluto's SADB_REGISTER
+ * user by pluto/kernel.c
+ */
+
+void
+kernel_alg_register_pfkey(const struct sadb_msg *msg_buf, int buflen)
+{
+ /* Trick: one 'type-mangle-able' pointer to ease offset/assign */
+ union {
+ const struct sadb_msg *msg;
+ const struct sadb_supported *supported;
+ const struct sadb_ext *ext;
+ const struct sadb_alg *alg;
+ const char *ch;
+ } sadb;
+
+ int satype;
+ int msglen;
+ int i = 0;
+
+ /* Initialize alg arrays */
+ kernel_alg_init();
+ satype = msg_buf->sadb_msg_satype;
+ sadb.msg = msg_buf;
+ msglen = sadb.msg->sadb_msg_len*IPSEC_PFKEYv2_ALIGN;
+ msglen -= sizeof(struct sadb_msg);
+ buflen -= sizeof(struct sadb_msg);
+ passert(buflen > 0);
+
+ sadb.msg++;
+
+ while(msglen)
+ {
+ int supp_exttype = sadb.supported->sadb_supported_exttype;
+ int supp_len = sadb.supported->sadb_supported_len*IPSEC_PFKEYv2_ALIGN;
+
+ DBG(DBG_KLIPS,
+ DBG_log("kernel_alg_register_pfkey(): SADB_SATYPE_%s: "
+ "sadb_msg_len=%d sadb_supported_len=%d"
+ , satype==SADB_SATYPE_ESP? "ESP" : "AH"
+ , msg_buf->sadb_msg_len, supp_len)
+ )
+ sadb.supported++;
+ msglen -= supp_len;
+ buflen -= supp_len;
+ passert(buflen >= 0);
+
+ for (supp_len -= sizeof(struct sadb_supported);
+ supp_len;
+ supp_len -= sizeof(struct sadb_alg), sadb.alg++,i++)
+ {
+ int ret = kernel_alg_add(satype, supp_exttype, sadb.alg);
+
+ DBG(DBG_KLIPS,
+ DBG_log("kernel_alg_register_pfkey(): SADB_SATYPE_%s: "
+ "alg[%d], exttype=%d, satype=%d, alg_id=%d, "
+ "alg_ivlen=%d, alg_minbits=%d, alg_maxbits=%d, "
+ "res=%d, ret=%d"
+ , satype==SADB_SATYPE_ESP? "ESP" : "AH"
+ , i
+ , supp_exttype
+ , satype
+ , sadb.alg->sadb_alg_id
+ , sadb.alg->sadb_alg_ivlen
+ , sadb.alg->sadb_alg_minbits
+ , sadb.alg->sadb_alg_maxbits
+ , sadb.alg->sadb_alg_reserved
+ , ret)
+ )
+ }
+ }
+}
+
+u_int
+kernel_alg_esp_enc_keylen(u_int alg_id)
+{
+ u_int keylen = 0;
+
+ if (!ESP_EALG_PRESENT(alg_id))
+ goto none;
+
+ keylen = esp_ealg[alg_id].sadb_alg_maxbits/BITS_PER_BYTE;
+
+ switch (alg_id)
+ {
+ /*
+ * this is veryUgly[TM]
+ * Peer should have sent KEY_LENGTH attribute for ESP_AES
+ * but if not do force it to 128 instead of using sadb_alg_maxbits
+ * from kernel.
+ */
+ case ESP_AES:
+ keylen = 128/BITS_PER_BYTE;
+ break;
+ }
+
+none:
+ DBG(DBG_KLIPS,
+ DBG_log("kernel_alg_esp_enc_keylen():"
+ "alg_id=%d, keylen=%d",
+ alg_id, keylen)
+ )
+ return keylen;
+}
+
+struct sadb_alg *
+kernel_alg_esp_sadb_alg(u_int alg_id)
+{
+ struct sadb_alg *sadb_alg = (ESP_EALG_PRESENT(alg_id))
+ ? &esp_ealg[alg_id] : NULL;
+
+ DBG(DBG_KLIPS,
+ DBG_log("kernel_alg_esp_sadb_alg(): alg_id=%d, sadb_alg=%p"
+ , alg_id, sadb_alg)
+ )
+ return sadb_alg;
+}
+
+#ifndef NO_PLUTO
+void kernel_alg_list(void)
+{
+ u_int sadb_id;
+
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of registered ESP Encryption Algorithms:");
+ whack_log(RC_COMMENT, " ");
+
+ for (sadb_id = 1; sadb_id <= SADB_EALG_MAX; sadb_id++)
+ {
+ if (ESP_EALG_PRESENT(sadb_id))
+ {
+ struct sadb_alg *alg_p = &esp_ealg[sadb_id];
+
+ whack_log(RC_COMMENT, "#%-5d %s, blocksize: %d, keylen: %d-%d"
+ , sadb_id
+ , enum_name(&esp_transformid_names, sadb_id)
+ , alg_p->sadb_alg_ivlen
+ , alg_p->sadb_alg_minbits
+ , alg_p->sadb_alg_maxbits
+ );
+ }
+ }
+
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of registered ESP Authentication Algorithms:");
+ whack_log(RC_COMMENT, " ");
+
+ for (sadb_id = 1; sadb_id <= SADB_AALG_MAX; sadb_id++)
+ {
+ if (ESP_AALG_PRESENT(sadb_id))
+ {
+ u_int aaid = alg_info_esp_sadb2aa(sadb_id);
+ struct sadb_alg *alg_p = &esp_aalg[sadb_id];
+
+ whack_log(RC_COMMENT, "#%-5d %s, keylen: %d-%d"
+ , aaid
+ , enum_name(&auth_alg_names, aaid)
+ , alg_p->sadb_alg_minbits
+ , alg_p->sadb_alg_maxbits
+ );
+ }
+ }
+}
+
+void
+kernel_alg_show_connection(struct connection *c, const char *instance)
+{
+ char buf[256];
+ struct state *st;
+
+ if (c->alg_info_esp)
+ {
+ alg_info_snprint(buf, sizeof(buf), (struct alg_info *)c->alg_info_esp);
+ whack_log(RC_COMMENT
+ , "\"%s\"%s: ESP algorithms wanted: %s"
+ , c->name
+ , instance
+ , buf);
+ }
+ if (c->alg_info_esp)
+ {
+ alg_info_snprint_esp(buf, sizeof(buf), c->alg_info_esp);
+ whack_log(RC_COMMENT
+ , "\"%s\"%s: ESP algorithms loaded: %s"
+ , c->name
+ , instance
+ , buf);
+ }
+ st = state_with_serialno(c->newest_ipsec_sa);
+ if (st && st->st_esp.present)
+ whack_log(RC_COMMENT
+ , "\"%s\"%s: ESP algorithm newest: %s_%d-%s; pfsgroup=%s"
+ , c->name
+ , instance
+ , enum_show(&esp_transformid_names, st->st_esp.attrs.transid)
+ +4 /* strlen("ESP_") */
+ , st->st_esp.attrs.key_len
+ , enum_show(&auth_alg_names, st->st_esp.attrs.auth)+
+ +15 /* strlen("AUTH_ALGORITHM_") */
+ , c->policy & POLICY_PFS ?
+ c->alg_info_esp->esp_pfsgroup ?
+ enum_show(&oakley_group_names,
+ c->alg_info_esp->esp_pfsgroup)
+ +13 /*strlen("OAKLEY_GROUP_")*/
+ : "<Phase1>"
+ : "<N/A>"
+ );
+}
+#endif /* NO_PLUTO */
+
+bool
+kernel_alg_esp_auth_ok(u_int auth,
+ struct alg_info_esp *alg_info __attribute__((unused)))
+{
+ return ESP_AALG_PRESENT(alg_info_esp_aa2sadb(auth));
+}
+
+u_int
+kernel_alg_esp_auth_keylen(u_int auth)
+{
+ u_int sadb_aalg = alg_info_esp_aa2sadb(auth);
+
+ u_int a_keylen = (sadb_aalg)
+ ? esp_aalg[sadb_aalg].sadb_alg_maxbits/BITS_PER_BYTE
+ : 0;
+
+ DBG(DBG_CONTROL | DBG_CRYPT | DBG_PARSING,
+ DBG_log("kernel_alg_esp_auth_keylen(auth=%d, sadb_aalg=%d): "
+ "a_keylen=%d", auth, sadb_aalg, a_keylen)
+ )
+ return a_keylen;
+}
+
+struct esp_info *
+kernel_alg_esp_info(int transid, int auth)
+{
+ int sadb_aalg, sadb_ealg;
+ static struct esp_info ei_buf;
+
+ sadb_ealg = transid;
+ sadb_aalg = alg_info_esp_aa2sadb(auth);
+
+ if (!ESP_EALG_PRESENT(sadb_ealg))
+ goto none;
+ if (!ESP_AALG_PRESENT(sadb_aalg))
+ goto none;
+
+ memset(&ei_buf, 0, sizeof (ei_buf));
+ ei_buf.transid = transid;
+ ei_buf.auth = auth;
+
+ /* don't return "default" keylen because this value is used from
+ * setup_half_ipsec_sa() to "validate" keylen
+ * In effect, enckeylen will be used as "max" value
+ */
+ ei_buf.enckeylen = esp_ealg[sadb_ealg].sadb_alg_maxbits/BITS_PER_BYTE;
+ ei_buf.authkeylen = esp_aalg[sadb_aalg].sadb_alg_maxbits/BITS_PER_BYTE;
+ ei_buf.encryptalg = sadb_ealg;
+ ei_buf.authalg = sadb_aalg;
+
+ DBG(DBG_PARSING,
+ DBG_log("kernel_alg_esp_info():"
+ "transid=%d, auth=%d, ei=%p, "
+ "enckeylen=%d, authkeylen=%d, encryptalg=%d, authalg=%d",
+ transid, auth, &ei_buf,
+ (int)ei_buf.enckeylen, (int)ei_buf.authkeylen,
+ ei_buf.encryptalg, ei_buf.authalg)
+ )
+ return &ei_buf;
+
+none:
+ DBG(DBG_PARSING,
+ DBG_log("kernel_alg_esp_info():"
+ "transid=%d, auth=%d, ei=NULL",
+ transid, auth)
+ )
+ return NULL;
+}
+
+#ifndef NO_PLUTO
+static void
+kernel_alg_policy_algorithms(struct esp_info *esp_info)
+{
+ u_int ealg_id = esp_info->esp_ealg_id;
+
+ switch(ealg_id)
+ {
+ case 0:
+ case ESP_DES:
+ case ESP_3DES:
+ case ESP_NULL:
+ case ESP_CAST:
+ break;
+ default:
+ if (!esp_info->esp_ealg_keylen)
+ {
+ /* algos that need KEY_LENGTH
+ *
+ * Note: this is a very dirty hack ;-)
+ * Idea: Add a key_length_needed attribute to
+ * esp_ealg ??
+ */
+ esp_info->esp_ealg_keylen = esp_ealg[ealg_id].sadb_alg_maxbits;
+ }
+ }
+}
+
+static bool
+kernel_alg_db_add(struct db_context *db_ctx, struct esp_info *esp_info, lset_t policy)
+{
+ u_int ealg_id, aalg_id;
+
+ ealg_id = esp_info->esp_ealg_id;
+
+ if (!ESP_EALG_PRESENT(ealg_id))
+ {
+ DBG_log("kernel_alg_db_add() kernel enc ealg_id=%d not present", ealg_id);
+ return FALSE;
+ }
+
+ if (!(policy & POLICY_AUTHENTICATE)) /* skip ESP auth attrs for AH */
+ {
+ aalg_id = alg_info_esp_aa2sadb(esp_info->esp_aalg_id);
+
+ if (!ESP_AALG_PRESENT(aalg_id))
+ {
+ DBG_log("kernel_alg_db_add() kernel auth "
+ "aalg_id=%d not present", aalg_id);
+ return FALSE;
+ }
+ }
+
+ /* do algo policy */
+ kernel_alg_policy_algorithms(esp_info);
+
+ /* open new transformation */
+ db_trans_add(db_ctx, ealg_id);
+
+ /* add ESP auth attr */
+ if (!(policy & POLICY_AUTHENTICATE))
+ db_attr_add_values(db_ctx, AUTH_ALGORITHM, esp_info->esp_aalg_id);
+
+ /* add keylegth if specified in esp= string */
+ if (esp_info->esp_ealg_keylen)
+ db_attr_add_values(db_ctx, KEY_LENGTH, esp_info->esp_ealg_keylen);
+
+ return TRUE;
+}
+
+/*
+ * Create proposal with runtime kernel algos, merging
+ * with passed proposal if not NULL
+ *
+ * for now this function does free() previous returned
+ * malloced pointer (this quirk allows easier spdb.c change)
+ */
+struct db_context *
+kernel_alg_db_new(struct alg_info_esp *alg_info, lset_t policy )
+{
+ const struct esp_info *esp_info;
+ struct esp_info tmp_esp_info;
+ struct db_context *ctx_new=NULL;
+ struct db_trans *t;
+ struct db_prop *prop;
+ u_int trans_cnt;
+ int tn = 0;
+
+ if (!(policy & POLICY_ENCRYPT)) /* not possible, I think */
+ return NULL;
+
+ trans_cnt = esp_ealg_num * esp_aalg_num;
+ DBG(DBG_EMITTING,
+ DBG_log("kernel_alg_db_prop_new() initial trans_cnt=%d"
+ , trans_cnt)
+ )
+
+ /* pass aprox. number of transforms and attributes */
+ ctx_new = db_prop_new(PROTO_IPSEC_ESP, trans_cnt, trans_cnt * 2);
+
+ /*
+ * Loop: for each element (struct esp_info) of alg_info,
+ * if kernel support is present then build the transform (and attrs)
+ * if NULL alg_info, propose everything ...
+ */
+
+ if (alg_info)
+ {
+ int i;
+
+ ALG_INFO_ESP_FOREACH(alg_info, esp_info, i)
+ {
+ tmp_esp_info = *esp_info;
+ kernel_alg_db_add(ctx_new, &tmp_esp_info, policy);
+ }
+ }
+ else
+ {
+ u_int ealg_id;
+
+ ESP_EALG_FOR_EACH_UPDOWN(ealg_id)
+ {
+ u_int aalg_id;
+
+ tmp_esp_info.esp_ealg_id = ealg_id;
+ tmp_esp_info.esp_ealg_keylen = 0;
+
+ for (aalg_id = 1; aalg_id <= SADB_AALG_MAX; aalg_id++)
+ {
+ if (ESP_AALG_PRESENT(aalg_id))
+ {
+ tmp_esp_info.esp_aalg_id = alg_info_esp_sadb2aa(aalg_id);
+ tmp_esp_info.esp_aalg_keylen = 0;
+ kernel_alg_db_add(ctx_new, &tmp_esp_info, policy);
+ }
+ }
+ }
+ }
+
+ prop = db_prop_get(ctx_new);
+
+ DBG(DBG_CONTROL|DBG_EMITTING,
+ DBG_log("kernel_alg_db_prop_new() "
+ "will return p_new->protoid=%d, p_new->trans_cnt=%d"
+ , prop->protoid, prop->trans_cnt)
+ )
+
+ for (t = prop->trans, tn = 0; tn < prop->trans_cnt; tn++)
+ {
+ DBG(DBG_CONTROL|DBG_EMITTING,
+ DBG_log("kernel_alg_db_prop_new() "
+ " trans[%d]: transid=%d, attr_cnt=%d, "
+ "attrs[0].type=%d, attrs[0].val=%d"
+ , tn
+ , t[tn].transid, t[tn].attr_cnt
+ , t[tn].attrs[0].type, t[tn].attrs[0].val)
+ )
+ }
+ return ctx_new;
+}
+#endif /* NO_PLUTO */
diff --git a/src/pluto/kernel_alg.h b/src/pluto/kernel_alg.h
new file mode 100644
index 000000000..483e97da1
--- /dev/null
+++ b/src/pluto/kernel_alg.h
@@ -0,0 +1,46 @@
+/* Kernel runtime algorithm handling interface definitions
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: kernel_alg.h,v 1.5 2005/08/17 16:31:24 as Exp $
+ */
+
+#ifndef _KERNEL_ALG_H
+#define _KERNEL_ALG_H
+
+#include "alg_info.h"
+#include "spdb.h"
+
+/* status info */
+extern void kernel_alg_show_status(void);
+void kernel_alg_show_connection(struct connection *c, const char *instance);
+
+/* Registration messages from pluto */
+extern void kernel_alg_register_pfkey(const struct sadb_msg *msg, int buflen);
+
+/* ESP interface */
+extern struct sadb_alg *kernel_alg_esp_sadb_alg(u_int alg_id);
+extern u_int kernel_alg_esp_ivlen(u_int alg_id);
+extern bool kernel_alg_esp_enc_ok(u_int alg_id, u_int key_len, struct alg_info_esp *nfo);
+extern bool kernel_alg_esp_ok_final(u_int ealg, u_int key_len, u_int aalg, struct alg_info_esp *alg_info);
+extern u_int kernel_alg_esp_enc_keylen(u_int alg_id);
+extern bool kernel_alg_esp_auth_ok(u_int auth, struct alg_info_esp *nfo);
+extern u_int kernel_alg_esp_auth_keylen(u_int auth);
+extern int kernel_alg_proc_read(void);
+extern void kernel_alg_list(void);
+
+/* get sadb_alg for passed args */
+extern const struct sadb_alg * kernel_alg_sadb_alg_get(int satype, int exttype, int alg_id);
+
+extern struct db_context * kernel_alg_db_new(struct alg_info_esp *ai, lset_t policy);
+struct esp_info * kernel_alg_esp_info(int esp_id, int auth_id);
+#endif /* _KERNEL_ALG_H */
diff --git a/src/pluto/kernel_netlink.c b/src/pluto/kernel_netlink.c
new file mode 100644
index 000000000..1947ddbac
--- /dev/null
+++ b/src/pluto/kernel_netlink.c
@@ -0,0 +1,1219 @@
+/* netlink interface to the kernel's IPsec mechanism
+ * Copyright (C) 2003 Herbert Xu.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: kernel_netlink.c,v 1.24 2006/03/10 14:49:43 as Exp $
+ */
+
+#if defined(linux) && defined(KERNEL26_SUPPORT)
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <unistd.h>
+
+#include "kameipsec.h"
+#include "linux26/rtnetlink.h"
+#include "linux26/xfrm.h"
+
+#include <freeswan.h>
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "kernel.h"
+#include "kernel_netlink.h"
+#include "kernel_pfkey.h"
+#include "log.h"
+#include "whack.h" /* for RC_LOG_SERIOUS */
+#include "kernel_alg.h"
+
+/* Minimum priority number in SPD used by pluto. */
+#define MIN_SPD_PRIORITY 1024
+
+static int netlinkfd = NULL_FD;
+static int netlink_bcast_fd = NULL_FD;
+
+#define NE(x) { x, #x } /* Name Entry -- shorthand for sparse_names */
+
+static sparse_names xfrm_type_names = {
+ NE(NLMSG_NOOP),
+ NE(NLMSG_ERROR),
+ NE(NLMSG_DONE),
+ NE(NLMSG_OVERRUN),
+
+ NE(XFRM_MSG_NEWSA),
+ NE(XFRM_MSG_DELSA),
+ NE(XFRM_MSG_GETSA),
+
+ NE(XFRM_MSG_NEWPOLICY),
+ NE(XFRM_MSG_DELPOLICY),
+ NE(XFRM_MSG_GETPOLICY),
+
+ NE(XFRM_MSG_ALLOCSPI),
+ NE(XFRM_MSG_ACQUIRE),
+ NE(XFRM_MSG_EXPIRE),
+
+ NE(XFRM_MSG_UPDPOLICY),
+ NE(XFRM_MSG_UPDSA),
+
+ NE(XFRM_MSG_POLEXPIRE),
+
+ NE(XFRM_MSG_MAX),
+
+ { 0, sparse_end }
+};
+
+#undef NE
+
+/* Authentication algorithms */
+static sparse_names aalg_list = {
+ { SADB_X_AALG_NULL, "digest_null" },
+ { SADB_AALG_MD5_HMAC, "md5" },
+ { SADB_AALG_SHA1_HMAC, "sha1" },
+ { SADB_AALG_SHA2_256_HMAC, "sha256" },
+ { SADB_AALG_SHA2_384_HMAC, "sha384" },
+ { SADB_AALG_SHA2_512_HMAC, "sha512" },
+ { SADB_AALG_RIPEMD_160_HMAC, "ripemd160" },
+ { SADB_X_AALG_NULL, "null" },
+ { 0, sparse_end }
+};
+
+/* Encryption algorithms */
+static sparse_names ealg_list = {
+ { SADB_EALG_NULL, "cipher_null" },
+ { SADB_EALG_DES_CBC, "des" },
+ { SADB_EALG_3DES_CBC, "des3_ede" },
+ { SADB_EALG_IDEA_CBC, "idea" },
+ { SADB_EALG_CAST_CBC, "cast128" },
+ { SADB_EALG_BLOWFISH_CBC, "blowfish" },
+ { SADB_EALG_AES_CBC, "aes" },
+ { SADB_X_EALG_SERPENT_CBC, "serpent" },
+ { SADB_X_EALG_TWOFISH_CBC, "twofish" },
+ { 0, sparse_end }
+};
+
+/* Compression algorithms */
+static sparse_names calg_list = {
+ { SADB_X_CALG_DEFLATE, "deflate" },
+ { SADB_X_CALG_LZS, "lzs" },
+ { SADB_X_CALG_LZJH, "lzjh" },
+ { 0, sparse_end }
+};
+
+/** ip2xfrm - Take an IP address and convert to an xfrm.
+ *
+ * @param addr ip_address
+ * @param xaddr xfrm_address_t - IPv[46] Address from addr is copied here.
+ */
+static void
+ip2xfrm(const ip_address *addr, xfrm_address_t *xaddr)
+{
+ if (addr->u.v4.sin_family == AF_INET)
+ {
+ xaddr->a4 = addr->u.v4.sin_addr.s_addr;
+ }
+ else
+ {
+ memcpy(xaddr->a6, &addr->u.v6.sin6_addr, sizeof(xaddr->a6));
+ }
+}
+
+/** init_netlink - Initialize the netlink inferface. Opens the sockets and
+ * then binds to the broadcast socket.
+ */
+static void
+init_netlink(void)
+{
+ struct sockaddr_nl addr;
+
+ netlinkfd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_XFRM);
+
+ if (netlinkfd < 0)
+ exit_log_errno((e, "socket() in init_netlink()"));
+
+ if (fcntl(netlinkfd, F_SETFD, FD_CLOEXEC) != 0)
+ exit_log_errno((e, "fcntl(FD_CLOEXEC) in init_netlink()"));
+
+ netlink_bcast_fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_XFRM);
+
+ if (netlink_bcast_fd < 0)
+ exit_log_errno((e, "socket() for bcast in init_netlink()"));
+
+ if (fcntl(netlink_bcast_fd, F_SETFD, FD_CLOEXEC) != 0)
+ exit_log_errno((e, "fcntl(FD_CLOEXEC) for bcast in init_netlink()"));
+
+ if (fcntl(netlink_bcast_fd, F_SETFL, O_NONBLOCK) != 0)
+ exit_log_errno((e, "fcntl(O_NONBLOCK) for bcast in init_netlink()"));
+
+ addr.nl_family = AF_NETLINK;
+ addr.nl_pid = getpid();
+ addr.nl_groups = XFRMGRP_ACQUIRE | XFRMGRP_EXPIRE;
+ if (bind(netlink_bcast_fd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
+ exit_log_errno((e, "Failed to bind bcast socket in init_netlink()"));
+}
+
+/** send_netlink_msg
+ *
+ * @param hdr - Data to be sent.
+ * @param rbuf - Return Buffer - contains data returned from the send.
+ * @param rbuf_len - Length of rbuf
+ * @param description - String - user friendly description of what is
+ * being attempted. Used for diagnostics
+ * @param text_said - String
+ * @return bool True if the message was succesfully sent.
+ */
+static bool
+send_netlink_msg(struct nlmsghdr *hdr, struct nlmsghdr *rbuf, size_t rbuf_len
+, const char *description, const char *text_said)
+{
+ struct {
+ struct nlmsghdr n;
+ struct nlmsgerr e;
+ char data[1024];
+ } rsp;
+
+ size_t len;
+ ssize_t r;
+ struct sockaddr_nl addr;
+ static uint32_t seq;
+
+ if (no_klips)
+ {
+ return TRUE;
+ }
+
+ hdr->nlmsg_seq = ++seq;
+ len = hdr->nlmsg_len;
+ do {
+ r = write(netlinkfd, hdr, len);
+ } while (r < 0 && errno == EINTR);
+ if (r < 0)
+ {
+ log_errno((e
+ , "netlink write() of %s message"
+ " for %s %s failed"
+ , sparse_val_show(xfrm_type_names, hdr->nlmsg_type)
+ , description, text_said));
+ return FALSE;
+ }
+ else if ((size_t)r != len)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "ERROR: netlink write() of %s message"
+ " for %s %s truncated: %ld instead of %lu"
+ , sparse_val_show(xfrm_type_names, hdr->nlmsg_type)
+ , description, text_said
+ , (long)r, (unsigned long)len);
+ return FALSE;
+ }
+
+ for (;;) {
+ socklen_t alen;
+
+ alen = sizeof(addr);
+ r = recvfrom(netlinkfd, &rsp, sizeof(rsp), 0
+ , (struct sockaddr *)&addr, &alen);
+ if (r < 0)
+ {
+ if (errno == EINTR)
+ {
+ continue;
+ }
+ log_errno((e
+ , "netlink recvfrom() of response to our %s message"
+ " for %s %s failed"
+ , sparse_val_show(xfrm_type_names, hdr->nlmsg_type)
+ , description, text_said));
+ return FALSE;
+ }
+ else if ((size_t) r < sizeof(rsp.n))
+ {
+ plog("netlink read truncated message: %ld bytes; ignore message"
+ , (long) r);
+ continue;
+ }
+ else if (addr.nl_pid != 0)
+ {
+ /* not for us: ignore */
+ DBG(DBG_KLIPS,
+ DBG_log("netlink: ignoring %s message from process %u"
+ , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type)
+ , addr.nl_pid));
+ continue;
+ }
+ else if (rsp.n.nlmsg_seq != seq)
+ {
+ DBG(DBG_KLIPS,
+ DBG_log("netlink: ignoring out of sequence (%u/%u) message %s"
+ , rsp.n.nlmsg_seq, seq
+ , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type)));
+ continue;
+ }
+ break;
+ }
+
+ if (rsp.n.nlmsg_len > (size_t) r)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "netlink recvfrom() of response to our %s message"
+ " for %s %s was truncated: %ld instead of %lu"
+ , sparse_val_show(xfrm_type_names, hdr->nlmsg_type)
+ , description, text_said
+ , (long) len, (unsigned long) rsp.n.nlmsg_len);
+ return FALSE;
+ }
+ else if (rsp.n.nlmsg_type != NLMSG_ERROR
+ && (rbuf && rsp.n.nlmsg_type != rbuf->nlmsg_type))
+ {
+ loglog(RC_LOG_SERIOUS
+ , "netlink recvfrom() of response to our %s message"
+ " for %s %s was of wrong type (%s)"
+ , sparse_val_show(xfrm_type_names, hdr->nlmsg_type)
+ , description, text_said
+ , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type));
+ return FALSE;
+ }
+ else if (rbuf)
+ {
+ if ((size_t) r > rbuf_len)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "netlink recvfrom() of response to our %s message"
+ " for %s %s was too long: %ld > %lu"
+ , sparse_val_show(xfrm_type_names, hdr->nlmsg_type)
+ , description, text_said
+ , (long)r, (unsigned long)rbuf_len);
+ return FALSE;
+ }
+ memcpy(rbuf, &rsp, r);
+ return TRUE;
+ }
+ else if (rsp.n.nlmsg_type == NLMSG_ERROR && rsp.e.error)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "ERROR: netlink response for %s %s included errno %d: %s"
+ , description, text_said
+ , -rsp.e.error
+ , strerror(-rsp.e.error));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/** netlink_policy -
+ *
+ * @param hdr - Data to check
+ * @param enoent_ok - Boolean - OK or not OK.
+ * @param text_said - String
+ * @return boolean
+ */
+static bool
+netlink_policy(struct nlmsghdr *hdr, bool enoent_ok, const char *text_said)
+{
+ struct {
+ struct nlmsghdr n;
+ struct nlmsgerr e;
+ } rsp;
+ int error;
+
+ rsp.n.nlmsg_type = NLMSG_ERROR;
+ if (!send_netlink_msg(hdr, &rsp.n, sizeof(rsp), "policy", text_said))
+ {
+ return FALSE;
+ }
+
+ error = -rsp.e.error;
+ if (!error)
+ {
+ return TRUE;
+ }
+
+ if (error == ENOENT && enoent_ok)
+ {
+ return TRUE;
+ }
+
+ loglog(RC_LOG_SERIOUS
+ , "ERROR: netlink %s response for flow %s included errno %d: %s"
+ , sparse_val_show(xfrm_type_names, hdr->nlmsg_type)
+ , text_said
+ , error
+ , strerror(error));
+ return FALSE;
+}
+
+/** netlink_raw_eroute
+ *
+ * @param this_host ip_address
+ * @param this_client ip_subnet
+ * @param that_host ip_address
+ * @param that_client ip_subnet
+ * @param spi
+ * @param proto int (Currently unused) Contains protocol (u=tcp, 17=udp, etc...)
+ * @param transport_proto int (Currently unused) 0=tunnel, 1=transport
+ * @param satype int
+ * @param proto_info
+ * @param lifetime (Currently unused)
+ * @param ip int
+ * @return boolean True if successful
+ */
+static bool
+netlink_raw_eroute(const ip_address *this_host
+ , const ip_subnet *this_client
+ , const ip_address *that_host
+ , const ip_subnet *that_client
+ , ipsec_spi_t spi
+ , unsigned int satype
+ , unsigned int transport_proto
+ , const struct pfkey_proto_info *proto_info
+ , time_t use_lifetime UNUSED
+ , unsigned int op
+ , const char *text_said)
+{
+ struct {
+ struct nlmsghdr n;
+ union {
+ struct xfrm_userpolicy_info p;
+ struct xfrm_userpolicy_id id;
+ } u;
+ char data[1024];
+ } req;
+ int shift;
+ int dir;
+ int family;
+ int policy;
+ bool ok;
+ bool enoent_ok;
+
+ policy = IPSEC_POLICY_IPSEC;
+
+ if (satype == SADB_X_SATYPE_INT)
+ {
+ /* shunt route */
+ switch (ntohl(spi))
+ {
+ case SPI_PASS:
+ policy = IPSEC_POLICY_NONE;
+ break;
+ case SPI_DROP:
+ case SPI_REJECT:
+ default:
+ policy = IPSEC_POLICY_DISCARD;
+ break;
+ case SPI_TRAP:
+ case SPI_TRAPSUBNET:
+ case SPI_HOLD:
+ if (op & (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT))
+ {
+ return TRUE;
+ }
+ break;
+ }
+ }
+
+ memset(&req, 0, sizeof(req));
+ req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+
+ family = that_client->addr.u.v4.sin_family;
+ shift = (family == AF_INET) ? 5 : 7;
+
+ req.u.p.sel.sport = portof(&this_client->addr);
+ req.u.p.sel.dport = portof(&that_client->addr);
+ req.u.p.sel.sport_mask = (req.u.p.sel.sport) ? ~0:0;
+ req.u.p.sel.dport_mask = (req.u.p.sel.dport) ? ~0:0;
+ ip2xfrm(&this_client->addr, &req.u.p.sel.saddr);
+ ip2xfrm(&that_client->addr, &req.u.p.sel.daddr);
+ req.u.p.sel.prefixlen_s = this_client->maskbits;
+ req.u.p.sel.prefixlen_d = that_client->maskbits;
+ req.u.p.sel.proto = transport_proto;
+ req.u.p.sel.family = family;
+
+ dir = XFRM_POLICY_OUT;
+ if (op & (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT))
+ {
+ dir = XFRM_POLICY_IN;
+ }
+
+ if ((op & ERO_MASK) == ERO_DELETE)
+ {
+ req.u.id.dir = dir;
+ req.n.nlmsg_type = XFRM_MSG_DELPOLICY;
+ req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.u.id)));
+ }
+ else
+ {
+ int src, dst;
+
+ req.u.p.dir = dir;
+
+ src = req.u.p.sel.prefixlen_s;
+ dst = req.u.p.sel.prefixlen_d;
+ if (dir != XFRM_POLICY_OUT) {
+ src = req.u.p.sel.prefixlen_d;
+ dst = req.u.p.sel.prefixlen_s;
+ }
+ req.u.p.priority = MIN_SPD_PRIORITY
+ + (((2 << shift) - src) << shift)
+ + (2 << shift) - dst;
+
+ req.u.p.action = XFRM_POLICY_ALLOW;
+ if (policy == IPSEC_POLICY_DISCARD)
+ {
+ req.u.p.action = XFRM_POLICY_BLOCK;
+ }
+ req.u.p.lft.soft_use_expires_seconds = use_lifetime;
+ req.u.p.lft.soft_byte_limit = XFRM_INF;
+ req.u.p.lft.soft_packet_limit = XFRM_INF;
+ req.u.p.lft.hard_byte_limit = XFRM_INF;
+ req.u.p.lft.hard_packet_limit = XFRM_INF;
+
+ req.n.nlmsg_type = XFRM_MSG_NEWPOLICY;
+ if (op & (SADB_X_SAFLAGS_REPLACEFLOW << ERO_FLAG_SHIFT))
+ {
+ req.n.nlmsg_type = XFRM_MSG_UPDPOLICY;
+ }
+ req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.u.p)));
+ }
+
+ if (policy == IPSEC_POLICY_IPSEC && (op & ERO_MASK) != ERO_DELETE)
+ {
+ struct rtattr *attr;
+ struct xfrm_user_tmpl tmpl[4];
+ int i;
+
+ memset(tmpl, 0, sizeof(tmpl));
+ for (i = 0; proto_info[i].proto; i++)
+ {
+ tmpl[i].reqid = proto_info[i].reqid;
+ tmpl[i].id.proto = proto_info[i].proto;
+ tmpl[i].optional =
+ proto_info[i].proto == IPPROTO_COMP && dir != XFRM_POLICY_OUT;
+ tmpl[i].aalgos = tmpl[i].ealgos = tmpl[i].calgos = ~0;
+ tmpl[i].mode =
+ proto_info[i].encapsulation == ENCAPSULATION_MODE_TUNNEL;
+
+ if (!tmpl[i].mode)
+ {
+ continue;
+ }
+
+ ip2xfrm(this_host, &tmpl[i].saddr);
+ ip2xfrm(that_host, &tmpl[i].id.daddr);
+ }
+
+ attr = (struct rtattr *)((char *)&req + req.n.nlmsg_len);
+ attr->rta_type = XFRMA_TMPL;
+ attr->rta_len = i * sizeof(tmpl[0]);
+ memcpy(RTA_DATA(attr), tmpl, attr->rta_len);
+ attr->rta_len = RTA_LENGTH(attr->rta_len);
+ req.n.nlmsg_len += attr->rta_len;
+ }
+
+ enoent_ok = FALSE;
+ if (op == ERO_DEL_INBOUND)
+ {
+ enoent_ok = TRUE;
+ }
+ else if (op == ERO_DELETE && ntohl(spi) == SPI_HOLD)
+ {
+ enoent_ok = TRUE;
+ }
+
+ ok = netlink_policy(&req.n, enoent_ok, text_said);
+ switch (dir)
+ {
+ case XFRM_POLICY_IN:
+ if (req.n.nlmsg_type == XFRM_MSG_DELPOLICY)
+ {
+ req.u.id.dir = XFRM_POLICY_FWD;
+ }
+ else if (!ok)
+ {
+ break;
+ }
+ else if (proto_info[0].encapsulation != ENCAPSULATION_MODE_TUNNEL
+ && satype != SADB_X_SATYPE_INT)
+ {
+ break;
+ }
+ else
+ {
+ req.u.p.dir = XFRM_POLICY_FWD;
+ }
+ ok &= netlink_policy(&req.n, enoent_ok, text_said);
+ break;
+ }
+
+ return ok;
+}
+
+/** netlink_add_sa - Add an SA into the kernel SPDB via netlink
+ *
+ * @param sa Kernel SA to add/modify
+ * @param replace boolean - true if this replaces an existing SA
+ * @return bool True if successfull
+ */
+static bool
+netlink_add_sa(const struct kernel_sa *sa, bool replace)
+{
+ struct {
+ struct nlmsghdr n;
+ struct xfrm_usersa_info p;
+ char data[1024];
+ } req;
+ struct rtattr *attr;
+
+ memset(&req, 0, sizeof(req));
+ req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ req.n.nlmsg_type = replace ? XFRM_MSG_UPDSA : XFRM_MSG_NEWSA;
+
+ ip2xfrm(sa->src, &req.p.saddr);
+ ip2xfrm(sa->dst, &req.p.id.daddr);
+
+ req.p.id.spi = sa->spi;
+ req.p.id.proto = satype2proto(sa->satype);
+ req.p.family = sa->src->u.v4.sin_family;
+ req.p.mode = (sa->encapsulation == ENCAPSULATION_MODE_TUNNEL);
+ req.p.replay_window = sa->replay_window;
+ req.p.reqid = sa->reqid;
+ req.p.lft.soft_byte_limit = XFRM_INF;
+ req.p.lft.soft_packet_limit = XFRM_INF;
+ req.p.lft.hard_byte_limit = XFRM_INF;
+ req.p.lft.hard_packet_limit = XFRM_INF;
+
+ req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.p)));
+
+ attr = (struct rtattr *)((char *)&req + req.n.nlmsg_len);
+
+ if (sa->authalg)
+ {
+ struct xfrm_algo algo;
+ const char *name;
+
+ name = sparse_name(aalg_list, sa->authalg);
+ if (!name) {
+ loglog(RC_LOG_SERIOUS, "unknown authentication algorithm: %u"
+ , sa->authalg);
+ return FALSE;
+ }
+
+ strcpy(algo.alg_name, name);
+ algo.alg_key_len = sa->authkeylen * BITS_PER_BYTE;
+
+ attr->rta_type = XFRMA_ALG_AUTH;
+ attr->rta_len = RTA_LENGTH(sizeof(algo) + sa->authkeylen);
+
+ memcpy(RTA_DATA(attr), &algo, sizeof(algo));
+ memcpy((char *)RTA_DATA(attr) + sizeof(algo), sa->authkey
+ , sa->authkeylen);
+
+ req.n.nlmsg_len += attr->rta_len;
+ attr = (struct rtattr *)((char *)attr + attr->rta_len);
+ }
+
+ if (sa->encalg)
+ {
+ struct xfrm_algo algo;
+ const char *name;
+
+ name = sparse_name(ealg_list, sa->encalg);
+ if (!name) {
+ loglog(RC_LOG_SERIOUS, "unknown encryption algorithm: %u"
+ , sa->encalg);
+ return FALSE;
+ }
+
+ strcpy(algo.alg_name, name);
+ algo.alg_key_len = sa->enckeylen * BITS_PER_BYTE;
+
+ attr->rta_type = XFRMA_ALG_CRYPT;
+ attr->rta_len = RTA_LENGTH(sizeof(algo) + sa->enckeylen);
+
+ memcpy(RTA_DATA(attr), &algo, sizeof(algo));
+ memcpy((char *)RTA_DATA(attr) + sizeof(algo), sa->enckey
+ , sa->enckeylen);
+
+ req.n.nlmsg_len += attr->rta_len;
+ attr = (struct rtattr *)((char *)attr + attr->rta_len);
+ }
+
+ if (sa->compalg)
+ {
+ struct xfrm_algo algo;
+ const char *name;
+
+ name = sparse_name(calg_list, sa->compalg);
+ if (!name) {
+ loglog(RC_LOG_SERIOUS, "unknown compression algorithm: %u"
+ , sa->compalg);
+ return FALSE;
+ }
+
+ strcpy(algo.alg_name, name);
+ algo.alg_key_len = 0;
+
+ attr->rta_type = XFRMA_ALG_COMP;
+ attr->rta_len = RTA_LENGTH(sizeof(algo));
+
+ memcpy(RTA_DATA(attr), &algo, sizeof(algo));
+
+ req.n.nlmsg_len += attr->rta_len;
+ attr = (struct rtattr *)((char *)attr + attr->rta_len);
+ }
+
+ if (sa->natt_type)
+ {
+ struct xfrm_encap_tmpl natt;
+
+ natt.encap_type = sa->natt_type;
+ natt.encap_sport = ntohs(sa->natt_sport);
+ natt.encap_dport = ntohs(sa->natt_dport);
+ memset (&natt.encap_oa, 0, sizeof (natt.encap_oa));
+
+ attr->rta_type = XFRMA_ENCAP;
+ attr->rta_len = RTA_LENGTH(sizeof(natt));
+
+ memcpy(RTA_DATA(attr), &natt, sizeof(natt));
+
+ req.n.nlmsg_len += attr->rta_len;
+ attr = (struct rtattr *)((char *)attr + attr->rta_len);
+ }
+
+ return send_netlink_msg(&req.n, NULL, 0, "Add SA", sa->text_said);
+}
+
+/** netlink_del_sa - Delete an SA from the Kernel
+ *
+ * @param sa Kernel SA to be deleted
+ * @return bool True if successfull
+ */
+static bool
+netlink_del_sa(const struct kernel_sa *sa)
+{
+ struct {
+ struct nlmsghdr n;
+ struct xfrm_usersa_id id;
+ char data[1024];
+ } req;
+
+ memset(&req, 0, sizeof(req));
+ req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ req.n.nlmsg_type = XFRM_MSG_DELSA;
+
+ ip2xfrm(sa->dst, &req.id.daddr);
+
+ req.id.spi = sa->spi;
+ req.id.family = sa->src->u.v4.sin_family;
+ req.id.proto = sa->proto;
+
+ req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.id)));
+
+ return send_netlink_msg(&req.n, NULL, 0, "Del SA", sa->text_said);
+}
+
+static bool
+netlink_error(const char *req_type, const struct nlmsghdr *n
+, const struct nlmsgerr *e, int rsp_size)
+{
+ if (n->nlmsg_type == NLMSG_ERROR)
+ {
+ DBG(DBG_KLIPS,
+ DBG_log("%s returned with errno %d: %s"
+ , req_type
+ , -e->error
+ , strerror(-e->error))
+ )
+ return TRUE;
+ }
+ if (n->nlmsg_len < NLMSG_LENGTH(rsp_size))
+ {
+ plog("%s returned message with length %lu < %lu bytes"
+ , req_type
+ , (unsigned long) n->nlmsg_len
+ , (unsigned long) rsp_size);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static bool
+netlink_get_policy(const struct kernel_sa *sa, bool inbound, time_t *use_time)
+{
+ struct {
+ struct nlmsghdr n;
+ struct xfrm_userpolicy_id id;
+ } req;
+
+ struct {
+ struct nlmsghdr n;
+ union {
+ struct nlmsgerr e;
+ struct xfrm_userpolicy_info info;
+ } u;
+ char data[1024];
+ } rsp;
+
+ memset(&req, 0, sizeof(req));
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.n.nlmsg_type = XFRM_MSG_GETPOLICY;
+
+ req.id.sel.sport = portof(&sa->src_client->addr);
+ req.id.sel.dport = portof(&sa->dst_client->addr);
+ req.id.sel.sport_mask = (req.id.sel.sport) ? ~0:0;
+ req.id.sel.dport_mask = (req.id.sel.dport) ? ~0:0;
+ ip2xfrm(&sa->src_client->addr, &req.id.sel.saddr);
+ ip2xfrm(&sa->dst_client->addr, &req.id.sel.daddr);
+ req.id.sel.prefixlen_s = sa->src_client->maskbits;
+ req.id.sel.prefixlen_d = sa->dst_client->maskbits;
+ req.id.sel.proto = sa->transport_proto;
+ req.id.sel.family = sa->dst_client->addr.u.v4.sin_family;
+
+ req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.id)));
+ rsp.n.nlmsg_type = XFRM_MSG_NEWPOLICY;
+
+ req.id.dir = (inbound)? XFRM_POLICY_IN:XFRM_POLICY_OUT;
+
+ if (!send_netlink_msg(&req.n, &rsp.n, sizeof(rsp), "Get policy", "?"))
+ return FALSE;
+
+ if (netlink_error("XFRM_MSG_GETPOLICY", &rsp.n, &rsp.u.e, sizeof(rsp.u.info)))
+ return FALSE;
+
+ *use_time = (time_t)rsp.u.info.curlft.use_time;
+
+ if (inbound && sa->encapsulation == ENCAPSULATION_MODE_TUNNEL)
+ {
+ time_t use_time_fwd;
+
+ req.id.dir = XFRM_POLICY_FWD;
+
+ if (!send_netlink_msg(&req.n, &rsp.n, sizeof(rsp), "Get policy", "?"))
+ return FALSE;
+
+ if (netlink_error("XFRM_MSG_GETPOLICY", &rsp.n, &rsp.u.e, sizeof(rsp.u.info)))
+ return FALSE;
+
+ use_time_fwd = (time_t)rsp.u.info.curlft.use_time;
+ *use_time = (*use_time > use_time_fwd)? *use_time : use_time_fwd;
+ }
+ return TRUE;
+}
+
+
+/** netlink_get_sa - Get information about an SA from the Kernel
+ *
+ * @param sa Kernel SA to be queried
+ * @return bool True if successfull
+ */
+static bool
+netlink_get_sa(const struct kernel_sa *sa, u_int *bytes)
+{
+ struct {
+ struct nlmsghdr n;
+ struct xfrm_usersa_id id;
+ } req;
+
+ struct {
+ struct nlmsghdr n;
+ union {
+ struct nlmsgerr e;
+ struct xfrm_usersa_info info;
+ } u;
+ char data[1024];
+ } rsp;
+
+ memset(&req, 0, sizeof(req));
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.n.nlmsg_type = XFRM_MSG_GETSA;
+
+ ip2xfrm(sa->dst, &req.id.daddr);
+
+ req.id.spi = sa->spi;
+ req.id.family = sa->src->u.v4.sin_family;
+ req.id.proto = sa->proto;
+
+ req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.id)));
+ rsp.n.nlmsg_type = XFRM_MSG_NEWSA;
+
+ if (!send_netlink_msg(&req.n, &rsp.n, sizeof(rsp), "Get SA", sa->text_said))
+ return FALSE;
+
+ if (netlink_error("XFRM_MSG_GETSA", &rsp.n, &rsp.u.e, sizeof(rsp.u.info)))
+ return FALSE;
+
+ *bytes = (u_int) rsp.u.info.curlft.bytes;
+
+ return TRUE;
+}
+
+static void
+linux_pfkey_register_response(const struct sadb_msg *msg)
+{
+ switch (msg->sadb_msg_satype)
+ {
+ case SADB_SATYPE_ESP:
+#ifndef NO_KERNEL_ALG
+ kernel_alg_register_pfkey(msg, msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN);
+#endif
+ break;
+ case SADB_X_SATYPE_IPCOMP:
+ can_do_IPcomp = TRUE;
+ break;
+ default:
+ break;
+ }
+}
+
+/** linux_pfkey_register - Register via PFKEY our capabilities
+ *
+ */
+static void
+linux_pfkey_register(void)
+{
+ pfkey_register_proto(SADB_SATYPE_AH, "AH");
+ pfkey_register_proto(SADB_SATYPE_ESP, "ESP");
+ pfkey_register_proto(SADB_X_SATYPE_IPCOMP, "IPCOMP");
+ pfkey_close();
+}
+
+/** Create ip_address out of xfrm_address_t.
+ *
+ * @param family
+ * @param src xfrm formatted IP address
+ * @param dst ip_address formatted destination
+ * @return err_t NULL if okay, otherwise an error
+ */
+static err_t
+xfrm_to_ip_address(unsigned family, const xfrm_address_t *src, ip_address *dst)
+{
+ switch (family)
+ {
+ case AF_INET: /* IPv4 */
+ case AF_UNSPEC: /* Unspecified, we assume IPv4 */
+ initaddr((const void *) &src->a4, sizeof(src->a4), AF_INET, dst);
+ return NULL;
+ case AF_INET6: /* IPv6 */
+ initaddr((const void *) &src->a6, sizeof(src->a6), AF_INET6, dst);
+ return NULL;
+ default:
+ return "unknown address family";
+ }
+}
+
+/* Create a pair of ip_address's out of xfrm_sel.
+ *
+ * @param sel xfrm selector
+ * @param src ip_address formatted source
+ * @param dst ip_address formatted destination
+ * @return err_t NULL if okay, otherwise an error
+ */
+static err_t
+xfrm_sel_to_ip_pair(const struct xfrm_selector *sel
+ , ip_address *src
+ , ip_address *dst)
+{
+ int family;
+ err_t ugh;
+
+ family = sel->family;
+
+ if ((ugh = xfrm_to_ip_address(family, &sel->saddr, src))
+ || (ugh = xfrm_to_ip_address(family, &sel->daddr, dst)))
+ return ugh;
+
+ /* family has been verified in xfrm_to_ip_address. */
+ if (family == AF_INET)
+ {
+ src->u.v4.sin_port = sel->sport;
+ dst->u.v4.sin_port = sel->dport;
+ }
+ else
+ {
+ src->u.v6.sin6_port = sel->sport;
+ dst->u.v6.sin6_port = sel->dport;
+ }
+
+ return NULL;
+}
+
+static void
+netlink_acquire(struct nlmsghdr *n)
+{
+ struct xfrm_user_acquire *acquire;
+ ip_address src, dst;
+ ip_subnet ours, his;
+ unsigned transport_proto;
+ err_t ugh = NULL;
+
+ if (n->nlmsg_len < NLMSG_LENGTH(sizeof(*acquire)))
+ {
+ plog("netlink_acquire got message with length %lu < %lu bytes; ignore message"
+ , (unsigned long) n->nlmsg_len
+ , (unsigned long) sizeof(*acquire));
+ return;
+ }
+
+ acquire = NLMSG_DATA(n);
+ transport_proto = acquire->sel.proto;
+
+ /* XXX also the type of src/dst should be checked to make sure
+ * that they aren't v4 to v6 or something goofy
+ */
+
+ if (!(ugh = xfrm_sel_to_ip_pair(&acquire->sel, &src, &dst))
+ && !(ugh = addrtosubnet(&src, &ours))
+ && !(ugh = addrtosubnet(&dst, &his)))
+ record_and_initiate_opportunistic(&ours, &his, transport_proto
+ , "%acquire-netlink");
+
+ if (ugh != NULL)
+ plog("XFRM_MSG_ACQUIRE message from kernel malformed: %s", ugh);
+}
+
+static void
+netlink_shunt_expire(struct xfrm_userpolicy_info *pol)
+{
+ ip_address src, dst;
+ unsigned transport_proto;
+ err_t ugh = NULL;
+
+ transport_proto = pol->sel.proto;
+
+ if (!(ugh = xfrm_sel_to_ip_pair(&pol->sel, &src, &dst)))
+ {
+ plog("XFRM_MSG_POLEXPIRE message from kernel malformed: %s", ugh);
+ return;
+ }
+
+ replace_bare_shunt(&src, &dst, BOTTOM_PRIO, SPI_PASS, FALSE, transport_proto
+ , "delete expired bare shunt");
+}
+
+static void
+netlink_policy_expire(struct nlmsghdr *n)
+{
+ struct xfrm_user_polexpire *upe;
+ struct {
+ struct nlmsghdr n;
+ struct xfrm_userpolicy_id id;
+ } req;
+
+ struct {
+ struct nlmsghdr n;
+ union {
+ struct nlmsgerr e;
+ struct xfrm_userpolicy_info pol;
+ } u;
+ char data[1024];
+ } rsp;
+
+ if (n->nlmsg_len < NLMSG_LENGTH(sizeof(*upe)))
+ {
+ plog("netlink_policy_expire got message with length %lu < %lu bytes; ignore message"
+ , (unsigned long) n->nlmsg_len
+ , (unsigned long) sizeof(*upe));
+ return;
+ }
+
+ upe = NLMSG_DATA(n);
+ req.id.dir = upe->pol.dir;
+ req.id.index = upe->pol.index;
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.n.nlmsg_type = XFRM_MSG_GETPOLICY;
+ req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.id)));
+
+ rsp.n.nlmsg_type = XFRM_MSG_NEWPOLICY;
+
+ if (!send_netlink_msg(&req.n, &rsp.n, sizeof(rsp), "Get policy", "?"))
+ return;
+
+ if (netlink_error("XFRM_MSG_GETPOLICY", &rsp.n, &rsp.u.e, sizeof(rsp.u.pol)))
+ return;
+
+ if (req.id.index != rsp.u.pol.index)
+ {
+ DBG(DBG_KLIPS,
+ DBG_log("netlink_policy_expire: policy was replaced: "
+ "dir=%d, oldindex=%d, newindex=%d"
+ , req.id.dir, req.id.index, rsp.u.pol.index));
+ return;
+ }
+
+ if (upe->pol.curlft.add_time != rsp.u.pol.curlft.add_time)
+ {
+ DBG(DBG_KLIPS,
+ DBG_log("netlink_policy_expire: policy was replaced "
+ " and you have won the lottery: "
+ "dir=%d, index=%d"
+ , req.id.dir, req.id.index));
+ return;
+ }
+
+ switch (upe->pol.dir)
+ {
+ case XFRM_POLICY_OUT:
+ netlink_shunt_expire(&rsp.u.pol);
+ break;
+ }
+}
+
+static bool
+netlink_get(void)
+{
+ struct {
+ struct nlmsghdr n;
+ char data[1024];
+ } rsp;
+ ssize_t r;
+ struct sockaddr_nl addr;
+ socklen_t alen;
+
+ alen = sizeof(addr);
+ r = recvfrom(netlink_bcast_fd, &rsp, sizeof(rsp), 0
+ , (struct sockaddr *)&addr, &alen);
+ if (r < 0)
+ {
+ if (errno == EAGAIN)
+ return FALSE;
+ if (errno != EINTR)
+ log_errno((e, "recvfrom() failed in netlink_get"));
+ return TRUE;
+ }
+ else if ((size_t) r < sizeof(rsp.n))
+ {
+ plog("netlink_get read truncated message: %ld bytes; ignore message"
+ , (long) r);
+ return TRUE;
+ }
+ else if (addr.nl_pid != 0)
+ {
+ /* not for us: ignore */
+ DBG(DBG_KLIPS,
+ DBG_log("netlink_get: ignoring %s message from process %u"
+ , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type)
+ , addr.nl_pid));
+ return TRUE;
+ }
+ else if ((size_t) r != rsp.n.nlmsg_len)
+ {
+ plog("netlink_get read message with length %ld that doesn't equal nlmsg_len %lu bytes; ignore message"
+ , (long) r
+ , (unsigned long) rsp.n.nlmsg_len);
+ return TRUE;
+ }
+
+ DBG(DBG_KLIPS,
+ DBG_log("netlink_get: %s message"
+ , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type)));
+
+ switch (rsp.n.nlmsg_type)
+ {
+ case XFRM_MSG_ACQUIRE:
+ netlink_acquire(&rsp.n);
+ break;
+ case XFRM_MSG_POLEXPIRE:
+ netlink_policy_expire(&rsp.n);
+ break;
+ default:
+ /* ignored */
+ break;
+ }
+
+ return TRUE;
+}
+
+static void
+netlink_process_msg(void)
+{
+ while (netlink_get())
+ ;
+}
+
+static ipsec_spi_t
+netlink_get_spi(const ip_address *src
+, const ip_address *dst
+, int proto
+, bool tunnel_mode
+, unsigned reqid
+, ipsec_spi_t min
+, ipsec_spi_t max
+, const char *text_said)
+{
+ struct {
+ struct nlmsghdr n;
+ struct xfrm_userspi_info spi;
+ } req;
+
+ struct {
+ struct nlmsghdr n;
+ union {
+ struct nlmsgerr e;
+ struct xfrm_usersa_info sa;
+ } u;
+ char data[1024];
+ } rsp;
+
+ memset(&req, 0, sizeof(req));
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.n.nlmsg_type = XFRM_MSG_ALLOCSPI;
+
+ ip2xfrm(src, &req.spi.info.saddr);
+ ip2xfrm(dst, &req.spi.info.id.daddr);
+ req.spi.info.mode = tunnel_mode;
+ req.spi.info.reqid = reqid;
+ req.spi.info.id.proto = proto;
+ req.spi.info.family = src->u.v4.sin_family;
+ req.spi.min = min;
+ req.spi.max = max;
+
+ req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.spi)));
+ rsp.n.nlmsg_type = XFRM_MSG_NEWSA;
+
+ if (!send_netlink_msg(&req.n, &rsp.n, sizeof(rsp), "Get SPI", text_said))
+ return 0;
+
+ if (netlink_error("XFRM_MSG_ALLOCSPI", &rsp.n, &rsp.u.e, sizeof(rsp.u.sa)))
+ return 0;
+
+ DBG(DBG_KLIPS,
+ DBG_log("netlink_get_spi: allocated 0x%x for %s"
+ , ntohl(rsp.u.sa.id.spi), text_said));
+ return rsp.u.sa.id.spi;
+}
+
+const struct kernel_ops linux_kernel_ops = {
+ type: KERNEL_TYPE_LINUX,
+ inbound_eroute: 1,
+ policy_lifetime: 1,
+ async_fdp: &netlink_bcast_fd,
+
+ init: init_netlink,
+ pfkey_register: linux_pfkey_register,
+ pfkey_register_response: linux_pfkey_register_response,
+ process_msg: netlink_process_msg,
+ raw_eroute: netlink_raw_eroute,
+ get_policy: netlink_get_policy,
+ add_sa: netlink_add_sa,
+ del_sa: netlink_del_sa,
+ get_sa: netlink_get_sa,
+ process_queue: NULL,
+ grp_sa: NULL,
+ get_spi: netlink_get_spi,
+};
+#endif /* linux && KLIPS */
diff --git a/src/pluto/kernel_netlink.h b/src/pluto/kernel_netlink.h
new file mode 100644
index 000000000..1b5f42e48
--- /dev/null
+++ b/src/pluto/kernel_netlink.h
@@ -0,0 +1,20 @@
+/* declarations of routines that interface with the kernel's pfkey mechanism
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ * Copyright (C) 2003 Herbert Xu
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: kernel_netlink.h,v 1.1 2004/03/15 20:35:28 as Exp $
+ */
+
+#if defined(KLIPS) && defined(linux)
+extern const struct kernel_ops linux_kernel_ops;
+#endif
diff --git a/src/pluto/kernel_noklips.c b/src/pluto/kernel_noklips.c
new file mode 100644
index 000000000..570bb0470
--- /dev/null
+++ b/src/pluto/kernel_noklips.c
@@ -0,0 +1,126 @@
+/* interface to fake kernel interface, used for testing pluto in-vitro.
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2002 D. Hugh Redelmeier.
+ * Copyright (C) 2003 Michael Richardson <mcr@freeswan.org>
+ * Copyright (C) 2003 Herbert Xu.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: kernel_noklips.c,v 1.5 2006/02/04 00:01:22 as Exp $
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include <freeswan.h>
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "kernel.h"
+#include "kernel_noklips.h"
+#include "log.h"
+#include "whack.h" /* for RC_LOG_SERIOUS */
+
+void
+init_noklips(void)
+{
+ return;
+}
+
+/* asynchronous messages from our queue */
+static void
+noklips_dequeue(void)
+{
+}
+
+/* asynchronous messages directly from PF_KEY socket */
+static void
+noklips_event(void)
+{
+}
+
+static void
+noklips_register_response(const struct sadb_msg *msg UNUSED)
+{
+}
+
+static void
+noklips_register(void)
+{
+}
+
+static bool
+noklips_raw_eroute(const ip_address *this_host UNUSED
+ , const ip_subnet *this_client UNUSED
+ , const ip_address *that_host UNUSED
+ , const ip_subnet *that_client UNUSED
+ , ipsec_spi_t spi UNUSED
+ , unsigned int satype UNUSED
+ , unsigned int transport_proto UNUSED
+ , const struct pfkey_proto_info *proto_info UNUSED
+ , time_t use_lifetime UNUSED
+ , unsigned int op UNUSED
+ , const char *text_said UNUSED)
+{
+ return TRUE;
+}
+
+static bool
+noklips_add_sa(const struct kernel_sa *sa UNUSED
+ , bool replace UNUSED)
+{
+ return TRUE;
+}
+
+static bool
+noklips_grp_sa(const struct kernel_sa *sa0 UNUSED
+ , const struct kernel_sa *sa1 UNUSED)
+{
+ return TRUE;
+}
+
+static bool
+noklips_del_sa(const struct kernel_sa *sa UNUSED)
+{
+ return TRUE;
+}
+
+
+const struct kernel_ops noklips_kernel_ops = {
+ type: KERNEL_TYPE_NONE,
+ async_fdp: NULL,
+
+ init: init_noklips,
+ pfkey_register: noklips_register,
+ pfkey_register_response: noklips_register_response,
+ process_queue: noklips_dequeue,
+ process_msg: noklips_event,
+ raw_eroute: noklips_raw_eroute,
+ add_sa: noklips_add_sa,
+ grp_sa: noklips_grp_sa,
+ del_sa: noklips_del_sa,
+ get_sa: NULL,
+ get_spi: NULL,
+ inbound_eroute: FALSE,
+ policy_lifetime: FALSE
+};
diff --git a/src/pluto/kernel_noklips.h b/src/pluto/kernel_noklips.h
new file mode 100644
index 000000000..fe4e77ec4
--- /dev/null
+++ b/src/pluto/kernel_noklips.h
@@ -0,0 +1,19 @@
+/* declarations of routines that interface with the kernel's pfkey mechanism
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ * Copyright (C) 2003 Herbert Xu
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: kernel_noklips.h,v 1.1 2004/03/15 20:35:28 as Exp $
+ */
+
+extern void init_noklips(void);
+extern const struct kernel_ops noklips_kernel_ops;
diff --git a/src/pluto/kernel_pfkey.c b/src/pluto/kernel_pfkey.c
new file mode 100644
index 000000000..ced7a1453
--- /dev/null
+++ b/src/pluto/kernel_pfkey.c
@@ -0,0 +1,926 @@
+/* pfkey interface to the kernel's IPsec mechanism
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2002 D. Hugh Redelmeier.
+ * Copyright (C) 2003 Herbert Xu.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: kernel_pfkey.c,v 1.8 2006/02/04 00:01:22 as Exp $
+ */
+
+#ifdef KLIPS
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include <freeswan.h>
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "kernel.h"
+#include "kernel_pfkey.h"
+#include "log.h"
+#include "whack.h" /* for RC_LOG_SERIOUS */
+#include "demux.h"
+#include "nat_traversal.h"
+#include "alg_info.h"
+#include "kernel_alg.h"
+
+
+static int pfkeyfd = NULL_FD;
+
+typedef u_int32_t pfkey_seq_t;
+static pfkey_seq_t pfkey_seq = 0; /* sequence number for our PF_KEY messages */
+
+static pid_t pid;
+
+#define NE(x) { x, #x } /* Name Entry -- shorthand for sparse_names */
+
+static sparse_names pfkey_type_names = {
+ NE(SADB_RESERVED),
+ NE(SADB_GETSPI),
+ NE(SADB_UPDATE),
+ NE(SADB_ADD),
+ NE(SADB_DELETE),
+ NE(SADB_GET),
+ NE(SADB_ACQUIRE),
+ NE(SADB_REGISTER),
+ NE(SADB_EXPIRE),
+ NE(SADB_FLUSH),
+ NE(SADB_DUMP),
+ NE(SADB_X_PROMISC),
+ NE(SADB_X_PCHANGE),
+ NE(SADB_X_GRPSA),
+ NE(SADB_X_ADDFLOW),
+ NE(SADB_X_DELFLOW),
+ NE(SADB_X_DEBUG),
+ NE(SADB_X_NAT_T_NEW_MAPPING),
+ NE(SADB_MAX),
+ { 0, sparse_end }
+};
+
+#ifdef NEVER /* not needed yet */
+static sparse_names pfkey_ext_names = {
+ NE(SADB_EXT_RESERVED),
+ NE(SADB_EXT_SA),
+ NE(SADB_EXT_LIFETIME_CURRENT),
+ NE(SADB_EXT_LIFETIME_HARD),
+ NE(SADB_EXT_LIFETIME_SOFT),
+ NE(SADB_EXT_ADDRESS_SRC),
+ NE(SADB_EXT_ADDRESS_DST),
+ NE(SADB_EXT_ADDRESS_PROXY),
+ NE(SADB_EXT_KEY_AUTH),
+ NE(SADB_EXT_KEY_ENCRYPT),
+ NE(SADB_EXT_IDENTITY_SRC),
+ NE(SADB_EXT_IDENTITY_DST),
+ NE(SADB_EXT_SENSITIVITY),
+ NE(SADB_EXT_PROPOSAL),
+ NE(SADB_EXT_SUPPORTED_AUTH),
+ NE(SADB_EXT_SUPPORTED_ENCRYPT),
+ NE(SADB_EXT_SPIRANGE),
+ NE(SADB_X_EXT_KMPRIVATE),
+ NE(SADB_X_EXT_SATYPE2),
+ NE(SADB_X_EXT_SA2),
+ NE(SADB_X_EXT_ADDRESS_DST2),
+ NE(SADB_X_EXT_ADDRESS_SRC_FLOW),
+ NE(SADB_X_EXT_ADDRESS_DST_FLOW),
+ NE(SADB_X_EXT_ADDRESS_SRC_MASK),
+ NE(SADB_X_EXT_ADDRESS_DST_MASK),
+ NE(SADB_X_EXT_DEBUG),
+ { 0, sparse_end }
+};
+#endif /* NEVER */
+
+#undef NE
+
+void
+init_pfkey(void)
+{
+ pid = getpid();
+
+ /* open PF_KEY socket */
+
+ pfkeyfd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);
+
+ if (pfkeyfd == -1)
+ exit_log_errno((e, "socket() in init_pfkeyfd()"));
+
+#ifdef NEVER /* apparently unsupported! */
+ if (fcntl(pfkeyfd, F_SETFL, O_NONBLOCK) != 0)
+ exit_log_errno((e, "fcntl(O_NONBLOCK) in init_pfkeyfd()"));
+#endif
+ if (fcntl(pfkeyfd, F_SETFD, FD_CLOEXEC) != 0)
+ exit_log_errno((e, "fcntl(FD_CLOEXEC) in init_pfkeyfd()"));
+
+ DBG(DBG_KLIPS,
+ DBG_log("process %u listening for PF_KEY_V2 on file descriptor %d", (unsigned)pid, pfkeyfd));
+}
+
+/* Kinds of PF_KEY message from the kernel:
+ * - response to a request from us
+ * + ACK/NAK
+ * + Register: indicates transforms supported by kernel
+ * + SPI requested by getspi
+ * - Acquire, requesting us to deal with trapped clear packet
+ * - expiration of of one of our SAs
+ * - messages to other processes
+ *
+ * To minimize the effect on the event-driven structure of Pluto,
+ * responses are dealt with synchronously. We hope that the Kernel
+ * produces them synchronously. We must "read ahead" in the PF_KEY
+ * stream, saving Acquire and Expiry messages that are encountered.
+ * We ignore messages to other processes.
+ */
+
+typedef union {
+ unsigned char bytes[PFKEYv2_MAX_MSGSIZE];
+ struct sadb_msg msg;
+ } pfkey_buf;
+
+/* queue of unprocessed PF_KEY messages input from kernel
+ * Note that the pfkey_buf may be partly allocated, reflecting
+ * the variable length nature of the messages. So the link field
+ * must come first.
+ */
+typedef struct pfkey_item {
+ struct pfkey_item *next;
+ pfkey_buf buf;
+ } pfkey_item;
+
+static pfkey_item *pfkey_iq_head = NULL; /* oldest */
+static pfkey_item *pfkey_iq_tail; /* youngest */
+
+static bool
+pfkey_input_ready(void)
+{
+ fd_set readfds;
+ int ndes;
+ struct timeval tm;
+
+ tm.tv_sec = 0; /* don't wait at all */
+ tm.tv_usec = 0;
+
+ FD_ZERO(&readfds); /* we only care about pfkeyfd */
+ FD_SET(pfkeyfd, &readfds);
+
+ do {
+ ndes = select(pfkeyfd + 1, &readfds, NULL, NULL, &tm);
+ } while (ndes == -1 && errno == EINTR);
+
+ if (ndes < 0)
+ {
+ log_errno((e, "select() failed in pfkey_get()"));
+ return FALSE;
+ }
+
+ if (ndes == 0)
+ return FALSE; /* nothing to read */
+
+ passert(ndes == 1 && FD_ISSET(pfkeyfd, &readfds));
+ return TRUE;
+}
+
+/* get a PF_KEY message from kernel.
+ * Returns TRUE is message found, FALSE if no message pending,
+ * and aborts or keeps trying when an error is encountered.
+ * The only validation of the message is that the message length
+ * received matches that in the message header, and that the message
+ * is for this process.
+ */
+static bool
+pfkey_get(pfkey_buf *buf)
+{
+ for (;;)
+ {
+ /* len must be less than PFKEYv2_MAX_MSGSIZE,
+ * so it should fit in an int. We use this fact when printing it.
+ */
+ ssize_t len;
+
+ if (!pfkey_input_ready())
+ return FALSE;
+
+ len = read(pfkeyfd, buf->bytes, sizeof(buf->bytes));
+
+ if (len < 0)
+ {
+ if (errno == EAGAIN)
+ return FALSE;
+
+ log_errno((e, "read() failed in pfkey_get()"));
+ return FALSE;
+ }
+ else if ((size_t) len < sizeof(buf->msg))
+ {
+ plog("pfkey_get read truncated PF_KEY message: %d bytes; ignoring message"
+ , (int) len);
+ }
+ else if ((size_t) len != buf->msg.sadb_msg_len * IPSEC_PFKEYv2_ALIGN)
+ {
+ plog("pfkey_get read PF_KEY message with length %d that doesn't equal sadb_msg_len %u * %u; ignoring message"
+ , (int) len
+ , (unsigned) buf->msg.sadb_msg_len
+ , (unsigned) IPSEC_PFKEYv2_ALIGN);
+ }
+ else if (!(buf->msg.sadb_msg_pid == (unsigned)pid
+ || (buf->msg.sadb_msg_pid == 0 && buf->msg.sadb_msg_type == SADB_ACQUIRE)
+ || (buf->msg.sadb_msg_type == SADB_REGISTER)
+ || (buf->msg.sadb_msg_pid == 0 && buf->msg.sadb_msg_type == SADB_X_NAT_T_NEW_MAPPING)))
+ {
+ /* not for us: ignore */
+ DBG(DBG_KLIPS,
+ DBG_log("pfkey_get: ignoring PF_KEY %s message %u for process %u"
+ , sparse_val_show(pfkey_type_names, buf->msg.sadb_msg_type)
+ , buf->msg.sadb_msg_seq
+ , buf->msg.sadb_msg_pid));
+ }
+ else
+ {
+ DBG(DBG_KLIPS,
+ DBG_log("pfkey_get: %s message %u"
+ , sparse_val_show(pfkey_type_names, buf->msg.sadb_msg_type)
+ , buf->msg.sadb_msg_seq));
+ return TRUE;
+ }
+ }
+}
+
+/* get a response to a specific message */
+static bool
+pfkey_get_response(pfkey_buf *buf, pfkey_seq_t seq)
+{
+ while (pfkey_get(buf))
+ {
+ if (buf->msg.sadb_msg_pid == (unsigned)pid
+ && buf->msg.sadb_msg_seq == seq)
+ {
+ return TRUE;
+ }
+ else
+ {
+ /* Not for us: queue it. */
+ size_t bl = buf->msg.sadb_msg_len * IPSEC_PFKEYv2_ALIGN;
+ pfkey_item *it = alloc_bytes(offsetof(pfkey_item, buf) + bl, "pfkey_item");
+
+ memcpy(&it->buf, buf, bl);
+
+ it->next = NULL;
+ if (pfkey_iq_head == NULL)
+ {
+ pfkey_iq_head = it;
+ }
+ else
+ {
+ pfkey_iq_tail->next = it;
+ }
+ pfkey_iq_tail = it;
+ }
+ }
+ return FALSE;
+}
+
+/* Process a SADB_REGISTER message from the kernel.
+ * This will be a response to one of ours, but it may be asynchronous
+ * (if kernel modules are loaded and unloaded).
+ * Some sanity checking has already been performed.
+ */
+static void
+klips_pfkey_register_response(const struct sadb_msg *msg)
+{
+ /* Find out what the kernel can support.
+ * In fact, the only question at the moment
+ * is whether it can support IPcomp.
+ * So we ignore the rest.
+ * ??? we really should pay attention to what transforms are supported.
+ */
+ switch (msg->sadb_msg_satype)
+ {
+ case SADB_SATYPE_AH:
+ break;
+ case SADB_SATYPE_ESP:
+#ifndef NO_KERNEL_ALG
+ kernel_alg_register_pfkey(msg, sizeof (pfkey_buf));
+#endif
+ break;
+ case SADB_X_SATYPE_COMP:
+ /* ??? There ought to be an extension to list the
+ * supported algorithms, but RFC 2367 doesn't
+ * list one for IPcomp. KLIPS uses SADB_X_CALG_DEFLATE.
+ * Since we only implement deflate, we'll assume this.
+ */
+ can_do_IPcomp = TRUE;
+ break;
+ case SADB_X_SATYPE_IPIP:
+ break;
+ default:
+ break;
+ }
+}
+
+/* Processs a SADB_ACQUIRE message from KLIPS.
+ * Try to build an opportunistic connection!
+ * See RFC 2367 "PF_KEY Key Management API, Version 2" 3.1.6
+ * <base, address(SD), (address(P)), (identity(SD),) (sensitivity,) proposal>
+ * - extensions for source and data IP addresses
+ * - optional extensions for identity [not useful for us?]
+ * - optional extension for sensitivity [not useful for us?]
+ * - expension for proposal [not useful for us?]
+ *
+ * ??? We must use the sequence number in creating an SA.
+ * We actually need to create up to 4 SAs each way. Which one?
+ * I guess it depends on the protocol present in the sadb_msg_satype.
+ * For now, we'll ignore this requirement.
+ *
+ * ??? We need some mechanism to make sure that multiple ACQUIRE messages
+ * don't cause a whole bunch of redundant negotiations.
+ */
+static void
+process_pfkey_acquire(pfkey_buf *buf, struct sadb_ext *extensions[SADB_EXT_MAX + 1])
+{
+ struct sadb_address *srcx = (void *) extensions[SADB_EXT_ADDRESS_SRC];
+ struct sadb_address *dstx = (void *) extensions[SADB_EXT_ADDRESS_DST];
+ int src_proto = srcx->sadb_address_proto;
+ int dst_proto = dstx->sadb_address_proto;
+ ip_address *src = (ip_address*)&srcx[1];
+ ip_address *dst = (ip_address*)&dstx[1];
+ ip_subnet ours, his;
+ err_t ugh = NULL;
+
+ /* assumption: we're only catching our own outgoing packets
+ * so source is our end and destination is the other end.
+ * Verifying this is not actually convenient.
+ *
+ * This stylized control structure yields a complaint or
+ * desired results. For compactness, a pointer value is
+ * treated as a boolean. Logically, the structure is:
+ * keep going as long as things are OK.
+ */
+ if (buf->msg.sadb_msg_pid == 0 /* we only wish to hear from kernel */
+ && !(ugh = src_proto == dst_proto? NULL : "src and dst protocols differ")
+ && !(ugh = addrtypeof(src) == addrtypeof(dst)? NULL : "conflicting address types")
+ && !(ugh = addrtosubnet(src, &ours))
+ && !(ugh = addrtosubnet(dst, &his)))
+ record_and_initiate_opportunistic(&ours, &his, src_proto, "%acquire");
+
+ if (ugh != NULL)
+ plog("SADB_ACQUIRE message from KLIPS malformed: %s", ugh);
+
+}
+
+/* Handle PF_KEY messages from the kernel that are not dealt with
+ * synchronously. In other words, all but responses to PF_KEY messages
+ * that we sent.
+ */
+static void
+pfkey_async(pfkey_buf *buf)
+{
+ struct sadb_ext *extensions[SADB_EXT_MAX + 1];
+
+ if (pfkey_msg_parse(&buf->msg, NULL, extensions, EXT_BITS_OUT))
+ {
+ plog("pfkey_async:"
+ " unparseable PF_KEY message:"
+ " %s len=%d, errno=%d, seq=%d, pid=%d; message ignored"
+ , sparse_val_show(pfkey_type_names, buf->msg.sadb_msg_type)
+ , buf->msg.sadb_msg_len
+ , buf->msg.sadb_msg_errno
+ , buf->msg.sadb_msg_seq
+ , buf->msg.sadb_msg_pid);
+ }
+ else
+ {
+ DBG(DBG_CONTROL | DBG_KLIPS, DBG_log("pfkey_async:"
+ " %s len=%u, errno=%u, satype=%u, seq=%u, pid=%u"
+ , sparse_val_show(pfkey_type_names, buf->msg.sadb_msg_type)
+ , buf->msg.sadb_msg_len
+ , buf->msg.sadb_msg_errno
+ , buf->msg.sadb_msg_satype
+ , buf->msg.sadb_msg_seq
+ , buf->msg.sadb_msg_pid));
+
+ switch (buf->msg.sadb_msg_type)
+ {
+ case SADB_REGISTER:
+ kernel_ops->pfkey_register_response(&buf->msg);
+ break;
+ case SADB_ACQUIRE:
+ /* to simulate loss of ACQUIRE, delete this call */
+ process_pfkey_acquire(buf, extensions);
+ break;
+ case SADB_X_NAT_T_NEW_MAPPING:
+ process_pfkey_nat_t_new_mapping(&(buf->msg), extensions);
+ break;
+ default:
+ /* ignored */
+ break;
+ }
+ }
+}
+
+/* asynchronous messages from our queue */
+static void
+pfkey_dequeue(void)
+{
+ while (pfkey_iq_head != NULL)
+ {
+ pfkey_item *it = pfkey_iq_head;
+
+ pfkey_async(&it->buf);
+ pfkey_iq_head = it->next;
+ pfree(it);
+ }
+
+ /* Handle any orphaned holds, but only if no pfkey input is pending.
+ * For each, we initiate Opportunistic.
+ * note: we don't need to advance the pointer because
+ * record_and_initiate_opportunistic will remove the current
+ * record each time we call it.
+ */
+ while (orphaned_holds != NULL && !pfkey_input_ready())
+ record_and_initiate_opportunistic(&orphaned_holds->ours
+ , &orphaned_holds->his
+ , orphaned_holds->transport_proto
+ , "%hold found-pfkey");
+
+}
+
+/* asynchronous messages directly from PF_KEY socket */
+static void
+pfkey_event(void)
+{
+ pfkey_buf buf;
+
+ if (pfkey_get(&buf))
+ pfkey_async(&buf);
+}
+
+static bool
+pfkey_build(int error
+, const char *description
+, const char *text_said
+, struct sadb_ext *extensions[SADB_EXT_MAX + 1])
+{
+ if (error == 0)
+ {
+ return TRUE;
+ }
+ else
+ {
+ loglog(RC_LOG_SERIOUS, "building of %s %s failed, code %d"
+ , description, text_said, error);
+ pfkey_extensions_free(extensions);
+ return FALSE;
+ }
+}
+
+/* pfkey_extensions_init + pfkey_build + pfkey_msg_hdr_build */
+static bool
+pfkey_msg_start(u_int8_t msg_type
+, u_int8_t satype
+, const char *description
+, const char *text_said
+, struct sadb_ext *extensions[SADB_EXT_MAX + 1])
+{
+ pfkey_extensions_init(extensions);
+ return pfkey_build(pfkey_msg_hdr_build(&extensions[0], msg_type
+ , satype, 0, ++pfkey_seq, pid)
+ , description, text_said, extensions);
+}
+
+/* pfkey_build + pfkey_address_build */
+static bool
+pfkeyext_address(u_int16_t exttype
+, const ip_address *address
+, const char *description
+, const char *text_said
+, struct sadb_ext *extensions[SADB_EXT_MAX + 1])
+{
+ /* the following variable is only needed to silence
+ * a warning caused by the fact that the argument
+ * to sockaddrof is NOT pointer to const!
+ */
+ ip_address t = *address;
+
+ return pfkey_build(pfkey_address_build(extensions + exttype
+ , exttype, 0, 0, sockaddrof(&t))
+ , description, text_said, extensions);
+}
+
+/* pfkey_build + pfkey_x_protocol_build */
+static bool
+pfkeyext_protocol(int transport_proto
+, const char *description
+, const char *text_said
+, struct sadb_ext *extensions[SADB_EXT_MAX + 1])
+{
+ return (transport_proto == 0)? TRUE
+ : pfkey_build(
+ pfkey_x_protocol_build(extensions + SADB_X_EXT_PROTOCOL, transport_proto)
+ , description, text_said, extensions);
+}
+
+
+/* Finish (building, sending, accepting response for) PF_KEY message.
+ * If response isn't NULL, the response from the kernel will be
+ * placed there (and its errno field will not be examined).
+ * Returns TRUE iff all appears well.
+ */
+static bool
+finish_pfkey_msg(struct sadb_ext *extensions[SADB_EXT_MAX + 1]
+, const char *description
+, const char *text_said
+, pfkey_buf *response)
+{
+ struct sadb_msg *pfkey_msg;
+ bool success = TRUE;
+ int error;
+
+ error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_IN);
+
+ if (error != 0)
+ {
+ loglog(RC_LOG_SERIOUS, "pfkey_msg_build of %s %s failed, code %d"
+ , description, text_said, error);
+ success = FALSE;
+ }
+ else
+ {
+ size_t len = pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN;
+
+ DBG(DBG_KLIPS,
+ DBG_log("finish_pfkey_msg: %s message %u for %s %s"
+ , sparse_val_show(pfkey_type_names, pfkey_msg->sadb_msg_type)
+ , pfkey_msg->sadb_msg_seq
+ , description, text_said);
+ DBG_dump(NULL, (void *) pfkey_msg, len));
+
+ if (!no_klips)
+ {
+ ssize_t r = write(pfkeyfd, pfkey_msg, len);
+
+ if (r != (ssize_t)len)
+ {
+ if (r < 0)
+ {
+ log_errno((e
+ , "pfkey write() of %s message %u"
+ " for %s %s failed"
+ , sparse_val_show(pfkey_type_names
+ , pfkey_msg->sadb_msg_type)
+ , pfkey_msg->sadb_msg_seq
+ , description, text_said));
+ }
+ else
+ {
+ loglog(RC_LOG_SERIOUS
+ , "ERROR: pfkey write() of %s message %u"
+ " for %s %s truncated: %ld instead of %ld"
+ , sparse_val_show(pfkey_type_names
+ , pfkey_msg->sadb_msg_type)
+ , pfkey_msg->sadb_msg_seq
+ , description, text_said
+ , (long)r, (long)len);
+ }
+ success = FALSE;
+
+ /* if we were compiled with debugging, but we haven't already
+ * dumped the KLIPS command, do so.
+ */
+#ifdef DEBUG
+ if ((cur_debugging & DBG_KLIPS) == 0)
+ DBG_dump(NULL, (void *) pfkey_msg, len);
+#endif
+ }
+ else
+ {
+ /* Check response from KLIPS.
+ * It ought to be an echo, perhaps with additional info.
+ * If the caller wants it, response will point to space.
+ */
+ pfkey_buf b;
+ pfkey_buf *bp = response != NULL? response : &b;
+
+ if (!pfkey_get_response(bp, ((struct sadb_msg *) extensions[0])->sadb_msg_seq))
+ {
+ loglog(RC_LOG_SERIOUS
+ , "ERROR: no response to our PF_KEY %s message for %s %s"
+ , sparse_val_show(pfkey_type_names, pfkey_msg->sadb_msg_type)
+ , description, text_said);
+ success = FALSE;
+ }
+ else if (pfkey_msg->sadb_msg_type != bp->msg.sadb_msg_type)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "FreeS/WAN ERROR: response to our PF_KEY %s message for %s %s was of wrong type (%s)"
+ , sparse_name(pfkey_type_names, pfkey_msg->sadb_msg_type)
+ , description, text_said
+ , sparse_val_show(pfkey_type_names, bp->msg.sadb_msg_type));
+ success = FALSE;
+ }
+ else if (response == NULL && bp->msg.sadb_msg_errno != 0)
+ {
+ /* KLIPS is signalling a problem */
+ loglog(RC_LOG_SERIOUS
+ , "ERROR: PF_KEY %s response for %s %s included errno %u: %s"
+ , sparse_val_show(pfkey_type_names, pfkey_msg->sadb_msg_type)
+ , description, text_said
+ , (unsigned) bp->msg.sadb_msg_errno
+ , strerror(bp->msg.sadb_msg_errno));
+ success = FALSE;
+ }
+ }
+ }
+ }
+
+ /* all paths must exit this way to free resources */
+ pfkey_extensions_free(extensions);
+ pfkey_msg_free(&pfkey_msg);
+ return success;
+}
+
+/* register SA types that can be negotiated */
+void
+pfkey_register_proto(unsigned satype, const char *satypename)
+{
+ struct sadb_ext *extensions[SADB_EXT_MAX + 1];
+ pfkey_buf pfb;
+
+ if (!(pfkey_msg_start(SADB_REGISTER
+ , satype
+ , satypename, NULL, extensions)
+ && finish_pfkey_msg(extensions, satypename, "", &pfb)))
+ {
+ /* ??? should this be loglog */
+ plog("no KLIPS support for %s", satypename);
+ }
+ else
+ {
+ kernel_ops->pfkey_register_response(&pfb.msg);
+ DBG(DBG_KLIPS,
+ DBG_log("%s registered with kernel.", satypename));
+ }
+}
+
+static void
+klips_pfkey_register(void)
+{
+ pfkey_register_proto(SADB_SATYPE_AH, "AH");
+ pfkey_register_proto(SADB_SATYPE_ESP, "ESP");
+ can_do_IPcomp = FALSE; /* until we get a response from KLIPS */
+ pfkey_register_proto(SADB_X_SATYPE_COMP, "IPCOMP");
+ pfkey_register_proto(SADB_X_SATYPE_IPIP, "IPIP");
+}
+
+static bool
+pfkey_raw_eroute(const ip_address *this_host
+ , const ip_subnet *this_client
+ , const ip_address *that_host
+ , const ip_subnet *that_client
+ , ipsec_spi_t spi
+ , unsigned int satype
+ , unsigned int transport_proto
+ , const struct pfkey_proto_info *proto_info UNUSED
+ , time_t use_lifetime UNUSED
+ , unsigned int op
+ , const char *text_said)
+{
+ struct sadb_ext *extensions[SADB_EXT_MAX + 1];
+ ip_address
+ sflow_ska,
+ dflow_ska,
+ smask_ska,
+ dmask_ska;
+ int sport = ntohs(portof(&this_client->addr));
+ int dport = ntohs(portof(&that_client->addr));
+
+ networkof(this_client, &sflow_ska);
+ maskof(this_client, &smask_ska);
+ setportof(sport ? ~0:0, &smask_ska);
+
+ networkof(that_client, &dflow_ska);
+ maskof(that_client, &dmask_ska);
+ setportof(dport ? ~0:0, &dmask_ska);
+
+ if (!pfkey_msg_start(op & ERO_MASK, satype
+ , "pfkey_msg_hdr flow", text_said, extensions))
+ {
+ return FALSE;
+ }
+
+ if (op != ERO_DELETE)
+ {
+ if (!(pfkey_build(pfkey_sa_build(&extensions[SADB_EXT_SA]
+ , SADB_EXT_SA
+ , spi /* in network order */
+ , 0, 0, 0, 0, op >> ERO_FLAG_SHIFT)
+ , "pfkey_sa add flow", text_said, extensions)
+
+ && pfkeyext_address(SADB_EXT_ADDRESS_SRC, this_host
+ , "pfkey_addr_s add flow", text_said, extensions)
+
+ && pfkeyext_address(SADB_EXT_ADDRESS_DST, that_host
+ , "pfkey_addr_d add flow", text_said
+ , extensions)))
+ {
+ return FALSE;
+ }
+ }
+
+ if (!pfkeyext_address(SADB_X_EXT_ADDRESS_SRC_FLOW, &sflow_ska
+ , "pfkey_addr_sflow", text_said, extensions))
+ {
+ return FALSE;
+ }
+
+ if (!pfkeyext_address(SADB_X_EXT_ADDRESS_DST_FLOW, &dflow_ska
+ , "pfkey_addr_dflow", text_said, extensions))
+ {
+ return FALSE;
+ }
+
+ if (!pfkeyext_address(SADB_X_EXT_ADDRESS_SRC_MASK, &smask_ska
+ , "pfkey_addr_smask", text_said, extensions))
+ {
+ return FALSE;
+ }
+
+ if (!pfkeyext_address(SADB_X_EXT_ADDRESS_DST_MASK, &dmask_ska
+ , "pfkey_addr_dmask", text_said, extensions))
+ {
+ return FALSE;
+ }
+
+ if (!pfkeyext_protocol(transport_proto
+ , "pfkey_x_protocol", text_said, extensions))
+ {
+ return FALSE;
+ }
+
+ return finish_pfkey_msg(extensions, "flow", text_said, NULL);
+}
+
+static bool
+pfkey_add_sa(const struct kernel_sa *sa, bool replace)
+{
+ struct sadb_ext *extensions[SADB_EXT_MAX + 1];
+
+ return pfkey_msg_start(replace ? SADB_UPDATE : SADB_ADD, sa->satype
+ , "pfkey_msg_hdr Add SA", sa->text_said, extensions)
+
+ && pfkey_build(pfkey_sa_build(&extensions[SADB_EXT_SA]
+ , SADB_EXT_SA
+ , sa->spi /* in network order */
+ , sa->replay_window, SADB_SASTATE_MATURE
+ , sa->authalg, sa->encalg ? sa->encalg: sa->compalg, 0)
+ , "pfkey_sa Add SA", sa->text_said, extensions)
+
+ && pfkeyext_address(SADB_EXT_ADDRESS_SRC, sa->src
+ , "pfkey_addr_s Add SA", sa->text_said, extensions)
+
+ && pfkeyext_address(SADB_EXT_ADDRESS_DST, sa->dst
+ , "pfkey_addr_d Add SA", sa->text_said, extensions)
+
+ && (sa->authkeylen == 0
+ || pfkey_build(pfkey_key_build(&extensions[SADB_EXT_KEY_AUTH]
+ , SADB_EXT_KEY_AUTH, sa->authkeylen * BITS_PER_BYTE
+ , sa->authkey)
+ , "pfkey_key_a Add SA", sa->text_said, extensions))
+
+ && (sa->enckeylen == 0
+ || pfkey_build(pfkey_key_build(&extensions[SADB_EXT_KEY_ENCRYPT]
+ , SADB_EXT_KEY_ENCRYPT, sa->enckeylen * BITS_PER_BYTE
+ , sa->enckey)
+ , "pfkey_key_e Add SA", sa->text_said, extensions))
+
+ && (sa->natt_type == 0
+ || pfkey_build(pfkey_x_nat_t_type_build(
+ &extensions[SADB_X_EXT_NAT_T_TYPE], sa->natt_type),
+ "pfkey_nat_t_type Add ESP SA", sa->text_said, extensions))
+ && (sa->natt_sport == 0
+ || pfkey_build(pfkey_x_nat_t_port_build(
+ &extensions[SADB_X_EXT_NAT_T_SPORT], SADB_X_EXT_NAT_T_SPORT,
+ sa->natt_sport), "pfkey_nat_t_sport Add ESP SA", sa->text_said,
+ extensions))
+ && (sa->natt_dport == 0
+ || pfkey_build(pfkey_x_nat_t_port_build(
+ &extensions[SADB_X_EXT_NAT_T_DPORT], SADB_X_EXT_NAT_T_DPORT,
+ sa->natt_dport), "pfkey_nat_t_dport Add ESP SA", sa->text_said,
+ extensions))
+ && (sa->natt_type == 0 || isanyaddr(sa->natt_oa)
+ || pfkeyext_address(SADB_X_EXT_NAT_T_OA, sa->natt_oa
+ , "pfkey_nat_t_oa Add ESP SA", sa->text_said, extensions))
+
+ && finish_pfkey_msg(extensions, "Add SA", sa->text_said, NULL);
+
+}
+
+static bool
+pfkey_grp_sa(const struct kernel_sa *sa0, const struct kernel_sa *sa1)
+{
+ struct sadb_ext *extensions[SADB_EXT_MAX + 1];
+
+ return pfkey_msg_start(SADB_X_GRPSA, sa1->satype
+ , "pfkey_msg_hdr group", sa1->text_said, extensions)
+
+ && pfkey_build(pfkey_sa_build(&extensions[SADB_EXT_SA]
+ , SADB_EXT_SA
+ , sa1->spi /* in network order */
+ , 0, 0, 0, 0, 0)
+ , "pfkey_sa group", sa1->text_said, extensions)
+
+ && pfkeyext_address(SADB_EXT_ADDRESS_DST, sa1->dst
+ , "pfkey_addr_d group", sa1->text_said, extensions)
+
+ && pfkey_build(pfkey_x_satype_build(&extensions[SADB_X_EXT_SATYPE2]
+ , sa0->satype)
+ , "pfkey_satype group", sa0->text_said, extensions)
+
+ && pfkey_build(pfkey_sa_build(&extensions[SADB_X_EXT_SA2]
+ , SADB_X_EXT_SA2
+ , sa0->spi /* in network order */
+ , 0, 0, 0, 0, 0)
+ , "pfkey_sa2 group", sa0->text_said, extensions)
+
+ && pfkeyext_address(SADB_X_EXT_ADDRESS_DST2, sa0->dst
+ , "pfkey_addr_d2 group", sa0->text_said, extensions)
+
+ && finish_pfkey_msg(extensions, "group", sa1->text_said, NULL);
+}
+
+static bool
+pfkey_del_sa(const struct kernel_sa *sa)
+{
+ struct sadb_ext *extensions[SADB_EXT_MAX + 1];
+
+ return pfkey_msg_start(SADB_DELETE, proto2satype(sa->proto)
+ , "pfkey_msg_hdr delete SA", sa->text_said, extensions)
+
+ && pfkey_build(pfkey_sa_build(&extensions[SADB_EXT_SA]
+ , SADB_EXT_SA
+ , sa->spi /* in host order */
+ , 0, SADB_SASTATE_MATURE, 0, 0, 0)
+ , "pfkey_sa delete SA", sa->text_said, extensions)
+
+ && pfkeyext_address(SADB_EXT_ADDRESS_SRC, sa->src
+ , "pfkey_addr_s delete SA", sa->text_said, extensions)
+
+ && pfkeyext_address(SADB_EXT_ADDRESS_DST, sa->dst
+ , "pfkey_addr_d delete SA", sa->text_said, extensions)
+
+ && finish_pfkey_msg(extensions, "Delete SA", sa->text_said, NULL);
+}
+
+void
+pfkey_close(void)
+{
+ while (pfkey_iq_head != NULL)
+ {
+ pfkey_item *it = pfkey_iq_head;
+
+ pfkey_iq_head = it->next;
+ pfree(it);
+ }
+
+ close(pfkeyfd);
+ pfkeyfd = NULL_FD;
+}
+
+const struct kernel_ops klips_kernel_ops = {
+ type: KERNEL_TYPE_KLIPS,
+ async_fdp: &pfkeyfd,
+
+ pfkey_register: klips_pfkey_register,
+ pfkey_register_response: klips_pfkey_register_response,
+ process_queue: pfkey_dequeue,
+ process_msg: pfkey_event,
+ raw_eroute: pfkey_raw_eroute,
+ add_sa: pfkey_add_sa,
+ grp_sa: pfkey_grp_sa,
+ del_sa: pfkey_del_sa,
+ get_sa: NULL,
+ get_spi: NULL,
+ inbound_eroute: FALSE,
+ policy_lifetime: FALSE,
+ init: NULL
+};
+#endif /* KLIPS */
diff --git a/src/pluto/kernel_pfkey.h b/src/pluto/kernel_pfkey.h
new file mode 100644
index 000000000..9dbcdd341
--- /dev/null
+++ b/src/pluto/kernel_pfkey.h
@@ -0,0 +1,23 @@
+/* declarations of routines that interface with the kernel's pfkey mechanism
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ * Copyright (C) 2003 Herbert Xu
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: kernel_pfkey.h,v 1.1 2004/03/15 20:35:28 as Exp $
+ */
+
+#ifdef KLIPS
+extern void init_pfkey(void);
+extern void pfkey_register_proto(unsigned satype, const char *satypename);
+extern void pfkey_close(void);
+extern const struct kernel_ops klips_kernel_ops;
+#endif
diff --git a/src/pluto/keys.c b/src/pluto/keys.c
new file mode 100644
index 000000000..eed81230f
--- /dev/null
+++ b/src/pluto/keys.c
@@ -0,0 +1,1514 @@
+/* mechanisms for preshared keys (public, private, and preshared secrets)
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: keys.c,v 1.24 2006/01/27 08:59:40 as Exp $
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */
+#include <sys/queue.h>
+
+#include <glob.h>
+#ifndef GLOB_ABORTED
+# define GLOB_ABORTED GLOB_ABEND /* fix for old versions */
+#endif
+
+#include <freeswan.h>
+#include <ipsec_policy.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "mp_defs.h"
+#include "id.h"
+#include "x509.h"
+#include "pgp.h"
+#include "certs.h"
+#include "smartcard.h"
+#include "connections.h"
+#include "state.h"
+#include "lex.h"
+#include "keys.h"
+#include "adns.h" /* needs <resolv.h> */
+#include "dnskey.h" /* needs keys.h and adns.h */
+#include "log.h"
+#include "whack.h" /* for RC_LOG_SERIOUS */
+#include "timer.h"
+#include "fetch.h"
+#include "xauth.h"
+
+const char *shared_secrets_file = SHARED_SECRETS_FILE;
+
+typedef struct id_list id_list_t;
+
+struct id_list {
+ struct id id;
+ id_list_t *next;
+};
+
+typedef struct secret secret_t;
+
+struct secret {
+ id_list_t *ids;
+ enum PrivateKeyKind kind;
+ union {
+ chunk_t preshared_secret;
+ RSA_private_key_t RSA_private_key;
+ xauth_t xauth_secret;
+ smartcard_t *smartcard;
+ } u;
+ secret_t *next;
+};
+
+static pubkey_t*
+allocate_RSA_public_key(const cert_t cert)
+{
+ pubkey_t *pk = alloc_thing(pubkey_t, "pubkey");
+ chunk_t e, n;
+
+ switch (cert.type)
+ {
+ case CERT_PGP:
+ e = cert.u.pgp->publicExponent;
+ n = cert.u.pgp->modulus;
+ break;
+ case CERT_X509_SIGNATURE:
+ e = cert.u.x509->publicExponent;
+ n = cert.u.x509->modulus;
+ break;
+ default:
+ plog("RSA public key allocation error");
+ }
+
+ init_RSA_public_key(&pk->u.rsa, e, n);
+ DBG(DBG_RAW,
+ RSA_show_public_key(&pk->u.rsa)
+ )
+
+ pk->alg = PUBKEY_ALG_RSA;
+ pk->id = empty_id;
+ pk->issuer = empty_chunk;
+ pk->serial = empty_chunk;
+
+ return pk;
+}
+
+/*
+ * free a public key struct
+ */
+static void
+free_public_key(pubkey_t *pk)
+{
+ free_id_content(&pk->id);
+ freeanychunk(pk->issuer);
+ freeanychunk(pk->serial);
+
+ /* algorithm-specific freeing */
+ switch (pk->alg)
+ {
+ case PUBKEY_ALG_RSA:
+ free_RSA_public_content(&pk->u.rsa);
+ break;
+ default:
+ bad_case(pk->alg);
+ }
+ pfree(pk);
+}
+
+secret_t *secrets = NULL;
+
+/* find the struct secret associated with the combination of
+ * me and the peer. We match the Id (if none, the IP address).
+ * Failure is indicated by a NULL.
+ */
+static const secret_t *
+get_secret(const struct connection *c, enum PrivateKeyKind kind, bool asym)
+{
+ enum { /* bits */
+ match_default = 01,
+ match_him = 02,
+ match_me = 04
+ };
+
+ unsigned int best_match = 0;
+ secret_t *best = NULL;
+ secret_t *s;
+ const struct id *my_id = &c->spd.this.id
+ , *his_id = &c->spd.that.id;
+ struct id rw_id;
+
+ /* is there a certificate assigned to this connection? */
+ if (kind == PPK_RSA && c->spd.this.cert.type != CERT_NONE)
+ {
+ pubkey_t *my_public_key = allocate_RSA_public_key(c->spd.this.cert);
+
+ for (s = secrets; s != NULL; s = s->next)
+ {
+ if (s->kind == kind &&
+ same_RSA_public_key(&s->u.RSA_private_key.pub, &my_public_key->u.rsa))
+ {
+ best = s;
+ break; /* we have found the private key - no sense in searching further */
+ }
+ }
+ free_public_key(my_public_key);
+ return best;
+ }
+
+ if (his_id_was_instantiated(c))
+ {
+ /* roadwarrior: replace him with 0.0.0.0 */
+ rw_id.kind = c->spd.that.id.kind;
+ rw_id.name = empty_chunk;
+ happy(anyaddr(addrtypeof(&c->spd.that.host_addr), &rw_id.ip_addr));
+ his_id = &rw_id;
+ }
+ else if (kind == PPK_PSK
+ && (c->policy & (POLICY_PSK | POLICY_XAUTH_PSK))
+ && ((c->kind == CK_TEMPLATE && c->spd.that.id.kind == ID_NONE) ||
+ (c->kind == CK_INSTANCE && id_is_ipaddr(&c->spd.that.id))))
+ {
+ /* roadwarrior: replace him with 0.0.0.0 */
+ rw_id.kind = ID_IPV4_ADDR;
+ happy(anyaddr(addrtypeof(&c->spd.that.host_addr), &rw_id.ip_addr));
+ his_id = &rw_id;
+ }
+
+ for (s = secrets; s != NULL; s = s->next)
+ {
+ if (s->kind == kind)
+ {
+ unsigned int match = 0;
+
+ if (s->ids == NULL)
+ {
+ /* a default (signified by lack of ids):
+ * accept if no more specific match found
+ */
+ match = match_default;
+ }
+ else
+ {
+ /* check if both ends match ids */
+ id_list_t *i;
+
+ for (i = s->ids; i != NULL; i = i->next)
+ {
+ if (same_id(my_id, &i->id))
+ match |= match_me;
+
+ if (same_id(his_id, &i->id))
+ match |= match_him;
+ }
+
+ /* If our end matched the only id in the list,
+ * default to matching any peer.
+ * A more specific match will trump this.
+ */
+ if (match == match_me
+ && s->ids->next == NULL)
+ match |= match_default;
+ }
+
+ switch (match)
+ {
+ case match_me:
+ /* if this is an asymmetric (eg. public key) system,
+ * allow this-side-only match to count, even if
+ * there are other ids in the list.
+ */
+ if (!asym)
+ break;
+ /* FALLTHROUGH */
+ case match_default: /* default all */
+ case match_me | match_default: /* default peer */
+ case match_me | match_him: /* explicit */
+ if (match == best_match)
+ {
+ /* two good matches are equally good:
+ * do they agree?
+ */
+ bool same = FALSE;
+
+ switch (kind)
+ {
+ case PPK_PSK:
+ same = s->u.preshared_secret.len == best->u.preshared_secret.len
+ && memcmp(s->u.preshared_secret.ptr, best->u.preshared_secret.ptr, s->u.preshared_secret.len) == 0;
+ break;
+ case PPK_RSA:
+ /* Dirty trick: since we have code to compare
+ * RSA public keys, but not private keys, we
+ * make the assumption that equal public keys
+ * mean equal private keys. This ought to work.
+ */
+ same = same_RSA_public_key(&s->u.RSA_private_key.pub
+ , &best->u.RSA_private_key.pub);
+ break;
+ default:
+ bad_case(kind);
+ }
+ if (!same)
+ {
+ loglog(RC_LOG_SERIOUS, "multiple ipsec.secrets entries with distinct secrets match endpoints:"
+ " first secret used");
+ best = s; /* list is backwards: take latest in list */
+ }
+ }
+ else if (match > best_match)
+ {
+ /* this is the best match so far */
+ best_match = match;
+ best = s;
+ }
+ }
+ }
+ }
+ return best;
+}
+
+/* find the appropriate preshared key (see get_secret).
+ * Failure is indicated by a NULL pointer.
+ * Note: the result is not to be freed by the caller.
+ */
+const chunk_t *
+get_preshared_secret(const struct connection *c)
+{
+ const secret_t *s = get_secret(c, PPK_PSK, FALSE);
+
+ DBG(DBG_PRIVATE,
+ if (s == NULL)
+ DBG_log("no Preshared Key Found");
+ else
+ DBG_dump_chunk("Preshared Key", s->u.preshared_secret);
+ )
+ return s == NULL? NULL : &s->u.preshared_secret;
+}
+
+/* check the existence of an RSA private key matching an RSA public
+ * key contained in an X.509 or OpenPGP certificate
+ */
+bool
+has_private_key(cert_t cert)
+{
+ secret_t *s;
+ bool has_key = FALSE;
+ pubkey_t *pubkey = allocate_RSA_public_key(cert);
+
+ for (s = secrets; s != NULL; s = s->next)
+ {
+ if (s->kind == PPK_RSA &&
+ same_RSA_public_key(&s->u.RSA_private_key.pub, &pubkey->u.rsa))
+ {
+ has_key = TRUE;
+ break;
+ }
+ }
+ free_public_key(pubkey);
+ return has_key;
+}
+
+/*
+ * get the matching RSA private key belonging to a given X.509 certificate
+ */
+const RSA_private_key_t*
+get_x509_private_key(const x509cert_t *cert)
+{
+ secret_t *s;
+ const RSA_private_key_t *pri = NULL;
+ const cert_t c = {CERT_X509_SIGNATURE, {cert}};
+
+ pubkey_t *pubkey = allocate_RSA_public_key(c);
+
+ for (s = secrets; s != NULL; s = s->next)
+ {
+ if (s->kind == PPK_RSA &&
+ same_RSA_public_key(&s->u.RSA_private_key.pub, &pubkey->u.rsa))
+ {
+ pri = &s->u.RSA_private_key;
+ break;
+ }
+ }
+ free_public_key(pubkey);
+ return pri;
+}
+
+/* find the appropriate RSA private key (see get_secret).
+ * Failure is indicated by a NULL pointer.
+ */
+const RSA_private_key_t *
+get_RSA_private_key(const struct connection *c)
+{
+ const secret_t *s = get_secret(c, PPK_RSA, TRUE);
+
+ return s == NULL? NULL : &s->u.RSA_private_key;
+}
+
+/* digest a secrets file
+ *
+ * The file is a sequence of records. A record is a maximal sequence of
+ * tokens such that the first, and only the first, is in the first column
+ * of a line.
+ *
+ * Tokens are generally separated by whitespace and are key words, ids,
+ * strings, or data suitable for ttodata(3). As a nod to convention,
+ * a trailing ":" on what would otherwise be a token is taken as a
+ * separate token. If preceded by whitespace, a "#" is taken as starting
+ * a comment: it and the rest of the line are ignored.
+ *
+ * One kind of record is an include directive. It starts with "include".
+ * The filename is the only other token in the record.
+ * If the filename does not start with /, it is taken to
+ * be relative to the directory containing the current file.
+ *
+ * The other kind of record describes a key. It starts with a
+ * sequence of ids and ends with key information. Each id
+ * is an IP address, a Fully Qualified Domain Name (which will immediately
+ * be resolved), or @FQDN which will be left as a name.
+ *
+ * The key part can be in several forms.
+ *
+ * The old form of the key is still supported: a simple
+ * quoted strings (with no escapes) is taken as a preshred key.
+ *
+ * The new form starts the key part with a ":".
+ *
+ * For Preshared Key, use the "PSK" keyword, and follow it by a string
+ * or a data token suitable for ttodata(3).
+ *
+ * For RSA Private Key, use the "RSA" keyword, followed by a
+ * brace-enclosed list of key field keywords and data values.
+ * The data values are large integers to be decoded by ttodata(3).
+ * The fields are a subset of those used by BIND 8.2 and have the
+ * same names.
+ */
+
+/* parse PSK from file */
+static err_t
+process_psk_secret(chunk_t *psk)
+{
+ err_t ugh = NULL;
+
+ if (*tok == '"' || *tok == '\'')
+ {
+ clonetochunk(*psk, tok+1, flp->cur - tok - 2, "PSK");
+ (void) shift();
+ }
+ else
+ {
+ char buf[BUF_LEN]; /* limit on size of binary representation of key */
+ size_t sz;
+
+ ugh = ttodatav(tok, flp->cur - tok, 0, buf, sizeof(buf), &sz
+ , diag_space, sizeof(diag_space), TTODATAV_SPACECOUNTS);
+ if (ugh != NULL)
+ {
+ /* ttodata didn't like PSK data */
+ ugh = builddiag("PSK data malformed (%s): %s", ugh, tok);
+ }
+ else
+ {
+ clonetochunk(*psk, buf, sz, "PSK");
+ (void) shift();
+ }
+ }
+ return ugh;
+}
+
+/* Parse fields of RSA private key.
+ * A braced list of keyword and value pairs.
+ * At the moment, each field is required, in order.
+ * The fields come from BIND 8.2's representation
+ */
+static err_t
+process_rsa_secret(RSA_private_key_t *rsak)
+{
+ char buf[RSA_MAX_ENCODING_BYTES]; /* limit on size of binary representation of key */
+ const struct fld *p;
+
+ /* save bytes of Modulus and PublicExponent for keyid calculation */
+ unsigned char ebytes[sizeof(buf)];
+ unsigned char *eb_next = ebytes;
+ chunk_t pub_bytes[2];
+ chunk_t *pb_next = &pub_bytes[0];
+
+ for (p = RSA_private_field; p < &RSA_private_field[RSA_PRIVATE_FIELD_ELEMENTS]; p++)
+ {
+ size_t sz;
+ err_t ugh;
+
+ if (!shift())
+ {
+ return "premature end of RSA key";
+ }
+ else if (!tokeqword(p->name))
+ {
+ return builddiag("%s keyword not found where expected in RSA key"
+ , p->name);
+ }
+ else if (!(shift()
+ && (!tokeq(":") || shift()))) /* ignore optional ":" */
+ {
+ return "premature end of RSA key";
+ }
+ else if (NULL != (ugh = ttodatav(tok, flp->cur - tok
+ , 0, buf, sizeof(buf), &sz, diag_space, sizeof(diag_space)
+ , TTODATAV_SPACECOUNTS)))
+ {
+ /* in RSA key, ttodata didn't like */
+ return builddiag("RSA data malformed (%s): %s", ugh, tok);
+ }
+ else
+ {
+ MP_INT *n = (MP_INT *) ((char *)rsak + p->offset);
+
+ n_to_mpz(n, buf, sz);
+ if (pb_next < &pub_bytes[elemsof(pub_bytes)])
+ {
+ if (eb_next - ebytes + sz > sizeof(ebytes))
+ return "public key takes too many bytes";
+
+ setchunk(*pb_next, eb_next, sz);
+ memcpy(eb_next, buf, sz);
+ eb_next += sz;
+ pb_next++;
+ }
+#if 0 /* debugging info that compromises security */
+ {
+ size_t sz = mpz_sizeinbase(n, 16);
+ char buf[RSA_MAX_OCTETS * 2 + 2]; /* ought to be big enough */
+
+ passert(sz <= sizeof(buf));
+ mpz_get_str(buf, 16, n);
+
+ loglog(RC_LOG_SERIOUS, "%s: %s", p->name, buf);
+ }
+#endif
+ }
+ }
+
+ /* We require an (indented) '}' and the end of the record.
+ * We break down the test so that the diagnostic will be
+ * more helpful. Some people don't seem to wish to indent
+ * the brace!
+ */
+ if (!shift() || !tokeq("}"))
+ {
+ return "malformed end of RSA private key -- indented '}' required";
+ }
+ else if (shift())
+ {
+ return "malformed end of RSA private key -- unexpected token after '}'";
+ }
+ else
+ {
+ unsigned bits = mpz_sizeinbase(&rsak->pub.n, 2);
+
+ rsak->pub.k = (bits + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
+ rsak->pub.keyid[0] = '\0'; /* in case of splitkeytoid failure */
+ splitkeytoid(pub_bytes[1].ptr, pub_bytes[1].len
+ , pub_bytes[0].ptr, pub_bytes[0].len
+ , rsak->pub.keyid, sizeof(rsak->pub.keyid));
+ return RSA_private_key_sanity(rsak);
+ }
+}
+
+/* process rsa key file protected with optional passphrase which can either be
+ * read from ipsec.secrets or prompted for by using whack
+ */
+static err_t
+process_rsa_keyfile(RSA_private_key_t *rsak, int whackfd)
+{
+ char filename[BUF_LEN];
+ prompt_pass_t pass;
+
+ memset(filename,'\0', BUF_LEN);
+ memset(pass.secret,'\0', sizeof(pass.secret));
+ pass.prompt = FALSE;
+ pass.fd = whackfd;
+
+ /* we expect the filename of a PKCS#1 private key file */
+
+ if (*tok == '"' || *tok == '\'') /* quoted filename */
+ memcpy(filename, tok+1, flp->cur - tok - 2);
+ else
+ memcpy(filename, tok, flp->cur - tok);
+
+ if (shift())
+ {
+ /* we expect an appended passphrase or passphrase prompt*/
+ if (tokeqword("%prompt"))
+ {
+ if (pass.fd == NULL_FD)
+ return "RSA private key file -- enter passphrase using 'ipsec secrets'";
+ pass.prompt = TRUE;
+ }
+ else
+ {
+ char *passphrase = tok;
+ size_t len = flp->cur - passphrase;
+
+ if (*tok == '"' || *tok == '\'') /* quoted passphrase */
+ {
+ passphrase++;
+ len -= 2;
+ }
+ if (len > PROMPT_PASS_LEN)
+ return "RSA private key file -- passphrase exceeds 64 characters";
+
+ memcpy(pass.secret, passphrase, len);
+ }
+ if (shift())
+ return "RSA private key file -- unexpected token after passphrase";
+ }
+ return load_rsa_private_key(filename, &pass, rsak);
+}
+
+/*
+ * process xauth secret read from ipsec.secrets
+ */
+static err_t
+process_xauth(secret_t *s)
+{
+ chunk_t user_name;
+
+ s->kind = PPK_XAUTH;
+
+ if (!shift())
+ return "missing xauth user name";
+ if (*tok == '"' || *tok == '\'') /* quoted user name */
+ {
+ user_name.ptr = tok + 1;
+ user_name.len = flp->cur - tok - 2;
+ }
+ else
+ {
+ user_name.ptr = tok;
+ user_name.len = flp->cur - tok;
+ }
+ plog(" loaded xauth credentials of user '%.*s'"
+ , user_name.len
+ , user_name.ptr);
+ clonetochunk(s->u.xauth_secret.user_name
+ , user_name.ptr, user_name.len, "xauth user name");
+
+ if (!shift())
+ return "missing xauth user password";
+ return process_psk_secret(&s->u.xauth_secret.user_password);
+}
+
+/* get XAUTH secret from chained secrets lists
+ * only one entry is currently supported
+ */
+static bool
+xauth_get_secret(xauth_t *xauth_secret)
+{
+ secret_t *s;
+ bool found = FALSE;
+
+ for (s = secrets; s != NULL; s = s->next)
+ {
+ if (s->kind == PPK_XAUTH)
+ {
+ if (found)
+ {
+ plog("found multiple xauth secrets - first selected");
+ }
+ else
+ {
+ found = TRUE;
+ *xauth_secret = s->u.xauth_secret;
+ }
+ }
+ }
+ return found;
+}
+
+/*
+ * find a matching secret
+ */
+static bool
+xauth_verify_secret(const xauth_t *xauth_secret)
+{
+ bool found = FALSE;
+ secret_t *s;
+
+ for (s = secrets; s != NULL; s = s->next)
+ {
+ if (s->kind == PPK_XAUTH)
+ {
+ if (!same_chunk(xauth_secret->user_name, s->u.xauth_secret.user_name))
+ continue;
+ found = TRUE;
+ if (same_chunk(xauth_secret->user_password, s->u.xauth_secret.user_password))
+ return TRUE;
+ }
+ }
+ plog("xauth user '%.*s' %s"
+ , xauth_secret->user_name.len, xauth_secret->user_name.ptr
+ , found? "sent wrong password":"not found");
+ return FALSE;
+}
+
+/*
+ * the global xauth_module struct is defined here
+ */
+xauth_module_t xauth_module;
+
+/*
+ * assign the default xauth functions to any null function pointers
+ */
+void
+xauth_defaults(void)
+{
+ if (xauth_module.get_secret == NULL)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("xauth module: using default get_secret() function")
+ )
+ xauth_module.get_secret = xauth_get_secret;
+ }
+ if (xauth_module.verify_secret == NULL)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("xauth module: using default verify_secret() function")
+ )
+ xauth_module.verify_secret = xauth_verify_secret;
+ }
+};
+
+/*
+ * process pin read from ipsec.secrets or prompted for it using whack
+ */
+static err_t
+process_pin(secret_t *s, int whackfd)
+{
+ smartcard_t *sc;
+ const char *pin_status = "no pin";
+
+ s->kind = PPK_PIN;
+
+ /* looking for the smartcard keyword */
+ if (!shift() || strncmp(tok, SCX_TOKEN, strlen(SCX_TOKEN)) != 0)
+ return "PIN keyword must be followed by %smartcard<reader>:<id>";
+
+ sc = scx_add(scx_parse_number_slot_id(tok + strlen(SCX_TOKEN)));
+ s->u.smartcard = sc;
+ scx_share(sc);
+ if (sc->pin.ptr != NULL)
+ {
+ scx_release_context(sc);
+ scx_free_pin(&sc->pin);
+ }
+ sc->valid = FALSE;
+
+ if (!shift())
+ return "PIN statement must be terminated either by <pin code>, %pinpad or %prompt";
+
+ if (tokeqword("%prompt"))
+ {
+ shift();
+ /* if whackfd exists, whack will be used to prompt for a pin */
+ if (whackfd != NULL_FD)
+ pin_status = scx_get_pin(sc, whackfd) ? "valid pin" : "invalid pin";
+ else
+ pin_status = "pin entry via prompt";
+ }
+ else if (tokeqword("%pinpad"))
+ {
+ shift();
+ /* pin will be entered via pin pad during verification */
+ clonetochunk(sc->pin, "", 0, "empty pin");
+ sc->pinpad = TRUE;
+ sc->valid = TRUE;
+ pin_status = "pin entry via pad";
+ if (pkcs11_keep_state)
+ scx_verify_pin(sc);
+ }
+ else
+ {
+ /* we read the pin directly from ipsec.secrets */
+ err_t ugh = process_psk_secret(&sc->pin);
+ if (ugh != NULL)
+ return ugh;
+ /* verify the pin */
+ pin_status = scx_verify_pin(sc) ? "valid PIN" : "invalid PIN";
+ }
+#ifdef SMARTCARD
+ {
+ char buf[BUF_LEN];
+
+ if (sc->any_slot)
+ snprintf(buf, BUF_LEN, "any slot");
+ else
+ snprintf(buf, BUF_LEN, "slot: %lu", sc->slot);
+
+ plog(" %s for #%d (%s, id: %s)"
+ , pin_status, sc->number, scx_print_slot(sc, ""), sc->id);
+ }
+#else
+ plog(" warning: SMARTCARD support is deactivated in pluto/Makefile!");
+#endif
+ return NULL;
+}
+
+static void
+process_secret(secret_t *s, int whackfd)
+{
+ err_t ugh = NULL;
+
+ s->kind = PPK_PSK; /* default */
+ if (*tok == '"' || *tok == '\'')
+ {
+ /* old PSK format: just a string */
+ ugh = process_psk_secret(&s->u.preshared_secret);
+ }
+ else if (tokeqword("psk"))
+ {
+ /* preshared key: quoted string or ttodata format */
+ ugh = !shift()? "unexpected end of record in PSK"
+ : process_psk_secret(&s->u.preshared_secret);
+ }
+ else if (tokeqword("rsa"))
+ {
+ /* RSA key: the fun begins.
+ * A braced list of keyword and value pairs.
+ */
+ s->kind = PPK_RSA;
+ if (!shift())
+ {
+ ugh = "bad RSA key syntax";
+ }
+ else if (tokeq("{"))
+ {
+ ugh = process_rsa_secret(&s->u.RSA_private_key);
+ }
+ else
+ {
+ ugh = process_rsa_keyfile(&s->u.RSA_private_key, whackfd);
+ }
+ }
+ else if (tokeqword("xauth"))
+ {
+ ugh = process_xauth(s);
+ }
+ else if (tokeqword("pin"))
+ {
+ ugh = process_pin(s, whackfd);
+ }
+ else
+ {
+ ugh = builddiag("unrecognized key format: %s", tok);
+ }
+
+ if (ugh != NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "\"%s\" line %d: %s"
+ , flp->filename, flp->lino, ugh);
+ pfree(s);
+ }
+ else if (flushline("expected record boundary in key"))
+ {
+ /* gauntlet has been run: install new secret */
+ lock_certs_and_keys("process_secret");
+ s->next = secrets;
+ secrets = s;
+ unlock_certs_and_keys("process_secrets");
+ }
+}
+
+static void process_secrets_file(const char *file_pat, int whackfd); /* forward declaration */
+
+static void
+process_secret_records(int whackfd)
+{
+ /* read records from ipsec.secrets and load them into our table */
+ for (;;)
+ {
+ (void)flushline(NULL); /* silently ditch leftovers, if any */
+ if (flp->bdry == B_file)
+ break;
+
+ flp->bdry = B_none; /* eat the Record Boundary */
+ (void)shift(); /* get real first token */
+
+ if (tokeqword("include"))
+ {
+ /* an include directive */
+ char fn[MAX_TOK_LEN]; /* space for filename (I hope) */
+ char *p = fn;
+ char *end_prefix = strrchr(flp->filename, '/');
+
+ if (!shift())
+ {
+ loglog(RC_LOG_SERIOUS, "\"%s\" line %d: unexpected end of include directive"
+ , flp->filename, flp->lino);
+ continue; /* abandon this record */
+ }
+
+ /* if path is relative and including file's pathname has
+ * a non-empty dirname, prefix this path with that dirname.
+ */
+ if (tok[0] != '/' && end_prefix != NULL)
+ {
+ size_t pl = end_prefix - flp->filename + 1;
+
+ /* "clamp" length to prevent problems now;
+ * will be rediscovered and reported later.
+ */
+ if (pl > sizeof(fn))
+ pl = sizeof(fn);
+ memcpy(fn, flp->filename, pl);
+ p += pl;
+ }
+ if (flp->cur - tok >= &fn[sizeof(fn)] - p)
+ {
+ loglog(RC_LOG_SERIOUS, "\"%s\" line %d: include pathname too long"
+ , flp->filename, flp->lino);
+ continue; /* abandon this record */
+ }
+ strcpy(p, tok);
+ (void) shift(); /* move to Record Boundary, we hope */
+ if (flushline("ignoring malformed INCLUDE -- expected Record Boundary after filename"))
+ {
+ process_secrets_file(fn, whackfd);
+ tok = NULL; /* correct, but probably redundant */
+ }
+ }
+ else
+ {
+ /* expecting a list of indices and then the key info */
+ secret_t *s = alloc_thing(secret_t, "secret");
+
+ s->ids = NULL;
+ s->kind = PPK_PSK; /* default */
+ setchunk(s->u.preshared_secret, NULL, 0);
+ s->next = NULL;
+
+ for (;;)
+ {
+ if (tok[0] == '"' || tok[0] == '\'')
+ {
+ /* found key part */
+ process_secret(s, whackfd);
+ break;
+ }
+ else if (tokeq(":"))
+ {
+ /* found key part */
+ shift(); /* discard explicit separator */
+ process_secret(s, whackfd);
+ break;
+ }
+ else
+ {
+ /* an id
+ * See RFC2407 IPsec Domain of Interpretation 4.6.2
+ */
+ struct id id;
+ err_t ugh;
+
+ if (tokeq("%any"))
+ {
+ id = empty_id;
+ id.kind = ID_IPV4_ADDR;
+ ugh = anyaddr(AF_INET, &id.ip_addr);
+ }
+ else if (tokeq("%any6"))
+ {
+ id = empty_id;
+ id.kind = ID_IPV6_ADDR;
+ ugh = anyaddr(AF_INET6, &id.ip_addr);
+ }
+ else
+ {
+ ugh = atoid(tok, &id, FALSE);
+ }
+
+ if (ugh != NULL)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "ERROR \"%s\" line %d: index \"%s\" %s"
+ , flp->filename, flp->lino, tok, ugh);
+ }
+ else
+ {
+ id_list_t *i = alloc_thing(id_list_t
+ , "id_list");
+
+ i->id = id;
+ unshare_id_content(&i->id);
+ i->next = s->ids;
+ s->ids = i;
+ /* DBG_log("id type %d: %s %.*s", i->kind, ip_str(&i->ip_addr), (int)i->name.len, i->name.ptr); */
+ }
+ if (!shift())
+ {
+ /* unexpected Record Boundary or EOF */
+ loglog(RC_LOG_SERIOUS, "\"%s\" line %d: unexpected end of id list"
+ , flp->filename, flp->lino);
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+static int
+globugh(const char *epath, int eerrno)
+{
+ log_errno_routine(eerrno, "problem with secrets file \"%s\"", epath);
+ return 1; /* stop glob */
+}
+
+static void
+process_secrets_file(const char *file_pat, int whackfd)
+{
+ struct file_lex_position pos;
+ char **fnp;
+ glob_t globbuf;
+
+ pos.depth = flp == NULL? 0 : flp->depth + 1;
+
+ if (pos.depth > 10)
+ {
+ loglog(RC_LOG_SERIOUS, "preshared secrets file \"%s\" nested too deeply", file_pat);
+ return;
+ }
+
+ /* do globbing */
+ {
+ int r = glob(file_pat, GLOB_ERR, globugh, &globbuf);
+
+ if (r != 0)
+ {
+ switch (r)
+ {
+ case GLOB_NOSPACE:
+ loglog(RC_LOG_SERIOUS, "out of space processing secrets filename \"%s\"", file_pat);
+ break;
+ case GLOB_ABORTED:
+ break; /* already logged */
+ case GLOB_NOMATCH:
+ loglog(RC_LOG_SERIOUS, "no secrets filename matched \"%s\"", file_pat);
+ break;
+ default:
+ loglog(RC_LOG_SERIOUS, "unknown glob error %d", r);
+ break;
+ }
+ globfree(&globbuf);
+ return;
+ }
+ }
+
+ /* for each file... */
+ for (fnp = globbuf.gl_pathv; *fnp != NULL; fnp++)
+ {
+ if (lexopen(&pos, *fnp, FALSE))
+ {
+ plog("loading secrets from \"%s\"", *fnp);
+ (void) flushline("file starts with indentation (continuation notation)");
+ process_secret_records(whackfd);
+ lexclose();
+ }
+ }
+
+ globfree(&globbuf);
+}
+
+void
+free_preshared_secrets(void)
+{
+ lock_certs_and_keys("free_preshared_secrets");
+
+ if (secrets != NULL)
+ {
+ secret_t *s, *ns;
+
+ plog("forgetting secrets");
+
+ for (s = secrets; s != NULL; s = ns)
+ {
+ id_list_t *i, *ni;
+
+ ns = s->next; /* grab before freeing s */
+ for (i = s->ids; i != NULL; i = ni)
+ {
+ ni = i->next; /* grab before freeing i */
+ free_id_content(&i->id);
+ pfree(i);
+ }
+ switch (s->kind)
+ {
+ case PPK_PSK:
+ pfree(s->u.preshared_secret.ptr);
+ break;
+ case PPK_RSA:
+ free_RSA_private_content(&s->u.RSA_private_key);
+ break;
+ case PPK_XAUTH:
+ pfree(s->u.xauth_secret.user_name.ptr);
+ pfree(s->u.xauth_secret.user_password.ptr);
+ break;
+ case PPK_PIN:
+ scx_release(s->u.smartcard);
+ break;
+ default:
+ bad_case(s->kind);
+ }
+ pfree(s);
+ }
+ secrets = NULL;
+ }
+
+ unlock_certs_and_keys("free_preshard_secrets");
+}
+
+void
+load_preshared_secrets(int whackfd)
+{
+ free_preshared_secrets();
+ (void) process_secrets_file(shared_secrets_file, whackfd);
+}
+
+/* public key machinery
+ * Note: caller must set dns_auth_level.
+ */
+
+pubkey_t *
+public_key_from_rsa(const RSA_public_key_t *k)
+{
+ pubkey_t *p = alloc_thing(pubkey_t, "pubkey");
+
+ p->id = empty_id; /* don't know, doesn't matter */
+ p->issuer = empty_chunk;
+ p->serial = empty_chunk;
+ p->alg = PUBKEY_ALG_RSA;
+
+ memcpy(p->u.rsa.keyid, k->keyid, sizeof(p->u.rsa.keyid));
+ p->u.rsa.k = k->k;
+ mpz_init_set(&p->u.rsa.e, &k->e);
+ mpz_init_set(&p->u.rsa.n, &k->n);
+
+ /* note that we return a 1 reference count upon creation:
+ * invariant: recount > 0.
+ */
+ p->refcnt = 1;
+ time(&p->installed_time);
+ return p;
+}
+
+/* Free a public key record.
+ * As a convenience, this returns a pointer to next.
+ */
+pubkey_list_t *
+free_public_keyentry(pubkey_list_t *p)
+{
+ pubkey_list_t *nxt = p->next;
+
+ if (p->key != NULL)
+ unreference_key(&p->key);
+ pfree(p);
+ return nxt;
+}
+
+void
+free_public_keys(pubkey_list_t **keys)
+{
+ while (*keys != NULL)
+ *keys = free_public_keyentry(*keys);
+}
+
+/* root of chained public key list */
+
+pubkey_list_t *pubkeys = NULL; /* keys from ipsec.conf */
+
+void
+free_remembered_public_keys(void)
+{
+ free_public_keys(&pubkeys);
+}
+
+/* transfer public keys from *keys list to front of pubkeys list */
+void
+transfer_to_public_keys(struct gw_info *gateways_from_dns
+#ifdef USE_KEYRR
+, pubkey_list_t **keys
+#endif /* USE_KEYRR */
+)
+{
+ {
+ struct gw_info *gwp;
+
+ for (gwp = gateways_from_dns; gwp != NULL; gwp = gwp->next)
+ {
+ pubkey_list_t *pl = alloc_thing(pubkey_list_t, "from TXT");
+
+ pl->key = gwp->key; /* note: this is a transfer */
+ gwp->key = NULL; /* really, it is! */
+ pl->next = pubkeys;
+ pubkeys = pl;
+ }
+ }
+
+#ifdef USE_KEYRR
+ {
+ pubkey_list_t **pp = keys;
+
+ while (*pp != NULL)
+ pp = &(*pp)->next;
+ *pp = pubkeys;
+ pubkeys = *keys;
+ *keys = NULL;
+ }
+#endif /* USE_KEYRR */
+}
+
+/* decode of RSA pubkey chunk
+ * - format specified in RFC 2537 RSA/MD5 Keys and SIGs in the DNS
+ * - exponent length in bytes (1 or 3 octets)
+ * + 1 byte if in [1, 255]
+ * + otherwise 0x00 followed by 2 bytes of length
+ * - exponent
+ * - modulus
+ */
+err_t
+unpack_RSA_public_key(RSA_public_key_t *rsa, const chunk_t *pubkey)
+{
+ chunk_t exp;
+ chunk_t mod;
+
+ if (pubkey->len < 3)
+ return "RSA public key blob way to short"; /* not even room for length! */
+
+ if (pubkey->ptr[0] != 0x00)
+ {
+ setchunk(exp, pubkey->ptr + 1, pubkey->ptr[0]);
+ }
+ else
+ {
+ setchunk(exp, pubkey->ptr + 3
+ , (pubkey->ptr[1] << BITS_PER_BYTE) + pubkey->ptr[2]);
+ }
+
+ if (pubkey->len - (exp.ptr - pubkey->ptr) < exp.len + RSA_MIN_OCTETS_RFC)
+ return "RSA public key blob too short";
+
+ mod.ptr = exp.ptr + exp.len;
+ mod.len = &pubkey->ptr[pubkey->len] - mod.ptr;
+
+ if (mod.len < RSA_MIN_OCTETS)
+ return RSA_MIN_OCTETS_UGH;
+
+ if (mod.len > RSA_MAX_OCTETS)
+ return RSA_MAX_OCTETS_UGH;
+
+ init_RSA_public_key(rsa, exp, mod);
+ rsa->k = mpz_sizeinbase(&rsa->n, 2); /* size in bits, for a start */
+ rsa->k = (rsa->k + BITS_PER_BYTE - 1) / BITS_PER_BYTE; /* now octets */
+ DBG(DBG_RAW,
+ RSA_show_public_key(rsa)
+ )
+
+ if (rsa->k != mod.len)
+ {
+ mpz_clear(&rsa->e);
+ mpz_clear(&rsa->n);
+ return "RSA modulus shorter than specified";
+ }
+
+ return NULL;
+}
+
+static void
+install_public_key(pubkey_t *pk, pubkey_list_t **head)
+{
+ pubkey_list_t *p = alloc_thing(pubkey_list_t, "pubkey entry");
+
+ unshare_id_content(&pk->id);
+
+ /* copy issuer dn */
+ if (pk->issuer.ptr != NULL)
+ pk->issuer.ptr = clone_bytes(pk->issuer.ptr, pk->issuer.len, "issuer dn");
+
+ /* copy serial number */
+ if (pk->serial.ptr != NULL)
+ pk->serial.ptr = clone_bytes(pk->serial.ptr, pk->serial.len, "serialNumber");
+
+ /* store the time the public key was installed */
+ time(&pk->installed_time);
+
+ /* install new key at front */
+ p->key = reference_key(pk);
+ p->next = *head;
+ *head = p;
+}
+
+
+void
+delete_public_keys(const struct id *id, enum pubkey_alg alg
+, chunk_t issuer, chunk_t serial)
+{
+ pubkey_list_t **pp, *p;
+ pubkey_t *pk;
+
+ for (pp = &pubkeys; (p = *pp) != NULL; )
+ {
+ pk = p->key;
+
+ if (same_id(id, &pk->id) && pk->alg == alg
+ && (issuer.ptr == NULL || pk->issuer.ptr == NULL
+ || same_dn(issuer, pk->issuer))
+ && same_serial(serial, pk->serial))
+ *pp = free_public_keyentry(p);
+ else
+ pp = &p->next;
+ }
+}
+
+pubkey_t *
+reference_key(pubkey_t *pk)
+{
+ pk->refcnt++;
+ return pk;
+}
+
+void
+unreference_key(pubkey_t **pkp)
+{
+ pubkey_t *pk = *pkp;
+ char b[BUF_LEN];
+
+ if (pk == NULL)
+ return;
+
+ /* print stuff */
+ DBG(DBG_CONTROLMORE,
+ idtoa(&pk->id, b, sizeof(b));
+ DBG_log("unreference key: %p %s cnt %d--", pk, b, pk->refcnt)
+ )
+
+ /* cancel out the pointer */
+ *pkp = NULL;
+
+ passert(pk->refcnt != 0);
+ pk->refcnt--;
+ if (pk->refcnt == 0)
+ free_public_key(pk);
+}
+
+err_t
+add_public_key(const struct id *id
+, enum dns_auth_level dns_auth_level
+, enum pubkey_alg alg
+, const chunk_t *key
+, pubkey_list_t **head)
+{
+ pubkey_t *pk = alloc_thing(pubkey_t, "pubkey");
+
+ /* first: algorithm-specific decoding of key chunk */
+ switch (alg)
+ {
+ case PUBKEY_ALG_RSA:
+ {
+ err_t ugh = unpack_RSA_public_key(&pk->u.rsa, key);
+
+ if (ugh != NULL)
+ {
+ pfree(pk);
+ return ugh;
+ }
+ }
+ break;
+ default:
+ bad_case(alg);
+ }
+
+ pk->id = *id;
+ pk->dns_auth_level = dns_auth_level;
+ pk->alg = alg;
+ pk->until_time = UNDEFINED_TIME;
+ pk->issuer = empty_chunk;
+ pk->serial = empty_chunk;
+
+ install_public_key(pk, head);
+ return NULL;
+}
+
+/* extract id and public key from x.509 certificate and
+ * insert it into a pubkeyrec
+ */
+void
+add_x509_public_key(x509cert_t *cert , time_t until
+ , enum dns_auth_level dns_auth_level)
+{
+ generalName_t *gn;
+ pubkey_t *pk;
+ cert_t c = { CERT_X509_SIGNATURE, {cert} };
+
+ /* we support RSA only */
+ if (cert->subjectPublicKeyAlgorithm != PUBKEY_ALG_RSA)
+ return;
+
+ /* ID type: ID_DER_ASN1_DN (X.509 subject field) */
+ pk = allocate_RSA_public_key(c);
+ pk->id.kind = ID_DER_ASN1_DN;
+ pk->id.name = cert->subject;
+ pk->dns_auth_level = dns_auth_level;
+ pk->until_time = until;
+ pk->issuer = cert->issuer;
+ pk->serial = cert->serialNumber;
+ delete_public_keys(&pk->id, pk->alg, pk->issuer, pk->serial);
+ install_public_key(pk, &pubkeys);
+
+ gn = cert->subjectAltName;
+
+ while (gn != NULL) /* insert all subjectAltNames */
+ {
+ struct id id = empty_id;
+
+ gntoid(&id, gn);
+ if (id.kind != ID_NONE)
+ {
+ pk = allocate_RSA_public_key(c);
+ pk->id = id;
+ pk->dns_auth_level = dns_auth_level;
+ pk->until_time = until;
+ pk->issuer = cert->issuer;
+ pk->serial = cert->serialNumber;
+ delete_public_keys(&pk->id, pk->alg, pk->issuer, pk->serial);
+ install_public_key(pk, &pubkeys);
+ }
+ gn = gn->next;
+ }
+}
+
+/* extract id and public key from OpenPGP certificate and
+ * insert it into a pubkeyrec
+ */
+void
+add_pgp_public_key(pgpcert_t *cert , time_t until
+ , enum dns_auth_level dns_auth_level)
+{
+ pubkey_t *pk;
+ cert_t c;
+
+ c.type = CERT_PGP;
+ c.u.pgp = cert;
+
+ /* we support RSA only */
+ if (cert->pubkeyAlg != PUBKEY_ALG_RSA)
+ {
+ plog(" RSA public keys supported only");
+ return;
+ }
+
+ pk = allocate_RSA_public_key(c);
+ pk->id.kind = ID_KEY_ID;
+ pk->id.name.ptr = cert->fingerprint;
+ pk->id.name.len = PGP_FINGERPRINT_SIZE;
+ pk->dns_auth_level = dns_auth_level;
+ pk->until_time = until;
+ delete_public_keys(&pk->id, pk->alg, empty_chunk, empty_chunk);
+ install_public_key(pk, &pubkeys);
+}
+
+/* when a X.509 certificate gets revoked, all instances of
+ * the corresponding public key must be removed
+ */
+void
+remove_x509_public_key(const x509cert_t *cert)
+{
+ const cert_t c = {CERT_X509_SIGNATURE, {cert}};
+ pubkey_list_t *p, **pp;
+ pubkey_t *revoked_pk;
+
+ revoked_pk = allocate_RSA_public_key(c);
+ p = pubkeys;
+ pp = &pubkeys;
+
+ while(p != NULL)
+ {
+ if (same_RSA_public_key(&p->key->u.rsa, &revoked_pk->u.rsa))
+ {
+ /* remove p from list and free memory */
+ *pp = free_public_keyentry(p);
+ loglog(RC_LOG_SERIOUS,
+ "invalid RSA public key deleted");
+ }
+ else
+ {
+ pp = &p->next;
+ }
+ p =*pp;
+ }
+ free_public_key(revoked_pk);
+}
+
+/*
+ * list all public keys in the chained list
+ */
+void list_public_keys(bool utc)
+{
+ pubkey_list_t *p = pubkeys;
+
+ if (p != NULL)
+ {
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of Public Keys:");
+ whack_log(RC_COMMENT, " ");
+ }
+
+ while (p != NULL)
+ {
+ pubkey_t *key = p->key;
+
+ if (key->alg == PUBKEY_ALG_RSA)
+ {
+ char buf[BUF_LEN];
+ char expires_buf[TIMETOA_BUF];
+
+ idtoa(&key->id, buf, BUF_LEN);
+ strcpy(expires_buf, timetoa(&key->until_time, utc));
+ whack_log(RC_COMMENT, "%s, %4d RSA Key %s, until %s %s",
+
+ timetoa(&key->installed_time, utc), 8*key->u.rsa.k, key->u.rsa.keyid,
+ expires_buf,
+ check_expiry(key->until_time, PUBKEY_WARNING_INTERVAL, TRUE));
+ whack_log(RC_COMMENT," %s '%s'",
+ enum_show(&ident_names, key->id.kind), buf);
+ if (key->issuer.len > 0)
+ {
+ dntoa(buf, BUF_LEN, key->issuer);
+ whack_log(RC_COMMENT," issuer: '%s'", buf);
+ }
+ if (key->serial.len > 0)
+ {
+ datatot(key->serial.ptr, key->serial.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT," serial: %s", buf);
+ }
+ }
+ p = p->next;
+ }
+}
diff --git a/src/pluto/keys.h b/src/pluto/keys.h
new file mode 100644
index 000000000..415bdc3c1
--- /dev/null
+++ b/src/pluto/keys.h
@@ -0,0 +1,113 @@
+/* mechanisms for preshared keys (public, private, and preshared secrets)
+ * Copyright (C) 1998-2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: keys.h,v 1.7 2006/01/26 20:10:34 as Exp $
+ */
+
+#ifndef _KEYS_H
+#define _KEYS_H
+
+#include <gmp.h> /* GNU Multi-Precision library */
+
+#include "pkcs1.h"
+#include "certs.h"
+
+#ifndef SHARED_SECRETS_FILE
+# define SHARED_SECRETS_FILE IPSEC_CONFDIR "/ipsec.secrets"
+#endif
+
+const char *shared_secrets_file;
+
+extern void load_preshared_secrets(int whackfd);
+extern void free_preshared_secrets(void);
+
+enum PrivateKeyKind {
+ PPK_PSK,
+ /* PPK_DSS, */ /* not implemented */
+ PPK_RSA,
+ PPK_XAUTH,
+ PPK_PIN
+};
+
+extern void xauth_defaults(void);
+
+/* forward declaration */
+struct connection;
+
+extern const chunk_t *get_preshared_secret(const struct connection *c);
+extern err_t unpack_RSA_public_key(RSA_public_key_t *rsa, const chunk_t *pubkey);
+extern const RSA_private_key_t *get_RSA_private_key(const struct connection *c);
+extern const RSA_private_key_t *get_x509_private_key(const x509cert_t *cert);
+
+/* public key machinery */
+
+typedef struct pubkey pubkey_t;
+
+struct pubkey {
+ struct id id;
+ unsigned refcnt; /* reference counted! */
+ enum dns_auth_level dns_auth_level;
+ char *dns_sig;
+ time_t installed_time
+ , last_tried_time
+ , last_worked_time
+ , until_time;
+ chunk_t issuer;
+ chunk_t serial;
+ enum pubkey_alg alg;
+ union {
+ RSA_public_key_t rsa;
+ } u;
+};
+
+typedef struct pubkey_list pubkey_list_t;
+
+struct pubkey_list {
+ pubkey_t *key;
+ pubkey_list_t *next;
+};
+
+extern pubkey_list_t *pubkeys; /* keys from ipsec.conf or from certs */
+
+extern pubkey_t *public_key_from_rsa(const RSA_public_key_t *k);
+extern pubkey_list_t *free_public_keyentry(pubkey_list_t *p);
+extern void free_public_keys(pubkey_list_t **keys);
+extern void free_remembered_public_keys(void);
+extern void delete_public_keys(const struct id *id, enum pubkey_alg alg
+ , chunk_t issuer, chunk_t serial);
+
+extern pubkey_t *reference_key(pubkey_t *pk);
+extern void unreference_key(pubkey_t **pkp);
+
+extern err_t add_public_key(const struct id *id
+ , enum dns_auth_level dns_auth_level
+ , enum pubkey_alg alg
+ , const chunk_t *key
+ , pubkey_list_t **head);
+
+extern bool has_private_key(cert_t cert);
+extern void add_x509_public_key(x509cert_t *cert, time_t until
+ , enum dns_auth_level dns_auth_level);
+extern void add_pgp_public_key(pgpcert_t *cert, time_t until
+ , enum dns_auth_level dns_auth_level);
+extern void remove_x509_public_key(const x509cert_t *cert);
+extern void list_public_keys(bool utc);
+
+struct gw_info; /* forward declaration of tag (defined in dnskey.h) */
+extern void transfer_to_public_keys(struct gw_info *gateways_from_dns
+#ifdef USE_KEYRR
+ , pubkey_list_t **keys
+#endif /* USE_KEYRR */
+ );
+
+#endif /* _KEYS_H */
diff --git a/src/pluto/lex.c b/src/pluto/lex.c
new file mode 100644
index 000000000..5c811725a
--- /dev/null
+++ b/src/pluto/lex.c
@@ -0,0 +1,213 @@
+/* lexer (lexical analyzer) for control files
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: lex.c,v 1.1 2004/03/15 20:35:28 as Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "whack.h" /* for RC_LOG_SERIOUS */
+#include "lex.h"
+
+struct file_lex_position *flp = NULL;
+
+/* Open a file for lexical processing.
+ * new_flp and name must point into storage with will live
+ * at least until the file is closed.
+ */
+bool
+lexopen(struct file_lex_position *new_flp, const char *name, bool optional)
+{
+ FILE *f = fopen(name, "r");
+
+ if (f == NULL)
+ {
+ if (!optional || errno != ENOENT)
+ log_errno((e, "could not open \"%s\"", name));
+ return FALSE;
+ }
+ else
+ {
+ new_flp->previous = flp;
+ flp = new_flp;
+ flp->filename = name;
+ flp->fp = f;
+ flp->lino = 0;
+ flp->bdry = B_none;
+
+ flp->cur = flp->buffer; /* nothing loaded yet */
+ flp->under = *flp->cur = '\0';
+
+ (void) shift(); /* prime tok */
+ return TRUE;
+ }
+}
+
+void
+lexclose(void)
+{
+ fclose(flp->fp);
+ flp = flp->previous;
+}
+
+/* Token decoding: shift() loads the next token into tok.
+ * Iff a token starts at the left margin, it is considered
+ * to be the first in a record. We create a special condition,
+ * Record Boundary (analogous to EOF), just before such a token.
+ * We are unwilling to shift through a record boundary:
+ * it must be overridden first.
+ * Returns FALSE iff Record Boundary or EOF (i.e. no token);
+ * tok will then be NULL.
+ */
+
+char *tok;
+#define tokeq(s) (streq(tok, (s)))
+#define tokeqword(s) (strcasecmp(tok, (s)) == 0)
+
+bool
+shift(void)
+{
+ char *p = flp->cur;
+ char *sor = NULL; /* start of record for any new lines */
+
+ passert(flp->bdry == B_none);
+
+ *p = flp->under;
+ flp->under = '\0';
+
+ for (;;)
+ {
+ switch (*p)
+ {
+ case '\0': /* end of line */
+ case '#': /* comment to end of line: treat as end of line */
+ /* get the next line */
+ if (fgets(flp->buffer, sizeof(flp->buffer)-1, flp->fp) == NULL)
+ {
+ flp->bdry = B_file;
+ tok = flp->cur = NULL;
+ return FALSE;
+ }
+ else
+ {
+ /* strip trailing whitespace, including \n */
+
+ for (p = flp->buffer+strlen(flp->buffer)-1
+ ; p>flp->buffer && isspace(p[-1]); p--)
+ ;
+ *p = '\0';
+
+ flp->lino++;
+ sor = p = flp->buffer;
+ }
+ break; /* try again for a token */
+
+ case ' ': /* whitespace */
+ case '\t':
+ p++;
+ break; /* try again for a token */
+
+ case '"': /* quoted token */
+ case '\'':
+ if (p != sor)
+ {
+ /* we have a quoted token: note and advance to its end */
+ tok = p;
+ p = strchr(p+1, *p);
+ if (p == NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "\"%s\" line %d: unterminated string"
+ , flp->filename, flp->lino);
+ p = tok + strlen(tok);
+ }
+ else
+ {
+ p++; /* include delimiter in token */
+ }
+
+ /* remember token delimiter and replace with '\0' */
+ flp->under = *p;
+ *p = '\0';
+ flp->cur = p;
+ return TRUE;
+ }
+ /* FALL THROUGH */
+ default:
+ if (p != sor)
+ {
+ /* we seem to have a token: note and advance to its end */
+ tok = p;
+
+ if (p[0] == '0' && p[1] == 't')
+ {
+ /* 0t... token goes to end of line */
+ p += strlen(p);
+ }
+ else
+ {
+ /* "ordinary" token: up to whitespace or end of line */
+ do {
+ p++;
+ } while (*p != '\0' && !isspace(*p))
+ ;
+
+ /* fudge to separate ':' from a preceding adjacent token */
+ if (p-1 > tok && p[-1] == ':')
+ p--;
+ }
+
+ /* remember token delimiter and replace with '\0' */
+ flp->under = *p;
+ *p = '\0';
+ flp->cur = p;
+ return TRUE;
+ }
+
+ /* we have a start-of-record: return it, deferring "real" token */
+ flp->bdry = B_record;
+ tok = NULL;
+ flp->under = *p;
+ flp->cur = p;
+ return FALSE;
+ }
+ }
+}
+
+/* ensures we are at a Record (or File) boundary, optionally warning if not */
+
+bool
+flushline(const char *m)
+{
+ if (flp->bdry != B_none)
+ {
+ return TRUE;
+ }
+ else
+ {
+ if (m != NULL)
+ loglog(RC_LOG_SERIOUS, "\"%s\" line %d: %s", flp->filename, flp->lino, m);
+ do ; while (shift());
+ return FALSE;
+ }
+}
diff --git a/src/pluto/lex.h b/src/pluto/lex.h
new file mode 100644
index 000000000..fb6c15236
--- /dev/null
+++ b/src/pluto/lex.h
@@ -0,0 +1,52 @@
+/* lexer (lexical analyzer) for control files
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: lex.h,v 1.1 2004/03/15 20:35:28 as Exp $
+ */
+
+#define MAX_TOK_LEN 2048 /* includes terminal '\0' */
+struct file_lex_position
+{
+ int depth; /* how deeply we are nested */
+ const char *filename;
+ FILE *fp;
+ enum { B_none, B_record, B_file } bdry; /* current boundary */
+ int lino; /* line number in file */
+ char buffer[MAX_TOK_LEN + 1]; /* note: one extra char for our use (jamming '"') */
+ char *cur; /* cursor */
+ char under; /* except in shift(): character orignally at *cur */
+ struct file_lex_position *previous;
+};
+
+extern struct file_lex_position *flp;
+
+extern bool lexopen(struct file_lex_position *new_flp, const char *name, bool optional);
+extern void lexclose(void);
+
+
+/* Token decoding: shift() loads the next token into tok.
+ * Iff a token starts at the left margin, it is considered
+ * to be the first in a record. We create a special condition,
+ * Record Boundary (analogous to EOF), just before such a token.
+ * We are unwilling to shift through a record boundary:
+ * it must be overridden first.
+ * Returns FALSE iff Record Boundary or EOF (i.e. no token);
+ * tok will then be NULL.
+ */
+
+extern char *tok;
+#define tokeq(s) (streq(tok, (s)))
+#define tokeqword(s) (strcasecmp(tok, (s)) == 0)
+
+extern bool shift(void);
+extern bool flushline(const char *m);
diff --git a/src/pluto/linux26/netlink.h b/src/pluto/linux26/netlink.h
new file mode 100644
index 000000000..6b0896da6
--- /dev/null
+++ b/src/pluto/linux26/netlink.h
@@ -0,0 +1,90 @@
+#ifndef __LINUX_NETLINK_H
+#define __LINUX_NETLINK_H
+
+#include <stdint.h>
+#include <sys/socket.h> /* for sa_family_t */
+
+#define NETLINK_ROUTE 0 /* Routing/device hook */
+#define NETLINK_SKIP 1 /* Reserved for ENskip */
+#define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */
+#define NETLINK_FIREWALL 3 /* Firewalling hook */
+#define NETLINK_TCPDIAG 4 /* TCP socket monitoring */
+#define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */
+#define NETLINK_XFRM 6 /* ipsec */
+#define NETLINK_ARPD 8
+#define NETLINK_ROUTE6 11 /* af_inet6 route comm channel */
+#define NETLINK_IP6_FW 13
+#define NETLINK_DNRTMSG 14 /* DECnet routing messages */
+#define NETLINK_TAPBASE 16 /* 16 to 31 are ethertap */
+
+#define MAX_LINKS 32
+
+struct sockaddr_nl
+{
+ sa_family_t nl_family; /* AF_NETLINK */
+ unsigned short nl_pad; /* zero */
+ uint32_t nl_pid; /* process pid */
+ uint32_t nl_groups; /* multicast groups mask */
+};
+
+struct nlmsghdr
+{
+ uint32_t nlmsg_len; /* Length of message including header */
+ uint16_t nlmsg_type; /* Message content */
+ uint16_t nlmsg_flags; /* Additional flags */
+ uint32_t nlmsg_seq; /* Sequence number */
+ uint32_t nlmsg_pid; /* Sending process PID */
+};
+
+/* Flags values */
+
+#define NLM_F_REQUEST 1 /* It is request message. */
+#define NLM_F_MULTI 2 /* Multipart message, terminated by NLMSG_DONE */
+#define NLM_F_ACK 4 /* Reply with ack, with zero or error code */
+#define NLM_F_ECHO 8 /* Echo this request */
+
+/* Modifiers to GET request */
+#define NLM_F_ROOT 0x100 /* specify tree root */
+#define NLM_F_MATCH 0x200 /* return all matching */
+#define NLM_F_ATOMIC 0x400 /* atomic GET */
+#define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH)
+
+/* Modifiers to NEW request */
+#define NLM_F_REPLACE 0x100 /* Override existing */
+#define NLM_F_EXCL 0x200 /* Do not touch, if it exists */
+#define NLM_F_CREATE 0x400 /* Create, if it does not exist */
+#define NLM_F_APPEND 0x800 /* Add to end of list */
+
+/*
+ 4.4BSD ADD NLM_F_CREATE|NLM_F_EXCL
+ 4.4BSD CHANGE NLM_F_REPLACE
+
+ True CHANGE NLM_F_CREATE|NLM_F_REPLACE
+ Append NLM_F_CREATE
+ Check NLM_F_EXCL
+ */
+
+#define NLMSG_ALIGNTO 4
+#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
+#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(sizeof(struct nlmsghdr)))
+#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
+#define NLMSG_DATA(nlh) ((void*)(((char*)nlh) + NLMSG_LENGTH(0)))
+#define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
+ (struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
+#define NLMSG_OK(nlh,len) ((len) > 0 && (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \
+ (nlh)->nlmsg_len <= (len))
+#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len)))
+
+#define NLMSG_NOOP 0x1 /* Nothing. */
+#define NLMSG_ERROR 0x2 /* Error */
+#define NLMSG_DONE 0x3 /* End of a dump */
+#define NLMSG_OVERRUN 0x4 /* Data lost */
+
+struct nlmsgerr
+{
+ int error;
+ struct nlmsghdr msg;
+};
+
+#define NET_MAJOR 36 /* Major 36 is reserved for networking */
+#endif /* __LINUX_NETLINK_H */
diff --git a/src/pluto/linux26/rtnetlink.h b/src/pluto/linux26/rtnetlink.h
new file mode 100644
index 000000000..341bc1f86
--- /dev/null
+++ b/src/pluto/linux26/rtnetlink.h
@@ -0,0 +1,562 @@
+#ifndef __LINUX_RTNETLINK_H
+#define __LINUX_RTNETLINK_H
+
+#include "netlink.h"
+#include <stdint.h>
+
+#define RTNL_DEBUG 1
+
+
+/****
+ * Routing/neighbour discovery messages.
+ ****/
+
+/* Types of messages */
+
+#define RTM_BASE 0x10
+
+#define RTM_NEWLINK (RTM_BASE+0)
+#define RTM_DELLINK (RTM_BASE+1)
+#define RTM_GETLINK (RTM_BASE+2)
+#define RTM_SETLINK (RTM_BASE+3)
+
+#define RTM_NEWADDR (RTM_BASE+4)
+#define RTM_DELADDR (RTM_BASE+5)
+#define RTM_GETADDR (RTM_BASE+6)
+
+#define RTM_NEWROUTE (RTM_BASE+8)
+#define RTM_DELROUTE (RTM_BASE+9)
+#define RTM_GETROUTE (RTM_BASE+10)
+
+#define RTM_NEWNEIGH (RTM_BASE+12)
+#define RTM_DELNEIGH (RTM_BASE+13)
+#define RTM_GETNEIGH (RTM_BASE+14)
+
+#define RTM_NEWRULE (RTM_BASE+16)
+#define RTM_DELRULE (RTM_BASE+17)
+#define RTM_GETRULE (RTM_BASE+18)
+
+#define RTM_NEWQDISC (RTM_BASE+20)
+#define RTM_DELQDISC (RTM_BASE+21)
+#define RTM_GETQDISC (RTM_BASE+22)
+
+#define RTM_NEWTCLASS (RTM_BASE+24)
+#define RTM_DELTCLASS (RTM_BASE+25)
+#define RTM_GETTCLASS (RTM_BASE+26)
+
+#define RTM_NEWTFILTER (RTM_BASE+28)
+#define RTM_DELTFILTER (RTM_BASE+29)
+#define RTM_GETTFILTER (RTM_BASE+30)
+
+#define RTM_MAX (RTM_BASE+31)
+
+/*
+ Generic structure for encapsulation optional route information.
+ It is reminiscent of sockaddr, but with sa_family replaced
+ with attribute type.
+ */
+
+struct rtattr
+{
+ unsigned short rta_len;
+ unsigned short rta_type;
+};
+
+/* Macros to handle rtattributes */
+
+#define RTA_ALIGNTO 4
+#define RTA_ALIGN(len) ( ((len)+RTA_ALIGNTO-1) & ~(RTA_ALIGNTO-1) )
+#define RTA_OK(rta,len) ((len) > 0 && (rta)->rta_len >= sizeof(struct rtattr) && \
+ (rta)->rta_len <= (len))
+#define RTA_NEXT(rta,attrlen) ((attrlen) -= RTA_ALIGN((rta)->rta_len), \
+ (struct rtattr*)(((char*)(rta)) + RTA_ALIGN((rta)->rta_len)))
+#define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len))
+#define RTA_SPACE(len) RTA_ALIGN(RTA_LENGTH(len))
+#define RTA_DATA(rta) ((void*)(((char*)(rta)) + RTA_LENGTH(0)))
+#define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0))
+
+
+
+
+/******************************************************************************
+ * Definitions used in routing table administation.
+ ****/
+
+struct rtmsg
+{
+ unsigned char rtm_family;
+ unsigned char rtm_dst_len;
+ unsigned char rtm_src_len;
+ unsigned char rtm_tos;
+
+ unsigned char rtm_table; /* Routing table id */
+ unsigned char rtm_protocol; /* Routing protocol; see below */
+ unsigned char rtm_scope; /* See below */
+ unsigned char rtm_type; /* See below */
+
+ unsigned rtm_flags;
+};
+
+/* rtm_type */
+
+enum
+{
+ RTN_UNSPEC,
+ RTN_UNICAST, /* Gateway or direct route */
+ RTN_LOCAL, /* Accept locally */
+ RTN_BROADCAST, /* Accept locally as broadcast,
+ send as broadcast */
+ RTN_ANYCAST, /* Accept locally as broadcast,
+ but send as unicast */
+ RTN_MULTICAST, /* Multicast route */
+ RTN_BLACKHOLE, /* Drop */
+ RTN_UNREACHABLE, /* Destination is unreachable */
+ RTN_PROHIBIT, /* Administratively prohibited */
+ RTN_THROW, /* Not in this table */
+ RTN_NAT, /* Translate this address */
+ RTN_XRESOLVE, /* Use external resolver */
+};
+
+#define RTN_MAX RTN_XRESOLVE
+
+
+/* rtm_protocol */
+
+#define RTPROT_UNSPEC 0
+#define RTPROT_REDIRECT 1 /* Route installed by ICMP redirects;
+ not used by current IPv4 */
+#define RTPROT_KERNEL 2 /* Route installed by kernel */
+#define RTPROT_BOOT 3 /* Route installed during boot */
+#define RTPROT_STATIC 4 /* Route installed by administrator */
+
+/* Values of protocol >= RTPROT_STATIC are not interpreted by kernel;
+ they just passed from user and back as is.
+ It will be used by hypothetical multiple routing daemons.
+ Note that protocol values should be standardized in order to
+ avoid conflicts.
+ */
+
+#define RTPROT_GATED 8 /* Apparently, GateD */
+#define RTPROT_RA 9 /* RDISC/ND router advertisments */
+#define RTPROT_MRT 10 /* Merit MRT */
+#define RTPROT_ZEBRA 11 /* Zebra */
+#define RTPROT_BIRD 12 /* BIRD */
+#define RTPROT_DNROUTED 13 /* DECnet routing daemon */
+
+/* rtm_scope
+
+ Really it is not scope, but sort of distance to the destination.
+ NOWHERE are reserved for not existing destinations, HOST is our
+ local addresses, LINK are destinations, located on directly attached
+ link and UNIVERSE is everywhere in the Universe.
+
+ Intermediate values are also possible f.e. interior routes
+ could be assigned a value between UNIVERSE and LINK.
+*/
+
+enum rt_scope_t
+{
+ RT_SCOPE_UNIVERSE=0,
+/* User defined values */
+ RT_SCOPE_SITE=200,
+ RT_SCOPE_LINK=253,
+ RT_SCOPE_HOST=254,
+ RT_SCOPE_NOWHERE=255
+};
+
+/* rtm_flags */
+
+#define RTM_F_NOTIFY 0x100 /* Notify user of route change */
+#define RTM_F_CLONED 0x200 /* This route is cloned */
+#define RTM_F_EQUALIZE 0x400 /* Multipath equalizer: NI */
+
+/* Reserved table identifiers */
+
+enum rt_class_t
+{
+ RT_TABLE_UNSPEC=0,
+/* User defined values */
+ RT_TABLE_DEFAULT=253,
+ RT_TABLE_MAIN=254,
+ RT_TABLE_LOCAL=255
+};
+#define RT_TABLE_MAX RT_TABLE_LOCAL
+
+
+
+/* Routing message attributes */
+
+enum rtattr_type_t
+{
+ RTA_UNSPEC,
+ RTA_DST,
+ RTA_SRC,
+ RTA_IIF,
+ RTA_OIF,
+ RTA_GATEWAY,
+ RTA_PRIORITY,
+ RTA_PREFSRC,
+ RTA_METRICS,
+ RTA_MULTIPATH,
+ RTA_PROTOINFO,
+ RTA_FLOW,
+ RTA_CACHEINFO,
+ RTA_SESSION,
+};
+
+#define RTA_MAX RTA_SESSION
+
+#define RTM_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct rtmsg))))
+#define RTM_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct rtmsg))
+
+/* RTM_MULTIPATH --- array of struct rtnexthop.
+ *
+ * "struct rtnexthop" describres all necessary nexthop information,
+ * i.e. parameters of path to a destination via this nextop.
+ *
+ * At the moment it is impossible to set different prefsrc, mtu, window
+ * and rtt for different paths from multipath.
+ */
+
+struct rtnexthop
+{
+ unsigned short rtnh_len;
+ unsigned char rtnh_flags;
+ unsigned char rtnh_hops;
+ int rtnh_ifindex;
+};
+
+/* rtnh_flags */
+
+#define RTNH_F_DEAD 1 /* Nexthop is dead (used by multipath) */
+#define RTNH_F_PERVASIVE 2 /* Do recursive gateway lookup */
+#define RTNH_F_ONLINK 4 /* Gateway is forced on link */
+
+/* Macros to handle hexthops */
+
+#define RTNH_ALIGNTO 4
+#define RTNH_ALIGN(len) ( ((len)+RTNH_ALIGNTO-1) & ~(RTNH_ALIGNTO-1) )
+#define RTNH_OK(rtnh,len) ((rtnh)->rtnh_len >= sizeof(struct rtnexthop) && \
+ ((int)(rtnh)->rtnh_len) <= (len))
+#define RTNH_NEXT(rtnh) ((struct rtnexthop*)(((char*)(rtnh)) + RTNH_ALIGN((rtnh)->rtnh_len)))
+#define RTNH_LENGTH(len) (RTNH_ALIGN(sizeof(struct rtnexthop)) + (len))
+#define RTNH_SPACE(len) RTNH_ALIGN(RTNH_LENGTH(len))
+#define RTNH_DATA(rtnh) ((struct rtattr*)(((char*)(rtnh)) + RTNH_LENGTH(0)))
+
+/* RTM_CACHEINFO */
+
+struct rta_cacheinfo
+{
+ uint32_t rta_clntref;
+ uint32_t rta_lastuse;
+ int32_t rta_expires;
+ uint32_t rta_error;
+ uint32_t rta_used;
+
+#define RTNETLINK_HAVE_PEERINFO 1
+ uint32_t rta_id;
+ uint32_t rta_ts;
+ uint32_t rta_tsage;
+};
+
+/* RTM_METRICS --- array of struct rtattr with types of RTAX_* */
+
+enum
+{
+ RTAX_UNSPEC,
+#define RTAX_UNSPEC RTAX_UNSPEC
+ RTAX_LOCK,
+#define RTAX_LOCK RTAX_LOCK
+ RTAX_MTU,
+#define RTAX_MTU RTAX_MTU
+ RTAX_WINDOW,
+#define RTAX_WINDOW RTAX_WINDOW
+ RTAX_RTT,
+#define RTAX_RTT RTAX_RTT
+ RTAX_RTTVAR,
+#define RTAX_RTTVAR RTAX_RTTVAR
+ RTAX_SSTHRESH,
+#define RTAX_SSTHRESH RTAX_SSTHRESH
+ RTAX_CWND,
+#define RTAX_CWND RTAX_CWND
+ RTAX_ADVMSS,
+#define RTAX_ADVMSS RTAX_ADVMSS
+ RTAX_REORDERING,
+#define RTAX_REORDERING RTAX_REORDERING
+};
+
+#define RTAX_MAX RTAX_REORDERING
+
+struct rta_session
+{
+ uint8_t proto;
+
+ union {
+ struct {
+ uint16_t sport;
+ uint16_t dport;
+ } ports;
+
+ struct {
+ uint8_t type;
+ uint8_t code;
+ uint16_t ident;
+ } icmpt;
+
+ uint32_t spi;
+ } u;
+};
+
+
+/*********************************************************
+ * Interface address.
+ ****/
+
+struct ifaddrmsg
+{
+ unsigned char ifa_family;
+ unsigned char ifa_prefixlen; /* The prefix length */
+ unsigned char ifa_flags; /* Flags */
+ unsigned char ifa_scope; /* See above */
+ int ifa_index; /* Link index */
+};
+
+enum
+{
+ IFA_UNSPEC,
+ IFA_ADDRESS,
+ IFA_LOCAL,
+ IFA_LABEL,
+ IFA_BROADCAST,
+ IFA_ANYCAST,
+ IFA_CACHEINFO
+};
+
+#define IFA_MAX IFA_CACHEINFO
+
+/* ifa_flags */
+
+#define IFA_F_SECONDARY 0x01
+#define IFA_F_TEMPORARY IFA_F_SECONDARY
+
+#define IFA_F_DEPRECATED 0x20
+#define IFA_F_TENTATIVE 0x40
+#define IFA_F_PERMANENT 0x80
+
+struct ifa_cacheinfo
+{
+ int32_t ifa_prefered;
+ int32_t ifa_valid;
+};
+
+
+#define IFA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))))
+#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg))
+
+/*
+ Important comment:
+ IFA_ADDRESS is prefix address, rather than local interface address.
+ It makes no difference for normally configured broadcast interfaces,
+ but for point-to-point IFA_ADDRESS is DESTINATION address,
+ local address is supplied in IFA_LOCAL attribute.
+ */
+
+/**************************************************************
+ * Neighbour discovery.
+ ****/
+
+struct ndmsg
+{
+ unsigned char ndm_family;
+ unsigned char ndm_pad1;
+ unsigned short ndm_pad2;
+ int ndm_ifindex; /* Link index */
+ uint16_t ndm_state;
+ uint8_t ndm_flags;
+ uint8_t ndm_type;
+};
+
+enum
+{
+ NDA_UNSPEC,
+ NDA_DST,
+ NDA_LLADDR,
+ NDA_CACHEINFO
+};
+
+#define NDA_MAX NDA_CACHEINFO
+
+#define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
+#define NDA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndmsg))
+
+/*
+ * Neighbor Cache Entry Flags
+ */
+
+#define NTF_PROXY 0x08 /* == ATF_PUBL */
+#define NTF_ROUTER 0x80
+
+/*
+ * Neighbor Cache Entry States.
+ */
+
+#define NUD_INCOMPLETE 0x01
+#define NUD_REACHABLE 0x02
+#define NUD_STALE 0x04
+#define NUD_DELAY 0x08
+#define NUD_PROBE 0x10
+#define NUD_FAILED 0x20
+
+/* Dummy states */
+#define NUD_NOARP 0x40
+#define NUD_PERMANENT 0x80
+#define NUD_NONE 0x00
+
+
+struct nda_cacheinfo
+{
+ uint32_t ndm_confirmed;
+ uint32_t ndm_used;
+ uint32_t ndm_updated;
+ uint32_t ndm_refcnt;
+};
+
+/****
+ * General form of address family dependent message.
+ ****/
+
+struct rtgenmsg
+{
+ unsigned char rtgen_family;
+};
+
+/*****************************************************************
+ * Link layer specific messages.
+ ****/
+
+/* struct ifinfomsg
+ * passes link level specific information, not dependent
+ * on network protocol.
+ */
+
+struct ifinfomsg
+{
+ unsigned char ifi_family;
+ unsigned char __ifi_pad;
+ unsigned short ifi_type; /* ARPHRD_* */
+ int ifi_index; /* Link index */
+ unsigned ifi_flags; /* IFF_* flags */
+ unsigned ifi_change; /* IFF_* change mask */
+};
+
+enum
+{
+ IFLA_UNSPEC,
+ IFLA_ADDRESS,
+ IFLA_BROADCAST,
+ IFLA_IFNAME,
+ IFLA_MTU,
+ IFLA_LINK,
+ IFLA_QDISC,
+ IFLA_STATS,
+ IFLA_COST,
+#define IFLA_COST IFLA_COST
+ IFLA_PRIORITY,
+#define IFLA_PRIORITY IFLA_PRIORITY
+ IFLA_MASTER,
+#define IFLA_MASTER IFLA_MASTER
+ IFLA_WIRELESS, /* Wireless Extension event - see wireless.h */
+#define IFLA_WIRELESS IFLA_WIRELESS
+};
+
+
+#define IFLA_MAX IFLA_WIRELESS
+
+#define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))
+#define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg))
+
+/* ifi_flags.
+
+ IFF_* flags.
+
+ The only change is:
+ IFF_LOOPBACK, IFF_BROADCAST and IFF_POINTOPOINT are
+ more not changeable by user. They describe link media
+ characteristics and set by device driver.
+
+ Comments:
+ - Combination IFF_BROADCAST|IFF_POINTOPOINT is invalid
+ - If neiher of these three flags are set;
+ the interface is NBMA.
+
+ - IFF_MULTICAST does not mean anything special:
+ multicasts can be used on all not-NBMA links.
+ IFF_MULTICAST means that this media uses special encapsulation
+ for multicast frames. Apparently, all IFF_POINTOPOINT and
+ IFF_BROADCAST devices are able to use multicasts too.
+ */
+
+/* IFLA_LINK.
+ For usual devices it is equal ifi_index.
+ If it is a "virtual interface" (f.e. tunnel), ifi_link
+ can point to real physical interface (f.e. for bandwidth calculations),
+ or maybe 0, what means, that real media is unknown (usual
+ for IPIP tunnels, when route to endpoint is allowed to change)
+ */
+
+/*****************************************************************
+ * Traffic control messages.
+ ****/
+
+struct tcmsg
+{
+ unsigned char tcm_family;
+ unsigned char tcm__pad1;
+ unsigned short tcm__pad2;
+ int tcm_ifindex;
+ uint32_t tcm_handle;
+ uint32_t tcm_parent;
+ uint32_t tcm_info;
+};
+
+enum
+{
+ TCA_UNSPEC,
+ TCA_KIND,
+ TCA_OPTIONS,
+ TCA_STATS,
+ TCA_XSTATS,
+ TCA_RATE,
+};
+
+#define TCA_MAX TCA_RATE
+
+#define TCA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct tcmsg))))
+#define TCA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct tcmsg))
+
+
+/* SUMMARY: maximal rtattr understood by kernel */
+
+#define RTATTR_MAX RTA_MAX
+
+/* RTnetlink multicast groups */
+
+#define RTMGRP_LINK 1
+#define RTMGRP_NOTIFY 2
+#define RTMGRP_NEIGH 4
+#define RTMGRP_TC 8
+
+#define RTMGRP_IPV4_IFADDR 0x10
+#define RTMGRP_IPV4_MROUTE 0x20
+#define RTMGRP_IPV4_ROUTE 0x40
+
+#define RTMGRP_IPV6_IFADDR 0x100
+#define RTMGRP_IPV6_MROUTE 0x200
+#define RTMGRP_IPV6_ROUTE 0x400
+
+#define RTMGRP_DECnet_IFADDR 0x1000
+#define RTMGRP_DECnet_ROUTE 0x4000
+
+/* End of information exported to user level */
+
+#endif /* __LINUX_RTNETLINK_H */
diff --git a/src/pluto/linux26/xfrm.h b/src/pluto/linux26/xfrm.h
new file mode 100644
index 000000000..4269ae29b
--- /dev/null
+++ b/src/pluto/linux26/xfrm.h
@@ -0,0 +1,233 @@
+#ifndef _LINUX_XFRM_H
+#define _LINUX_XFRM_H
+
+#include <stdint.h>
+
+/* All of the structures in this file may not change size as they are
+ * passed into the kernel from userspace via netlink sockets.
+ */
+
+/* Structure to encapsulate addresses. I do not want to use
+ * "standard" structure. My apologies.
+ */
+typedef union
+{
+ uint32_t a4;
+ uint32_t a6[4];
+} xfrm_address_t;
+
+/* Ident of a specific xfrm_state. It is used on input to lookup
+ * the state by (spi,daddr,ah/esp) or to store information about
+ * spi, protocol and tunnel address on output.
+ */
+struct xfrm_id
+{
+ xfrm_address_t daddr;
+ uint32_t spi;
+ uint8_t proto;
+};
+
+/* Selector, used as selector both on policy rules (SPD) and SAs. */
+
+struct xfrm_selector
+{
+ xfrm_address_t daddr;
+ xfrm_address_t saddr;
+ uint16_t dport;
+ uint16_t dport_mask;
+ uint16_t sport;
+ uint16_t sport_mask;
+ uint16_t family;
+ uint8_t prefixlen_d;
+ uint8_t prefixlen_s;
+ uint8_t proto;
+ int ifindex;
+ uid_t user;
+};
+
+#define XFRM_INF (~(uint64_t)0)
+
+struct xfrm_lifetime_cfg
+{
+ uint64_t soft_byte_limit;
+ uint64_t hard_byte_limit;
+ uint64_t soft_packet_limit;
+ uint64_t hard_packet_limit;
+ uint64_t soft_add_expires_seconds;
+ uint64_t hard_add_expires_seconds;
+ uint64_t soft_use_expires_seconds;
+ uint64_t hard_use_expires_seconds;
+};
+
+struct xfrm_lifetime_cur
+{
+ uint64_t bytes;
+ uint64_t packets;
+ uint64_t add_time;
+ uint64_t use_time;
+};
+
+struct xfrm_replay_state
+{
+ uint32_t oseq;
+ uint32_t seq;
+ uint32_t bitmap;
+};
+
+struct xfrm_algo {
+ char alg_name[64];
+ int alg_key_len; /* in bits */
+ char alg_key[0];
+};
+
+struct xfrm_stats {
+ uint32_t replay_window;
+ uint32_t replay;
+ uint32_t integrity_failed;
+};
+
+enum
+{
+ XFRM_POLICY_IN = 0,
+ XFRM_POLICY_OUT = 1,
+ XFRM_POLICY_FWD = 2,
+ XFRM_POLICY_MAX = 3
+};
+
+enum
+{
+ XFRM_SHARE_ANY, /* No limitations */
+ XFRM_SHARE_SESSION, /* For this session only */
+ XFRM_SHARE_USER, /* For this user only */
+ XFRM_SHARE_UNIQUE /* Use once */
+};
+
+/* Netlink configuration messages. */
+#define XFRM_MSG_BASE 0x10
+
+#define XFRM_MSG_NEWSA (XFRM_MSG_BASE + 0)
+#define XFRM_MSG_DELSA (XFRM_MSG_BASE + 1)
+#define XFRM_MSG_GETSA (XFRM_MSG_BASE + 2)
+
+#define XFRM_MSG_NEWPOLICY (XFRM_MSG_BASE + 3)
+#define XFRM_MSG_DELPOLICY (XFRM_MSG_BASE + 4)
+#define XFRM_MSG_GETPOLICY (XFRM_MSG_BASE + 5)
+
+#define XFRM_MSG_ALLOCSPI (XFRM_MSG_BASE + 6)
+#define XFRM_MSG_ACQUIRE (XFRM_MSG_BASE + 7)
+#define XFRM_MSG_EXPIRE (XFRM_MSG_BASE + 8)
+
+#define XFRM_MSG_UPDPOLICY (XFRM_MSG_BASE + 9)
+#define XFRM_MSG_UPDSA (XFRM_MSG_BASE + 10)
+
+#define XFRM_MSG_POLEXPIRE (XFRM_MSG_BASE + 11)
+
+#define XFRM_MSG_MAX (XFRM_MSG_POLEXPIRE+1)
+
+struct xfrm_user_tmpl {
+ struct xfrm_id id;
+ uint16_t family;
+ xfrm_address_t saddr;
+ uint32_t reqid;
+ uint8_t mode;
+ uint8_t share;
+ uint8_t optional;
+ uint32_t aalgos;
+ uint32_t ealgos;
+ uint32_t calgos;
+};
+
+struct xfrm_encap_tmpl {
+ uint16_t encap_type;
+ uint16_t encap_sport;
+ uint16_t encap_dport;
+ xfrm_address_t encap_oa;
+};
+
+/* Netlink message attributes. */
+enum xfrm_attr_type_t {
+ XFRMA_UNSPEC,
+ XFRMA_ALG_AUTH, /* struct xfrm_algo */
+ XFRMA_ALG_CRYPT, /* struct xfrm_algo */
+ XFRMA_ALG_COMP, /* struct xfrm_algo */
+ XFRMA_ENCAP, /* struct xfrm_algo + struct xfrm_encap_tmpl */
+ XFRMA_TMPL, /* 1 or more struct xfrm_user_tmpl */
+
+#define XFRMA_MAX XFRMA_TMPL
+};
+
+struct xfrm_usersa_info {
+ struct xfrm_selector sel;
+ struct xfrm_id id;
+ xfrm_address_t saddr;
+ struct xfrm_lifetime_cfg lft;
+ struct xfrm_lifetime_cur curlft;
+ struct xfrm_stats stats;
+ uint32_t seq;
+ uint32_t reqid;
+ uint16_t family;
+ uint8_t mode; /* 0=transport,1=tunnel */
+ uint8_t replay_window;
+ uint8_t flags;
+#define XFRM_STATE_NOECN 1
+};
+
+struct xfrm_usersa_id {
+ xfrm_address_t daddr;
+ uint32_t spi;
+ uint16_t family;
+ uint8_t proto;
+};
+
+struct xfrm_userspi_info {
+ struct xfrm_usersa_info info;
+ uint32_t min;
+ uint32_t max;
+};
+
+struct xfrm_userpolicy_info {
+ struct xfrm_selector sel;
+ struct xfrm_lifetime_cfg lft;
+ struct xfrm_lifetime_cur curlft;
+ uint32_t priority;
+ uint32_t index;
+ uint8_t dir;
+ uint8_t action;
+#define XFRM_POLICY_ALLOW 0
+#define XFRM_POLICY_BLOCK 1
+ uint8_t flags;
+#define XFRM_POLICY_LOCALOK 1 /* Allow user to override global policy */
+ uint8_t share;
+};
+
+struct xfrm_userpolicy_id {
+ struct xfrm_selector sel;
+ uint32_t index;
+ uint8_t dir;
+};
+
+struct xfrm_user_acquire {
+ struct xfrm_id id;
+ xfrm_address_t saddr;
+ struct xfrm_selector sel;
+ struct xfrm_userpolicy_info policy;
+ uint32_t aalgos;
+ uint32_t ealgos;
+ uint32_t calgos;
+ uint32_t seq;
+};
+
+struct xfrm_user_expire {
+ struct xfrm_usersa_info state;
+ uint8_t hard;
+};
+
+struct xfrm_user_polexpire {
+ struct xfrm_userpolicy_info pol;
+ uint8_t hard;
+};
+
+#define XFRMGRP_ACQUIRE 1
+#define XFRMGRP_EXPIRE 2
+
+#endif /* _LINUX_XFRM_H */
diff --git a/src/pluto/log.c b/src/pluto/log.c
new file mode 100644
index 000000000..36997122c
--- /dev/null
+++ b/src/pluto/log.c
@@ -0,0 +1,841 @@
+/* error logging functions
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: log.c,v 1.8 2006/04/29 18:16:02 as Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h> /* used only if MSG_NOSIGNAL not defined */
+#include <sys/queue.h>
+#include <libgen.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "server.h"
+#include "state.h"
+#include "connections.h"
+#include "kernel.h"
+#include "whack.h" /* needs connections.h */
+#include "timer.h"
+
+/* close one per-peer log */
+static void perpeer_logclose(struct connection *c); /* forward */
+
+
+bool
+ log_to_stderr = TRUE, /* should log go to stderr? */
+ log_to_syslog = TRUE, /* should log go to syslog? */
+ log_to_perpeer= FALSE; /* should log go to per-IP file? */
+
+bool
+ logged_txt_warning = FALSE; /* should we complain about finding KEY? */
+
+/* should we complain when we find no local id */
+bool
+ logged_myid_fqdn_txt_warning = FALSE,
+ logged_myid_ip_txt_warning = FALSE,
+ logged_myid_fqdn_key_warning = FALSE,
+ logged_myid_ip_key_warning = FALSE;
+
+/* may include trailing / */
+const char *base_perpeer_logdir = PERPEERLOGDIR;
+static int perpeer_count = 0;
+
+/* from sys/queue.h */
+static CIRCLEQ_HEAD(,connection) perpeer_list;
+
+
+/* Context for logging.
+ *
+ * Global variables: must be carefully adjusted at transaction boundaries!
+ * If the context provides a whack file descriptor, messages
+ * should be copied to it -- see whack_log()
+ */
+int whack_log_fd = NULL_FD; /* only set during whack_handle() */
+struct state *cur_state = NULL; /* current state, for diagnostics */
+struct connection *cur_connection = NULL; /* current connection, for diagnostics */
+const ip_address *cur_from = NULL; /* source of current current message */
+u_int16_t cur_from_port; /* host order */
+
+void
+init_log(const char *program)
+{
+ if (log_to_stderr)
+ setbuf(stderr, NULL);
+ if (log_to_syslog)
+ openlog(program, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_AUTHPRIV);
+
+ CIRCLEQ_INIT(&perpeer_list);
+}
+
+void
+close_peerlog(void)
+{
+ /* end of circular queue is given by pointer to "HEAD"
+ * BUT if the queue is not initialized, this won't be true
+ * so we must guard by test perpeer_list.cqh_first != NULL
+ */
+ if (perpeer_list.cqh_first != NULL)
+ while (perpeer_list.cqh_first != (void *)&perpeer_list)
+ perpeer_logclose(perpeer_list.cqh_first);
+}
+
+void
+close_log(void)
+{
+ if (log_to_syslog)
+ closelog();
+
+ close_peerlog();
+}
+
+/* Sanitize character string in situ: turns dangerous characters into \OOO.
+ * With a bit of work, we could use simpler reps for \\, \r, etc.,
+ * but this is only to protect against something that shouldn't be used.
+ * Truncate resulting string to what fits in buffer.
+ */
+static size_t
+sanitize(char *buf, size_t size)
+{
+# define UGLY_WIDTH 4 /* width for ugly character: \OOO */
+ size_t len;
+ size_t added = 0;
+ char *p;
+
+ passert(size >= UGLY_WIDTH); /* need room to swing cat */
+
+ /* find right side of string to be sanitized and count
+ * number of columns to be added. Stop on end of string
+ * or lack of room for more result.
+ */
+ for (p = buf; *p != '\0' && &p[added] < &buf[size - UGLY_WIDTH]; )
+ {
+ unsigned char c = *p++;
+
+ if (c == '\\' || !isprint(c))
+ added += UGLY_WIDTH - 1;
+ }
+
+ /* at this point, p points after last original character to be
+ * included. added is how many characters are added to sanitize.
+ * so p[added] will point after last sanitized character.
+ */
+
+ p[added] = '\0';
+ len = &p[added] - buf;
+
+ /* scan backwards, copying characters to their new home
+ * and inserting the expansions for ugly characters.
+ * It is finished when no more shifting is required.
+ * This is a predecrement loop.
+ */
+ while (added != 0)
+ {
+ char fmtd[UGLY_WIDTH + 1];
+ unsigned char c;
+
+ while ((c = *--p) != '\\' && isprint(c))
+ p[added] = c;
+ added -= UGLY_WIDTH - 1;
+ snprintf(fmtd, sizeof(fmtd), "\\%03o", c);
+ memcpy(p + added, fmtd, UGLY_WIDTH);
+ }
+ return len;
+# undef UGLY_WIDTH
+}
+
+/* format a string for the log, with suitable prefixes.
+ * A format starting with ~ indicates that this is a reprocessing
+ * of the message, so prefixing and quoting is suppressed.
+ */
+static void
+fmt_log(char *buf, size_t buf_len, const char *fmt, va_list ap)
+{
+ bool reproc = *fmt == '~';
+ size_t ps;
+ struct connection *c = cur_state != NULL ? cur_state->st_connection
+ : cur_connection;
+
+ buf[0] = '\0';
+ if (reproc)
+ fmt++; /* ~ at start of format suppresses this prefix */
+ else if (c != NULL)
+ {
+ /* start with name of connection */
+ char *const be = buf + buf_len;
+ char *bp = buf;
+
+ snprintf(bp, be - bp, "\"%s\"", c->name);
+ bp += strlen(bp);
+
+ /* if it fits, put in any connection instance information */
+ if (be - bp > CONN_INST_BUF)
+ {
+ fmt_conn_instance(c, bp);
+ bp += strlen(bp);
+ }
+
+ if (cur_state != NULL)
+ {
+ /* state number */
+ snprintf(bp, be - bp, " #%lu", cur_state->st_serialno);
+ bp += strlen(bp);
+ }
+ snprintf(bp, be - bp, ": ");
+ }
+ else if (cur_from != NULL)
+ {
+ /* peer's IP address */
+ /* Note: must not use ip_str() because our caller might! */
+ char ab[ADDRTOT_BUF];
+
+ (void) addrtot(cur_from, 0, ab, sizeof(ab));
+ snprintf(buf, buf_len, "packet from %s:%u: "
+ , ab, (unsigned)cur_from_port);
+ }
+
+ ps = strlen(buf);
+ vsnprintf(buf + ps, buf_len - ps, fmt, ap);
+ if (!reproc)
+ (void)sanitize(buf, buf_len);
+}
+
+static void
+perpeer_logclose(struct connection *c)
+{
+ /* only free/close things if we had used them! */
+ if (c->log_file != NULL)
+ {
+ passert(perpeer_count > 0);
+
+ CIRCLEQ_REMOVE(&perpeer_list, c, log_link);
+ perpeer_count--;
+ fclose(c->log_file);
+ c->log_file=NULL;
+ }
+}
+
+void
+perpeer_logfree(struct connection *c)
+{
+ perpeer_logclose(c);
+ if (c->log_file_name != NULL)
+ {
+ pfree(c->log_file_name);
+ c->log_file_name = NULL;
+ c->log_file_err = FALSE;
+ }
+}
+
+/* open the per-peer log */
+static void
+open_peerlog(struct connection *c)
+{
+ syslog(LOG_INFO, "opening log file for conn %s", c->name);
+
+ if (c->log_file_name == NULL)
+ {
+ char peername[ADDRTOT_BUF], dname[ADDRTOT_BUF];
+ int peernamelen, lf_len;
+
+ addrtot(&c->spd.that.host_addr, 'Q', peername, sizeof(peername));
+ peernamelen = strlen(peername);
+
+ /* copy IP address, turning : and . into / */
+ {
+ char c, *p, *q;
+
+ p = peername;
+ q = dname;
+ do {
+ c = *p++;
+ if (c == '.' || c == ':')
+ c = '/';
+ *q++ = c;
+ } while (c != '\0');
+ }
+
+ lf_len = peernamelen * 2
+ + strlen(base_perpeer_logdir)
+ + sizeof("//.log")
+ + 1;
+ c->log_file_name = alloc_bytes(lf_len, "per-peer log file name");
+
+ fprintf(stderr, "base dir |%s| dname |%s| peername |%s|"
+ , base_perpeer_logdir, dname, peername);
+ snprintf(c->log_file_name, lf_len, "%s/%s/%s.log"
+ , base_perpeer_logdir, dname, peername);
+
+ syslog(LOG_DEBUG, "conn %s logfile is %s", c->name, c->log_file_name);
+ }
+
+ /* now open the file, creating directories if necessary */
+
+ { /* create the directory */
+ char *dname;
+ int bpl_len = strlen(base_perpeer_logdir);
+ char *slashloc;
+
+ dname = clone_str(c->log_file_name, "temp copy of file name");
+ dname = dirname(dname);
+
+ if (access(dname, W_OK) != 0)
+ {
+ if (errno != ENOENT)
+ {
+ if (c->log_file_err)
+ {
+ syslog(LOG_CRIT, "can not write to %s: %s"
+ , dname, strerror(errno));
+ c->log_file_err = TRUE;
+ pfree(dname);
+ return;
+ }
+ }
+
+ /* directory does not exist, walk path creating dirs */
+ /* start at base_perpeer_logdir */
+ slashloc = dname + bpl_len;
+ slashloc++; /* since, by construction there is a slash
+ right there */
+
+ while (*slashloc != '\0')
+ {
+ char saveslash;
+
+ /* look for next slash */
+ while (*slashloc != '\0' && *slashloc != '/') slashloc++;
+
+ saveslash = *slashloc;
+
+ *slashloc = '\0';
+
+ if (mkdir(dname, 0750) != 0 && errno != EEXIST)
+ {
+ syslog(LOG_CRIT, "can not create dir %s: %s"
+ , dname, strerror(errno));
+ c->log_file_err = TRUE;
+ pfree(dname);
+ return;
+ }
+ syslog(LOG_DEBUG, "created new directory %s", dname);
+ *slashloc = saveslash;
+ slashloc++;
+ }
+ }
+
+ pfree(dname);
+ }
+
+ c->log_file = fopen(c->log_file_name, "a");
+ if (c->log_file == NULL)
+ {
+ if (c->log_file_err)
+ {
+ syslog(LOG_CRIT, "logging system can not open %s: %s"
+ , c->log_file_name, strerror(errno));
+ c->log_file_err = TRUE;
+ }
+ return;
+ }
+
+ /* look for a connection to close! */
+ while (perpeer_count >= MAX_PEERLOG_COUNT)
+ {
+ /* can not be NULL because perpeer_count > 0 */
+ passert(perpeer_list.cqh_last != (void *)&perpeer_list);
+
+ perpeer_logclose(perpeer_list.cqh_last);
+ }
+
+ /* insert this into the list */
+ CIRCLEQ_INSERT_HEAD(&perpeer_list, c, log_link);
+ passert(c->log_file != NULL);
+ perpeer_count++;
+}
+
+/* log a line to cur_connection's log */
+static void
+peerlog(const char *prefix, const char *m)
+{
+ if (cur_connection == NULL)
+ {
+ /* we can not log it in this case. Oh well. */
+ return;
+ }
+
+ if (cur_connection->log_file == NULL)
+ {
+ open_peerlog(cur_connection);
+ }
+
+ /* despite our attempts above, we may not be able to open the file. */
+ if (cur_connection->log_file != NULL)
+ {
+ char datebuf[32];
+ time_t n;
+ struct tm *t;
+
+ time(&n);
+ t = localtime(&n);
+
+ strftime(datebuf, sizeof(datebuf), "%Y-%m-%d %T", t);
+ fprintf(cur_connection->log_file, "%s %s%s\n", datebuf, prefix, m);
+
+ /* now move it to the front of the list */
+ CIRCLEQ_REMOVE(&perpeer_list, cur_connection, log_link);
+ CIRCLEQ_INSERT_HEAD(&perpeer_list, cur_connection, log_link);
+ }
+}
+
+void
+plog(const char *message, ...)
+{
+ va_list args;
+ char m[LOG_WIDTH]; /* longer messages will be truncated */
+
+ va_start(args, message);
+ fmt_log(m, sizeof(m), message, args);
+ va_end(args);
+
+ if (log_to_stderr)
+ fprintf(stderr, "%s\n", m);
+ if (log_to_syslog)
+ syslog(LOG_WARNING, "%s", m);
+ if (log_to_perpeer)
+ peerlog("", m);
+
+ whack_log(RC_LOG, "~%s", m);
+}
+
+void
+loglog(int mess_no, const char *message, ...)
+{
+ va_list args;
+ char m[LOG_WIDTH]; /* longer messages will be truncated */
+
+ va_start(args, message);
+ fmt_log(m, sizeof(m), message, args);
+ va_end(args);
+
+ if (log_to_stderr)
+ fprintf(stderr, "%s\n", m);
+ if (log_to_syslog)
+ syslog(LOG_WARNING, "%s", m);
+ if (log_to_perpeer)
+ peerlog("", m);
+
+ whack_log(mess_no, "~%s", m);
+}
+
+void
+log_errno_routine(int e, const char *message, ...)
+{
+ va_list args;
+ char m[LOG_WIDTH]; /* longer messages will be truncated */
+
+ va_start(args, message);
+ fmt_log(m, sizeof(m), message, args);
+ va_end(args);
+
+ if (log_to_stderr)
+ fprintf(stderr, "ERROR: %s. Errno %d: %s\n", m, e, strerror(e));
+ if (log_to_syslog)
+ syslog(LOG_ERR, "ERROR: %s. Errno %d: %s", m, e, strerror(e));
+ if (log_to_perpeer)
+ {
+ peerlog(strerror(e), m);
+ }
+
+ whack_log(RC_LOG_SERIOUS
+ , "~ERROR: %s. Errno %d: %s", m, e, strerror(e));
+}
+
+void
+exit_log(const char *message, ...)
+{
+ va_list args;
+ char m[LOG_WIDTH]; /* longer messages will be truncated */
+
+ va_start(args, message);
+ fmt_log(m, sizeof(m), message, args);
+ va_end(args);
+
+ if (log_to_stderr)
+ fprintf(stderr, "FATAL ERROR: %s\n", m);
+ if (log_to_syslog)
+ syslog(LOG_ERR, "FATAL ERROR: %s", m);
+ if (log_to_perpeer)
+ peerlog("FATAL ERROR: ", m);
+
+ whack_log(RC_LOG_SERIOUS, "~FATAL ERROR: %s", m);
+
+ exit_pluto(1);
+}
+
+void
+exit_log_errno_routine(int e, const char *message, ...)
+{
+ va_list args;
+ char m[LOG_WIDTH]; /* longer messages will be truncated */
+
+ va_start(args, message);
+ fmt_log(m, sizeof(m), message, args);
+ va_end(args);
+
+ if (log_to_stderr)
+ fprintf(stderr, "FATAL ERROR: %s. Errno %d: %s\n", m, e, strerror(e));
+ if (log_to_syslog)
+ syslog(LOG_ERR, "FATAL ERROR: %s. Errno %d: %s", m, e, strerror(e));
+ if (log_to_perpeer)
+ peerlog(strerror(e), m);
+
+ whack_log(RC_LOG_SERIOUS
+ , "~FATAL ERROR: %s. Errno %d: %s", m, e, strerror(e));
+
+ exit_pluto(1);
+}
+
+/* emit message to whack.
+ * form is "ddd statename text" where
+ * - ddd is a decimal status code (RC_*) as described in whack.h
+ * - text is a human-readable annotation
+ */
+#ifdef DEBUG
+static volatile sig_atomic_t dying_breath = FALSE;
+#endif
+
+void
+whack_log(int mess_no, const char *message, ...)
+{
+ int wfd = whack_log_fd != NULL_FD ? whack_log_fd
+ : cur_state != NULL ? cur_state->st_whack_sock
+ : NULL_FD;
+
+ if (wfd != NULL_FD
+#ifdef DEBUG
+ || dying_breath
+#endif
+ )
+ {
+ va_list args;
+ char m[LOG_WIDTH]; /* longer messages will be truncated */
+ int prelen = snprintf(m, sizeof(m), "%03d ", mess_no);
+
+ passert(prelen >= 0);
+
+ va_start(args, message);
+ fmt_log(m+prelen, sizeof(m)-prelen, message, args);
+ va_end(args);
+
+#if DEBUG
+ if (dying_breath)
+ {
+ /* status output copied to log */
+ if (log_to_stderr)
+ fprintf(stderr, "%s\n", m + prelen);
+ if (log_to_syslog)
+ syslog(LOG_WARNING, "%s", m + prelen);
+ if (log_to_perpeer)
+ peerlog("", m);
+ }
+#endif
+
+ if (wfd != NULL_FD)
+ {
+ /* write to whack socket, but suppress possible SIGPIPE */
+ size_t len = strlen(m);
+#ifdef MSG_NOSIGNAL /* depends on version of glibc??? */
+ m[len] = '\n'; /* don't need NUL, do need NL */
+ (void) send(wfd, m, len + 1, MSG_NOSIGNAL);
+#else /* !MSG_NOSIGNAL */
+ int r;
+ struct sigaction act
+ , oldact;
+
+ m[len] = '\n'; /* don't need NUL, do need NL */
+ act.sa_handler = SIG_IGN;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0; /* no nothing */
+ r = sigaction(SIGPIPE, &act, &oldact);
+ passert(r == 0);
+
+ (void) write(wfd, m, len + 1);
+
+ r = sigaction(SIGPIPE, &oldact, NULL);
+ passert(r == 0);
+#endif /* !MSG_NOSIGNAL */
+ }
+ }
+}
+
+/* Build up a diagnostic in a static buffer.
+ * Although this would be a generally useful function, it is very
+ * hard to come up with a discipline that prevents different uses
+ * from interfering. It is intended that by limiting it to building
+ * diagnostics, we will avoid this problem.
+ * Juggling is performed to allow an argument to be a previous
+ * result: the new string may safely depend on the old one. This
+ * restriction is not checked in any way: violators will produce
+ * confusing results (without crashing!).
+ */
+char diag_space[sizeof(diag_space)];
+
+err_t
+builddiag(const char *fmt, ...)
+{
+ static char diag_space[LOG_WIDTH]; /* longer messages will be truncated */
+ char t[sizeof(diag_space)]; /* build result here first */
+ va_list args;
+
+ va_start(args, fmt);
+ t[0] = '\0'; /* in case nothing terminates string */
+ vsnprintf(t, sizeof(t), fmt, args);
+ va_end(args);
+ strcpy(diag_space, t);
+ return diag_space;
+}
+
+/* Debugging message support */
+
+#ifdef DEBUG
+
+void
+switch_fail(int n, const char *file_str, unsigned long line_no)
+{
+ char buf[30];
+
+ snprintf(buf, sizeof(buf), "case %d unexpected", n);
+ passert_fail(buf, file_str, line_no);
+}
+
+void
+passert_fail(const char *pred_str, const char *file_str, unsigned long line_no)
+{
+ /* we will get a possibly unplanned prefix. Hope it works */
+ loglog(RC_LOG_SERIOUS, "ASSERTION FAILED at %s:%lu: %s", file_str, line_no, pred_str);
+ if (!dying_breath)
+ {
+ dying_breath = TRUE;
+ show_status(TRUE, NULL);
+ }
+ abort(); /* exiting correctly doesn't always work */
+}
+
+void
+pexpect_log(const char *pred_str, const char *file_str, unsigned long line_no)
+{
+ /* we will get a possibly unplanned prefix. Hope it works */
+ loglog(RC_LOG_SERIOUS, "EXPECTATION FAILED at %s:%lu: %s", file_str, line_no, pred_str);
+}
+
+lset_t
+ base_debugging = DBG_NONE, /* default to reporting nothing */
+ cur_debugging = DBG_NONE;
+
+void
+extra_debugging(const struct connection *c)
+{
+ if(c == NULL)
+ {
+ reset_debugging();
+ return;
+ }
+
+ if (c!= NULL && c->extra_debugging != 0)
+ {
+ plog("enabling for connection: %s"
+ , bitnamesof(debug_bit_names, c->extra_debugging & ~cur_debugging));
+ cur_debugging |= c->extra_debugging;
+ }
+}
+
+/* log a debugging message (prefixed by "| ") */
+
+void
+DBG_log(const char *message, ...)
+{
+ va_list args;
+ char m[LOG_WIDTH]; /* longer messages will be truncated */
+
+ va_start(args, message);
+ vsnprintf(m, sizeof(m), message, args);
+ va_end(args);
+
+ (void)sanitize(m, sizeof(m));
+
+ if (log_to_stderr)
+ fprintf(stderr, "| %s\n", m);
+ if (log_to_syslog)
+ syslog(LOG_DEBUG, "| %s", m);
+ if (log_to_perpeer)
+ peerlog("| ", m);
+}
+
+/* dump raw bytes in hex to stderr (for lack of any better destination) */
+
+void
+DBG_dump(const char *label, const void *p, size_t len)
+{
+# define DUMP_LABEL_WIDTH 20 /* arbitrary modest boundary */
+# define DUMP_WIDTH (4 * (1 + 4 * 3) + 1)
+ char buf[DUMP_LABEL_WIDTH + DUMP_WIDTH];
+ char *bp;
+ const unsigned char *cp = p;
+
+ bp = buf;
+
+ if (label != NULL && label[0] != '\0')
+ {
+ /* Handle the label. Care must be taken to avoid buffer overrun. */
+ size_t llen = strlen(label);
+
+ if (llen + 1 > sizeof(buf))
+ {
+ DBG_log("%s", label);
+ }
+ else
+ {
+ strcpy(buf, label);
+ if (buf[llen-1] == '\n')
+ {
+ buf[llen-1] = '\0'; /* get rid of newline */
+ DBG_log("%s", buf);
+ }
+ else if (llen < DUMP_LABEL_WIDTH)
+ {
+ bp = buf + llen;
+ }
+ else
+ {
+ DBG_log("%s", buf);
+ }
+ }
+ }
+
+ do {
+ int i, j;
+
+ for (i = 0; len!=0 && i!=4; i++)
+ {
+ *bp++ = ' ';
+ for (j = 0; len!=0 && j!=4; len--, j++)
+ {
+ static const char hexdig[] = "0123456789abcdef";
+
+ *bp++ = ' ';
+ *bp++ = hexdig[(*cp >> 4) & 0xF];
+ *bp++ = hexdig[*cp & 0xF];
+ cp++;
+ }
+ }
+ *bp = '\0';
+ DBG_log("%s", buf);
+ bp = buf;
+ } while (len != 0);
+# undef DUMP_LABEL_WIDTH
+# undef DUMP_WIDTH
+}
+
+#endif /* DEBUG */
+
+void
+show_status(bool all, const char *name)
+{
+ if (all)
+ {
+ show_ifaces_status();
+ show_myid_status();
+ show_debug_status();
+ whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */
+ }
+ show_connections_status(all, name);
+ show_states_status(all, name);
+#ifdef KLIPS
+ show_shunt_status();
+#endif
+}
+
+/* ip_str: a simple to use variant of addrtot.
+ * It stores its result in a static buffer.
+ * This means that newer calls overwrite the storage of older calls.
+ * Note: this is not used in any of the logging functions, so their
+ * callers may use it.
+ */
+const char *
+ip_str(const ip_address *src)
+{
+ static char buf[ADDRTOT_BUF];
+
+ addrtot(src, 0, buf, sizeof(buf));
+ return buf;
+}
+
+/*
+ * a routine that attempts to schedule itself daily.
+ *
+ */
+
+void
+daily_log_reset(void)
+{
+ /* now perform actions */
+ logged_txt_warning = FALSE;
+
+ logged_myid_fqdn_txt_warning = FALSE;
+ logged_myid_ip_txt_warning = FALSE;
+ logged_myid_fqdn_key_warning = FALSE;
+ logged_myid_ip_key_warning = FALSE;
+}
+
+void
+daily_log_event(void)
+{
+ struct tm *ltime;
+ time_t n, interval;
+
+ /* attempt to schedule oneself to midnight, local time
+ * do this by getting seconds in the day, and delaying
+ * by 86400 - hour*3600+minutes*60+seconds.
+ */
+ time(&n);
+ ltime = localtime(&n);
+ interval = (24 * 60 * 60)
+ - (ltime->tm_sec
+ + ltime->tm_min * 60
+ + ltime->tm_hour * 3600);
+
+ event_schedule(EVENT_LOG_DAILY, interval, NULL);
+
+ daily_log_reset();
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset:4
+ * c-style: pluto
+ * End:
+ */
diff --git a/src/pluto/log.h b/src/pluto/log.h
new file mode 100644
index 000000000..a4eae9d1c
--- /dev/null
+++ b/src/pluto/log.h
@@ -0,0 +1,236 @@
+/* logging definitions
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: log.h,v 1.4 2005/07/11 18:33:45 as Exp $
+ */
+
+#include <freeswan.h>
+
+#define LOG_WIDTH 1024 /* roof of number of chars in log line */
+
+#ifndef PERPEERLOGDIR
+#define PERPEERLOGDIR "/var/log/pluto/peer"
+#endif
+
+/* our versions of assert: log result */
+
+#ifdef DEBUG
+
+extern void passert_fail(const char *pred_str
+ , const char *file_str, unsigned long line_no) NEVER_RETURNS;
+
+extern void pexpect_log(const char *pred_str
+ , const char *file_str, unsigned long line_no);
+
+# define impossible() passert_fail("impossible", __FILE__, __LINE__)
+
+extern void switch_fail(int n
+ , const char *file_str, unsigned long line_no) NEVER_RETURNS;
+
+# define bad_case(n) switch_fail((int) n, __FILE__, __LINE__)
+
+# define passert(pred) { \
+ if (!(pred)) \
+ passert_fail(#pred, __FILE__, __LINE__); \
+ }
+
+# define pexpect(pred) { \
+ if (!(pred)) \
+ pexpect_log(#pred, __FILE__, __LINE__); \
+ }
+
+/* assert that an err_t is NULL; evaluate exactly once */
+# define happy(x) { \
+ err_t ugh = x; \
+ if (ugh != NULL) \
+ passert_fail(ugh, __FILE__, __LINE__); \
+ }
+
+#else /*!DEBUG*/
+
+# define impossible() abort()
+# define bad_case(n) abort()
+# define passert(pred) { } /* do nothing */
+# define happy(x) { (void) x; } /* evaluate non-judgementally */
+
+#endif /*!DEBUG*/
+
+
+extern bool
+ log_to_stderr, /* should log go to stderr? */
+ log_to_syslog, /* should log go to syslog? */
+ log_to_perpeer; /* should log go to per-IP file? */
+
+extern const char *base_perpeer_logdir;
+
+/* maximum number of files to keep open for per-peer log files */
+#define MAX_PEERLOG_COUNT 16
+
+/* Context for logging.
+ *
+ * Global variables: must be carefully adjusted at transaction boundaries!
+ * All are to be left in RESET condition and will be checked.
+ * There are several pairs of routines to set and reset them.
+ * If the context provides a whack file descriptor, messages
+ * should be copied to it -- see whack_log()
+ */
+extern int whack_log_fd; /* only set during whack_handle() */
+extern struct state *cur_state; /* current state, for diagnostics */
+extern struct connection *cur_connection; /* current connection, for diagnostics */
+extern const ip_address *cur_from; /* source of current current message */
+extern u_int16_t cur_from_port; /* host order */
+
+#ifdef DEBUG
+
+ extern lset_t cur_debugging; /* current debugging level */
+
+ extern void extra_debugging(const struct connection *c);
+
+# define reset_debugging() { cur_debugging = base_debugging; }
+
+# define GLOBALS_ARE_RESET() (whack_log_fd == NULL_FD \
+ && cur_state == NULL \
+ && cur_connection == NULL \
+ && cur_from == NULL \
+ && cur_debugging == base_debugging)
+
+#else /*!DEBUG*/
+
+# define extra_debugging(c) { }
+
+# define reset_debugging() { }
+
+# define GLOBALS_ARE_RESET() (whack_log_fd == NULL_FD \
+ && cur_state == NULL \
+ && cur_connection == NULL \
+ && cur_from == NULL)
+
+#endif /*!DEBUG*/
+
+#define reset_globals() { \
+ whack_log_fd = NULL_FD; \
+ cur_state = NULL; \
+ cur_from = NULL; \
+ reset_cur_connection(); \
+ }
+
+
+#define set_cur_connection(c) { \
+ cur_connection = (c); \
+ extra_debugging(c); \
+ }
+
+#define reset_cur_connection() { \
+ cur_connection = NULL; \
+ reset_debugging(); \
+ }
+
+
+#define set_cur_state(s) { \
+ cur_state = (s); \
+ extra_debugging((s)->st_connection); \
+ }
+
+#define reset_cur_state() { \
+ cur_state = NULL; \
+ reset_debugging(); \
+ }
+
+extern void init_log(const char *program);
+extern void close_log(void);
+extern void plog(const char *message, ...) PRINTF_LIKE(1);
+extern void exit_log(const char *message, ...) PRINTF_LIKE(1) NEVER_RETURNS;
+
+/* close of all per-peer logging */
+extern void close_peerlog(void);
+
+/* free all per-peer log resources */
+extern void perpeer_logfree(struct connection *c);
+
+
+
+/* the following routines do a dance to capture errno before it is changed
+ * A call must doubly parenthesize the argument list (no varargs macros).
+ * The first argument must be "e", the local variable that captures errno.
+ */
+#define log_errno(a) { int e = errno; log_errno_routine a; }
+extern void log_errno_routine(int e, const char *message, ...) PRINTF_LIKE(2);
+#define exit_log_errno(a) { int e = errno; exit_log_errno_routine a; }
+extern void exit_log_errno_routine(int e, const char *message, ...) PRINTF_LIKE(2) NEVER_RETURNS NEVER_RETURNS;
+
+extern void whack_log(int mess_no, const char *message, ...) PRINTF_LIKE(2);
+
+/* Log to both main log and whack log
+ * Much like log, actually, except for specifying mess_no.
+ */
+extern void loglog(int mess_no, const char *message, ...) PRINTF_LIKE(2);
+
+/* show status, usually on whack log */
+extern void show_status(bool all, const char *name);
+
+/* Build up a diagnostic in a static buffer.
+ * Although this would be a generally useful function, it is very
+ * hard to come up with a discipline that prevents different uses
+ * from interfering. It is intended that by limiting it to building
+ * diagnostics, we will avoid this problem.
+ * Juggling is performed to allow an argument to be a previous
+ * result: the new string may safely depend on the old one. This
+ * restriction is not checked in any way: violators will produce
+ * confusing results (without crashing!).
+ */
+extern char diag_space[LOG_WIDTH]; /* output buffer, but can be occupied at call */
+extern err_t builddiag(const char *fmt, ...) PRINTF_LIKE(1);
+
+#ifdef DEBUG
+
+extern lset_t base_debugging; /* bits selecting what to report */
+
+#define DBGP(cond) (cur_debugging & (cond))
+#define DBG(cond, action) { if (DBGP(cond)) { action ; } }
+
+extern void DBG_log(const char *message, ...) PRINTF_LIKE(1);
+extern void DBG_dump(const char *label, const void *p, size_t len);
+#define DBG_dump_chunk(label, ch) DBG_dump(label, (ch).ptr, (ch).len)
+
+#else /*!DEBUG*/
+
+#define DBG(cond, action) { } /* do nothing */
+
+#endif /*!DEBUG*/
+
+#define DBG_cond_dump(cond, label, p, len) DBG(cond, DBG_dump(label, p, len))
+#define DBG_cond_dump_chunk(cond, label, ch) DBG(cond, DBG_dump_chunk(label, ch))
+
+
+/* ip_str: a simple to use variant of addrtot.
+ * It stores its result in a static buffer.
+ * This means that newer calls overwrite the storage of older calls.
+ * Note: this is not used in any of the logging functions, so their
+ * callers may use it.
+ */
+extern const char *ip_str(const ip_address *src);
+
+/*
+ * call this routine to reset daily items.
+ */
+extern void daily_log_reset(void);
+extern void daily_log_event(void);
+
+/*
+ * some events are to be logged only occasionally.
+ */
+extern bool logged_txt_warning;
+extern bool logged_myid_ip_txt_warning;
+extern bool logged_myid_ip_key_warning;
+extern bool logged_myid_fqdn_txt_warning;
+extern bool logged_myid_fqdn_key_warning;
diff --git a/src/pluto/md2.c b/src/pluto/md2.c
new file mode 100644
index 000000000..d6465477d
--- /dev/null
+++ b/src/pluto/md2.c
@@ -0,0 +1,237 @@
+/* MD2C.C - RSA Data Security, Inc., MD2 message-digest algorithm
+ */
+
+/* Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
+ rights reserved.
+
+ License to copy and use this software is granted for
+ non-commercial Internet Privacy-Enhanced Mail provided that it is
+ identified as the "RSA Data Security, Inc. MD2 Message Digest
+ Algorithm" in all material mentioning or referencing this software
+ or this function.
+
+ RSA Data Security, Inc. makes no representations concerning either
+ the merchantability of this software or the suitability of this
+ software for any particular purpose. It is provided "as is"
+ without express or implied warranty of any kind.
+
+ These notices must be retained in any copies of any part of this
+ documentation and/or software.
+ */
+
+#include "md2.h"
+
+#define HAVEMEMCOPY 1 /* use ISO C's memcpy and memset */
+
+static void MD2Transform PROTO_LIST
+ ((unsigned char [16], unsigned char [16], const unsigned char [16]));
+
+#ifdef HAVEMEMCOPY
+#include <memory.h>
+#define MD2_memcpy memcpy
+#define MD2_memset memset
+#else
+#ifdef HAVEBCOPY
+#define MD2_memcpy(_a,_b,_c) memcpy((_a), (_b),(_c))
+#define MD2_memset(_a,_b,_c) memset((_a), '\0',(_c))
+#else
+static void MD2_memcpy PROTO_LIST ((POINTER, CONST_POINTER, unsigned int));
+static void MD2_memset PROTO_LIST ((POINTER, int, unsigned int));
+#endif
+#endif
+
+/* Permutation of 0..255 constructed from the digits of pi. It gives a
+ "random" nonlinear byte substitution operation.
+ */
+static unsigned char PI_SUBST[256] = {
+ 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
+ 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
+ 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
+ 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
+ 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
+ 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
+ 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
+ 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
+ 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
+ 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
+ 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
+ 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
+ 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
+ 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
+ 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
+ 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
+ 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
+ 31, 26, 219, 153, 141, 51, 159, 17, 131, 20
+};
+
+static const unsigned char *PADDING[] = {
+ (const unsigned char *)"",
+ (const unsigned char *)"\001",
+ (const unsigned char *)"\002\002",
+ (const unsigned char *)"\003\003\003",
+ (const unsigned char *)"\004\004\004\004",
+ (const unsigned char *)"\005\005\005\005\005",
+ (const unsigned char *)"\006\006\006\006\006\006",
+ (const unsigned char *)"\007\007\007\007\007\007\007",
+ (const unsigned char *)"\010\010\010\010\010\010\010\010",
+ (const unsigned char *)"\011\011\011\011\011\011\011\011\011",
+ (const unsigned char *)"\012\012\012\012\012\012\012\012\012\012",
+ (const unsigned char *)"\013\013\013\013\013\013\013\013\013\013\013",
+ (const unsigned char *)"\014\014\014\014\014\014\014\014\014\014\014\014",
+ (const unsigned char *)
+ "\015\015\015\015\015\015\015\015\015\015\015\015\015",
+ (const unsigned char *)
+ "\016\016\016\016\016\016\016\016\016\016\016\016\016\016",
+ (const unsigned char *)
+ "\017\017\017\017\017\017\017\017\017\017\017\017\017\017\017",
+ (const unsigned char *)
+ "\020\020\020\020\020\020\020\020\020\020\020\020\020\020\020\020"
+};
+
+/* MD2 initialization. Begins an MD2 operation, writing a new context.
+ */
+void MD2Init (context)
+MD2_CTX *context; /* context */
+{
+ context->count = 0;
+ MD2_memset ((POINTER)context->state, 0, sizeof (context->state));
+ MD2_memset
+ ((POINTER)context->checksum, 0, sizeof (context->checksum));
+}
+
+/* MD2 block update operation. Continues an MD2 message-digest
+ operation, processing another message block, and updating the
+ context.
+ */
+void MD2Update (context, input, inputLen)
+MD2_CTX *context; /* context */
+const unsigned char *input; /* input block */
+unsigned int inputLen; /* length of input block */
+{
+ unsigned int i, index, partLen;
+
+ /* Update number of bytes mod 16 */
+ index = context->count;
+ context->count = (index + inputLen) & 0xf;
+
+ partLen = 16 - index;
+
+ /* Transform as many times as possible.
+ */
+ if (inputLen >= partLen) {
+ MD2_memcpy
+ ((POINTER)&context->buffer[index], (CONST_POINTER)input, partLen);
+ MD2Transform (context->state, context->checksum, context->buffer);
+
+ for (i = partLen; i + 15 < inputLen; i += 16)
+ MD2Transform (context->state, context->checksum, &input[i]);
+
+ index = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ MD2_memcpy
+ ((POINTER)&context->buffer[index], (CONST_POINTER)&input[i],
+ inputLen-i);
+}
+
+/* MD2 finalization. Ends an MD2 message-digest operation, writing the
+ message digest and zeroizing the context.
+ */
+void MD2Final (digest, context)
+
+unsigned char digest[16]; /* message digest */
+MD2_CTX *context; /* context */
+{
+ unsigned int index, padLen;
+
+ /* Pad out to multiple of 16.
+ */
+ index = context->count;
+ padLen = 16 - index;
+ MD2Update (context, PADDING[padLen], padLen);
+
+ /* Extend with checksum */
+ MD2Update (context, context->checksum, 16);
+
+ /* Store state in digest */
+ MD2_memcpy ((POINTER)digest, (POINTER)context->state, 16);
+
+ /* Zeroize sensitive information.
+ */
+ MD2_memset ((POINTER)context, 0, sizeof (*context));
+}
+
+/* MD2 basic transformation. Transforms state and updates checksum
+ based on block.
+ */
+static void MD2Transform (state, checksum, block)
+unsigned char state[16];
+unsigned char checksum[16];
+const unsigned char block[16];
+{
+ unsigned int i, j, t;
+ unsigned char x[48];
+
+ /* Form encryption block from state, block, state ^ block.
+ */
+ MD2_memcpy ((POINTER)x, (CONST_POINTER)state, 16);
+ MD2_memcpy ((POINTER)x+16, (CONST_POINTER)block, 16);
+ for (i = 0; i < 16; i++)
+ x[i+32] = state[i] ^ block[i];
+
+ /* Encrypt block (18 rounds).
+ */
+ t = 0;
+ for (i = 0; i < 18; i++) {
+ for (j = 0; j < 48; j++)
+ t = x[j] ^= PI_SUBST[t];
+ t = (t + i) & 0xff;
+ }
+
+ /* Save new state */
+ MD2_memcpy ((POINTER)state, (POINTER)x, 16);
+
+ /* Update checksum.
+ */
+ t = checksum[15];
+ for (i = 0; i < 16; i++)
+ t = checksum[i] ^= PI_SUBST[block[i] ^ t];
+
+ /* Zeroize sensitive information.
+ */
+ MD2_memset ((POINTER)x, 0, sizeof (x));
+}
+
+#ifndef HAVEMEMCOPY
+#ifndef HAVEBCOPY
+/* Note: Replace "for loop" with standard memcpy if possible.
+ */
+static void MD2_memcpy (output, input, len)
+POINTER output;
+POINTER input;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ output[i] = input[i];
+}
+
+/* Note: Replace "for loop" with standard memset if possible.
+ */
+static void MD2_memset (output, value, len)
+POINTER output;
+int value;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ ((char *)output)[i] = (char)value;
+}
+#endif
+#endif
+
diff --git a/src/pluto/md2.h b/src/pluto/md2.h
new file mode 100644
index 000000000..b3b48dd92
--- /dev/null
+++ b/src/pluto/md2.h
@@ -0,0 +1,72 @@
+#ifndef _GLOBAL_H_
+#define _GLOBAL_H_
+/* GLOBAL.H - RSAREF types and constants
+ */
+
+/* PROTOTYPES should be set to one if and only if the compiler supports
+ function argument prototyping.
+ The following makes PROTOTYPES default to 0 if it has not already
+ been defined with C compiler flags.
+ */
+#ifndef PROTOTYPES
+#define PROTOTYPES 1
+#endif
+
+/* POINTER defines a generic pointer type */
+typedef unsigned char *POINTER;
+typedef const unsigned char *CONST_POINTER;
+
+/* UINT2 defines a two byte word */
+typedef unsigned short int UINT2;
+
+/* UINT4 defines a four byte word */
+typedef unsigned long int UINT4;
+
+/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
+ If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
+ returns an empty list.
+ */
+
+#if PROTOTYPES
+#define PROTO_LIST(list) list
+#else
+#define PROTO_LIST(list) ()
+#endif
+
+#endif
+
+/* MD2.H - header file for MD2C.C
+ */
+
+/* Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
+ rights reserved.
+
+ License to copy and use this software is granted for
+ non-commercial Internet Privacy-Enhanced Mail provided that it is
+ identified as the "RSA Data Security, Inc. MD2 Message Digest
+ Algorithm" in all material mentioning or referencing this software
+ or this function.
+
+ RSA Data Security, Inc. makes no representations concerning either
+ the merchantability of this software or the suitability of this
+ software for any particular purpose. It is provided "as is"
+ without express or implied warranty of any kind.
+
+ These notices must be retained in any copies of any part of this
+ documentation and/or software.
+ */
+
+/* MD2 context. */
+typedef struct {
+ unsigned char state[16]; /* state */
+ unsigned char checksum[16]; /* checksum */
+ unsigned int count; /* number of bytes, modulo 16 */
+ unsigned char buffer[16]; /* input buffer */
+} MD2_CTX;
+
+void MD2Init PROTO_LIST ((MD2_CTX *));
+void MD2Update PROTO_LIST
+ ((MD2_CTX *, const unsigned char *, unsigned int));
+void MD2Final PROTO_LIST ((unsigned char [16], MD2_CTX *));
+
+#define _MD2_H_
diff --git a/src/pluto/md5.c b/src/pluto/md5.c
new file mode 100644
index 000000000..5d75e38a4
--- /dev/null
+++ b/src/pluto/md5.c
@@ -0,0 +1,385 @@
+/*
+ * The rest of the code is derived from MD5C.C by RSADSI. Minor cosmetic
+ * changes to accomodate it in the kernel by ji.
+ * Minor changes to make 64 bit clean by Peter Onion (i.e. using u_int*_t).
+ */
+
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+/*
+ * Additions by JI
+ *
+ * HAVEMEMCOPY is defined if mem* routines are available
+ *
+ * HAVEHTON is defined if htons() and htonl() can be used
+ * for big/little endian conversions
+ *
+ */
+
+#include <stddef.h>
+#include <string.h>
+#include <sys/types.h> /* for u_int*_t */
+#include <endian.h> /* sets BYTE_ORDER, LITTLE_ENDIAN, and BIG_ENDIAN */
+
+#include "md5.h"
+
+#define HAVEMEMCOPY 1 /* use ISO C's memcpy and memset */
+
+/* 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
+
+#define MD5Transform _MD5Transform
+
+static void MD5Transform PROTO_LIST ((UINT4 [4], const unsigned char [64]));
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define Encode MD5_memcpy
+#define Decode MD5_memcpy
+#else
+static void Encode PROTO_LIST
+ ((unsigned char *, UINT4 *, unsigned int));
+static void Decode PROTO_LIST
+ ((UINT4 *, unsigned char *, unsigned int));
+#endif
+
+#ifdef HAVEMEMCOPY
+#include <memory.h>
+#define MD5_memcpy memcpy
+#define MD5_memset memset
+#else
+#ifdef HAVEBCOPY
+#define MD5_memcpy(_a,_b,_c) memcpy((_a), (_b),(_c))
+#define MD5_memset(_a,_b,_c) memset((_a), '\0',(_c))
+#else
+static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
+static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
+#endif
+#endif
+static unsigned char 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
+};
+
+/* 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) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+void MD5Init (context)
+MD5_CTX *context; /* context */
+{
+ context->count[0] = context->count[1] = 0;
+ /* Load magic initialization constants.
+*/
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+ operation, processing another message block, and updating the
+ context.
+ */
+void MD5Update (context, input, inputLen)
+MD5_CTX *context; /* context */
+const unsigned char *input; /* input block */
+UINT4 inputLen; /* length of input block */
+{
+ UINT4 i;
+ unsigned int index, partLen;
+
+ /* Compute number of bytes mod 64 */
+ index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((context->count[0] += (inputLen << 3)) < (inputLen << 3))
+ context->count[1]++;
+ context->count[1] += (inputLen >> 29);
+
+ partLen = 64 - index;
+
+ /* Transform as many times as possible. */
+ if (inputLen >= partLen) {
+ MD5_memcpy((POINTER)&context->buffer[index], (CONSTPOINTER)input, partLen);
+ MD5Transform (context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ MD5Transform (context->state, &input[i]);
+
+ index = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ MD5_memcpy((POINTER)&context->buffer[index], (CONSTPOINTER)&input[i], inputLen-i);
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+ the message digest and zeroizing the context.
+ */
+void MD5Final (digest, context)
+unsigned char digest[16]; /* message digest */
+MD5_CTX *context; /* context */
+{
+ unsigned char bits[8];
+ unsigned int index, padLen;
+
+ /* Save number of bits */
+ Encode (bits, context->count, 8);
+
+ /* Pad out to 56 mod 64.
+*/
+ index = (unsigned int)((context->count[0] >> 3) & 0x3f);
+ padLen = (index < 56) ? (56 - index) : (120 - index);
+ MD5Update (context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ MD5Update (context, bits, 8);
+
+ if (digest != NULL) /* Bill Simpson's padding */
+ {
+ /* store state in digest */
+ Encode (digest, context->state, 16);
+
+ /* Zeroize sensitive information.
+ */
+ MD5_memset ((POINTER)context, 0, sizeof (*context));
+ }
+}
+
+/* MD5 basic transformation. Transforms state based on block.
+ */
+static void MD5Transform (state, block)
+UINT4 state[4];
+const unsigned char block[64];
+{
+ UINT4 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;
+
+ /* Zeroize sensitive information.
+*/
+ MD5_memset ((POINTER)x, 0, sizeof (x));
+}
+
+#if BYTE_ORDER != LITTLE_ENDIAN
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+ a multiple of 4.
+ */
+static void Encode (output, input, len)
+unsigned char *output;
+UINT4 *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+ }
+}
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+ a multiple of 4.
+ */
+static void Decode (output, input, len)
+UINT4 *output;
+unsigned char *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+ (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
+#endif
+
+#ifndef HAVEMEMCOPY
+#ifndef HAVEBCOPY
+/* Note: Replace "for loop" with standard memcpy if possible.
+ */
+
+static void MD5_memcpy (output, input, len)
+POINTER output;
+POINTER input;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+
+ output[i] = input[i];
+}
+
+/* Note: Replace "for loop" with standard memset if possible.
+ */
+static void MD5_memset (output, value, len)
+POINTER output;
+int value;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ ((char *)output)[i] = (char)value;
+}
+#endif
+#endif
+
diff --git a/src/pluto/md5.h b/src/pluto/md5.h
new file mode 100644
index 000000000..9b29bc46e
--- /dev/null
+++ b/src/pluto/md5.h
@@ -0,0 +1,75 @@
+#ifndef _GLOBAL_H_
+#define _GLOBAL_H_
+/* GLOBAL.H - RSAREF types and constants
+ */
+
+/* PROTOTYPES should be set to one if and only if the compiler supports
+ function argument prototyping.
+ The following makes PROTOTYPES default to 0 if it has not already
+ been defined with C compiler flags.
+ */
+#ifndef PROTOTYPES
+#define PROTOTYPES 1
+#endif
+
+/* POINTER defines a generic pointer type */
+typedef unsigned char *POINTER;
+typedef const unsigned char *CONSTPOINTER;
+
+/* UINT2 defines a two byte word */
+typedef u_int16_t UINT2;
+
+/* UINT4 defines a four byte word */
+typedef u_int32_t UINT4;
+
+/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
+ If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
+ returns an empty list.
+ */
+
+#if PROTOTYPES
+#define PROTO_LIST(list) list
+#else
+#define PROTO_LIST(list) ()
+#endif
+
+#endif
+
+/* MD5.H - header file for MD5C.C
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+/* MD5 context. */
+typedef struct {
+ UINT4 state[4]; /* state (ABCD) */
+ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[64]; /* input buffer */
+} MD5_CTX;
+
+void MD5Init PROTO_LIST ((MD5_CTX *));
+void MD5Update PROTO_LIST
+ ((MD5_CTX *, const unsigned char *, UINT4));
+void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
+
+#define _MD5_H_
diff --git a/src/pluto/modecfg.c b/src/pluto/modecfg.c
new file mode 100644
index 000000000..ab44a113e
--- /dev/null
+++ b/src/pluto/modecfg.c
@@ -0,0 +1,1078 @@
+/* Mode config related functions
+ * Copyright (C) 2001-2002 Colubris Networks
+ * Copyright (C) 2003 Sean Mathews - Nu Tech Software Solutions, inc.
+ * Copyright (C) 2003-2004 Xelerance Corporation
+ * Copyright (C) 2006-2007 Andreas Steffen - Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: modecfg.c,v 1.6 2006/04/24 20:44:57 as Exp $
+ *
+ * This code originally written by Colubris Networks, Inc.
+ * Extraction of patch and porting to 1.99 codebases by Xelerance Corporation
+ * Porting to 2.x by Sean Mathews
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "state.h"
+#include "demux.h"
+#include "timer.h"
+#include "ipsec_doi.h"
+#include "log.h"
+#include "md5.h"
+#include "sha1.h"
+#include "crypto.h"
+#include "modecfg.h"
+#include "whack.h"
+#include "xauth.h"
+
+#define MAX_XAUTH_TRIES 3
+
+#define SUPPORTED_ATTR_SET ( LELEM(INTERNAL_IP4_ADDRESS) \
+ | LELEM(INTERNAL_IP4_NETMASK) \
+ | LELEM(INTERNAL_IP4_DNS) \
+ | LELEM(INTERNAL_IP4_NBNS) \
+ | LELEM(APPLICATION_VERSION) \
+ )
+
+#define SUPPORTED_UNITY_ATTR_SET ( LELEM(UNITY_BANNER - UNITY_BASE) )
+
+#define UNITY_BANNER_STR "Welcome to strongSwan - the Linux VPN Solution!\n"
+
+/*
+ * Addresses assigned (usually via ModeCfg) to the Initiator
+ */
+typedef struct internal_addr internal_addr_t;
+
+struct internal_addr
+{
+ lset_t attr_set;
+ lset_t xauth_attr_set;
+ lset_t unity_attr_set;
+
+ /* ModeCfg variables */
+ ip_address ipaddr;
+ ip_address dns[2];
+ ip_address wins[2];
+
+ char *unity_banner;
+
+ /* XAUTH variables */
+ u_int16_t xauth_type;
+ xauth_t xauth_secret;
+ bool xauth_status;
+};
+
+/*
+ * Initialize an internal_addr struct
+ */
+static void
+init_internal_addr(internal_addr_t *ia)
+{
+ ia->attr_set = LEMPTY;
+ ia->xauth_attr_set = LEMPTY;
+ ia->xauth_secret.user_name = empty_chunk;
+ ia->xauth_secret.user_password = empty_chunk;
+ ia->xauth_type = XAUTH_TYPE_GENERIC;
+ ia->xauth_status = XAUTH_STATUS_FAIL;
+ ia->unity_attr_set = LEMPTY;
+ ia->unity_banner = NULL;
+
+ anyaddr(AF_INET, &ia->ipaddr);
+ anyaddr(AF_INET, &ia->dns[0]);
+ anyaddr(AF_INET, &ia->dns[1]);
+ anyaddr(AF_INET, &ia->wins[0]);
+ anyaddr(AF_INET, &ia->wins[1]);
+}
+
+/*
+ * get internal IP address for a connection
+ */
+static void
+get_internal_addr(struct connection *c, internal_addr_t *ia)
+{
+ if (isanyaddr(&c->spd.that.host_srcip))
+ {
+ /* not defined in connection - fetch it from LDAP */
+ }
+ else
+ {
+ char srcip[ADDRTOT_BUF];
+
+ ia->ipaddr = c->spd.that.host_srcip;
+
+ addrtot(&ia->ipaddr, 0, srcip, sizeof(srcip));
+ plog("assigning virtual IP source address %s", srcip);
+ }
+
+ if (!isanyaddr(&ia->ipaddr)) /* We got an IP address, send it */
+ {
+ c->spd.that.client.addr = ia->ipaddr;
+ c->spd.that.client.maskbits = 32;
+ c->spd.that.has_client = TRUE;
+
+ ia->attr_set = LELEM(INTERNAL_IP4_ADDRESS)
+ | LELEM(INTERNAL_IP4_NETMASK);
+ }
+
+ if (!isanyaddr(&ia->dns[0])) /* We got DNS addresses, send them */
+ ia->attr_set |= LELEM(INTERNAL_IP4_DNS);
+
+ if (!isanyaddr(&ia->wins[0])) /* We got WINS addresses, send them */
+ ia->attr_set |= LELEM(INTERNAL_IP4_NBNS);
+}
+
+/*
+ * Set srcip and client subnet to internal IP address
+ */
+static bool
+set_internal_addr(struct connection *c, internal_addr_t *ia)
+{
+ if (ia->attr_set & LELEM(INTERNAL_IP4_ADDRESS)
+ && !isanyaddr(&ia->ipaddr))
+ {
+ if (addrbytesptr(&c->spd.this.host_srcip, NULL) == 0
+ || isanyaddr(&c->spd.this.host_srcip)
+ || sameaddr(&c->spd.this.host_srcip, &ia->ipaddr))
+ {
+ char srcip[ADDRTOT_BUF];
+
+ addrtot(&ia->ipaddr, 0, srcip, sizeof(srcip));
+ plog("setting virtual IP source address to %s", srcip);
+ }
+ else
+ {
+ char old_srcip[ADDRTOT_BUF];
+ char new_srcip[ADDRTOT_BUF];
+
+ addrtot(&c->spd.this.host_srcip, 0, old_srcip, sizeof(old_srcip));
+ addrtot(&ia->ipaddr, 0, new_srcip, sizeof(new_srcip));
+ plog("replacing virtual IP source address %s by %s"
+ , old_srcip, new_srcip);
+ }
+
+ /* setting srcip */
+ c->spd.this.host_srcip = ia->ipaddr;
+
+ /* setting client subnet to srcip/32 */
+ addrtosubnet(&ia->ipaddr, &c->spd.this.client);
+ setportof(0, &c->spd.this.client.addr);
+ c->spd.this.has_client = TRUE;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Compute HASH of Mode Config.
+ */
+static size_t
+modecfg_hash(u_char *dest, const u_char *start, const u_char *roof
+ , const struct state *st)
+{
+ struct hmac_ctx ctx;
+
+ hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid_a);
+ hmac_update(&ctx, (const u_char *) &st->st_msgid, sizeof(st->st_msgid));
+ hmac_update(&ctx, start, roof-start);
+ hmac_final(dest, &ctx);
+
+ DBG(DBG_CRYPT,
+ DBG_log("ModeCfg HASH computed:");
+ DBG_dump("", dest, ctx.hmac_digest_size)
+ )
+ return ctx.hmac_digest_size;
+}
+
+
+/*
+ * Generate an IKE message containing ModeCfg information (eg: IP, DNS, WINS)
+ */
+static stf_status
+modecfg_build_msg(struct state *st, pb_stream *rbody
+ , u_int16_t msg_type
+ , internal_addr_t *ia
+ , u_int16_t ap_id)
+{
+ u_char *r_hash_start, *r_hashval;
+
+ START_HASH_PAYLOAD(*rbody, ISAKMP_NEXT_ATTR);
+
+ /* ATTR out */
+ {
+ struct isakmp_mode_attr attrh;
+ struct isakmp_attribute attr;
+ pb_stream strattr,attrval;
+ int attr_type;
+ int dns_idx, wins_idx;
+ bool dont_advance;
+ bool is_xauth_attr_set = ia->xauth_attr_set != LEMPTY;
+ bool is_unity_attr_set = ia->unity_attr_set != LEMPTY;
+ lset_t attr_set = ia->attr_set;
+
+ attrh.isama_np = ISAKMP_NEXT_NONE;
+ attrh.isama_type = msg_type;
+ attrh.isama_identifier = ap_id;
+
+ if (!out_struct(&attrh, &isakmp_attr_desc, rbody, &strattr))
+ return STF_INTERNAL_ERROR;
+
+ attr_type = 0;
+ dns_idx = 0;
+ wins_idx = 0;
+
+ while (attr_set != LEMPTY || is_xauth_attr_set || is_unity_attr_set)
+ {
+ if (attr_set == LEMPTY)
+ {
+ if (is_xauth_attr_set)
+ {
+ attr_set = ia->xauth_attr_set;
+ attr_type = XAUTH_BASE;
+ is_xauth_attr_set = FALSE;
+ }
+ else
+ {
+ attr_set = ia->unity_attr_set;
+ attr_type = UNITY_BASE;
+ is_unity_attr_set = FALSE;
+ }
+ }
+
+ dont_advance = FALSE;
+
+ if (attr_set & 1)
+ {
+ const u_char *byte_ptr;
+ u_int len;
+
+ /* ISAKMP attr out */
+ if (attr_type == XAUTH_TYPE)
+ {
+ attr.isaat_af_type = attr_type | ISAKMP_ATTR_AF_TV;
+ attr.isaat_lv = ia->xauth_type;
+ }
+ else if (attr_type == XAUTH_STATUS)
+ {
+ attr.isaat_af_type = attr_type | ISAKMP_ATTR_AF_TV;
+ attr.isaat_lv = ia->xauth_status;
+ }
+ else
+ {
+ attr.isaat_af_type = attr_type | ISAKMP_ATTR_AF_TLV;
+ }
+ out_struct(&attr, &isakmp_modecfg_attribute_desc, &strattr, &attrval);
+
+ switch (attr_type)
+ {
+ case INTERNAL_IP4_ADDRESS:
+ if (!isanyaddr(&ia->ipaddr))
+ {
+ len = addrbytesptr(&ia->ipaddr, &byte_ptr);
+ out_raw(byte_ptr, len, &attrval, "IP4_addr");
+ }
+ break;
+ case INTERNAL_IP4_NETMASK:
+ {
+ u_int mask;
+#if 0
+ char mask[4],bits[8]={0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe};
+ int t,m=st->st_connection->that.host_addr.maskbit;
+ for (t=0; t<4; t++)
+ {
+ if (m < 8)
+ mask[t] = bits[m];
+ else
+ mask[t] = 0xff;
+ m -= 8;
+ }
+#endif
+ if (st->st_connection->spd.this.client.maskbits == 0)
+ mask = 0;
+ else
+ mask = 0xffffffff * 1;
+ out_raw(&mask, 4, &attrval, "IP4_mask");
+ }
+ break;
+ case INTERNAL_IP4_SUBNET:
+ {
+ char mask[4];
+ char bits[8] = {0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe};
+ int t;
+ int m = st->st_connection->spd.this.client.maskbits;
+
+ for (t = 0; t < 4; t++)
+ {
+ if (m < 8)
+ mask[t] = bits[m];
+ else
+ mask[t] = 0xff;
+ m -= 8;
+ if (m < 0)
+ m = 0;
+ }
+ len = addrbytesptr(&st->st_connection->spd.this.client.addr, &byte_ptr);
+ out_raw(byte_ptr, len, &attrval, "IP4_subnet");
+ out_raw(mask, sizeof(mask), &attrval, "IP4_submsk");
+ }
+ break;
+ case INTERNAL_IP4_DNS:
+ if (!isanyaddr(&ia->dns[dns_idx]))
+ {
+ len = addrbytesptr(&ia->dns[dns_idx++], &byte_ptr);
+ out_raw(byte_ptr, len, &attrval, "IP4_dns");
+ }
+ if (dns_idx < 2 && !isanyaddr(&ia->dns[dns_idx]))
+ {
+ dont_advance = TRUE;
+ }
+ break;
+ case INTERNAL_IP4_NBNS:
+ if (!isanyaddr(&ia->wins[wins_idx]))
+ {
+ len = addrbytesptr(&ia->wins[wins_idx++], &byte_ptr);
+ out_raw(byte_ptr, len, &attrval, "IP4_wins");
+ }
+ if (wins_idx < 2 && !isanyaddr(&ia->wins[wins_idx]))
+ {
+ dont_advance = TRUE;
+ }
+ break;
+ case XAUTH_TYPE:
+ break;
+ case XAUTH_USER_NAME:
+ if (ia->xauth_secret.user_name.ptr != NULL)
+ {
+ out_raw(ia->xauth_secret.user_name.ptr
+ , ia->xauth_secret.user_name.len
+ , &attrval, "xauth_user_name");
+ }
+ break;
+ case XAUTH_USER_PASSWORD:
+ if (ia->xauth_secret.user_password.ptr != NULL)
+ {
+ out_raw(ia->xauth_secret.user_password.ptr
+ , ia->xauth_secret.user_password.len
+ , &attrval, "xauth_user_password");
+ }
+ break;
+ case XAUTH_STATUS:
+ break;
+ case UNITY_BANNER:
+ if (ia->unity_banner != NULL)
+ {
+ out_raw(ia->unity_banner
+ , strlen(ia->unity_banner)
+ , &attrval, "UNITY_BANNER");
+ }
+ break;
+ default:
+ plog("attempt to send unsupported mode cfg attribute %s."
+ , enum_show(&modecfg_attr_names, attr_type));
+ break;
+ }
+ close_output_pbs(&attrval);
+ }
+ if (!dont_advance)
+ {
+ attr_type++;
+ attr_set >>= 1;
+ }
+ }
+ close_message(&strattr);
+ }
+
+ modecfg_hash(r_hashval, r_hash_start, rbody->cur, st);
+ close_message(rbody);
+ encrypt_message(rbody, st);
+ return STF_OK;
+}
+
+/*
+ * Send ModeCfg message
+ */
+static stf_status
+modecfg_send_msg(struct state *st, int isama_type, internal_addr_t *ia)
+{
+ pb_stream msg;
+ pb_stream rbody;
+ char buf[BUF_LEN];
+
+ /* set up attr */
+ init_pbs(&msg, buf, sizeof(buf), "ModeCfg msg buffer");
+
+ /* this is the beginning of a new exchange */
+ st->st_msgid = generate_msgid(st);
+ init_phase2_iv(st, &st->st_msgid);
+
+ /* HDR out */
+ {
+ struct isakmp_hdr hdr;
+
+ zero(&hdr); /* default to 0 */
+ hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION;
+ hdr.isa_np = ISAKMP_NEXT_HASH;
+ hdr.isa_xchg = ISAKMP_XCHG_MODE_CFG;
+ hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION;
+ memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE);
+ memcpy(hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE);
+ hdr.isa_msgid = st->st_msgid;
+
+ if (!out_struct(&hdr, &isakmp_hdr_desc, &msg, &rbody))
+ {
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+ /* ATTR out */
+ modecfg_build_msg(st, &rbody
+ , isama_type
+ , ia
+ , 0 /* XXX isama_id */
+ );
+
+ freeanychunk(st->st_tpacket);
+ clonetochunk(st->st_tpacket, msg.start, pbs_offset(&msg), "ModeCfg msg");
+
+ /* Transmit */
+ send_packet(st, "ModeCfg msg");
+
+ if (st->st_event->ev_type != EVENT_RETRANSMIT)
+ {
+ delete_event(st);
+ event_schedule(EVENT_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0, st);
+ }
+ return STF_OK;
+}
+
+/*
+ * Parse a ModeCfg attribute payload
+ */
+static stf_status
+modecfg_parse_attributes(pb_stream *attrs, internal_addr_t *ia)
+{
+ struct isakmp_attribute attr;
+ pb_stream strattr;
+
+ while (pbs_left(attrs) >= sizeof(struct isakmp_attribute))
+ {
+ u_int16_t attr_type;
+ u_int16_t attr_len;
+
+ if (!in_struct(&attr, &isakmp_modecfg_attribute_desc, attrs, &strattr))
+ {
+ return STF_FAIL;
+ }
+ attr_type = attr.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK;
+ attr_len = attr.isaat_lv;
+
+ switch (attr_type)
+ {
+ case INTERNAL_IP4_ADDRESS:
+ if (attr_len == 4)
+ {
+ initaddr((char *)(strattr.cur), 4, AF_INET, &ia->ipaddr);
+ }
+ /* fall through to set attribute flag */
+ case INTERNAL_IP4_NETMASK:
+ case INTERNAL_IP4_DNS:
+ case INTERNAL_IP4_SUBNET:
+ case INTERNAL_IP4_NBNS:
+ case INTERNAL_ADDRESS_EXPIRY:
+ case INTERNAL_IP4_DHCP:
+ case INTERNAL_IP6_ADDRESS:
+ case INTERNAL_IP6_NETMASK:
+ case INTERNAL_IP6_DNS:
+ case INTERNAL_IP6_NBNS:
+ case INTERNAL_IP6_DHCP:
+ case SUPPORTED_ATTRIBUTES:
+ case INTERNAL_IP6_SUBNET:
+ ia->attr_set |= LELEM(attr_type);
+ break;
+ case APPLICATION_VERSION:
+ if (attr_len > 0)
+ {
+ DBG(DBG_PARSING,
+ DBG_log(" '%.*s'", attr_len, strattr.cur)
+ )
+ }
+ ia->attr_set |= LELEM(attr_type);
+ break;
+ case XAUTH_TYPE:
+ ia->xauth_type = attr.isaat_lv;
+ ia->xauth_attr_set |= LELEM(attr_type - XAUTH_BASE);
+ break;
+ case XAUTH_USER_NAME:
+ setchunk(ia->xauth_secret.user_name, strattr.cur, attr_len);
+ ia->xauth_attr_set |= LELEM(attr_type - XAUTH_BASE);
+ break;
+ case XAUTH_USER_PASSWORD:
+ setchunk(ia->xauth_secret.user_password, strattr.cur, attr_len);
+ ia->xauth_attr_set |= LELEM(attr_type - XAUTH_BASE);
+ break;
+ case XAUTH_STATUS:
+ ia->xauth_status = attr.isaat_lv;
+ ia->xauth_attr_set |= LELEM(attr_type - XAUTH_BASE);
+ break;
+ case XAUTH_MESSAGE:
+ if (attr_len > 0)
+ {
+ DBG(DBG_PARSING,
+ DBG_log(" '%.*s'", attr_len, strattr.cur)
+ )
+ }
+ /* fall through to set attribute flag */
+ case XAUTH_PASSCODE:
+ case XAUTH_CHALLENGE:
+ case XAUTH_DOMAIN:
+ case XAUTH_NEXT_PIN:
+ case XAUTH_ANSWER:
+ ia->xauth_attr_set |= LELEM(attr_type - XAUTH_BASE);
+ break;
+ case UNITY_DDNS_HOSTNAME:
+ if (attr_len > 0)
+ {
+ DBG(DBG_PARSING,
+ DBG_log(" '%.*s'", attr_len, strattr.cur)
+ )
+ }
+ /* fall through to set attribute flag */
+ case UNITY_BANNER:
+ case UNITY_SAVE_PASSWD:
+ case UNITY_DEF_DOMAIN:
+ case UNITY_SPLITDNS_NAME:
+ case UNITY_SPLIT_INCLUDE:
+ case UNITY_NATT_PORT:
+ case UNITY_LOCAL_LAN:
+ case UNITY_PFS:
+ case UNITY_FW_TYPE:
+ case UNITY_BACKUP_SERVERS:
+ ia->unity_attr_set |= LELEM(attr_type - UNITY_BASE);
+ break;
+ default:
+ plog("unsupported ModeCfg attribute %s received."
+ , enum_show(&modecfg_attr_names, attr_type));
+ break;
+ }
+ }
+ return STF_OK;
+}
+
+/*
+ * Parse a ModeCfg message
+ */
+static stf_status
+modecfg_parse_msg(struct msg_digest *md, int isama_type, u_int16_t *isama_id
+ , internal_addr_t *ia)
+{
+ struct state *const st = md->st;
+ struct payload_digest *p;
+ stf_status stat;
+
+ st->st_msgid = md->hdr.isa_msgid;
+
+ CHECK_QUICK_HASH(md, modecfg_hash(hash_val
+ , hash_pbs->roof
+ , md->message_pbs.roof, st)
+ , "MODECFG-HASH", "ISAKMP_CFG_MSG");
+
+ /* process the ModeCfg payloads received */
+ for (p = md->chain[ISAKMP_NEXT_ATTR]; p != NULL; p = p->next)
+ {
+ internal_addr_t ia_candidate;
+
+ init_internal_addr(&ia_candidate);
+
+ if (p->payload.attribute.isama_type == isama_type)
+ {
+ *isama_id = p->payload.attribute.isama_identifier;
+
+ stat = modecfg_parse_attributes(&p->pbs, &ia_candidate);
+ if (stat == STF_OK)
+ {
+ /* return with a valid set of attributes */
+ *ia = ia_candidate;
+ return STF_OK;
+ }
+ }
+ else
+ {
+ plog("expected %s, got %s instead (ignored)"
+ , enum_name(&attr_msg_type_names, isama_type)
+ , enum_name(&attr_msg_type_names, p->payload.attribute.isama_type));
+
+ stat = modecfg_parse_attributes(&p->pbs, &ia_candidate);
+ }
+ if (stat != STF_OK)
+ return stat;
+ }
+ return STF_IGNORE;
+}
+
+/*
+ * Send ModeCfg request message from client to server in pull mode
+ */
+stf_status
+modecfg_send_request(struct state *st)
+{
+ stf_status stat;
+ internal_addr_t ia;
+
+ init_internal_addr(&ia);
+
+ ia.attr_set = LELEM(INTERNAL_IP4_ADDRESS)
+ | LELEM(INTERNAL_IP4_NETMASK);
+
+ plog("sending ModeCfg request");
+ st->st_state = STATE_MODE_CFG_I1;
+ stat = modecfg_send_msg(st, ISAKMP_CFG_REQUEST, &ia);
+ if (stat == STF_OK)
+ st->st_modecfg.started = TRUE;
+ return stat;
+}
+
+/* STATE_MODE_CFG_R0:
+ * HDR*, HASH, ATTR(REQ=IP) --> HDR*, HASH, ATTR(REPLY=IP)
+ *
+ * used in ModeCfg pull mode, on the server (responder)
+ */
+stf_status
+modecfg_inR0(struct msg_digest *md)
+{
+ struct state *const st = md->st;
+ u_int16_t isama_id;
+ internal_addr_t ia;
+ bool want_unity_banner;
+ stf_status stat, stat_build;
+
+ stat = modecfg_parse_msg(md, ISAKMP_CFG_REQUEST, &isama_id, &ia);
+ if (stat != STF_OK)
+ return stat;
+
+ want_unity_banner = (ia.unity_attr_set & LELEM(UNITY_BANNER - UNITY_BASE)) != LEMPTY;
+
+ init_internal_addr(&ia);
+ get_internal_addr(st->st_connection, &ia);
+
+ if (want_unity_banner)
+ {
+ ia.unity_banner = UNITY_BANNER_STR;
+ ia.unity_attr_set |= LELEM(UNITY_BANNER - UNITY_BASE);
+ }
+
+ plog("sending ModeCfg reply");
+
+ stat_build = modecfg_build_msg(st, &md->rbody
+ , ISAKMP_CFG_REPLY
+ , &ia
+ , isama_id);
+ if (stat_build != STF_OK)
+ return stat_build;
+
+ st->st_msgid = 0;
+ return STF_OK;
+}
+
+/* STATE_MODE_CFG_I1:
+ * HDR*, HASH, ATTR(REPLY=IP)
+ *
+ * used in ModeCfg pull mode, on the client (initiator)
+ */
+stf_status
+modecfg_inI1(struct msg_digest *md)
+{
+ struct state *const st = md->st;
+ u_int16_t isama_id;
+ internal_addr_t ia;
+ stf_status stat;
+
+ plog("parsing ModeCfg reply");
+
+ stat = modecfg_parse_msg(md, ISAKMP_CFG_REPLY, &isama_id, &ia);
+ if (stat != STF_OK)
+ return stat;
+
+ st->st_modecfg.vars_set = set_internal_addr(st->st_connection, &ia);
+ st->st_msgid = 0;
+ return STF_OK;
+}
+
+
+/*
+ * Send ModeCfg set message from server to client in push mode
+ */
+stf_status
+modecfg_send_set(struct state *st)
+{
+ stf_status stat;
+ internal_addr_t ia;
+
+ init_internal_addr(&ia);
+ get_internal_addr(st->st_connection, &ia);
+
+#ifdef CISCO_QUIRKS
+ ia.unity_banner = UNITY_BANNER_STR;
+ ia.unity_attr_set |= LELEM(UNITY_BANNER - UNITY_BASE);
+#endif
+
+ plog("sending ModeCfg set");
+ st->st_state = STATE_MODE_CFG_R3;
+ stat = modecfg_send_msg(st, ISAKMP_CFG_SET, &ia);
+ if (stat == STF_OK)
+ st->st_modecfg.started = TRUE;
+ return stat;
+}
+
+/* STATE_MODE_CFG_I0:
+ * HDR*, HASH, ATTR(SET=IP) --> HDR*, HASH, ATTR(ACK,OK)
+ *
+ * used in ModeCfg push mode, on the client (initiator).
+ */
+stf_status
+modecfg_inI0(struct msg_digest *md)
+{
+ struct state *const st = md->st;
+ u_int16_t isama_id;
+ internal_addr_t ia;
+ lset_t attr_set, unity_attr_set;
+ stf_status stat, stat_build;
+
+ plog("parsing ModeCfg set");
+
+ stat = modecfg_parse_msg(md, ISAKMP_CFG_SET, &isama_id, &ia);
+ if (stat != STF_OK)
+ return stat;
+
+ st->st_modecfg.vars_set = set_internal_addr(st->st_connection, &ia);
+
+ /* prepare ModeCfg ack which sends zero length attributes */
+ attr_set = ia.attr_set;
+ unity_attr_set = ia.unity_attr_set;
+ init_internal_addr(&ia);
+ ia.attr_set = attr_set & SUPPORTED_ATTR_SET;
+ ia.unity_attr_set = unity_attr_set & SUPPORTED_UNITY_ATTR_SET;
+
+ plog("sending ModeCfg ack");
+
+ stat_build = modecfg_build_msg(st, &md->rbody
+ , ISAKMP_CFG_ACK
+ , &ia
+ , isama_id);
+ if (stat_build != STF_OK)
+ return stat_build;
+
+ st->st_msgid = 0;
+ return STF_OK;
+}
+
+/* STATE_MODE_CFG_R3:
+ * HDR*, HASH, ATTR(ACK,OK)
+ *
+ * used in ModeCfg push mode, on the server (responder)
+ */
+stf_status
+modecfg_inR3(struct msg_digest *md)
+{
+ struct state *const st = md->st;
+ u_int16_t isama_id;
+ internal_addr_t ia;
+ stf_status stat;
+
+ plog("parsing ModeCfg ack");
+
+ stat = modecfg_parse_msg(md, ISAKMP_CFG_ACK, &isama_id, &ia);
+ if (stat != STF_OK)
+ return stat;
+
+ st->st_msgid = 0;
+ return STF_OK;
+}
+
+/*
+ * Send XAUTH credentials request (username + password)
+ */
+stf_status
+xauth_send_request(struct state *st)
+{
+ stf_status stat;
+ internal_addr_t ia;
+
+ init_internal_addr(&ia);
+ ia.xauth_attr_set = LELEM(XAUTH_USER_NAME - XAUTH_BASE)
+ | LELEM(XAUTH_USER_PASSWORD - XAUTH_BASE);
+
+ plog("sending XAUTH request");
+ st->st_state = STATE_XAUTH_R1;
+ stat = modecfg_send_msg(st, ISAKMP_CFG_REQUEST, &ia);
+ if (stat == STF_OK)
+ st->st_xauth.started = TRUE;
+ return stat;
+}
+
+/* STATE_XAUTH_I0:
+ * HDR*, HASH, ATTR(REQ) --> HDR*, HASH, ATTR(REPLY=USERNAME/PASSWORD)
+ *
+ * used on the XAUTH client (initiator)
+ */
+stf_status
+xauth_inI0(struct msg_digest *md)
+{
+ struct state *const st = md->st;
+ u_int16_t isama_id;
+ internal_addr_t ia;
+ stf_status stat, stat_build;
+ bool xauth_type_present;
+
+ plog("parsing XAUTH request");
+
+ stat = modecfg_parse_msg(md, ISAKMP_CFG_REQUEST, &isama_id, &ia);
+ if (stat != STF_OK)
+ return stat;
+
+ /* check XAUTH attributes */
+ xauth_type_present = (ia.xauth_attr_set & LELEM(XAUTH_TYPE - XAUTH_BASE)) != LEMPTY;
+
+ if (xauth_type_present && ia.xauth_type != XAUTH_TYPE_GENERIC)
+ {
+ plog("xauth type %s is not supported", enum_name(&xauth_type_names, ia.xauth_type));
+ stat = STF_FAIL;
+ }
+ else if ((ia.xauth_attr_set & LELEM(XAUTH_USER_NAME - XAUTH_BASE)) == LEMPTY)
+ {
+ plog("user name attribute is missing in XAUTH request");
+ stat = STF_FAIL;
+ }
+ else if ((ia.xauth_attr_set & LELEM(XAUTH_USER_PASSWORD - XAUTH_BASE)) == LEMPTY)
+ {
+ plog("user password attribute is missing in XAUTH request");
+ stat = STF_FAIL;
+ }
+
+ /* prepare XAUTH reply */
+ init_internal_addr(&ia);
+
+ if (stat == STF_OK)
+ {
+ /* get user credentials using a plugin function */
+ if (!xauth_module.get_secret(&ia.xauth_secret))
+ {
+ plog("xauth user credentials not found");
+ stat = STF_FAIL;
+ }
+ }
+ if (stat == STF_OK)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("my xauth user name is '%.*s'"
+ , ia.xauth_secret.user_name.len
+ , ia.xauth_secret.user_name.ptr)
+ )
+ DBG(DBG_PRIVATE,
+ DBG_log("my xauth user password is '%.*s'"
+ , ia.xauth_secret.user_password.len
+ , ia.xauth_secret.user_password.ptr)
+ )
+ ia.xauth_attr_set = LELEM(XAUTH_USER_NAME - XAUTH_BASE)
+ | LELEM(XAUTH_USER_PASSWORD - XAUTH_BASE);
+ if (xauth_type_present)
+ ia.xauth_attr_set |= LELEM(XAUTH_TYPE - XAUTH_BASE);
+ }
+ else
+ {
+ ia.xauth_attr_set = LELEM(XAUTH_STATUS - XAUTH_BASE);
+ ia.xauth_status = XAUTH_STATUS_FAIL;
+ }
+
+ plog("sending XAUTH reply");
+
+ stat_build = modecfg_build_msg(st, &md->rbody
+ , ISAKMP_CFG_REPLY
+ , &ia
+ , isama_id);
+ if (stat_build != STF_OK)
+ return stat_build;
+
+ if (stat == STF_OK)
+ {
+ st->st_xauth.started = TRUE;
+ st->st_msgid = 0;
+ return STF_OK;
+ }
+ else
+ {
+ /* send XAUTH reply msg and then delete ISAKMP SA */
+ freeanychunk(st->st_tpacket);
+ clonetochunk(st->st_tpacket, md->reply.start
+ , pbs_offset(&md->reply), "XAUTH reply msg");
+ send_packet(st, "XAUTH reply msg");
+ delete_state(st);
+ return STF_IGNORE;
+ }
+}
+
+/* STATE_XAUTH_R1:
+ * HDR*, HASH, ATTR(REPLY=USERNAME/PASSWORD) --> HDR*, HASH, ATTR(STATUS)
+ *
+ * used on the XAUTH server (responder)
+ */
+stf_status
+xauth_inR1(struct msg_digest *md)
+{
+ struct state *const st = md->st;
+ u_int16_t isama_id;
+ internal_addr_t ia;
+ stf_status stat, stat_build;
+
+ plog("parsing XAUTH reply");
+
+ stat = modecfg_parse_msg(md, ISAKMP_CFG_REPLY, &isama_id, &ia);
+ if (stat != STF_OK)
+ return stat;
+
+ /* did the client return an XAUTH FAIL status? */
+ if ((ia.xauth_attr_set & LELEM(XAUTH_STATUS - XAUTH_BASE)) != LEMPTY)
+ {
+ plog("received FAIL status in XAUTH reply");
+
+ /* client is not able to do XAUTH, delete ISAKMP SA */
+ delete_state(st);
+ return STF_IGNORE;
+ }
+
+ /* check XAUTH reply */
+ if ((ia.xauth_attr_set & LELEM(XAUTH_USER_NAME - XAUTH_BASE)) == LEMPTY)
+ {
+ plog("user name attribute is missing in XAUTH reply");
+ st->st_xauth.status = FALSE;
+ }
+ else if ((ia.xauth_attr_set & LELEM(XAUTH_USER_PASSWORD - XAUTH_BASE)) == LEMPTY)
+ {
+ plog("user password attribute is missing in XAUTH reply");
+ st->st_xauth.status = FALSE;
+ }
+ else
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("peer xauth user name is '%.*s'"
+ , ia.xauth_secret.user_name.len
+ , ia.xauth_secret.user_name.ptr)
+ )
+ DBG(DBG_PRIVATE,
+ DBG_log("peer xauth user password is '%.*s'"
+ , ia.xauth_secret.user_password.len
+ , ia.xauth_secret.user_password.ptr)
+ )
+ /* verify the user credentials using a plugn function */
+ st->st_xauth.status = xauth_module.verify_secret(&ia.xauth_secret);
+ plog("extended authentication %s", st->st_xauth.status? "was successful":"failed");
+ }
+
+ /* prepare XAUTH set which sends the authentication status */
+ init_internal_addr(&ia);
+ ia.xauth_attr_set = LELEM(XAUTH_STATUS - XAUTH_BASE);
+ ia.xauth_status = (st->st_xauth.status)? XAUTH_STATUS_OK : XAUTH_STATUS_FAIL;
+
+ plog("sending XAUTH status:");
+
+ stat_build = modecfg_send_msg(st, ISAKMP_CFG_SET, &ia);
+ if (stat_build != STF_OK)
+ return stat_build;
+ return STF_OK;
+}
+
+/* STATE_XAUTH_I1:
+ * HDR*, HASH, ATTR(STATUS) --> HDR*, HASH, ATTR(ACK)
+ *
+ * used on the XAUTH client (initiator)
+ */
+stf_status
+xauth_inI1(struct msg_digest *md)
+{
+ struct state *const st = md->st;
+ u_int16_t isama_id;
+ internal_addr_t ia;
+ stf_status stat, stat_build;
+
+ plog("parsing XAUTH status");
+ stat = modecfg_parse_msg(md, ISAKMP_CFG_SET, &isama_id, &ia);
+ if (stat != STF_OK)
+ {
+ /* notification payload - not exactly the right choice, but okay */
+ md->note = ATTRIBUTES_NOT_SUPPORTED;
+ return stat;
+ }
+
+ st->st_xauth.status = ia.xauth_status;
+ plog("extended authentication %s", st->st_xauth.status? "was successful":"failed");
+
+ plog("sending XAUTH ack");
+ init_internal_addr(&ia);
+ stat_build = modecfg_build_msg(st, &md->rbody
+ , ISAKMP_CFG_ACK
+ , &ia
+ , isama_id);
+ if (stat_build != STF_OK)
+ return stat_build;
+
+ if (st->st_xauth.status)
+ {
+ st->st_msgid = 0;
+ return STF_OK;
+ }
+ else
+ {
+ /* send XAUTH ack msg and then delete ISAKMP SA */
+ freeanychunk(st->st_tpacket);
+ clonetochunk(st->st_tpacket, md->reply.start
+ , pbs_offset(&md->reply), "XAUTH ack msg");
+ send_packet(st, "XAUTH ack msg");
+ delete_state(st);
+ return STF_IGNORE;
+ }
+}
+
+/* STATE_XAUTH_R2:
+ * HDR*, ATTR(STATUS), HASH --> Done
+ *
+ * used on the XAUTH server (responder)
+ */
+stf_status
+xauth_inR2(struct msg_digest *md)
+{
+ struct state *const st = md->st;
+ u_int16_t isama_id;
+ internal_addr_t ia;
+ stf_status stat;
+
+ plog("parsing XAUTH ack");
+
+ stat = modecfg_parse_msg(md, ISAKMP_CFG_ACK, &isama_id, &ia);
+ if (stat != STF_OK)
+ return stat;
+
+ st->st_msgid = 0;
+ if (st->st_xauth.status)
+ {
+ return STF_OK;
+ }
+ else
+ {
+ delete_state(st);
+ return STF_IGNORE;
+ }
+}
diff --git a/src/pluto/modecfg.h b/src/pluto/modecfg.h
new file mode 100644
index 000000000..68b7ef446
--- /dev/null
+++ b/src/pluto/modecfg.h
@@ -0,0 +1,47 @@
+/* Mode Config related functions
+ * Copyright (C) 2001-2002 Colubris Networks
+ * Copyright (C) 2003-2004 Xelerance Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: modecfg.h,v 1.1 2005/01/06 22:10:15 as Exp $
+ */
+
+#ifndef _MODECFG_H
+#define _MODECFG_H
+
+struct state;
+struct msg_digest;
+
+/* ModeConfig pull mode start function */
+extern stf_status modecfg_send_request(struct state *st);
+
+/* ModeConfig pull mode state transition functions */
+extern stf_status modecfg_inR0(struct msg_digest *md);
+extern stf_status modecfg_inI1(struct msg_digest *md);
+
+/* ModeConfig push mode start function */
+extern stf_status modecfg_send_set(struct state *st);
+
+/* ModeConfig push mode state transition functions */
+extern stf_status modecfg_inI0(struct msg_digest *md);
+extern stf_status modecfg_inR3(struct msg_digest *md);
+
+/* XAUTH start function */
+extern stf_status xauth_send_request(struct state *st);
+
+/* XAUTH state transition funcgtions */
+extern stf_status xauth_inI0(struct msg_digest *md);
+extern stf_status xauth_inR1(struct msg_digest *md);
+extern stf_status xauth_inI1(struct msg_digest *md);
+extern stf_status xauth_inR2(struct msg_digest *md);
+
+#endif /* _MODECFG_H */
diff --git a/src/pluto/mp_defs.c b/src/pluto/mp_defs.c
new file mode 100644
index 000000000..7ad896751
--- /dev/null
+++ b/src/pluto/mp_defs.c
@@ -0,0 +1,70 @@
+/* some multiprecision utilities
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: mp_defs.c,v 1.1 2006/01/05 12:37:11 as Exp $
+ */
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "mp_defs.h"
+#include "log.h"
+
+/* Convert MP_INT to network form (binary octets, big-endian).
+ * We do the malloc; caller must eventually do free.
+ */
+chunk_t
+mpz_to_n(const MP_INT *mp, size_t bytes)
+{
+ chunk_t r;
+ MP_INT temp1, temp2;
+ int i;
+
+ r.len = bytes;
+ r.ptr = alloc_bytes(r.len, "host representation of large integer");
+
+ mpz_init(&temp1);
+ mpz_init(&temp2);
+
+ mpz_set(&temp1, mp);
+
+ for (i = r.len-1; i >= 0; i--)
+ {
+ r.ptr[i] = mpz_mdivmod_ui(&temp2, NULL, &temp1, 1 << BITS_PER_BYTE);
+ mpz_set(&temp1, &temp2);
+ }
+
+ passert(mpz_sgn(&temp1) == 0); /* we must have done all the bits */
+ mpz_clear(&temp1);
+ mpz_clear(&temp2);
+
+ return r;
+}
+
+/* Convert network form (binary bytes, big-endian) to MP_INT.
+ * The *mp must not be previously mpz_inited.
+ */
+void
+n_to_mpz(MP_INT *mp, const u_char *nbytes, size_t nlen)
+{
+ size_t i;
+
+ mpz_init_set_ui(mp, 0);
+
+ for (i = 0; i != nlen; i++)
+ {
+ mpz_mul_ui(mp, mp, 1 << BITS_PER_BYTE);
+ mpz_add_ui(mp, mp, nbytes[i]);
+ }
+}
diff --git a/src/pluto/mp_defs.h b/src/pluto/mp_defs.h
new file mode 100644
index 000000000..744a028d1
--- /dev/null
+++ b/src/pluto/mp_defs.h
@@ -0,0 +1,36 @@
+/* some multiprecision utilities
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: mp_defs.h,v 1.2 2006/01/06 11:40:45 as Exp $
+ */
+
+#ifndef _MP_DEFS_H
+#define _MP_DEFS_H
+
+#include <gmp.h>
+
+#include "defs.h"
+
+extern void n_to_mpz(MP_INT *mp, const u_char *nbytes, size_t nlen);
+extern chunk_t mpz_to_n(const MP_INT *mp, size_t bytes);
+
+/* var := mod(base ** exp, mod), ensuring var is mpz_inited */
+#define mpz_init_powm(flag, var, base, exp, mod) { \
+ if (!(flag)) \
+ mpz_init(&(var)); \
+ (flag) = TRUE; \
+ mpz_powm(&(var), &(base), &(exp), (mod)); \
+ }
+
+#endif /* _MP_DEFS_H */
diff --git a/src/pluto/nat_traversal.c b/src/pluto/nat_traversal.c
new file mode 100644
index 000000000..4a52cc107
--- /dev/null
+++ b/src/pluto/nat_traversal.c
@@ -0,0 +1,866 @@
+/* FreeS/WAN NAT-Traversal
+ * Copyright (C) 2002-2005 Mathieu Lafon - Arkoon Network Security
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: nat_traversal.c,v 1.8 2005/01/06 22:36:58 as Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h> /* used only if MSG_NOSIGNAL not defined */
+#include <sys/queue.h>
+
+#include <freeswan.h>
+#include <ipsec_policy.h>
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "server.h"
+#include "state.h"
+#include "connections.h"
+#include "packet.h"
+#include "demux.h"
+#include "kernel.h"
+#include "whack.h"
+#include "timer.h"
+#include "cookie.h"
+#include "sha1.h"
+#include "md5.h"
+#include "crypto.h"
+#include "vendor.h"
+#include "ike_alg.h"
+#include "nat_traversal.h"
+
+/* #define FORCE_NAT_TRAVERSAL */
+#define NAT_D_DEBUG
+#define NAT_T_SUPPORT_LAST_DRAFTS
+
+#ifndef SOL_UDP
+#define SOL_UDP 17
+#endif
+
+#ifndef UDP_ESPINUDP
+#define UDP_ESPINUDP 100
+#endif
+
+#define DEFAULT_KEEP_ALIVE_PERIOD 20
+
+#ifdef _IKE_ALG_H
+/* Alg patch: hash_digest_len -> hash_digest_size */
+#define hash_digest_len hash_digest_size
+#endif
+
+bool nat_traversal_enabled = FALSE;
+bool nat_traversal_support_non_ike = FALSE;
+bool nat_traversal_support_port_floating = FALSE;
+
+static unsigned int _kap = 0;
+static unsigned int _ka_evt = 0;
+static bool _force_ka = 0;
+
+static const char *natt_version = "0.6c";
+
+void init_nat_traversal (bool activate, unsigned int keep_alive_period,
+ bool fka, bool spf)
+{
+ nat_traversal_enabled = activate;
+ nat_traversal_support_non_ike = activate;
+#ifdef NAT_T_SUPPORT_LAST_DRAFTS
+ nat_traversal_support_port_floating = activate ? spf : FALSE;
+#endif
+ _force_ka = fka;
+ _kap = keep_alive_period ? keep_alive_period : DEFAULT_KEEP_ALIVE_PERIOD;
+ plog(" including NAT-Traversal patch (Version %s)%s%s%s"
+ , natt_version, activate ? "" : " [disabled]"
+ , activate & fka ? " [Force KeepAlive]" : ""
+ , activate & !spf ? " [Port Floating disabled]" : "");
+}
+
+static void disable_nat_traversal (int type)
+{
+ if (type == ESPINUDP_WITH_NON_IKE)
+ nat_traversal_support_non_ike = FALSE;
+ else
+ nat_traversal_support_port_floating = FALSE;
+
+ if (!nat_traversal_support_non_ike &&
+ !nat_traversal_support_port_floating)
+ nat_traversal_enabled = FALSE;
+}
+
+static void _natd_hash(const struct hash_desc *hasher, char *hash,
+ u_int8_t *icookie, u_int8_t *rcookie,
+ const ip_address *ip, u_int16_t port)
+{
+ union hash_ctx ctx;
+
+ if (is_zero_cookie(icookie))
+ DBG_log("_natd_hash: Warning, icookie is zero !!");
+ if (is_zero_cookie(rcookie))
+ DBG_log("_natd_hash: Warning, rcookie is zero !!");
+
+ /**
+ * draft-ietf-ipsec-nat-t-ike-01.txt
+ *
+ * HASH = HASH(CKY-I | CKY-R | IP | Port)
+ *
+ * All values in network order
+ */
+ hasher->hash_init(&ctx);
+ hasher->hash_update(&ctx, icookie, COOKIE_SIZE);
+ hasher->hash_update(&ctx, rcookie, COOKIE_SIZE);
+ switch (addrtypeof(ip)) {
+ case AF_INET:
+ hasher->hash_update(&ctx, (const u_char *)&ip->u.v4.sin_addr.s_addr
+ , sizeof(ip->u.v4.sin_addr.s_addr));
+ break;
+ case AF_INET6:
+ hasher->hash_update(&ctx, (const u_char *)&ip->u.v6.sin6_addr.s6_addr
+ , sizeof(ip->u.v6.sin6_addr.s6_addr));
+ break;
+ }
+ hasher->hash_update(&ctx, (const u_char *)&port, sizeof(u_int16_t));
+ hasher->hash_final(hash, &ctx);
+#ifdef NAT_D_DEBUG
+ DBG(DBG_NATT,
+ DBG_log("_natd_hash: hasher=%p(%d)", hasher, (int)hasher->hash_digest_len);
+ DBG_dump("_natd_hash: icookie=", icookie, COOKIE_SIZE);
+ DBG_dump("_natd_hash: rcookie=", rcookie, COOKIE_SIZE);
+ switch (addrtypeof(ip)) {
+ case AF_INET:
+ DBG_dump("_natd_hash: ip=", &ip->u.v4.sin_addr.s_addr
+ , sizeof(ip->u.v4.sin_addr.s_addr));
+ break;
+ }
+ DBG_log("_natd_hash: port=%d", port);
+ DBG_dump("_natd_hash: hash=", hash, hasher->hash_digest_len);
+ );
+#endif
+}
+
+/* Add NAT-Traversal VIDs (supported ones)
+ * used when we are Initiator
+ */
+bool nat_traversal_add_vid(u_int8_t np, pb_stream *outs)
+{
+ bool r = TRUE;
+
+ if (nat_traversal_support_port_floating)
+ {
+ u_int8_t last_np = nat_traversal_support_non_ike ?
+ ISAKMP_NEXT_VID : np;
+
+ if (r)
+ r = out_vendorid(ISAKMP_NEXT_VID, outs, VID_NATT_RFC);
+ if (r)
+ r = out_vendorid(ISAKMP_NEXT_VID, outs, VID_NATT_IETF_03);
+ if (r)
+ r = out_vendorid(ISAKMP_NEXT_VID, outs, VID_NATT_IETF_02);
+ if (r)
+ r = out_vendorid(last_np, outs, VID_NATT_IETF_02_N);
+ }
+ if (nat_traversal_support_non_ike)
+ {
+ if (r)
+ r = out_vendorid(np, outs, VID_NATT_IETF_00);
+ }
+ return r;
+}
+
+u_int32_t nat_traversal_vid_to_method(unsigned short nat_t_vid)
+{
+ switch (nat_t_vid)
+ {
+ case VID_NATT_IETF_00:
+ return LELEM(NAT_TRAVERSAL_IETF_00_01);
+ case VID_NATT_IETF_02:
+ case VID_NATT_IETF_02_N:
+ case VID_NATT_IETF_03:
+ return LELEM(NAT_TRAVERSAL_IETF_02_03);
+ case VID_NATT_RFC:
+ return LELEM(NAT_TRAVERSAL_RFC);
+ }
+ return 0;
+}
+
+void nat_traversal_natd_lookup(struct msg_digest *md)
+{
+ char hash[MAX_DIGEST_LEN];
+ struct payload_digest *p;
+ struct state *st = md->st;
+ int i;
+
+ if (!st || !md->iface || !st->st_oakley.hasher)
+ {
+ loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d"
+ , __FILE__, __LINE__);
+ return;
+ }
+
+ /** Count NAT-D **/
+ for (p = md->chain[ISAKMP_NEXT_NATD_RFC], i=0; p != NULL; p = p->next, i++);
+
+ /*
+ * We need at least 2 NAT-D (1 for us, many for peer)
+ */
+ if (i < 2)
+ {
+ loglog(RC_LOG_SERIOUS,
+ "NAT-Traversal: Only %d NAT-D - Aborting NAT-Traversal negociation", i);
+ st->nat_traversal = 0;
+ return;
+ }
+
+ /*
+ * First one with my IP & port
+ */
+ p = md->chain[ISAKMP_NEXT_NATD_RFC];
+ _natd_hash(st->st_oakley.hasher, hash, st->st_icookie, st->st_rcookie,
+ &(md->iface->addr), ntohs(st->st_connection->spd.this.host_port));
+
+ if (!(pbs_left(&p->pbs) == st->st_oakley.hasher->hash_digest_len &&
+ memcmp(p->pbs.cur, hash, st->st_oakley.hasher->hash_digest_len) == 0))
+ {
+#ifdef NAT_D_DEBUG
+ DBG(DBG_NATT,
+ DBG_log("NAT_TRAVERSAL_NAT_BHND_ME");
+ DBG_dump("expected NAT-D:", hash
+ , st->st_oakley.hasher->hash_digest_len);
+ DBG_dump("received NAT-D:", p->pbs.cur, pbs_left(&p->pbs));
+ )
+#endif
+ st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_ME);
+ }
+
+ /*
+ * The others with sender IP & port
+ */
+ _natd_hash(st->st_oakley.hasher, hash, st->st_icookie, st->st_rcookie,
+ &(md->sender), ntohs(md->sender_port));
+ for (p = p->next, i=0 ; p != NULL; p = p->next)
+ {
+ if (pbs_left(&p->pbs) == st->st_oakley.hasher->hash_digest_len &&
+ memcmp(p->pbs.cur, hash, st->st_oakley.hasher->hash_digest_len) == 0)
+ {
+ i++;
+ }
+ }
+ if (!i)
+ {
+#ifdef NAT_D_DEBUG
+ DBG(DBG_NATT,
+ DBG_log("NAT_TRAVERSAL_NAT_BHND_PEER");
+ DBG_dump("expected NAT-D:", hash
+ , st->st_oakley.hasher->hash_digest_len);
+ p = md->chain[ISAKMP_NEXT_NATD_RFC];
+ for (p = p->next, i=0 ; p != NULL; p = p->next)
+ {
+ DBG_dump("received NAT-D:", p->pbs.cur, pbs_left(&p->pbs));
+ }
+ )
+#endif
+ st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_PEER);
+ }
+#ifdef FORCE_NAT_TRAVERSAL
+ st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_PEER);
+ st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_ME);
+#endif
+}
+
+bool nat_traversal_add_natd(u_int8_t np, pb_stream *outs,
+ struct msg_digest *md)
+{
+ char hash[MAX_DIGEST_LEN];
+ struct state *st = md->st;
+
+ if (!st || !st->st_oakley.hasher)
+ {
+ loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d"
+ , __FILE__, __LINE__);
+ return FALSE;
+ }
+
+ DBG(DBG_EMITTING,
+ DBG_log("sending NATD payloads")
+ )
+
+ /*
+ * First one with sender IP & port
+ */
+ _natd_hash(st->st_oakley.hasher, hash, st->st_icookie,
+ is_zero_cookie(st->st_rcookie) ? md->hdr.isa_rcookie : st->st_rcookie,
+ &(md->sender),
+#ifdef FORCE_NAT_TRAVERSAL
+ 0
+#else
+ ntohs(md->sender_port)
+#endif
+ );
+ if (!out_generic_raw((st->nat_traversal & NAT_T_WITH_RFC_VALUES
+ ? ISAKMP_NEXT_NATD_RFC : ISAKMP_NEXT_NATD_DRAFTS), &isakmp_nat_d, outs,
+ hash, st->st_oakley.hasher->hash_digest_len, "NAT-D"))
+ {
+ return FALSE;
+ }
+
+ /*
+ * Second one with my IP & port
+ */
+ _natd_hash(st->st_oakley.hasher, hash, st->st_icookie,
+ is_zero_cookie(st->st_rcookie) ? md->hdr.isa_rcookie : st->st_rcookie,
+ &(md->iface->addr),
+#ifdef FORCE_NAT_TRAVERSAL
+ 0
+#else
+ ntohs(st->st_connection->spd.this.host_port)
+#endif
+ );
+ return (out_generic_raw(np, &isakmp_nat_d, outs,
+ hash, st->st_oakley.hasher->hash_digest_len, "NAT-D"));
+}
+
+/*
+ * nat_traversal_natoa_lookup()
+ *
+ * Look for NAT-OA in message
+ */
+void nat_traversal_natoa_lookup(struct msg_digest *md)
+{
+ struct payload_digest *p;
+ struct state *st = md->st;
+ int i;
+ ip_address ip;
+
+ if (!st || !md->iface)
+ {
+ loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d"
+ , __FILE__, __LINE__);
+ return;
+ }
+
+ /* Initialize NAT-OA */
+ anyaddr(AF_INET, &st->nat_oa);
+
+ /* Count NAT-OA **/
+ for (p = md->chain[ISAKMP_NEXT_NATOA_RFC], i=0; p != NULL; p = p->next, i++);
+
+ DBG(DBG_NATT,
+ DBG_log("NAT-Traversal: received %d NAT-OA.", i)
+ )
+
+ if (i == 0)
+ return;
+
+ if (!(st->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_PEER)))
+ {
+ loglog(RC_LOG_SERIOUS, "NAT-Traversal: received %d NAT-OA. "
+ "ignored because peer is not NATed", i);
+ return;
+ }
+
+ if (i > 1)
+ {
+ loglog(RC_LOG_SERIOUS, "NAT-Traversal: received %d NAT-OA. "
+ "using first, ignoring others", i);
+ }
+
+ /* Take first */
+ p = md->chain[ISAKMP_NEXT_NATOA_RFC];
+
+ DBG(DBG_PARSING,
+ DBG_dump("NAT-OA:", p->pbs.start, pbs_room(&p->pbs));
+ );
+
+ switch (p->payload.nat_oa.isanoa_idtype)
+ {
+ case ID_IPV4_ADDR:
+ if (pbs_left(&p->pbs) == sizeof(struct in_addr))
+ {
+ initaddr(p->pbs.cur, pbs_left(&p->pbs), AF_INET, &ip);
+ }
+ else
+ {
+ loglog(RC_LOG_SERIOUS, "NAT-Traversal: received IPv4 NAT-OA "
+ "with invalid IP size (%d)", (int)pbs_left(&p->pbs));
+ return;
+ }
+ break;
+ case ID_IPV6_ADDR:
+ if (pbs_left(&p->pbs) == sizeof(struct in6_addr))
+ {
+ initaddr(p->pbs.cur, pbs_left(&p->pbs), AF_INET6, &ip);
+ }
+ else
+ {
+ loglog(RC_LOG_SERIOUS, "NAT-Traversal: received IPv6 NAT-OA "
+ "with invalid IP size (%d)", (int)pbs_left(&p->pbs));
+ return;
+ }
+ break;
+ default:
+ loglog(RC_LOG_SERIOUS, "NAT-Traversal: "
+ "invalid ID Type (%d) in NAT-OA - ignored",
+ p->payload.nat_oa.isanoa_idtype);
+ return;
+ }
+
+ DBG(DBG_NATT,
+ {
+ char ip_t[ADDRTOT_BUF];
+ addrtot(&ip, 0, ip_t, sizeof(ip_t));
+
+ DBG_log("received NAT-OA: %s", ip_t);
+ }
+ )
+
+ if (isanyaddr(&ip))
+ loglog(RC_LOG_SERIOUS, "NAT-Traversal: received %%any NAT-OA...");
+ else
+ st->nat_oa = ip;
+}
+
+bool nat_traversal_add_natoa(u_int8_t np, pb_stream *outs,
+ struct state *st)
+{
+ struct isakmp_nat_oa natoa;
+ pb_stream pbs;
+ unsigned char ip_val[sizeof(struct in6_addr)];
+ size_t ip_len = 0;
+ ip_address *ip;
+
+ if ((!st) || (!st->st_connection))
+ {
+ loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d"
+ , __FILE__, __LINE__);
+ return FALSE;
+ }
+ ip = &(st->st_connection->spd.this.host_addr);
+
+ memset(&natoa, 0, sizeof(natoa));
+ natoa.isanoa_np = np;
+
+ switch (addrtypeof(ip))
+ {
+ case AF_INET:
+ ip_len = sizeof(ip->u.v4.sin_addr.s_addr);
+ memcpy(ip_val, &ip->u.v4.sin_addr.s_addr, ip_len);
+ natoa.isanoa_idtype = ID_IPV4_ADDR;
+ break;
+ case AF_INET6:
+ ip_len = sizeof(ip->u.v6.sin6_addr.s6_addr);
+ memcpy(ip_val, &ip->u.v6.sin6_addr.s6_addr, ip_len);
+ natoa.isanoa_idtype = ID_IPV6_ADDR;
+ break;
+ default:
+ loglog(RC_LOG_SERIOUS, "NAT-Traversal: "
+ "invalid addrtypeof()=%d", addrtypeof(ip));
+ return FALSE;
+ }
+
+ if (!out_struct(&natoa, &isakmp_nat_oa, outs, &pbs))
+ return FALSE;
+
+ if (!out_raw(ip_val, ip_len, &pbs, "NAT-OA"))
+ return FALSE;
+
+ DBG(DBG_NATT,
+ DBG_dump("NAT-OA (S):", ip_val, ip_len)
+ )
+
+ close_output_pbs(&pbs);
+ return TRUE;
+}
+
+void nat_traversal_show_result (u_int32_t nt, u_int16_t sport)
+{
+ const char *mth = NULL, *rslt = NULL;
+
+ switch (nt & NAT_TRAVERSAL_METHOD)
+ {
+ case LELEM(NAT_TRAVERSAL_IETF_00_01):
+ mth = natt_type_bitnames[0];
+ break;
+ case LELEM(NAT_TRAVERSAL_IETF_02_03):
+ mth = natt_type_bitnames[1];
+ break;
+ case LELEM(NAT_TRAVERSAL_RFC):
+ mth = natt_type_bitnames[2];
+ break;
+ }
+
+ switch (nt & NAT_T_DETECTED)
+ {
+ case 0:
+ rslt = "no NAT detected";
+ break;
+ case LELEM(NAT_TRAVERSAL_NAT_BHND_ME):
+ rslt = "i am NATed";
+ break;
+ case LELEM(NAT_TRAVERSAL_NAT_BHND_PEER):
+ rslt = "peer is NATed";
+ break;
+ case LELEM(NAT_TRAVERSAL_NAT_BHND_ME) | LELEM(NAT_TRAVERSAL_NAT_BHND_PEER):
+ rslt = "both are NATed";
+ break;
+ }
+
+ loglog(RC_LOG_SERIOUS,
+ "NAT-Traversal: Result using %s: %s",
+ mth ? mth : "unknown method",
+ rslt ? rslt : "unknown result"
+ );
+
+ if ((nt & LELEM(NAT_TRAVERSAL_NAT_BHND_PEER))
+ && (sport == IKE_UDP_PORT)
+ && ((nt & NAT_T_WITH_PORT_FLOATING)==0))
+ {
+ loglog(RC_LOG_SERIOUS,
+ "Warning: peer is NATed but source port is still udp/%d. "
+ "Ipsec-passthrough NAT device suspected -- NAT-T may not work.",
+ IKE_UDP_PORT
+ );
+ }
+}
+
+int nat_traversal_espinudp_socket (int sk, u_int32_t type)
+{
+ int r = setsockopt(sk, SOL_UDP, UDP_ESPINUDP, &type, sizeof(type));
+
+ if (r < 0 && errno == ENOPROTOOPT)
+ {
+ loglog(RC_LOG_SERIOUS,
+ "NAT-Traversal: ESPINUDP(%d) not supported by kernel -- "
+ "NAT-T disabled", type);
+ disable_nat_traversal(type);
+ }
+ return r;
+}
+
+void nat_traversal_new_ka_event (void)
+{
+ if (_ka_evt)
+ return; /* event already scheduled */
+
+ event_schedule(EVENT_NAT_T_KEEPALIVE, _kap, NULL);
+ _ka_evt = 1;
+}
+
+static void nat_traversal_send_ka (struct state *st)
+{
+ static unsigned char ka_payload = 0xff;
+ chunk_t sav;
+
+ DBG(DBG_NATT,
+ DBG_log("ka_event: send NAT-KA to %s:%d",
+ ip_str(&st->st_connection->spd.that.host_addr),
+ st->st_connection->spd.that.host_port);
+ )
+
+ /* save state chunk */
+ setchunk(sav, st->st_tpacket.ptr, st->st_tpacket.len);
+
+ /* send keep alive */
+ setchunk(st->st_tpacket, &ka_payload, 1);
+ send_packet(st, "NAT-T Keep Alive");
+
+ /* restore state chunk */
+ setchunk(st->st_tpacket, sav.ptr, sav.len);
+}
+
+/**
+ * Find ISAKMP States with NAT-T and send keep-alive
+ */
+static void nat_traversal_ka_event_state (struct state *st, void *data)
+{
+ unsigned int *_kap_st = (unsigned int *)data;
+ const struct connection *c = st->st_connection;
+
+ if (!c)
+ return;
+
+ if ((st->st_state == STATE_MAIN_R3 || st->st_state == STATE_MAIN_I4)
+ && (st->nat_traversal & NAT_T_DETECTED)
+ && ((st->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME)) || _force_ka))
+ {
+ /*
+ * - ISAKMP established
+ * - NAT-Traversal detected
+ * - NAT-KeepAlive needed (we are NATed)
+ */
+ if (c->newest_isakmp_sa != st->st_serialno)
+ {
+ /*
+ * if newest is also valid, ignore this one, we will only use
+ * newest.
+ */
+ struct state *st_newest;
+
+ st_newest = state_with_serialno(c->newest_isakmp_sa);
+ if (st_newest
+ && (st_newest->st_state == STATE_MAIN_R3 || st_newest->st_state == STATE_MAIN_I4)
+ && (st_newest->nat_traversal & NAT_T_DETECTED)
+ && ((st_newest->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME)) || _force_ka))
+ {
+ return;
+ }
+ }
+ set_cur_state(st);
+ nat_traversal_send_ka(st);
+ reset_cur_state();
+ (*_kap_st)++;
+ }
+}
+
+void nat_traversal_ka_event (void)
+{
+ unsigned int _kap_st = 0;
+
+ _ka_evt = 0; /* ready to be reschedule */
+
+ for_each_state((void *)nat_traversal_ka_event_state, &_kap_st);
+
+ /* if there are still states who needs Keep-Alive, schedule new event */
+ if (_kap_st)
+ nat_traversal_new_ka_event();
+}
+
+struct _new_mapp_nfo {
+ ip_address addr;
+ u_int16_t sport, dport;
+};
+
+static void nat_traversal_find_new_mapp_state (struct state *st, void *data)
+{
+ struct connection *c = st->st_connection;
+ struct _new_mapp_nfo *nfo = (struct _new_mapp_nfo *)data;
+
+ if (c != NULL
+ && sameaddr(&c->spd.that.host_addr, &(nfo->addr))
+ && c->spd.that.host_port == nfo->sport)
+ {
+
+ /* change host port */
+ c->spd.that.host_port = nfo->dport;
+
+ if (IS_IPSEC_SA_ESTABLISHED(st->st_state)
+ || IS_ONLY_INBOUND_IPSEC_SA_ESTABLISHED(st->st_state))
+ {
+ if (!update_ipsec_sa(st))
+ {
+ /*
+ * If ipsec update failed, restore old port or we'll
+ * not be able to update anymore.
+ */
+ c->spd.that.host_port = nfo->sport;
+ }
+ }
+ }
+}
+
+static int nat_traversal_new_mapping(const ip_address *src, u_int16_t sport,
+ const ip_address *dst, u_int16_t dport)
+{
+ char srca[ADDRTOT_BUF], dsta[ADDRTOT_BUF];
+ struct _new_mapp_nfo nfo;
+
+ addrtot(src, 0, srca, ADDRTOT_BUF);
+ addrtot(dst, 0, dsta, ADDRTOT_BUF);
+
+ if (!sameaddr(src, dst))
+ {
+ loglog(RC_LOG_SERIOUS, "nat_traversal_new_mapping: "
+ "address change currently not supported [%s:%d,%s:%d]",
+ srca, sport, dsta, dport);
+ return -1;
+ }
+
+ if (sport == dport)
+ {
+ /* no change */
+ return 0;
+ }
+
+ DBG_log("NAT-T: new mapping %s:%d/%d)", srca, sport, dport);
+
+ nfo.addr = *src;
+ nfo.sport = sport;
+ nfo.dport = dport;
+
+ for_each_state((void *)nat_traversal_find_new_mapp_state, &nfo);
+
+ return 0;
+}
+
+void nat_traversal_change_port_lookup(struct msg_digest *md, struct state *st)
+{
+ struct connection *c = st ? st->st_connection : NULL;
+ struct iface *i = NULL;
+
+ if ((st == NULL) || (c == NULL))
+ return;
+
+ if (md)
+ {
+ /*
+ * If source port has changed, update (including other states and
+ * established kernel SA)
+ */
+ if (c->spd.that.host_port != md->sender_port)
+ {
+ nat_traversal_new_mapping(&c->spd.that.host_addr, c->spd.that.host_port,
+ &c->spd.that.host_addr, md->sender_port);
+ }
+
+ /*
+ * If interface type has changed, update local port (500/4500)
+ */
+ if ((c->spd.this.host_port == NAT_T_IKE_FLOAT_PORT && !md->iface->ike_float)
+ || (c->spd.this.host_port != NAT_T_IKE_FLOAT_PORT && md->iface->ike_float))
+ {
+ c->spd.this.host_port = (md->iface->ike_float)
+ ? NAT_T_IKE_FLOAT_PORT : pluto_port;
+
+ DBG(DBG_NATT,
+ DBG_log("NAT-T: updating local port to %d", c->spd.this.host_port);
+ );
+ }
+ }
+
+ /*
+ * If we're initiator and NAT-T (with port floating) is detected, we
+ * need to change port (MAIN_I3 or QUICK_I1)
+ */
+ if ((st->st_state == STATE_MAIN_I3 || st->st_state == STATE_QUICK_I1)
+ && (st->nat_traversal & NAT_T_WITH_PORT_FLOATING)
+ && (st->nat_traversal & NAT_T_DETECTED)
+ && (c->spd.this.host_port != NAT_T_IKE_FLOAT_PORT))
+ {
+ DBG(DBG_NATT,
+ DBG_log("NAT-T: floating to port %d", NAT_T_IKE_FLOAT_PORT);
+ )
+ c->spd.this.host_port = NAT_T_IKE_FLOAT_PORT;
+ c->spd.that.host_port = NAT_T_IKE_FLOAT_PORT;
+ /*
+ * Also update pending connections or they will be deleted if uniqueids
+ * option is set.
+ */
+ update_pending(st, st);
+ }
+
+ /*
+ * Find valid interface according to local port (500/4500)
+ */
+ if ((c->spd.this.host_port == NAT_T_IKE_FLOAT_PORT && !c->interface->ike_float)
+ || (c->spd.this.host_port != NAT_T_IKE_FLOAT_PORT && c->interface->ike_float))
+ {
+ for (i = interfaces; i != NULL; i = i->next)
+ {
+ if (sameaddr(&c->interface->addr, &i->addr)
+ && i->ike_float != c->interface->ike_float)
+ {
+ DBG(DBG_NATT,
+ DBG_log("NAT-T: using interface %s:%d", i->rname,
+ i->ike_float ? NAT_T_IKE_FLOAT_PORT : pluto_port);
+ )
+ c->interface = i;
+ break;
+ }
+ }
+ }
+}
+
+struct _new_klips_mapp_nfo {
+ struct sadb_sa *sa;
+ ip_address src, dst;
+ u_int16_t sport, dport;
+};
+
+static void nat_t_new_klips_mapp (struct state *st, void *data)
+{
+ struct connection *c = st->st_connection;
+ struct _new_klips_mapp_nfo *nfo = (struct _new_klips_mapp_nfo *)data;
+
+ if (c != NULL && st->st_esp.present
+ && sameaddr(&c->spd.that.host_addr, &(nfo->src))
+ && st->st_esp.our_spi == nfo->sa->sadb_sa_spi)
+ {
+ nat_traversal_new_mapping(&c->spd.that.host_addr, c->spd.that.host_port,
+ &(nfo->dst), nfo->dport);
+ }
+}
+
+void process_pfkey_nat_t_new_mapping(
+ struct sadb_msg *msg __attribute__ ((unused)),
+ struct sadb_ext *extensions[SADB_EXT_MAX + 1])
+{
+ struct _new_klips_mapp_nfo nfo;
+ struct sadb_address *srcx = (void *) extensions[SADB_EXT_ADDRESS_SRC];
+ struct sadb_address *dstx = (void *) extensions[SADB_EXT_ADDRESS_DST];
+ struct sockaddr *srca, *dsta;
+ err_t ugh = NULL;
+
+ nfo.sa = (void *) extensions[SADB_EXT_SA];
+
+ if (!nfo.sa || !srcx || !dstx)
+ {
+ plog("SADB_X_NAT_T_NEW_MAPPING message from KLIPS malformed: "
+ "got NULL params");
+ return;
+ }
+
+ srca = ((struct sockaddr *)(void *)&srcx[1]);
+ dsta = ((struct sockaddr *)(void *)&dstx[1]);
+
+ if (srca->sa_family != AF_INET || dsta->sa_family != AF_INET)
+ {
+ ugh = "only AF_INET supported";
+ }
+ else
+ {
+ char text_said[SATOT_BUF];
+ char _srca[ADDRTOT_BUF], _dsta[ADDRTOT_BUF];
+ ip_said said;
+
+ initaddr((const void *) &((const struct sockaddr_in *)srca)->sin_addr,
+ sizeof(((const struct sockaddr_in *)srca)->sin_addr),
+ srca->sa_family, &(nfo.src));
+ nfo.sport = ntohs(((const struct sockaddr_in *)srca)->sin_port);
+ initaddr((const void *) &((const struct sockaddr_in *)dsta)->sin_addr,
+ sizeof(((const struct sockaddr_in *)dsta)->sin_addr),
+ dsta->sa_family, &(nfo.dst));
+ nfo.dport = ntohs(((const struct sockaddr_in *)dsta)->sin_port);
+
+ DBG(DBG_NATT,
+ initsaid(&nfo.src, nfo.sa->sadb_sa_spi, SA_ESP, &said);
+ satot(&said, 0, text_said, SATOT_BUF);
+ addrtot(&nfo.src, 0, _srca, ADDRTOT_BUF);
+ addrtot(&nfo.dst, 0, _dsta, ADDRTOT_BUF);
+ DBG_log("new klips mapping %s %s:%d %s:%d",
+ text_said, _srca, nfo.sport, _dsta, nfo.dport);
+ )
+
+ for_each_state((void *)nat_t_new_klips_mapp, &nfo);
+ }
+
+ if (ugh != NULL)
+ plog("SADB_X_NAT_T_NEW_MAPPING message from KLIPS malformed: %s", ugh);
+}
+
diff --git a/src/pluto/nat_traversal.h b/src/pluto/nat_traversal.h
new file mode 100644
index 000000000..71222c54c
--- /dev/null
+++ b/src/pluto/nat_traversal.h
@@ -0,0 +1,154 @@
+/* FreeS/WAN NAT-Traversal
+ * Copyright (C) 2002-2003 Mathieu Lafon - Arkoon Network Security
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: nat_traversal.h,v 1.4 2004/07/27 21:11:30 as Exp $
+ */
+
+#ifndef _NAT_TRAVERSAL_H
+#define _NAT_TRAVERSAL_H
+
+#include "packet.h"
+
+#define NAT_TRAVERSAL_IETF_00_01 1
+#define NAT_TRAVERSAL_IETF_02_03 2
+#define NAT_TRAVERSAL_RFC 3
+
+#define NAT_TRAVERSAL_NAT_BHND_ME 30
+#define NAT_TRAVERSAL_NAT_BHND_PEER 31
+
+#define NAT_TRAVERSAL_METHOD (0xffffffff - LELEM(30) - LELEM(31))
+
+/**
+ * NAT-Traversal methods which need NAT-D
+ */
+#define NAT_T_WITH_NATD \
+ ( LELEM(NAT_TRAVERSAL_IETF_00_01) | LELEM(NAT_TRAVERSAL_IETF_02_03) | \
+ LELEM(NAT_TRAVERSAL_RFC) )
+/**
+ * NAT-Traversal methods which need NAT-OA
+ */
+#define NAT_T_WITH_NATOA \
+ ( LELEM(NAT_TRAVERSAL_IETF_00_01) | LELEM(NAT_TRAVERSAL_IETF_02_03) | \
+ LELEM(NAT_TRAVERSAL_RFC) )
+/**
+ * NAT-Traversal methods which use NAT-KeepAlive
+ */
+#define NAT_T_WITH_KA \
+ ( LELEM(NAT_TRAVERSAL_IETF_00_01) | LELEM(NAT_TRAVERSAL_IETF_02_03) | \
+ LELEM(NAT_TRAVERSAL_RFC) )
+/**
+ * NAT-Traversal methods which use floating port
+ */
+#define NAT_T_WITH_PORT_FLOATING \
+ ( LELEM(NAT_TRAVERSAL_IETF_02_03) | LELEM(NAT_TRAVERSAL_RFC) )
+
+/**
+ * NAT-Traversal methods which use officials values (RFC)
+ */
+#define NAT_T_WITH_RFC_VALUES \
+ ( LELEM(NAT_TRAVERSAL_RFC) )
+
+/**
+ * NAT-Traversal detected
+ */
+#define NAT_T_DETECTED \
+ ( LELEM(NAT_TRAVERSAL_NAT_BHND_ME) | LELEM(NAT_TRAVERSAL_NAT_BHND_PEER) )
+
+/**
+ * NAT-T Port Floating
+ */
+#define NAT_T_IKE_FLOAT_PORT 4500
+
+void init_nat_traversal (bool activate, unsigned int keep_alive_period,
+ bool fka, bool spf);
+
+extern bool nat_traversal_enabled;
+extern bool nat_traversal_support_non_ike;
+extern bool nat_traversal_support_port_floating;
+
+/**
+ * NAT-D
+ */
+void nat_traversal_natd_lookup(struct msg_digest *md);
+#ifndef PB_STREAM_UNDEFINED
+bool nat_traversal_add_natd(u_int8_t np, pb_stream *outs,
+ struct msg_digest *md);
+#endif
+
+/**
+ * NAT-OA
+ */
+void nat_traversal_natoa_lookup(struct msg_digest *md);
+#ifndef PB_STREAM_UNDEFINED
+bool nat_traversal_add_natoa(u_int8_t np, pb_stream *outs,
+ struct state *st);
+#endif
+
+/**
+ * NAT-keep_alive
+ */
+void nat_traversal_new_ka_event (void);
+void nat_traversal_ka_event (void);
+
+void nat_traversal_show_result (u_int32_t nt, u_int16_t sport);
+
+int nat_traversal_espinudp_socket (int sk, u_int32_t type);
+
+/**
+ * Vendor ID
+ */
+#ifndef PB_STREAM_UNDEFINED
+bool nat_traversal_add_vid(u_int8_t np, pb_stream *outs);
+#endif
+u_int32_t nat_traversal_vid_to_method(unsigned short nat_t_vid);
+
+void nat_traversal_change_port_lookup(struct msg_digest *md, struct state *st);
+
+/**
+ * New NAT mapping
+ */
+#ifdef __PFKEY_V2_H
+void process_pfkey_nat_t_new_mapping(
+ struct sadb_msg *,
+ struct sadb_ext *[SADB_EXT_MAX + 1]);
+#endif
+
+/**
+ * IKE port floating
+ */
+bool
+nat_traversal_port_float(struct state *st, struct msg_digest *md, bool in);
+
+/**
+ * Encapsulation mode macro (see demux.c)
+ */
+#define NAT_T_ENCAPSULATION_MODE(st,nat_t_policy) ( \
+ ((st)->nat_traversal & NAT_T_DETECTED) \
+ ? ( ((nat_t_policy) & POLICY_TUNNEL) \
+ ? ( ((st)->nat_traversal & NAT_T_WITH_RFC_VALUES) \
+ ? (ENCAPSULATION_MODE_UDP_TUNNEL_RFC) \
+ : (ENCAPSULATION_MODE_UDP_TUNNEL_DRAFTS) \
+ ) \
+ : ( ((st)->nat_traversal & NAT_T_WITH_RFC_VALUES) \
+ ? (ENCAPSULATION_MODE_UDP_TRANSPORT_RFC) \
+ : (ENCAPSULATION_MODE_UDP_TRANSPORT_DRAFTS) \
+ ) \
+ ) \
+ : ( ((st)->st_policy & POLICY_TUNNEL) \
+ ? (ENCAPSULATION_MODE_TUNNEL) \
+ : (ENCAPSULATION_MODE_TRANSPORT) \
+ ) \
+ )
+
+#endif /* _NAT_TRAVERSAL_H */
+
diff --git a/src/pluto/ocsp.c b/src/pluto/ocsp.c
new file mode 100644
index 000000000..a338be446
--- /dev/null
+++ b/src/pluto/ocsp.c
@@ -0,0 +1,1568 @@
+/* Support of the Online Certificate Status Protocol (OCSP)
+ * Copyright (C) 2003 Christoph Gysin, Simon Zwahlen
+ * 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.
+ *
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <freeswan.h>
+#include <ipsec_policy.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "x509.h"
+#include "crl.h"
+#include "ca.h"
+#include "rnd.h"
+#include "asn1.h"
+#include "certs.h"
+#include "smartcard.h"
+#include "oid.h"
+#include "whack.h"
+#include "pkcs1.h"
+#include "keys.h"
+#include "fetch.h"
+#include "ocsp.h"
+
+#define NONCE_LENGTH 16
+
+static const char *const cert_status_names[] = {
+ "good",
+ "revoked",
+ "unknown",
+ "undefined"
+};
+
+
+static const char *const response_status_names[] = {
+ "successful",
+ "malformed request",
+ "internal error",
+ "try later",
+ "signature required",
+ "unauthorized"
+};
+
+/* response container */
+typedef struct response response_t;
+
+struct response {
+ chunk_t tbs;
+ chunk_t responder_id_name;
+ chunk_t responder_id_key;
+ time_t produced_at;
+ chunk_t responses;
+ chunk_t nonce;
+ int algorithm;
+ chunk_t signature;
+};
+
+const response_t empty_response = {
+ { NULL, 0 } , /* tbs */
+ { NULL, 0 } , /* responder_id_name */
+ { NULL, 0 } , /* responder_id_key */
+ UNDEFINED_TIME, /* produced_at */
+ { NULL, 0 } , /* single_response */
+ { NULL, 0 } , /* nonce */
+ OID_UNKNOWN , /* signature_algorithm */
+ { NULL, 0 } /* signature */
+};
+
+/* single response container */
+typedef struct single_response single_response_t;
+
+struct single_response {
+ single_response_t *next;
+ int hash_algorithm;
+ chunk_t issuer_name_hash;
+ chunk_t issuer_key_hash;
+ chunk_t serialNumber;
+ cert_status_t status;
+ time_t revocationTime;
+ crl_reason_t revocationReason;
+ time_t thisUpdate;
+ time_t nextUpdate;
+};
+
+const single_response_t empty_single_response = {
+ NULL , /* *next */
+ OID_UNKNOWN , /* hash_algorithm */
+ { NULL, 0 } , /* issuer_name_hash */
+ { NULL, 0 } , /* issuer_key_hash */
+ { NULL, 0 } , /* serial_number */
+ CERT_UNDEFINED , /* status */
+ UNDEFINED_TIME , /* revocationTime */
+ REASON_UNSPECIFIED, /* revocationReason */
+ UNDEFINED_TIME , /* this_update */
+ UNDEFINED_TIME /* next_update */
+};
+
+
+/* list of single requests */
+typedef struct request_list request_list_t;
+struct request_list {
+ chunk_t request;
+ request_list_t *next;
+};
+
+/* some OCSP specific prefabricated ASN.1 constants */
+
+static u_char ASN1_nonce_oid_str[] = {
+ 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x02
+};
+
+static const chunk_t ASN1_nonce_oid = strchunk(ASN1_nonce_oid_str);
+
+static u_char ASN1_response_oid_str[] = {
+ 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x04
+};
+
+static const chunk_t ASN1_response_oid = strchunk(ASN1_response_oid_str);
+
+static u_char ASN1_response_content_str[] = {
+ 0x04, 0x0D,
+ 0x30, 0x0B,
+ 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01
+};
+
+static const chunk_t ASN1_response_content = strchunk(ASN1_response_content_str);
+
+/* default OCSP uri */
+static chunk_t ocsp_default_uri;
+
+/* ocsp cache: pointer to first element */
+static ocsp_location_t *ocsp_cache = NULL;
+
+/* static temporary storage for ocsp requestor information */
+static x509cert_t *ocsp_requestor_cert = NULL;
+
+static smartcard_t *ocsp_requestor_sc = NULL;
+
+static const struct RSA_private_key *ocsp_requestor_pri = NULL;
+
+/* asn.1 definitions for parsing */
+
+static const asn1Object_t ocspResponseObjects[] = {
+ { 0, "OCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "responseStatus", ASN1_ENUMERATED, ASN1_BODY }, /* 1 */
+ { 1, "responseBytesContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 2 */
+ { 2, "responseBytes", ASN1_SEQUENCE, ASN1_NONE }, /* 3 */
+ { 3, "responseType", ASN1_OID, ASN1_BODY }, /* 4 */
+ { 3, "response", ASN1_OCTET_STRING, ASN1_BODY }, /* 5 */
+ { 1, "end opt", ASN1_EOC, ASN1_END } /* 6 */
+};
+
+#define OCSP_RESPONSE_STATUS 1
+#define OCSP_RESPONSE_TYPE 4
+#define OCSP_RESPONSE 5
+#define OCSP_RESPONSE_ROOF 7
+
+static const asn1Object_t basicResponseObjects[] = {
+ { 0, "BasicOCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "tbsResponseData", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
+ { 2, "versionContext", ASN1_CONTEXT_C_0, ASN1_NONE |
+ ASN1_DEF }, /* 2 */
+ { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */
+ { 2, "responderIdContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 4 */
+ { 3, "responderIdByName", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */
+ { 2, "end choice", ASN1_EOC, ASN1_END }, /* 6 */
+ { 2, "responderIdContext", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 7 */
+ { 3, "responderIdByKey", ASN1_OCTET_STRING, ASN1_BODY }, /* 8 */
+ { 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */
+ { 2, "producedAt", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 10 */
+ { 2, "responses", ASN1_SEQUENCE, ASN1_OBJ }, /* 11 */
+ { 2, "responseExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 12 */
+ { 3, "responseExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 13 */
+ { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 14 */
+ { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 15 */
+ { 5, "critical", ASN1_BOOLEAN, ASN1_BODY |
+ ASN1_DEF }, /* 16 */
+ { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 17 */
+ { 4, "end loop", ASN1_EOC, ASN1_END }, /* 18 */
+ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 19 */
+ { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 20 */
+ { 1, "signature", ASN1_BIT_STRING, ASN1_BODY }, /* 21 */
+ { 1, "certsContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 22 */
+ { 2, "certs", ASN1_SEQUENCE, ASN1_LOOP }, /* 23 */
+ { 3, "certificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 24 */
+ { 2, "end loop", ASN1_EOC, ASN1_END }, /* 25 */
+ { 1, "end opt", ASN1_EOC, ASN1_END } /* 26 */
+};
+
+#define BASIC_RESPONSE_TBS_DATA 1
+#define BASIC_RESPONSE_VERSION 3
+#define BASIC_RESPONSE_ID_BY_NAME 5
+#define BASIC_RESPONSE_ID_BY_KEY 8
+#define BASIC_RESPONSE_PRODUCED_AT 10
+#define BASIC_RESPONSE_RESPONSES 11
+#define BASIC_RESPONSE_EXT_ID 15
+#define BASIC_RESPONSE_CRITICAL 16
+#define BASIC_RESPONSE_EXT_VALUE 17
+#define BASIC_RESPONSE_ALGORITHM 20
+#define BASIC_RESPONSE_SIGNATURE 21
+#define BASIC_RESPONSE_CERTIFICATE 24
+#define BASIC_RESPONSE_ROOF 27
+
+static const asn1Object_t responsesObjects[] = {
+ { 0, "responses", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */
+ { 1, "singleResponse", ASN1_EOC, ASN1_RAW }, /* 1 */
+ { 0, "end loop", ASN1_EOC, ASN1_END } /* 2 */
+};
+
+#define RESPONSES_SINGLE_RESPONSE 1
+#define RESPONSES_ROOF 3
+
+static const asn1Object_t singleResponseObjects[] = {
+ { 0, "singleResponse", ASN1_SEQUENCE, ASN1_BODY }, /* 0 */
+ { 1, "certID", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */
+ { 2, "algorithm", ASN1_EOC, ASN1_RAW }, /* 2 */
+ { 2, "issuerNameHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 3 */
+ { 2, "issuerKeyHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 4 */
+ { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 5 */
+ { 1, "certStatusGood", ASN1_CONTEXT_S_0, ASN1_OPT }, /* 6 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 7 */
+ { 1, "certStatusRevoked", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 8 */
+ { 2, "revocationTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 9 */
+ { 2, "revocationReason", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 10 */
+ { 3, "crlReason", ASN1_ENUMERATED, ASN1_BODY }, /* 11 */
+ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 12 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 13 */
+ { 1, "certStatusUnknown", ASN1_CONTEXT_S_2, ASN1_OPT }, /* 14 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 15 */
+ { 1, "thisUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 16 */
+ { 1, "nextUpdateContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 17 */
+ { 2, "nextUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 18 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 19 */
+ { 1, "singleExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 20 */
+ { 2, "singleExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 21 */
+ { 3, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 22 */
+ { 4, "extnID", ASN1_OID, ASN1_BODY }, /* 23 */
+ { 4, "critical", ASN1_BOOLEAN, ASN1_BODY |
+ ASN1_DEF }, /* 24 */
+ { 4, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 25 */
+ { 2, "end loop", ASN1_EOC, ASN1_END }, /* 26 */
+ { 1, "end opt", ASN1_EOC, ASN1_END } /* 27 */
+};
+
+#define SINGLE_RESPONSE_ALGORITHM 2
+#define SINGLE_RESPONSE_ISSUER_NAME_HASH 3
+#define SINGLE_RESPONSE_ISSUER_KEY_HASH 4
+#define SINGLE_RESPONSE_SERIAL_NUMBER 5
+#define SINGLE_RESPONSE_CERT_STATUS_GOOD 6
+#define SINGLE_RESPONSE_CERT_STATUS_REVOKED 8
+#define SINGLE_RESPONSE_CERT_STATUS_REVOCATION_TIME 9
+#define SINGLE_RESPONSE_CERT_STATUS_CRL_REASON 11
+#define SINGLE_RESPONSE_CERT_STATUS_UNKNOWN 14
+#define SINGLE_RESPONSE_THIS_UPDATE 16
+#define SINGLE_RESPONSE_NEXT_UPDATE 18
+#define SINGLE_RESPONSE_EXT_ID 23
+#define SINGLE_RESPONSE_CRITICAL 24
+#define SINGLE_RESPONSE_EXT_VALUE 25
+#define SINGLE_RESPONSE_ROOF 28
+
+/* build an ocsp location from certificate information
+ * without unsharing its contents
+ */
+static bool
+build_ocsp_location(const x509cert_t *cert, ocsp_location_t *location)
+{
+ static u_char digest[SHA1_DIGEST_SIZE]; /* temporary storage */
+
+ location->uri = cert->accessLocation;
+
+ if (location->uri.ptr == NULL)
+ {
+ ca_info_t *ca = get_ca_info(cert->issuer, cert->authKeySerialNumber
+ , cert->authKeyID);
+ if (ca != NULL && ca->ocspuri != NULL)
+ setchunk(location->uri, ca->ocspuri, strlen(ca->ocspuri))
+ else
+ /* abort if no ocsp location uri is defined */
+ return FALSE;
+ }
+
+ setchunk(location->authNameID, digest, SHA1_DIGEST_SIZE);
+ compute_digest(cert->issuer, OID_SHA1, &location->authNameID);
+
+ location->next = NULL;
+ location->issuer = cert->issuer;
+ location->authKeyID = cert->authKeyID;
+ location->authKeySerialNumber = cert->authKeySerialNumber;
+
+ if (cert->authKeyID.ptr == NULL)
+ {
+ x509cert_t *authcert = get_authcert(cert->issuer
+ , cert->authKeySerialNumber, cert->authKeyID, AUTH_CA);
+
+ if (authcert != NULL)
+ {
+ location->authKeyID = authcert->subjectKeyID;
+ location->authKeySerialNumber = authcert->serialNumber;
+ }
+ }
+
+ location->nonce = empty_chunk;
+ location->certinfo = NULL;
+
+ return TRUE;
+}
+
+/*
+ * compare two ocsp locations for equality
+ */
+static bool
+same_ocsp_location(const ocsp_location_t *a, const ocsp_location_t *b)
+{
+ return ((a->authKeyID.ptr != NULL)
+ ? same_keyid(a->authKeyID, b->authKeyID)
+ : (same_dn(a->issuer, b->issuer)
+ && same_serial(a->authKeySerialNumber, b->authKeySerialNumber)))
+ && same_chunk(a->uri, b->uri);
+}
+
+/*
+ * find an existing ocsp location in a chained list
+ */
+ocsp_location_t*
+get_ocsp_location(const ocsp_location_t * loc, ocsp_location_t *chain)
+{
+
+ while (chain != NULL)
+ {
+ if (same_ocsp_location(loc, chain))
+ return chain;
+ chain = chain->next;
+ }
+ return NULL;
+}
+
+/* retrieves the status of a cert from the ocsp cache
+ * returns CERT_UNDEFINED if no status is found
+ */
+static cert_status_t
+get_ocsp_status(const ocsp_location_t *loc, chunk_t serialNumber
+ ,time_t *nextUpdate, time_t *revocationTime, crl_reason_t *revocationReason)
+{
+ ocsp_certinfo_t *certinfo, **certinfop;
+ int cmp = -1;
+
+ /* find location */
+ ocsp_location_t *location = get_ocsp_location(loc, ocsp_cache);
+
+ if (location == NULL)
+ return CERT_UNDEFINED;
+
+ /* traverse list of certinfos in increasing order */
+ certinfop = &location->certinfo;
+ certinfo = *certinfop;
+
+ while (certinfo != NULL)
+ {
+ cmp = cmp_chunk(serialNumber, certinfo->serialNumber);
+ if (cmp <= 0)
+ break;
+ certinfop = &certinfo->next;
+ certinfo = *certinfop;
+ }
+
+ if (cmp == 0)
+ {
+ *nextUpdate = certinfo->nextUpdate;
+ *revocationTime = certinfo->revocationTime;
+ *revocationReason = certinfo->revocationReason;
+ return certinfo->status;
+ }
+
+ return CERT_UNDEFINED;
+}
+
+/*
+ * verify the ocsp status of a certificate
+ */
+cert_status_t
+verify_by_ocsp(const x509cert_t *cert, time_t *until
+, time_t *revocationDate, crl_reason_t *revocationReason)
+{
+ cert_status_t status;
+ ocsp_location_t location;
+ time_t nextUpdate = 0;
+
+ *revocationDate = UNDEFINED_TIME;
+ *revocationReason = REASON_UNSPECIFIED;
+
+ /* is an ocsp location defined? */
+ if (!build_ocsp_location(cert, &location))
+ return CERT_UNDEFINED;
+
+ lock_ocsp_cache("verify_by_ocsp");
+ status = get_ocsp_status(&location, cert->serialNumber, &nextUpdate
+ , revocationDate, revocationReason);
+ unlock_ocsp_cache("verify_by_ocsp");
+
+ if (status == CERT_UNDEFINED || nextUpdate < time(NULL))
+ {
+ plog("ocsp status is stale or not in cache");
+ add_ocsp_fetch_request(&location, cert->serialNumber);
+
+ /* inititate fetching of ocsp status */
+ wake_fetch_thread("verify_by_ocsp");
+ }
+ *until = nextUpdate;
+ return status;
+}
+
+/*
+ * check if an ocsp status is about to expire
+ */
+void
+check_ocsp(void)
+{
+ ocsp_location_t *location;
+
+ lock_ocsp_cache("check_ocsp");
+ location = ocsp_cache;
+
+ while (location != NULL)
+ {
+ char buf[BUF_LEN];
+ bool first = TRUE;
+ ocsp_certinfo_t *certinfo = location->certinfo;
+
+ while (certinfo != NULL)
+ {
+ if (!certinfo->once)
+ {
+ time_t time_left = certinfo->nextUpdate - time(NULL);
+
+ DBG(DBG_CONTROL,
+ if (first)
+ {
+ dntoa(buf, BUF_LEN, location->issuer);
+ DBG_log("issuer: '%s'", buf);
+ if (location->authKeyID.ptr != NULL)
+ {
+ datatot(location->authKeyID.ptr, location->authKeyID.len
+ , ':', buf, BUF_LEN);
+ DBG_log("authkey: %s", buf);
+ }
+ first = FALSE;
+ }
+ datatot(certinfo->serialNumber.ptr, certinfo->serialNumber.len
+ , ':', buf, BUF_LEN);
+ DBG_log("serial: %s, %ld seconds left", buf, time_left)
+ )
+
+ if (time_left < 2*crl_check_interval)
+ add_ocsp_fetch_request(location, certinfo->serialNumber);
+ }
+ certinfo = certinfo->next;
+ }
+ location = location->next;
+ }
+ unlock_ocsp_cache("check_ocsp");
+}
+
+/*
+ * frees the allocated memory of a certinfo struct
+ */
+static void
+free_certinfo(ocsp_certinfo_t *certinfo)
+{
+ freeanychunk(certinfo->serialNumber);
+ pfree(certinfo);
+}
+
+/*
+ * frees all certinfos in a chained list
+ */
+static void
+free_certinfos(ocsp_certinfo_t *chain)
+{
+ ocsp_certinfo_t *certinfo;
+
+ while (chain != NULL)
+ {
+ certinfo = chain;
+ chain = chain->next;
+ free_certinfo(certinfo);
+ }
+}
+
+/*
+ * frees the memory allocated to an ocsp location including all certinfos
+ */
+static void
+free_ocsp_location(ocsp_location_t* location)
+{
+ freeanychunk(location->issuer);
+ freeanychunk(location->authNameID);
+ freeanychunk(location->authKeyID);
+ freeanychunk(location->authKeySerialNumber);
+ freeanychunk(location->uri);
+ free_certinfos(location->certinfo);
+ pfree(location);
+}
+
+/*
+ * free a chained list of ocsp locations
+ */
+void
+free_ocsp_locations(ocsp_location_t **chain)
+{
+ while (*chain != NULL)
+ {
+ ocsp_location_t *location = *chain;
+ *chain = location->next;
+ free_ocsp_location(location);
+ }
+}
+
+/*
+ * free the ocsp cache
+ */
+void
+free_ocsp_cache(void)
+{
+ lock_ocsp_cache("free_ocsp_cache");
+ free_ocsp_locations(&ocsp_cache);
+ unlock_ocsp_cache("free_ocsp_cache");
+}
+
+/*
+ * frees the ocsp cache and global variables
+ */
+void
+free_ocsp(void)
+{
+ pfreeany(ocsp_default_uri.ptr);
+ free_ocsp_cache();
+}
+
+/*
+ * list a chained list of ocsp_locations
+ */
+void
+list_ocsp_locations(ocsp_location_t *location, bool requests, bool utc
+, bool strict)
+{
+ bool first = TRUE;
+
+ while (location != NULL)
+ {
+ ocsp_certinfo_t *certinfo = location->certinfo;
+
+ if (certinfo != NULL)
+ {
+ u_char buf[BUF_LEN];
+
+ if (first)
+ {
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of OCSP %s:", requests?
+ "fetch requests":"responses");
+ first = FALSE;
+ }
+ whack_log(RC_COMMENT, " ");
+ if (location->issuer.ptr != NULL)
+ {
+ dntoa(buf, BUF_LEN, location->issuer);
+ whack_log(RC_COMMENT, " issuer: '%s'", buf);
+ }
+ whack_log(RC_COMMENT, " uri: '%.*s'", (int)location->uri.len
+ , location->uri.ptr);
+ if (location->authNameID.ptr != NULL)
+ {
+ datatot(location->authNameID.ptr, location->authNameID.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " authname: %s", buf);
+ }
+ if (location->authKeyID.ptr != NULL)
+ {
+ datatot(location->authKeyID.ptr, location->authKeyID.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " authkey: %s", buf);
+ }
+ if (location->authKeySerialNumber.ptr != NULL)
+ {
+ datatot(location->authKeySerialNumber.ptr
+ , location->authKeySerialNumber.len, ':', buf, BUF_LEN);
+ whack_log(RC_COMMENT, " aserial: %s", buf);
+ }
+ while (certinfo != NULL)
+ {
+ char thisUpdate[TIMETOA_BUF];
+
+ strcpy(thisUpdate, timetoa(&certinfo->thisUpdate, utc));
+
+ if (requests)
+ {
+ whack_log(RC_COMMENT, "%s, trials: %d", thisUpdate
+ , certinfo->trials);
+ }
+ else if (certinfo->once)
+ {
+ whack_log(RC_COMMENT, "%s, onetime use%s", thisUpdate
+ , (certinfo->nextUpdate < time(NULL))? " (expired)": "");
+ }
+ else
+ {
+ whack_log(RC_COMMENT, "%s, until %s %s", thisUpdate
+ , timetoa(&certinfo->nextUpdate, utc)
+ , check_expiry(certinfo->nextUpdate, OCSP_WARNING_INTERVAL, strict));
+ }
+ datatot(certinfo->serialNumber.ptr, certinfo->serialNumber.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " serial: %s, %s", buf
+ , cert_status_names[certinfo->status]);
+ certinfo = certinfo->next;
+ }
+ }
+ location = location->next;
+ }
+}
+
+/*
+ * list the ocsp cache
+ */
+void
+list_ocsp_cache(bool utc, bool strict)
+{
+ lock_ocsp_cache("list_ocsp_cache");
+ list_ocsp_locations(ocsp_cache, FALSE, utc, strict);
+ unlock_ocsp_cache("list_ocsp_cache");
+}
+
+static bool
+get_ocsp_requestor_cert(ocsp_location_t *location)
+{
+ x509cert_t *cert = NULL;
+
+ /* initialize temporary static storage */
+ ocsp_requestor_cert = NULL;
+ ocsp_requestor_sc = NULL;
+ ocsp_requestor_pri = NULL;
+
+ for (;;)
+ {
+ char buf[BUF_LEN];
+
+ /* looking for a certificate from the same issuer */
+ cert = get_x509cert(location->issuer, location->authKeySerialNumber
+ ,location->authKeyID, cert);
+ if (cert == NULL)
+ break;
+
+ DBG(DBG_CONTROL,
+ dntoa(buf, BUF_LEN, cert->subject);
+ DBG_log("candidate: '%s'", buf);
+ )
+
+ if (cert->smartcard)
+ {
+ /* look for a matching private key on a smartcard */
+ smartcard_t *sc = scx_get(cert);
+
+ if (sc != NULL)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("matching smartcard found")
+ )
+ if (sc->valid)
+ {
+ ocsp_requestor_cert = cert;
+ ocsp_requestor_sc = sc;
+ return TRUE;
+ }
+ plog("unable to sign ocsp request without PIN");
+ }
+ }
+ else
+ {
+ /* look for a matching private key in the chained list */
+ const struct RSA_private_key *pri = get_x509_private_key(cert);
+
+ if (pri != NULL)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("matching private key found")
+ )
+ ocsp_requestor_cert = cert;
+ ocsp_requestor_pri = pri;
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+static chunk_t
+generate_signature(chunk_t digest, smartcard_t *sc
+ , const RSA_private_key_t *pri)
+{
+ chunk_t sigdata;
+ u_char *pos;
+ size_t siglen = 0;
+
+ if (sc != NULL)
+ {
+ /* RSA signature is done on smartcard */
+
+ if (!scx_establish_context(sc) || !scx_login(sc))
+ {
+ scx_release_context(sc);
+ return empty_chunk;
+ }
+
+ siglen = scx_get_keylength(sc);
+
+ if (siglen == 0)
+ {
+ plog("failed to get keylength from smartcard");
+ scx_release_context(sc);
+ return empty_chunk;
+ }
+
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ DBG_log("signing hash with RSA key from smartcard (slot: %d, id: %s)"
+ , (int)sc->slot, sc->id)
+ )
+
+ pos = build_asn1_object(&sigdata, ASN1_BIT_STRING, 1 + siglen);
+ *pos++ = 0x00;
+ scx_sign_hash(sc, digest.ptr, digest.len, pos, siglen);
+ if (!pkcs11_keep_state)
+ scx_release_context(sc);
+ }
+ else
+ {
+ /* RSA signature is done in software */
+ siglen = pri->pub.k;
+ pos = build_asn1_object(&sigdata, ASN1_BIT_STRING, 1 + siglen);
+ *pos++ = 0x00;
+ sign_hash(pri, digest.ptr, digest.len, pos, siglen);
+ }
+ return sigdata;
+}
+
+/*
+ * build signature into ocsp request
+ * gets built only if a request cert with
+ * a corresponding private key is found
+ */
+static chunk_t
+build_signature(chunk_t tbsRequest)
+{
+ chunk_t sigdata, certs;
+ chunk_t digest_info;
+
+ u_char digest_buf[MAX_DIGEST_LEN];
+ chunk_t digest_raw = { digest_buf, MAX_DIGEST_LEN };
+
+ if (!compute_digest(tbsRequest, OID_SHA1, &digest_raw))
+ return empty_chunk;
+
+ /* according to PKCS#1 v2.1 digest must be packaged into
+ * an ASN.1 structure for encryption
+ */
+ digest_info = asn1_wrap(ASN1_SEQUENCE, "cm"
+ , ASN1_sha1_id
+ , asn1_simple_object(ASN1_OCTET_STRING, digest_raw));
+
+ /* generate the RSA signature */
+ sigdata = generate_signature(digest_info
+ , ocsp_requestor_sc
+ , ocsp_requestor_pri);
+ freeanychunk(digest_info);
+
+ /* has the RSA signature generation been successful? */
+ if (sigdata.ptr == NULL)
+ return empty_chunk;
+
+ /* include our certificate */
+ certs = asn1_wrap(ASN1_CONTEXT_C_0, "m"
+ , asn1_simple_object(ASN1_SEQUENCE
+ , ocsp_requestor_cert->certificate
+ )
+ );
+
+ /* build signature comprising algorithm, signature and cert */
+ return asn1_wrap(ASN1_CONTEXT_C_0, "m"
+ , asn1_wrap(ASN1_SEQUENCE, "cmm"
+ , ASN1_sha1WithRSA_id
+ , sigdata
+ , certs
+ )
+ );
+}
+
+/* build request (into requestList)
+ * no singleRequestExtensions used
+ */
+static chunk_t
+build_request(ocsp_location_t *location, ocsp_certinfo_t *certinfo)
+{
+ chunk_t reqCert = asn1_wrap(ASN1_SEQUENCE, "cmmm"
+ , ASN1_sha1_id
+ , asn1_simple_object(ASN1_OCTET_STRING, location->authNameID)
+ , asn1_simple_object(ASN1_OCTET_STRING, location->authKeyID)
+ , asn1_simple_object(ASN1_INTEGER, certinfo->serialNumber));
+
+ return asn1_wrap(ASN1_SEQUENCE, "m", reqCert);
+}
+
+/*
+ * build requestList (into TBSRequest)
+ */
+static chunk_t
+build_request_list(ocsp_location_t *location)
+{
+ chunk_t requestList;
+ request_list_t *reqs = NULL;
+ ocsp_certinfo_t *certinfo = location->certinfo;
+ u_char *pos;
+
+ size_t datalen = 0;
+
+ /* build content */
+ while (certinfo != NULL)
+ {
+ /* build request for every certificate in list
+ * and store them in a chained list
+ */
+ request_list_t *req = alloc_thing(request_list_t, "ocsp request");
+
+ req->request = build_request(location, certinfo);
+ req->next = reqs;
+ reqs = req;
+
+ datalen += req->request.len;
+ certinfo = certinfo->next;
+ }
+
+ pos = build_asn1_object(&requestList, ASN1_SEQUENCE
+ , datalen);
+
+ /* copy all in chained list, free list afterwards */
+ while (reqs != NULL)
+ {
+ request_list_t *req = reqs;
+
+ mv_chunk(&pos, req->request);
+ reqs = reqs->next;
+ pfree(req);
+ }
+
+ return requestList;
+}
+
+/*
+ * build requestorName (into TBSRequest)
+ */
+static chunk_t
+build_requestor_name(void)
+{
+ return asn1_wrap(ASN1_CONTEXT_C_1, "m"
+ , asn1_simple_object(ASN1_CONTEXT_C_4
+ , ocsp_requestor_cert->subject));
+}
+
+/*
+ * build nonce extension (into requestExtensions)
+ */
+static chunk_t
+build_nonce_extension(ocsp_location_t *location)
+{
+ /* generate a random nonce */
+ location->nonce.ptr = alloc_bytes(NONCE_LENGTH, "ocsp nonce"),
+ location->nonce.len = NONCE_LENGTH;
+ get_rnd_bytes(location->nonce.ptr, NONCE_LENGTH);
+
+ return asn1_wrap(ASN1_SEQUENCE, "cm"
+ , ASN1_nonce_oid
+ , asn1_simple_object(ASN1_OCTET_STRING, location->nonce));
+}
+
+/*
+ * build requestExtensions (into TBSRequest)
+ */
+static chunk_t
+build_request_ext(ocsp_location_t *location)
+{
+ return asn1_wrap(ASN1_CONTEXT_C_2, "m"
+ , asn1_wrap(ASN1_SEQUENCE, "mm"
+ , build_nonce_extension(location)
+ , asn1_wrap(ASN1_SEQUENCE, "cc"
+ , ASN1_response_oid
+ , ASN1_response_content
+ )
+ )
+ );
+}
+
+/*
+ * build TBSRequest (into OCSPRequest)
+ */
+static chunk_t
+build_tbs_request(ocsp_location_t *location, bool has_requestor_cert)
+{
+ /* version is skipped since the default is ok */
+ return asn1_wrap(ASN1_SEQUENCE, "mmm"
+ , (has_requestor_cert)
+ ? build_requestor_name()
+ : empty_chunk
+ , build_request_list(location)
+ , build_request_ext(location));
+}
+
+/* assembles an ocsp request to given location
+ * and sets nonce field in location to the sent nonce
+ */
+chunk_t
+build_ocsp_request(ocsp_location_t *location)
+{
+ bool has_requestor_cert;
+ chunk_t tbsRequest, signature;
+ char buf[BUF_LEN];
+
+ DBG(DBG_CONTROL,
+ DBG_log("assembling ocsp request");
+ dntoa(buf, BUF_LEN, location->issuer);
+ DBG_log("issuer: '%s'", buf);
+ if (location->authKeyID.ptr != NULL)
+ {
+ datatot(location->authKeyID.ptr, location->authKeyID.len, ':'
+ , buf, BUF_LEN);
+ DBG_log("authkey: %s", buf);
+ }
+ )
+ lock_certs_and_keys("build_ocsp_request");
+
+ /* looks for requestor cert and matching private key */
+ has_requestor_cert = get_ocsp_requestor_cert(location);
+
+ /* build content */
+ tbsRequest = build_tbs_request(location, has_requestor_cert);
+
+ /* sign tbsReuqest */
+ signature = (has_requestor_cert)? build_signature(tbsRequest)
+ : empty_chunk;
+
+ unlock_certs_and_keys("build_ocsp_request");
+
+ return asn1_wrap(ASN1_SEQUENCE, "mm"
+ , tbsRequest
+ , signature);
+}
+
+/*
+ * check if the OCSP response has a valid signature
+ */
+static bool
+valid_ocsp_response(response_t *res)
+{
+ int pathlen;
+ x509cert_t *authcert;
+
+ lock_authcert_list("valid_ocsp_response");
+
+ authcert = get_authcert(res->responder_id_name, empty_chunk
+ , res->responder_id_key, AUTH_OCSP | AUTH_CA);
+
+ if (authcert == NULL)
+ {
+ plog("no matching ocsp signer cert found");
+ unlock_authcert_list("valid_ocsp_response");
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("ocsp signer cert found")
+ )
+
+ if (!check_signature(res->tbs, res->signature, res->algorithm
+ , res->algorithm, authcert))
+ {
+ plog("signature of ocsp response is invalid");
+ unlock_authcert_list("valid_ocsp_response");
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("signature of ocsp response is valid")
+ )
+
+
+ for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++)
+ {
+ u_char buf[BUF_LEN];
+ err_t ugh = NULL;
+ time_t until;
+
+ x509cert_t *cert = authcert;
+
+ DBG(DBG_CONTROL,
+ dntoa(buf, BUF_LEN, cert->subject);
+ DBG_log("subject: '%s'",buf);
+ dntoa(buf, BUF_LEN, cert->issuer);
+ DBG_log("issuer: '%s'",buf);
+ if (cert->authKeyID.ptr != NULL)
+ {
+ datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':'
+ , buf, BUF_LEN);
+ DBG_log("authkey: %s", buf);
+ }
+ )
+
+ ugh = check_validity(authcert, &until);
+
+ if (ugh != NULL)
+ {
+ plog("%s", ugh);
+ unlock_authcert_list("valid_ocsp_response");
+ return FALSE;
+ }
+
+ DBG(DBG_CONTROL,
+ DBG_log("certificate is valid")
+ )
+
+ authcert = get_authcert(cert->issuer, cert->authKeySerialNumber
+ , cert->authKeyID, AUTH_CA);
+
+ if (authcert == NULL)
+ {
+ plog("issuer cacert not found");
+ unlock_authcert_list("valid_ocsp_response");
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("issuer cacert found")
+ )
+
+ if (!check_signature(cert->tbsCertificate, cert->signature
+ , cert->algorithm, cert->algorithm, authcert))
+ {
+ plog("certificate signature is invalid");
+ unlock_authcert_list("valid_ocsp_response");
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("certificate signature is valid")
+ )
+
+ /* check if cert is self-signed */
+ if (same_dn(cert->issuer, cert->subject))
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("reached self-signed root ca")
+ )
+ unlock_authcert_list("valid_ocsp_response");
+ return TRUE;
+ }
+ }
+ plog("maximum ca path length of %d levels exceeded", MAX_CA_PATH_LEN);
+ unlock_authcert_list("valid_ocsp_response");
+ return FALSE;
+}
+
+/*
+ * parse a basic OCSP response
+ */
+static bool
+parse_basic_ocsp_response(chunk_t blob, int level0, response_t *res)
+{
+ u_int level, version;
+ u_int extn_oid = OID_UNKNOWN;
+ u_char buf[BUF_LEN];
+ asn1_ctx_t ctx;
+ bool critical;
+ chunk_t object;
+ int objectID = 0;
+
+ asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
+
+ while (objectID < BASIC_RESPONSE_ROOF)
+ {
+ if (!extract_object(basicResponseObjects, &objectID, &object, &level, &ctx))
+ return FALSE;
+
+ switch (objectID)
+ {
+ case BASIC_RESPONSE_TBS_DATA:
+ res->tbs = object;
+ break;
+ case BASIC_RESPONSE_VERSION:
+ version = (object.len)? (1 + (u_int)*object.ptr) : 1;
+ if (version != OCSP_BASIC_RESPONSE_VERSION)
+ {
+ plog("wrong ocsp basic response version (version= %i)", version);
+ return FALSE;
+ }
+ break;
+ case BASIC_RESPONSE_ID_BY_NAME:
+ res->responder_id_name = object;
+ DBG(DBG_PARSING,
+ dntoa(buf, BUF_LEN, object);
+ DBG_log(" '%s'",buf)
+ )
+ break;
+ case BASIC_RESPONSE_ID_BY_KEY:
+ res->responder_id_key = object;
+ break;
+ case BASIC_RESPONSE_PRODUCED_AT:
+ res->produced_at = asn1totime(&object, ASN1_GENERALIZEDTIME);
+ break;
+ case BASIC_RESPONSE_RESPONSES:
+ res->responses = object;
+ break;
+ case BASIC_RESPONSE_EXT_ID:
+ extn_oid = known_oid(object);
+ break;
+ case BASIC_RESPONSE_CRITICAL:
+ critical = object.len && *object.ptr;
+ DBG(DBG_PARSING,
+ DBG_log(" %s",(critical)?"TRUE":"FALSE");
+ )
+ break;
+ case BASIC_RESPONSE_EXT_VALUE:
+ if (extn_oid == OID_NONCE)
+ res->nonce = object;
+ break;
+ case BASIC_RESPONSE_ALGORITHM:
+ res->algorithm = parse_algorithmIdentifier(object, level+1, NULL);
+ break;
+ case BASIC_RESPONSE_SIGNATURE:
+ res->signature = object;
+ break;
+ case BASIC_RESPONSE_CERTIFICATE:
+ {
+ chunk_t blob;
+ x509cert_t *cert = alloc_thing(x509cert_t, "ocspcert");
+
+ clonetochunk(blob, object.ptr, object.len, "ocspcert blob");
+ *cert = empty_x509cert;
+
+ if (parse_x509cert(blob, level+1, cert)
+ && cert->isOcspSigner
+ && trust_authcert_candidate(cert, NULL))
+ {
+ add_authcert(cert, AUTH_OCSP);
+ }
+ else
+ {
+ DBG(DBG_CONTROL | DBG_PARSING,
+ DBG_log("embedded ocsp certificate rejected")
+ )
+ free_x509cert(cert);
+ }
+ }
+ break;
+ }
+ objectID++;
+ }
+ return TRUE;
+}
+
+
+/*
+ * parse an ocsp response and return the result as a response_t struct
+ */
+static response_status
+parse_ocsp_response(chunk_t blob, response_t * res)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+
+ response_status rStatus = STATUS_INTERNALERROR;
+ u_int ocspResponseType = OID_UNKNOWN;
+
+ asn1_init(&ctx, blob, 0, FALSE, DBG_RAW);
+
+ while (objectID < OCSP_RESPONSE_ROOF)
+ {
+ if (!extract_object(ocspResponseObjects, &objectID, &object, &level, &ctx))
+ return STATUS_INTERNALERROR;
+
+ switch (objectID) {
+ case OCSP_RESPONSE_STATUS:
+ rStatus = (response_status) *object.ptr;
+
+ switch (rStatus)
+ {
+ case STATUS_SUCCESSFUL:
+ break;
+ case STATUS_MALFORMEDREQUEST:
+ case STATUS_INTERNALERROR:
+ case STATUS_TRYLATER:
+ case STATUS_SIGREQUIRED:
+ case STATUS_UNAUTHORIZED:
+ plog("ocsp response: server said '%s'"
+ , response_status_names[rStatus]);
+ return rStatus;
+ default:
+ return STATUS_INTERNALERROR;
+ }
+ break;
+ case OCSP_RESPONSE_TYPE:
+ ocspResponseType = known_oid(object);
+ break;
+ case OCSP_RESPONSE:
+ {
+ switch (ocspResponseType) {
+ case OID_BASIC:
+ if (!parse_basic_ocsp_response(object, level+1, res))
+ return STATUS_INTERNALERROR;
+ break;
+ default:
+ DBG(DBG_CONTROL,
+ DBG_log("ocsp response is not of type BASIC");
+ DBG_dump_chunk("ocsp response OID: ", object);
+ )
+ return STATUS_INTERNALERROR;
+ }
+ }
+ break;
+ }
+ objectID++;
+ }
+ return rStatus;
+}
+
+/*
+ * parse a basic OCSP response
+ */
+static bool
+parse_ocsp_single_response(chunk_t blob, int level0, single_response_t *sres)
+{
+ u_int level, extn_oid;
+ asn1_ctx_t ctx;
+ bool critical;
+ chunk_t object;
+ int objectID = 0;
+
+ asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
+
+ while (objectID < SINGLE_RESPONSE_ROOF)
+ {
+ if (!extract_object(singleResponseObjects, &objectID, &object, &level, &ctx))
+ return FALSE;
+
+ switch (objectID)
+ {
+ case SINGLE_RESPONSE_ALGORITHM:
+ sres->hash_algorithm = parse_algorithmIdentifier(object, level+1, NULL);
+ break;
+ case SINGLE_RESPONSE_ISSUER_NAME_HASH:
+ sres->issuer_name_hash = object;
+ break;
+ case SINGLE_RESPONSE_ISSUER_KEY_HASH:
+ sres->issuer_key_hash = object;
+ break;
+ case SINGLE_RESPONSE_SERIAL_NUMBER:
+ sres->serialNumber = object;
+ break;
+ case SINGLE_RESPONSE_CERT_STATUS_GOOD:
+ sres->status = CERT_GOOD;
+ break;
+ case SINGLE_RESPONSE_CERT_STATUS_REVOKED:
+ sres->status = CERT_REVOKED;
+ break;
+ case SINGLE_RESPONSE_CERT_STATUS_REVOCATION_TIME:
+ sres->revocationTime = asn1totime(&object, ASN1_GENERALIZEDTIME);
+ break;
+ case SINGLE_RESPONSE_CERT_STATUS_CRL_REASON:
+ sres->revocationReason = (object.len == 1)
+ ? *object.ptr : REASON_UNSPECIFIED;
+ break;
+ case SINGLE_RESPONSE_CERT_STATUS_UNKNOWN:
+ sres->status = CERT_UNKNOWN;
+ break;
+ case SINGLE_RESPONSE_THIS_UPDATE:
+ sres->thisUpdate = asn1totime(&object, ASN1_GENERALIZEDTIME);
+ break;
+ case SINGLE_RESPONSE_NEXT_UPDATE:
+ sres->nextUpdate = asn1totime(&object, ASN1_GENERALIZEDTIME);
+ break;
+ case SINGLE_RESPONSE_EXT_ID:
+ extn_oid = known_oid(object);
+ break;
+ case SINGLE_RESPONSE_CRITICAL:
+ critical = object.len && *object.ptr;
+ DBG(DBG_PARSING,
+ DBG_log(" %s",(critical)?"TRUE":"FALSE");
+ )
+ case SINGLE_RESPONSE_EXT_VALUE:
+ break;
+ }
+ objectID++;
+ }
+ return TRUE;
+}
+
+/*
+ * add an ocsp location to a chained list
+ */
+ocsp_location_t*
+add_ocsp_location(const ocsp_location_t *loc, ocsp_location_t **chain)
+{
+ ocsp_location_t *location = alloc_thing(ocsp_location_t, "ocsp location");
+
+ /* unshare location fields */
+ clonetochunk(location->issuer
+ , loc->issuer.ptr, loc->issuer.len
+ , "ocsp issuer");
+
+ clonetochunk(location->authNameID
+ , loc->authNameID.ptr, loc->authNameID.len
+ , "ocsp authNameID");
+
+ if (loc->authKeyID.ptr == NULL)
+ location->authKeyID = empty_chunk;
+ else
+ clonetochunk(location->authKeyID
+ , loc->authKeyID.ptr, loc->authKeyID.len
+ , "ocsp authKeyID");
+
+ if (loc->authKeySerialNumber.ptr == NULL)
+ location->authKeySerialNumber = empty_chunk;
+ else
+ clonetochunk(location->authKeySerialNumber
+ , loc->authKeySerialNumber.ptr, loc->authKeySerialNumber.len
+ , "ocsp authKeySerialNumber");
+
+ clonetochunk(location->uri
+ , loc->uri.ptr, loc->uri.len
+ , "ocsp uri");
+
+ location->certinfo = NULL;
+
+ /* insert new ocsp location in front of chain */
+ location->next = *chain;
+ *chain = location;
+
+ DBG(DBG_CONTROL,
+ DBG_log("new ocsp location added")
+ )
+
+ return location;
+}
+
+/*
+ * add a certinfo struct to a chained list
+ */
+void
+add_certinfo(ocsp_location_t *loc, ocsp_certinfo_t *info, ocsp_location_t **chain
+ , bool request)
+{
+ ocsp_location_t *location;
+ ocsp_certinfo_t *certinfo, **certinfop;
+ char buf[BUF_LEN];
+ time_t now;
+ int cmp = -1;
+
+ location = get_ocsp_location(loc, *chain);
+ if (location == NULL)
+ location = add_ocsp_location(loc, chain);
+
+ /* traverse list of certinfos in increasing order */
+ certinfop = &location->certinfo;
+ certinfo = *certinfop;
+
+ while (certinfo != NULL)
+ {
+ cmp = cmp_chunk(info->serialNumber, certinfo->serialNumber);
+ if (cmp <= 0)
+ break;
+ certinfop = &certinfo->next;
+ certinfo = *certinfop;
+ }
+
+ if (cmp != 0)
+ {
+ /* add a new certinfo entry */
+ ocsp_certinfo_t *cnew = alloc_thing(ocsp_certinfo_t, "ocsp certinfo");
+ clonetochunk(cnew->serialNumber, info->serialNumber.ptr
+ , info->serialNumber.len, "serialNumber");
+ cnew->next = certinfo;
+ *certinfop = cnew;
+ certinfo = cnew;
+ }
+
+ DBG(DBG_CONTROL,
+ datatot(info->serialNumber.ptr, info->serialNumber.len, ':'
+ , buf, BUF_LEN);
+ DBG_log("ocsp %s for serial %s %s"
+ , request?"fetch request":"certinfo"
+ , buf
+ , (cmp == 0)? (request?"already exists":"updated"):"added")
+ )
+
+ time(&now);
+
+ if (request)
+ {
+ certinfo->status = CERT_UNDEFINED;
+
+ if (cmp != 0)
+ certinfo->thisUpdate = now;
+
+ certinfo->nextUpdate = UNDEFINED_TIME;
+ }
+ else
+ {
+ certinfo->status = info->status;
+ certinfo->revocationTime = info->revocationTime;
+ certinfo->revocationReason = info->revocationReason;
+
+ certinfo->thisUpdate = (info->thisUpdate != UNDEFINED_TIME)?
+ info->thisUpdate : now;
+
+ certinfo->once = (info->nextUpdate == UNDEFINED_TIME);
+
+ certinfo->nextUpdate = (certinfo->once)?
+ (now + OCSP_DEFAULT_VALID_TIME) : info->nextUpdate;
+ }
+}
+
+/*
+ * process received ocsp single response and add it to ocsp cache
+ */
+static void
+process_single_response(ocsp_location_t *location, single_response_t *sres)
+{
+ ocsp_certinfo_t *certinfo, **certinfop;
+ int cmp = -1;
+
+ if (sres->hash_algorithm != OID_SHA1)
+ {
+ plog("only SHA-1 hash supported in OCSP single response");
+ return;
+ }
+ if (!(same_chunk(sres->issuer_name_hash, location->authNameID)
+ && same_chunk(sres->issuer_key_hash, location->authKeyID)))
+ {
+ plog("ocsp single response has wrong issuer");
+ return;
+ }
+
+ /* traverse list of certinfos in increasing order */
+ certinfop = &location->certinfo;
+ certinfo = *certinfop;
+
+ while (certinfo != NULL)
+ {
+ cmp = cmp_chunk(sres->serialNumber, certinfo->serialNumber);
+ if (cmp <= 0)
+ break;
+ certinfop = &certinfo->next;
+ certinfo = *certinfop;
+ }
+
+ if (cmp != 0)
+ {
+ plog("received unrequested cert status from ocsp server");
+ return;
+ }
+
+ /* unlink cert from ocsp fetch request list */
+ *certinfop = certinfo->next;
+
+ /* update certinfo using the single response information */
+ certinfo->thisUpdate = sres->thisUpdate;
+ certinfo->nextUpdate = sres->nextUpdate;
+ certinfo->status = sres->status;
+ certinfo->revocationTime = sres->revocationTime;
+ certinfo->revocationReason = sres->revocationReason;
+
+ /* add or update certinfo in ocsp cache */
+ lock_ocsp_cache("process_single_response");
+ add_certinfo(location, certinfo, &ocsp_cache, FALSE);
+ unlock_ocsp_cache("process_single_response");
+
+ /* free certinfo unlinked from ocsp fetch request list */
+ free_certinfo(certinfo);
+
+}
+
+/*
+ * parse and verify ocsp response and update the ocsp cache
+ */
+void
+parse_ocsp(ocsp_location_t *location, chunk_t blob)
+{
+ response_t res = empty_response;
+
+ /* parse the ocsp response without looking at the single responses yet */
+ response_status status = parse_ocsp_response(blob, &res);
+
+ if (status != STATUS_SUCCESSFUL)
+ {
+ plog("error in ocsp response");
+ return;
+ }
+ /* check if there was a nonce in the request */
+ if (location->nonce.ptr != NULL && res.nonce.ptr == NULL)
+ {
+ plog("ocsp response contains no nonce, replay attack possible");
+ }
+ /* check if the nonce is identical */
+ if (res.nonce.ptr != NULL && !same_chunk(res.nonce, location->nonce))
+ {
+ plog("invalid nonce in ocsp response");
+ return;
+ }
+ /* check if the response is signed by a trusted key */
+ if (!valid_ocsp_response(&res))
+ {
+ plog("invalid ocsp response");
+ return;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("valid ocsp response")
+ )
+
+ /* now parse the single responses one at a time */
+ {
+ u_int level;
+ asn1_ctx_t ctx;
+ chunk_t object;
+ int objectID = 0;
+
+ asn1_init(&ctx, res.responses, 0, FALSE, DBG_RAW);
+
+ while (objectID < RESPONSES_ROOF)
+ {
+ if (!extract_object(responsesObjects, &objectID, &object, &level, &ctx))
+ return;
+
+ if (objectID == RESPONSES_SINGLE_RESPONSE)
+ {
+ single_response_t sres = empty_single_response;
+
+ if (parse_ocsp_single_response(object, level+1, &sres))
+ {
+ process_single_response(location, &sres);
+ }
+ }
+ objectID++;
+ }
+ }
+}
diff --git a/src/pluto/ocsp.h b/src/pluto/ocsp.h
new file mode 100644
index 000000000..49e1026ec
--- /dev/null
+++ b/src/pluto/ocsp.h
@@ -0,0 +1,85 @@
+/* Support of the Online Certificate Status Protocol (OCSP) Support
+ * Copyright (C) 2003 Christoph Gysin, Simon Zwahlen
+ * 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.
+ *
+ */
+
+#include "constants.h"
+
+/* constants */
+
+#define OCSP_BASIC_RESPONSE_VERSION 1
+#define OCSP_DEFAULT_VALID_TIME 120 /* validity of one-time response in seconds */
+#define OCSP_WARNING_INTERVAL 2 /* days */
+
+/* OCSP response status */
+
+typedef enum {
+ STATUS_SUCCESSFUL = 0,
+ STATUS_MALFORMEDREQUEST = 1,
+ STATUS_INTERNALERROR = 2,
+ STATUS_TRYLATER = 3,
+ STATUS_SIGREQUIRED = 5,
+ STATUS_UNAUTHORIZED= 6
+} response_status;
+
+/* OCSP access structures */
+
+typedef struct ocsp_certinfo ocsp_certinfo_t;
+
+struct ocsp_certinfo {
+ ocsp_certinfo_t *next;
+ int trials;
+ chunk_t serialNumber;
+ cert_status_t status;
+ bool once;
+ crl_reason_t revocationReason;
+ time_t revocationTime;
+ time_t thisUpdate;
+ time_t nextUpdate;
+};
+
+typedef struct ocsp_location ocsp_location_t;
+
+struct ocsp_location {
+ ocsp_location_t *next;
+ chunk_t issuer;
+ chunk_t authNameID;
+ chunk_t authKeyID;
+ chunk_t authKeySerialNumber;
+ chunk_t uri;
+ chunk_t nonce;
+ ocsp_certinfo_t *certinfo;
+};
+
+extern ocsp_location_t* get_ocsp_location(const ocsp_location_t *loc
+ , ocsp_location_t *chain);
+extern ocsp_location_t* add_ocsp_location(const ocsp_location_t *loc
+ , ocsp_location_t **chain);
+extern void add_certinfo(ocsp_location_t *loc, ocsp_certinfo_t *info
+ , ocsp_location_t **chain, bool request);
+extern void check_ocsp(void);
+extern cert_status_t verify_by_ocsp(const x509cert_t *cert, time_t *until
+ , time_t *revocationTime, crl_reason_t *revocationReason);
+extern bool ocsp_set_request_cert(char* path);
+extern void ocsp_set_default_uri(char* uri);
+extern void ocsp_cache_add_cert(const x509cert_t* cert);
+extern chunk_t build_ocsp_request(ocsp_location_t* location);
+extern void parse_ocsp(ocsp_location_t* location, chunk_t blob);
+extern void list_ocsp_locations(ocsp_location_t *location, bool requests
+ , bool utc, bool strict);
+extern void list_ocsp_cache(bool utc, bool strict);
+extern void free_ocsp_locations(ocsp_location_t **chain);
+extern void free_ocsp_cache(void);
+extern void free_ocsp(void);
+extern void ocsp_purge_cache(void);
diff --git a/src/pluto/oid.c b/src/pluto/oid.c
new file mode 100644
index 000000000..4b0632de2
--- /dev/null
+++ b/src/pluto/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/src/pluto/oid.h b/src/pluto/oid.h
new file mode 100644
index 000000000..ccdfb2954
--- /dev/null
+++ b/src/pluto/oid.h
@@ -0,0 +1,78 @@
+/* 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!
+ */
+
+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_SHA256 157
+#define OID_SHA384 158
+#define OID_SHA512 159
+#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
diff --git a/src/pluto/oid.pl b/src/pluto/oid.pl
new file mode 100644
index 000000000..52ac8eae0
--- /dev/null
+++ b/src/pluto/oid.pl
@@ -0,0 +1,123 @@
+#!/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",
+ "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++;
+}
+
+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/src/pluto/oid.txt b/src/pluto/oid.txt
new file mode 100644
index 000000000..e8750024e
--- /dev/null
+++ b/src/pluto/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" OID_SHA256
+ 0x02 "id-SHA-384" OID_SHA384
+ 0x03 "id-SHA-512" OID_SHA512
+ 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/src/pluto/packet.c b/src/pluto/packet.c
new file mode 100644
index 000000000..9f04c8bb2
--- /dev/null
+++ b/src/pluto/packet.c
@@ -0,0 +1,1244 @@
+/* parsing packets: formats and tools
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: packet.c,v 1.7 2005/01/06 22:39:04 as Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <netinet/in.h>
+#include <string.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "packet.h"
+#include "whack.h" /* for RC_LOG_SERIOUS */
+
+/* ISAKMP Header: for all messages
+ * layout from RFC 2408 "ISAKMP" section 3.1
+ * 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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Initiator !
+ * ! Cookie !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Responder !
+ * ! Cookie !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! MjVer ! MnVer ! Exchange Type ! Flags !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Message ID !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+static field_desc isa_fields[] = {
+ { ft_raw, COOKIE_SIZE, "initiator cookie", NULL },
+ { ft_raw, COOKIE_SIZE, "responder cookie", NULL },
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+ { ft_enum, 8/BITS_PER_BYTE, "ISAKMP version", &version_names },
+ { ft_enum, 8/BITS_PER_BYTE, "exchange type", &exchange_names },
+ { ft_set, 8/BITS_PER_BYTE, "flags", flag_bit_names },
+ { ft_raw, 32/BITS_PER_BYTE, "message ID", NULL },
+ { ft_len, 32/BITS_PER_BYTE, "length", NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_hdr_desc = { "ISAKMP Message", isa_fields, sizeof(struct isakmp_hdr) };
+
+/* Generic portion of all ISAKMP payloads.
+ * layout from RFC 2408 "ISAKMP" section 3.2
+ * This describes the first 32-bit chunk of all payloads.
+ * The previous next payload depends on the actual payload type.
+ * 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 ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+static field_desc isag_fields[] = {
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+ { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_generic_desc = { "ISAKMP Generic Payload", isag_fields, sizeof(struct isakmp_generic) };
+
+
+/* ISAKMP Data Attribute (generic representation within payloads)
+ * layout from RFC 2408 "ISAKMP" section 3.3
+ * This is not a payload type.
+ * In TLV format, this is followed by a value field.
+ * 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 .
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+/* Oakley Attributes */
+static field_desc isaat_fields_oakley[] = {
+ { ft_af_enum, 16/BITS_PER_BYTE, "af+type", &oakley_attr_names },
+ { ft_lv, 16/BITS_PER_BYTE, "length/value", NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_oakley_attribute_desc = {
+ "ISAKMP Oakley attribute",
+ isaat_fields_oakley, sizeof(struct isakmp_attribute) };
+
+/* IPsec DOI Attributes */
+static field_desc isaat_fields_ipsec[] = {
+ { ft_af_enum, 16/BITS_PER_BYTE, "af+type", &ipsec_attr_names },
+ { ft_lv, 16/BITS_PER_BYTE, "length/value", NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_ipsec_attribute_desc = {
+ "ISAKMP IPsec DOI attribute",
+ isaat_fields_ipsec, sizeof(struct isakmp_attribute) };
+
+/* Mode Config Attributes */
+static field_desc isaat_fields_modecfg[] = {
+ { ft_af_loose_enum, 16/BITS_PER_BYTE, "ModeCfg attr type", &modecfg_attr_names },
+ { ft_lv, 16/BITS_PER_BYTE, "length/value", NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_modecfg_attribute_desc = {
+ "ISAKMP ModeCfg attribute",
+ isaat_fields_modecfg, sizeof(struct isakmp_attribute) };
+
+/* ISAKMP Security Association Payload
+ * layout from RFC 2408 "ISAKMP" section 3.4
+ * A variable length Situation follows.
+ * Previous next payload: ISAKMP_NEXT_SA
+ * 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 ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Domain of Interpretation (DOI) !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Situation ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+static field_desc isasa_fields[] = {
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+ { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_enum, 32/BITS_PER_BYTE, "DOI", &doi_names },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_sa_desc = { "ISAKMP Security Association Payload", isasa_fields, sizeof(struct isakmp_sa) };
+
+static field_desc ipsec_sit_field[] = {
+ { ft_set, 32/BITS_PER_BYTE, "IPsec DOI SIT", &sit_bit_names },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc ipsec_sit_desc = { "IPsec DOI SIT", ipsec_sit_field, sizeof(u_int32_t) };
+
+/* ISAKMP Proposal Payload
+ * layout from RFC 2408 "ISAKMP" section 3.5
+ * A variable length SPI follows.
+ * Previous next payload: ISAKMP_NEXT_P
+ * 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 ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Proposal # ! Protocol-Id ! SPI Size !# of Transforms!
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! SPI (variable) !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+static field_desc isap_fields[] = {
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+ { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_nat, 8/BITS_PER_BYTE, "proposal number", NULL },
+ { ft_enum, 8/BITS_PER_BYTE, "protocol ID", &protocol_names },
+ { ft_nat, 8/BITS_PER_BYTE, "SPI size", NULL },
+ { ft_nat, 8/BITS_PER_BYTE, "number of transforms", NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_proposal_desc = { "ISAKMP Proposal Payload", isap_fields, sizeof(struct isakmp_proposal) };
+
+/* ISAKMP Transform Payload
+ * layout from RFC 2408 "ISAKMP" section 3.6
+ * Variable length SA Attributes follow.
+ * Previous next payload: ISAKMP_NEXT_T
+ * 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 ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Transform # ! Transform-Id ! RESERVED2 !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ SA Attributes ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+/* PROTO_ISAKMP */
+static field_desc isat_fields_isakmp[] = {
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+ { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_nat, 8/BITS_PER_BYTE, "transform number", NULL },
+ { ft_enum, 8/BITS_PER_BYTE, "transform ID", &isakmp_transformid_names },
+ { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_isakmp_transform_desc = {
+ "ISAKMP Transform Payload (ISAKMP)",
+ isat_fields_isakmp, sizeof(struct isakmp_transform) };
+
+/* PROTO_IPSEC_AH */
+static field_desc isat_fields_ah[] = {
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+ { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_nat, 8/BITS_PER_BYTE, "transform number", NULL },
+ { ft_enum, 8/BITS_PER_BYTE, "transform ID", &ah_transformid_names },
+ { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_ah_transform_desc = {
+ "ISAKMP Transform Payload (AH)",
+ isat_fields_ah, sizeof(struct isakmp_transform) };
+
+/* PROTO_IPSEC_ESP */
+static field_desc isat_fields_esp[] = {
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+ { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_nat, 8/BITS_PER_BYTE, "transform number", NULL },
+ { ft_enum, 8/BITS_PER_BYTE, "transform ID", &esp_transformid_names },
+ { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_esp_transform_desc = {
+ "ISAKMP Transform Payload (ESP)",
+ isat_fields_esp, sizeof(struct isakmp_transform) };
+
+/* PROTO_IPCOMP */
+static field_desc isat_fields_ipcomp[] = {
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+ { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_nat, 8/BITS_PER_BYTE, "transform number", NULL },
+ { ft_enum, 8/BITS_PER_BYTE, "transform ID", &ipcomp_transformid_names },
+ { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_ipcomp_transform_desc = {
+ "ISAKMP Transform Payload (COMP)",
+ isat_fields_ipcomp, sizeof(struct isakmp_transform) };
+
+
+/* ISAKMP Key Exchange Payload: no fixed fields beyond the generic ones.
+ * layout from RFC 2408 "ISAKMP" section 3.7
+ * Variable Key Exchange Data follow the generic fields.
+ * Previous next payload: ISAKMP_NEXT_KE
+ * 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 ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Key Exchange Data ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct_desc isakmp_keyex_desc = { "ISAKMP Key Exchange Payload", isag_fields, sizeof(struct isakmp_generic) };
+
+/* ISAKMP Identification Payload
+ * layout from RFC 2408 "ISAKMP" section 3.8
+ * See "struct identity" declared later.
+ * Variable length Identification Data follow.
+ * Previous next payload: ISAKMP_NEXT_ID
+ * 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 ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! ID Type ! DOI Specific ID Data !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Identification Data ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+static field_desc isaid_fields[] = {
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+ { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_enum, 8/BITS_PER_BYTE, "ID type", &ident_names }, /* ??? depends on DOI? */
+ { ft_nat, 8/BITS_PER_BYTE, "DOI specific A", NULL }, /* ??? depends on DOI? */
+ { ft_nat, 16/BITS_PER_BYTE, "DOI specific B", NULL }, /* ??? depends on DOI? */
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_identification_desc = { "ISAKMP Identification Payload", isaid_fields, sizeof(struct isakmp_id) };
+
+/* IPSEC Identification Payload Content
+ * layout from RFC 2407 "IPsec DOI" section 4.6.2
+ * See struct isakmp_id declared earlier.
+ * Note: Hashing skips the ISAKMP generic payload header
+ * Variable length Identification Data follow.
+ * 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 ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! ID Type ! Protocol ID ! Port !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ~ Identification Data ~
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+static field_desc isaiid_fields[] = {
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+ { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_enum, 8/BITS_PER_BYTE, "ID type", &ident_names },
+ { ft_nat, 8/BITS_PER_BYTE, "Protocol ID", NULL }, /* ??? UDP/TCP or 0? */
+ { ft_nat, 16/BITS_PER_BYTE, "port", NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_ipsec_identification_desc = { "ISAKMP Identification Payload (IPsec DOI)", isaiid_fields, sizeof(struct isakmp_ipsec_id) };
+
+/* ISAKMP Certificate Payload: oddball fixed field beyond the generic ones.
+ * layout from RFC 2408 "ISAKMP" section 3.9
+ * Variable length Certificate Data follow the generic fields.
+ * Previous next payload: ISAKMP_NEXT_CERT.
+ * 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 ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Cert Encoding ! !
+ * +-+-+-+-+-+-+-+-+ !
+ * ~ Certificate Data ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+static field_desc isacert_fields[] = {
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+ { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_enum, 8/BITS_PER_BYTE, "cert encoding", &cert_type_names },
+ { ft_end, 0, NULL, NULL }
+};
+
+/* Note: the size field of isakmp_ipsec_certificate_desc cannot be
+ * sizeof(struct isakmp_cert) because that will rounded up for padding.
+ */
+ struct_desc isakmp_ipsec_certificate_desc = { "ISAKMP Certificate Payload", isacert_fields, ISAKMP_CERT_SIZE };
+
+/* ISAKMP Certificate Request Payload: oddball field beyond the generic ones.
+ * layout from RFC 2408 "ISAKMP" section 3.10
+ * Variable length Certificate Types and Certificate Authorities follow.
+ * Previous next payload: ISAKMP_NEXT_CR.
+ * 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 ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Cert. Type ! !
+ * +-+-+-+-+-+-+-+-+ !
+ * ~ Certificate Authority ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+static field_desc isacr_fields[] = {
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+ { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_enum, 8/BITS_PER_BYTE, "cert type", &cert_type_names },
+ { ft_end, 0, NULL, NULL }
+};
+
+/* Note: the size field of isakmp_ipsec_cert_req_desc cannot be
+ * sizeof(struct isakmp_cr) because that will rounded up for padding.
+ */
+struct_desc isakmp_ipsec_cert_req_desc = { "ISAKMP Certificate RequestPayload", isacr_fields, ISAKMP_CR_SIZE };
+
+/* ISAKMP Hash Payload: no fixed fields beyond the generic ones.
+ * layout from RFC 2408 "ISAKMP" section 3.11
+ * Variable length Hash Data follow.
+ * Previous next payload: ISAKMP_NEXT_HASH.
+ * 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 ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Hash Data ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct_desc isakmp_hash_desc = { "ISAKMP Hash Payload", isag_fields, sizeof(struct isakmp_generic) };
+
+/* ISAKMP Signature Payload: no fixed fields beyond the generic ones.
+ * layout from RFC 2408 "ISAKMP" section 3.12
+ * Variable length Signature Data follow.
+ * Previous next payload: ISAKMP_NEXT_SIG.
+ * 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 ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Signature Data ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct_desc isakmp_signature_desc = { "ISAKMP Signature Payload", isag_fields, sizeof(struct isakmp_generic) };
+
+/* ISAKMP Nonce Payload: no fixed fields beyond the generic ones.
+ * layout from RFC 2408 "ISAKMP" section 3.13
+ * Variable length Nonce Data follow.
+ * Previous next payload: ISAKMP_NEXT_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 ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Nonce Data ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct_desc isakmp_nonce_desc = { "ISAKMP Nonce Payload", isag_fields, sizeof(struct isakmp_generic) };
+
+/* ISAKMP Notification Payload
+ * layout from RFC 2408 "ISAKMP" section 3.14
+ * This is followed by a variable length SPI
+ * and then possibly by variable length Notification Data.
+ * Previous next payload: ISAKMP_NEXT_N
+ * 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 ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Domain of Interpretation (DOI) !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Protocol-ID ! SPI Size ! Notify Message Type !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Security Parameter Index (SPI) ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Notification Data ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+static field_desc isan_fields[] = {
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+ { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_enum, 32/BITS_PER_BYTE, "DOI", &doi_names },
+ { ft_nat, 8/BITS_PER_BYTE, "protocol ID", NULL }, /* ??? really enum: ISAKMP, IPSEC, ESP, ... */
+ { ft_nat, 8/BITS_PER_BYTE, "SPI size", NULL },
+ { ft_enum, 16/BITS_PER_BYTE, "Notify Message Type", &notification_names },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_notification_desc = { "ISAKMP Notification Payload", isan_fields, sizeof(struct isakmp_notification) };
+
+/* ISAKMP Delete Payload
+ * layout from RFC 2408 "ISAKMP" section 3.15
+ * This is followed by a variable length SPI.
+ * Previous next payload: ISAKMP_NEXT_D
+ * 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 ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Domain of Interpretation (DOI) !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Protocol-Id ! SPI Size ! # of SPIs !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Security Parameter Index(es) (SPI) ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+static field_desc isad_fields[] = {
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+ { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_enum, 32/BITS_PER_BYTE, "DOI", &doi_names },
+ { ft_nat, 8/BITS_PER_BYTE, "protocol ID", NULL }, /* ??? really enum: ISAKMP, IPSEC */
+ { ft_nat, 8/BITS_PER_BYTE, "SPI size", NULL },
+ { ft_nat, 16/BITS_PER_BYTE, "number of SPIs", NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_delete_desc = { "ISAKMP Delete Payload", isad_fields, sizeof(struct isakmp_delete) };
+
+/* ISAKMP Vendor ID Payload
+ * layout from RFC 2408 "ISAKMP" section 3.15
+ * This is followed by a variable length VID.
+ * Previous next payload: ISAKMP_NEXT_VID
+ * 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 ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Vendor ID (VID) ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct_desc isakmp_vendor_id_desc = { "ISAKMP Vendor ID Payload", isag_fields, sizeof(struct isakmp_generic) };
+
+/* MODECFG */
+/*
+ * From draft-dukes-ike-mode-cfg
+3.2. Attribute Payload
+ 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 ! RESERVED ! Payload Length !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Type ! RESERVED ! Identifier !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! !
+ ~ Attributes ~
+ ! !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+static field_desc isaattr_fields[] = {
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+ { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_enum, 8/BITS_PER_BYTE, "Attr Msg Type", &attr_msg_type_names },
+ { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+ { ft_nat, 16/BITS_PER_BYTE, "Identifier", NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_attr_desc = { "ISAKMP Mode Attribute", isaattr_fields, sizeof(struct isakmp_mode_attr) };
+
+/* ISAKMP NAT-Traversal NAT-D
+ * layout from draft-ietf-ipsec-nat-t-ike-01.txt section 3.2
+ *
+ * 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 ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! HASH of the address and port !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct_desc isakmp_nat_d = { "ISAKMP NAT-D Payload", isag_fields, sizeof(struct isakmp_generic) };
+
+/* ISAKMP NAT-Traversal NAT-OA
+ * layout from draft-ietf-ipsec-nat-t-ike-01.txt section 4.2
+ *
+ * 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 ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! ID Type ! RESERVED ! RESERVED !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! IPv4 (4 octets) or IPv6 address (16 octets) !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+static field_desc isanat_oa_fields[] = {
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+ { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_enum, 8/BITS_PER_BYTE, "ID type", &ident_names },
+ { ft_mbz, 24/BITS_PER_BYTE, NULL, NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_nat_oa = { "ISAKMP NAT-OA Payload", isanat_oa_fields, sizeof(struct isakmp_nat_oa) };
+
+/* descriptor for each payload type
+ *
+ * There is a slight problem in that some payloads differ, depending
+ * on the mode. Since this is table only used for top-level payloads,
+ * Proposal and Transform payloads need not be handled.
+ * That leaves only Identification payloads as a problem.
+ * We make all these entries NULL
+ */
+struct_desc *const payload_descs[ISAKMP_NEXT_ROOF] = {
+ NULL, /* 0 ISAKMP_NEXT_NONE (No other payload following) */
+ &isakmp_sa_desc, /* 1 ISAKMP_NEXT_SA (Security Association) */
+ NULL, /* 2 ISAKMP_NEXT_P (Proposal) */
+ NULL, /* 3 ISAKMP_NEXT_T (Transform) */
+ &isakmp_keyex_desc, /* 4 ISAKMP_NEXT_KE (Key Exchange) */
+ NULL, /* 5 ISAKMP_NEXT_ID (Identification) */
+ &isakmp_ipsec_certificate_desc, /* 6 ISAKMP_NEXT_CERT (Certificate) */
+ &isakmp_ipsec_cert_req_desc, /* 7 ISAKMP_NEXT_CR (Certificate Request) */
+ &isakmp_hash_desc, /* 8 ISAKMP_NEXT_HASH (Hash) */
+ &isakmp_signature_desc, /* 9 ISAKMP_NEXT_SIG (Signature) */
+ &isakmp_nonce_desc, /* 10 ISAKMP_NEXT_NONCE (Nonce) */
+ &isakmp_notification_desc, /* 11 ISAKMP_NEXT_N (Notification) */
+ &isakmp_delete_desc, /* 12 ISAKMP_NEXT_D (Delete) */
+ &isakmp_vendor_id_desc, /* 13 ISAKMP_NEXT_VID (Vendor ID) */
+ &isakmp_attr_desc, /* 14 ISAKMP_NEXT_ATTR (Mode Config) */
+ NULL, /* 15 */
+ NULL, /* 16 */
+ NULL, /* 17 */
+ NULL, /* 18 */
+ NULL, /* 19 */
+ &isakmp_nat_d, /* 20=130 ISAKMP_NEXT_NATD (NAT-D) */
+ &isakmp_nat_oa, /* 20=131 ISAKMP_NEXT_NATOA (NAT-OA) */
+};
+
+void
+init_pbs(pb_stream *pbs, u_int8_t *start, size_t len, const char *name)
+{
+ pbs->container = NULL;
+ pbs->desc = NULL;
+ pbs->name = name;
+ pbs->start = pbs->cur = start;
+ pbs->roof = start + len;
+ pbs->lenfld = NULL;
+ pbs->lenfld_desc = NULL;
+}
+
+#ifdef DEBUG
+
+/* print a host struct
+ *
+ * This code assumes that the network and host structure
+ * members have the same alignment and size! This requires
+ * that all padding be explicit.
+ */
+void
+DBG_print_struct(const char *label, const void *struct_ptr
+, struct_desc *sd, bool len_meaningful)
+{
+ bool immediate = FALSE;
+ const u_int8_t *inp = struct_ptr;
+ field_desc *fp;
+
+ DBG_log("%s%s:", label, sd->name);
+
+ for (fp = sd->fields; fp->field_type != ft_end; fp++)
+ {
+ int i = fp->size;
+ u_int32_t n = 0;
+
+ switch (fp->field_type)
+ {
+ case ft_mbz: /* must be zero */
+ inp += i;
+ break;
+ case ft_nat: /* natural number (may be 0) */
+ case ft_len: /* length of this struct and any following crud */
+ case ft_lv: /* length/value field of attribute */
+ case ft_enum: /* value from an enumeration */
+ case ft_loose_enum: /* value from an enumeration with only some names known */
+ case ft_af_enum: /* Attribute Format + value from an enumeration */
+ case ft_af_loose_enum: /* Attribute Format + value from an enumeration */
+ case ft_set: /* bits representing set */
+ switch (i)
+ {
+ case 8/BITS_PER_BYTE:
+ n = *(const u_int8_t *)inp;
+ break;
+ case 16/BITS_PER_BYTE:
+ n = *(const u_int16_t *)inp;
+ break;
+ case 32/BITS_PER_BYTE:
+ n = *(const u_int32_t *)inp;
+ break;
+ default:
+ bad_case(i);
+ }
+ switch (fp->field_type)
+ {
+ case ft_len: /* length of this struct and any following crud */
+ case ft_lv: /* length/value field of attribute */
+ if (!immediate && !len_meaningful)
+ break;
+ /* FALL THROUGH */
+ case ft_nat: /* natural number (may be 0) */
+ DBG_log(" %s: %lu", fp->name, (unsigned long)n);
+ break;
+ case ft_af_enum: /* Attribute Format + value from an enumeration */
+ case ft_af_loose_enum: /* Attribute Format + value from an enumeration */
+ if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV)
+ immediate = TRUE;
+ /* FALL THROUGH */
+ case ft_enum: /* value from an enumeration */
+ case ft_loose_enum: /* value from an enumeration with only some names known */
+ DBG_log(" %s: %s", fp->name, enum_show(fp->desc, n));
+ break;
+ case ft_set: /* bits representing set */
+ DBG_log(" %s: %s", fp->name, bitnamesof(fp->desc, n));
+ break;
+ default:
+ bad_case(fp->field_type);
+ }
+ inp += i;
+ break;
+
+ case ft_raw: /* bytes to be left in network-order */
+ {
+ char m[50]; /* arbitrary limit on name width in log */
+
+ snprintf(m, sizeof(m), " %s:", fp->name);
+ DBG_dump(m, inp, i);
+ inp += i;
+ }
+ break;
+ default:
+ bad_case(fp->field_type);
+ }
+ }
+}
+
+static void
+DBG_prefix_print_struct(const pb_stream *pbs
+, const char *label, const void *struct_ptr
+, struct_desc *sd, bool len_meaningful)
+{
+ /* print out a title, with a prefix of asterisks to show
+ * the nesting level.
+ */
+ char space[40]; /* arbitrary limit on label+flock-of-* */
+ size_t len = strlen(label);
+
+ if (sizeof(space) <= len)
+ {
+ DBG_print_struct(label, struct_ptr, sd, len_meaningful);
+ }
+ else
+ {
+ const pb_stream *p = pbs;
+ char *pre = &space[sizeof(space) - (len + 1)];
+
+ strcpy(pre, label);
+
+ /* put at least one * out */
+ for (;;)
+ {
+ if (pre <= space)
+ break;
+ *--pre = '*';
+ if (p == NULL)
+ break;
+ p = p->container;
+ }
+ DBG_print_struct(pre, struct_ptr, sd, len_meaningful);
+ }
+}
+
+#endif
+
+/* "parse" a network struct into a host struct.
+ *
+ * This code assumes that the network and host structure
+ * members have the same alignment and size! This requires
+ * that all padding be explicit.
+ *
+ * If obj_pbs is supplied, a new pb_stream is created for the
+ * variable part of the structure (this depends on their
+ * being one length field in the structure). The cursor of this
+ * new PBS is set to after the parsed part of the struct.
+ *
+ * This routine returns TRUE iff it succeeds.
+ */
+
+bool
+in_struct(void *struct_ptr, struct_desc *sd
+, pb_stream *ins, pb_stream *obj_pbs)
+{
+ err_t ugh = NULL;
+ u_int8_t *cur = ins->cur;
+
+ if (ins->roof - cur < (ptrdiff_t)sd->size)
+ {
+ ugh = builddiag("not enough room in input packet for %s", sd->name);
+ }
+ else
+ {
+ u_int8_t *roof = cur + sd->size; /* may be changed by a length field */
+ u_int8_t *outp = struct_ptr;
+ bool immediate = FALSE;
+ field_desc *fp;
+
+ for (fp = sd->fields; ugh == NULL; fp++)
+ {
+ size_t i = fp->size;
+
+ passert(ins->roof - cur >= (ptrdiff_t)i);
+ passert(cur - ins->cur <= (ptrdiff_t)(sd->size - i));
+ passert(outp - (cur - ins->cur) == struct_ptr);
+
+#if 0
+ DBG(DBG_PARSING, DBG_log("%d %s"
+ , (int) (cur - ins->cur), fp->name == NULL? "" : fp->name));
+#endif
+ switch (fp->field_type)
+ {
+ case ft_mbz: /* must be zero */
+ for (; i != 0; i--)
+ {
+ if (*cur++ != 0)
+ {
+ ugh = builddiag("byte %d of %s must be zero, but is not"
+ , (int) (cur - ins->cur), sd->name);
+ break;
+ }
+ *outp++ = '\0'; /* probably redundant */
+ }
+ break;
+
+ case ft_nat: /* natural number (may be 0) */
+ case ft_len: /* length of this struct and any following crud */
+ case ft_lv: /* length/value field of attribute */
+ case ft_enum: /* value from an enumeration */
+ case ft_loose_enum: /* value from an enumeration with only some names known */
+ case ft_af_enum: /* Attribute Format + value from an enumeration */
+ case ft_af_loose_enum: /* Attribute Format + value from an enumeration */
+ case ft_set: /* bits representing set */
+ {
+ u_int32_t n = 0;
+
+ for (; i != 0; i--)
+ n = (n << BITS_PER_BYTE) | *cur++;
+
+ switch (fp->field_type)
+ {
+ case ft_len: /* length of this struct and any following crud */
+ case ft_lv: /* length/value field of attribute */
+ {
+ u_int32_t len = fp->field_type == ft_len? n
+ : immediate? sd->size : n + sd->size;
+
+ if (len < sd->size)
+ {
+ ugh = builddiag("%s of %s is smaller than minimum"
+ , fp->name, sd->name);
+ }
+ else if (pbs_left(ins) < len)
+ {
+ ugh = builddiag("%s of %s is larger than can fit"
+ , fp->name, sd->name);
+ }
+ else
+ {
+ roof = ins->cur + len;
+ }
+ break;
+ }
+ case ft_af_loose_enum: /* Attribute Format + value from an enumeration */
+ if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV)
+ immediate = TRUE;
+ break;
+ case ft_af_enum: /* Attribute Format + value from an enumeration */
+ if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV)
+ immediate = TRUE;
+ /* FALL THROUGH */
+ case ft_enum: /* value from an enumeration */
+ if (enum_name(fp->desc, n) == NULL)
+ {
+ ugh = builddiag("%s of %s has an unknown value: %lu"
+ , fp->name, sd->name, (unsigned long)n);
+ }
+ /* FALL THROUGH */
+ case ft_loose_enum: /* value from an enumeration with only some names known */
+ break;
+ case ft_set: /* bits representing set */
+ if (!testset(fp->desc, n))
+ {
+ ugh = builddiag("bitset %s of %s has unknown member(s): %s"
+ , fp->name, sd->name, bitnamesof(fp->desc, n));
+ }
+ break;
+ default:
+ break;
+ }
+ i = fp->size;
+ switch (i)
+ {
+ case 8/BITS_PER_BYTE:
+ *(u_int8_t *)outp = n;
+ break;
+ case 16/BITS_PER_BYTE:
+ *(u_int16_t *)outp = n;
+ break;
+ case 32/BITS_PER_BYTE:
+ *(u_int32_t *)outp = n;
+ break;
+ default:
+ bad_case(i);
+ }
+ outp += i;
+ break;
+ }
+
+ case ft_raw: /* bytes to be left in network-order */
+ for (; i != 0; i--)
+ {
+ *outp++ = *cur++;
+ }
+ break;
+
+ case ft_end: /* end of field list */
+ passert(cur == ins->cur + sd->size);
+ if (obj_pbs != NULL)
+ {
+ init_pbs(obj_pbs, ins->cur, roof - ins->cur, sd->name);
+ obj_pbs->container = ins;
+ obj_pbs->desc = sd;
+ obj_pbs->cur = cur;
+ }
+ ins->cur = roof;
+ DBG(DBG_PARSING
+ , DBG_prefix_print_struct(ins, "parse ", struct_ptr, sd, TRUE));
+ return TRUE;
+
+ default:
+ bad_case(fp->field_type);
+ }
+ }
+ }
+
+ /* some failure got us here: report it */
+ loglog(RC_LOG_SERIOUS, ugh);
+ return FALSE;
+}
+
+bool
+in_raw(void *bytes, size_t len, pb_stream *ins, const char *name)
+{
+ if (pbs_left(ins) < len)
+ {
+ loglog(RC_LOG_SERIOUS, "not enough bytes left to get %s from %s", name, ins->name);
+ return FALSE;
+ }
+ else
+ {
+ if (bytes == NULL)
+ {
+ DBG(DBG_PARSING
+ , DBG_log("skipping %u raw bytes of %s (%s)"
+ , (unsigned) len, ins->name, name);
+ DBG_dump(name, ins->cur, len));
+ }
+ else
+ {
+ memcpy(bytes, ins->cur, len);
+ DBG(DBG_PARSING
+ , DBG_log("parsing %u raw bytes of %s into %s"
+ , (unsigned) len, ins->name, name);
+ DBG_dump(name, bytes, len));
+ }
+ ins->cur += len;
+ return TRUE;
+ }
+}
+
+/* "emit" a host struct into a network packet.
+ *
+ * This code assumes that the network and host structure
+ * members have the same alignment and size! This requires
+ * that all padding be explicit.
+ *
+ * If obj_pbs is non-NULL, its pbs describes a new output stream set up
+ * to contain the object. The cursor will be left at the variable part.
+ * This new stream must subsequently be finalized by close_output_pbs().
+ *
+ * The value of any field of type ft_len is computed, not taken
+ * from the input struct. The length is actually filled in when
+ * the object's output stream is finalized. If obj_pbs is NULL,
+ * finalization is done by out_struct before it returns.
+ *
+ * This routine returns TRUE iff it succeeds.
+ */
+
+bool
+out_struct(const void *struct_ptr, struct_desc *sd
+, pb_stream *outs, pb_stream *obj_pbs)
+{
+ err_t ugh = NULL;
+ const u_int8_t *inp = struct_ptr;
+ u_int8_t *cur = outs->cur;
+
+ DBG(DBG_EMITTING
+ , DBG_prefix_print_struct(outs, "emit ", struct_ptr, sd, obj_pbs==NULL));
+
+ if (outs->roof - cur < (ptrdiff_t)sd->size)
+ {
+ ugh = builddiag("not enough room left in output packet to place %s"
+ , sd->name);
+ }
+ else
+ {
+ bool immediate = FALSE;
+ pb_stream obj;
+ field_desc *fp;
+
+ obj.lenfld = NULL; /* until a length field is discovered */
+ obj.lenfld_desc = NULL;
+
+ for (fp = sd->fields; ugh == NULL; fp++)
+ {
+ size_t i = fp->size;
+
+ passert(outs->roof - cur >= (ptrdiff_t)i);
+ passert(cur - outs->cur <= (ptrdiff_t)(sd->size - i));
+ passert(inp - (cur - outs->cur) == struct_ptr);
+
+#if 0
+ DBG(DBG_EMITTING, DBG_log("%d %s"
+ , (int) (cur - outs->cur), fp->name == NULL? "" : fp->name);
+#endif
+ switch (fp->field_type)
+ {
+ case ft_mbz: /* must be zero */
+ inp += i;
+ for (; i != 0; i--)
+ *cur++ = '\0';
+ break;
+ case ft_nat: /* natural number (may be 0) */
+ case ft_len: /* length of this struct and any following crud */
+ case ft_lv: /* length/value field of attribute */
+ case ft_enum: /* value from an enumeration */
+ case ft_loose_enum: /* value from an enumeration with only some names known */
+ case ft_af_enum: /* Attribute Format + value from an enumeration */
+ case ft_af_loose_enum: /* Attribute Format + value from an enumeration */
+ case ft_set: /* bits representing set */
+ {
+ u_int32_t n = 0;
+
+ switch (i)
+ {
+ case 8/BITS_PER_BYTE:
+ n = *(const u_int8_t *)inp;
+ break;
+ case 16/BITS_PER_BYTE:
+ n = *(const u_int16_t *)inp;
+ break;
+ case 32/BITS_PER_BYTE:
+ n = *(const u_int32_t *)inp;
+ break;
+ default:
+ bad_case(i);
+ }
+
+ switch (fp->field_type)
+ {
+ case ft_len: /* length of this struct and any following crud */
+ case ft_lv: /* length/value field of attribute */
+ if (immediate)
+ break; /* not a length */
+ /* We can't check the length because it will likely
+ * be filled in after variable part is supplied.
+ * We do record where this is so that it can be
+ * filled in by a subsequent close_output_pbs().
+ */
+ passert(obj.lenfld == NULL); /* only one ft_len allowed */
+ obj.lenfld = cur;
+ obj.lenfld_desc = fp;
+ break;
+ case ft_af_loose_enum: /* Attribute Format + value from an enumeration */
+ if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV)
+ immediate = TRUE;
+ break;
+ case ft_af_enum: /* Attribute Format + value from an enumeration */
+ if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV)
+ immediate = TRUE;
+ /* FALL THROUGH */
+ case ft_enum: /* value from an enumeration */
+ if (enum_name(fp->desc, n) == NULL)
+ {
+ ugh = builddiag("%s of %s has an unknown value: %lu"
+ , fp->name, sd->name, (unsigned long)n);
+ }
+ /* FALL THROUGH */
+ case ft_loose_enum: /* value from an enumeration with only some names known */
+ break;
+ case ft_set: /* bits representing set */
+ if (!testset(fp->desc, n))
+ {
+ ugh = builddiag("bitset %s of %s has unknown member(s): %s"
+ , fp->name, sd->name, bitnamesof(fp->desc, n));
+ }
+ break;
+ default:
+ break;
+ }
+
+ while (i-- != 0)
+ {
+ cur[i] = (u_int8_t)n;
+ n >>= BITS_PER_BYTE;
+ }
+ inp += fp->size;
+ cur += fp->size;
+ break;
+ }
+ case ft_raw: /* bytes to be left in network-order */
+ for (; i != 0; i--)
+ *cur++ = *inp++;
+ break;
+ case ft_end: /* end of field list */
+ passert(cur == outs->cur + sd->size);
+
+ obj.container = outs;
+ obj.desc = sd;
+ obj.name = sd->name;
+ obj.start = outs->cur;
+ obj.cur = cur;
+ obj.roof = outs->roof; /* limit of possible */
+ /* obj.lenfld and obj.lenfld_desc already set */
+
+ if (obj_pbs == NULL)
+ {
+ close_output_pbs(&obj); /* fill in length field, if any */
+ }
+ else
+ {
+ /* We set outs->cur to outs->roof so that
+ * any attempt to output something into outs
+ * before obj is closed will trigger an error.
+ */
+ outs->cur = outs->roof;
+
+ *obj_pbs = obj;
+ }
+ return TRUE;
+
+ default:
+ bad_case(fp->field_type);
+ }
+ }
+ }
+
+ /* some failure got us here: report it */
+ loglog(RC_LOG_SERIOUS, ugh); /* ??? serious, but errno not relevant */
+ return FALSE;
+}
+
+bool
+out_generic(u_int8_t np, struct_desc *sd
+, pb_stream *outs, pb_stream *obj_pbs)
+{
+ struct isakmp_generic gen;
+
+ passert(sd->fields == isakmp_generic_desc.fields);
+ gen.isag_np = np;
+ return out_struct(&gen, sd, outs, obj_pbs);
+}
+
+bool
+out_generic_raw(u_int8_t np, struct_desc *sd
+, pb_stream *outs, const void *bytes, size_t len, const char *name)
+{
+ pb_stream pbs;
+
+ if (!out_generic(np, sd, outs, &pbs)
+ || !out_raw(bytes, len, &pbs, name))
+ return FALSE;
+ close_output_pbs(&pbs);
+ return TRUE;
+}
+
+bool
+out_raw(const void *bytes, size_t len, pb_stream *outs, const char *name)
+{
+ if (pbs_left(outs) < len)
+ {
+ loglog(RC_LOG_SERIOUS, "not enough room left to place %lu bytes of %s in %s"
+ , (unsigned long) len, name, outs->name);
+ return FALSE;
+ }
+ else
+ {
+ DBG(DBG_EMITTING
+ , DBG_log("emitting %u raw bytes of %s into %s"
+ , (unsigned) len, name, outs->name);
+ DBG_dump(name, bytes, len));
+ memcpy(outs->cur, bytes, len);
+ outs->cur += len;
+ return TRUE;
+ }
+}
+
+bool
+out_zero(size_t len, pb_stream *outs, const char *name)
+{
+ if (pbs_left(outs) < len)
+ {
+ loglog(RC_LOG_SERIOUS, "not enough room left to place %s in %s", name, outs->name);
+ return FALSE;
+ }
+ else
+ {
+ DBG(DBG_EMITTING, DBG_log("emitting %u zero bytes of %s into %s"
+ , (unsigned) len, name, outs->name));
+ memset(outs->cur, 0x00, len);
+ outs->cur += len;
+ return TRUE;
+ }
+}
+
+/* Record current length.
+ * Note: currently, this may be repeated any number of times;
+ * the last one wins.
+ */
+void
+close_output_pbs(pb_stream *pbs)
+{
+ if (pbs->lenfld != NULL)
+ {
+ u_int32_t len = pbs_offset(pbs);
+ int i = pbs->lenfld_desc->size;
+
+ if (pbs->lenfld_desc->field_type == ft_lv)
+ len -= sizeof(struct isakmp_attribute);
+ DBG(DBG_EMITTING, DBG_log("emitting length of %s: %lu"
+ , pbs->name, (unsigned long) len));
+ while (i-- != 0)
+ {
+ pbs->lenfld[i] = (u_int8_t)len;
+ len >>= BITS_PER_BYTE;
+ }
+ }
+ if (pbs->container != NULL)
+ pbs->container->cur = pbs->cur; /* pass space utilization up */
+}
diff --git a/src/pluto/packet.h b/src/pluto/packet.h
new file mode 100644
index 000000000..676a5e6cd
--- /dev/null
+++ b/src/pluto/packet.h
@@ -0,0 +1,655 @@
+/* parsing packets: formats and tools
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: packet.h,v 1.5 2005/01/06 22:10:15 as Exp $
+ */
+
+#ifndef _PACKET_H
+#define _PACKET_H
+
+/* a struct_desc describes a structure for the struct I/O routines.
+ * This requires arrays of field_desc values to describe struct fields.
+ */
+
+typedef const struct struct_desc {
+ const char *name;
+ const struct field_desc *fields;
+ size_t size;
+} struct_desc;
+
+/* Note: if an ft_af_enum field has the ISAKMP_ATTR_AF_TV bit set,
+ * the subsequent ft_lv field will be interpreted as an immediate value.
+ * This matches how attributes are encoded.
+ * See RFC 2408 "ISAKMP" 3.3
+ */
+
+enum field_type {
+ ft_mbz, /* must be zero */
+ ft_nat, /* natural number (may be 0) */
+ ft_len, /* length of this struct and any following crud */
+ ft_lv, /* length/value field of attribute */
+ ft_enum, /* value from an enumeration */
+ ft_loose_enum, /* value from an enumeration with only some names known */
+ ft_af_loose_enum, /* Attribute Format + enumeration, some names known */
+ ft_af_enum, /* Attribute Format + value from an enumeration */
+ ft_set, /* bits representing set */
+ ft_raw, /* bytes to be left in network-order */
+ ft_end, /* end of field list */
+};
+
+typedef const struct field_desc {
+ enum field_type field_type;
+ int size; /* size, in bytes, of field */
+ const char *name;
+ const void *desc; /* enum_names for enum or char *[] for bits */
+} field_desc;
+
+/* The formatting of input and output of packets is done
+ * through packet_byte_stream objects.
+ * These describe a stream of bytes in memory.
+ * Several routines are provided to manipulate these objects
+ * Actual packet transfer is done elsewhere.
+ */
+typedef struct packet_byte_stream {
+ struct packet_byte_stream *container; /* PBS of which we are part */
+ struct_desc *desc;
+ const char *name; /* what does this PBS represent? */
+ u_int8_t
+ *start,
+ *cur, /* current position in stream */
+ *roof; /* byte after last in PBS (actually just a limit on output) */
+ /* For an output PBS, the length field will be filled in later so
+ * we need to record its particulars. Note: it may not be aligned.
+ */
+ u_int8_t *lenfld;
+ field_desc *lenfld_desc;
+} pb_stream;
+
+/* For an input PBS, pbs_offset is amount of stream processed.
+ * For an output PBS, pbs_offset is current size of stream.
+ * For an input PBS, pbs_room is size of stream.
+ * For an output PBS, pbs_room is maximum size allowed.
+ */
+#define pbs_offset(pbs) ((size_t)((pbs)->cur - (pbs)->start))
+#define pbs_room(pbs) ((size_t)((pbs)->roof - (pbs)->start))
+#define pbs_left(pbs) ((size_t)((pbs)->roof - (pbs)->cur))
+
+extern void init_pbs(pb_stream *pbs, u_int8_t *start, size_t len, const char *name);
+
+extern bool in_struct(void *struct_ptr, struct_desc *sd,
+ pb_stream *ins, pb_stream *obj_pbs);
+extern bool in_raw(void *bytes, size_t len, pb_stream *ins, const char *name);
+
+extern bool out_struct(const void *struct_ptr, struct_desc *sd,
+ pb_stream *outs, pb_stream *obj_pbs);
+extern bool out_generic(u_int8_t np, struct_desc *sd,
+ pb_stream *outs, pb_stream *obj_pbs);
+extern bool out_generic_raw(u_int8_t np, struct_desc *sd,
+ pb_stream *outs, const void *bytes, size_t len, const char *name);
+#define out_generic_chunk(np, sd, outs, ch, name) \
+ out_generic_raw(np, sd, outs, (ch).ptr, (ch).len, name)
+extern bool out_zero(size_t len, pb_stream *outs, const char *name);
+extern bool out_raw(const void *bytes, size_t len, pb_stream *outs, const char *name);
+#define out_chunk(ch, outs, name) out_raw((ch).ptr, (ch).len, (outs), (name))
+extern void close_output_pbs(pb_stream *pbs);
+
+#ifdef DEBUG
+extern void DBG_print_struct(const char *label, const void *struct_ptr,
+ struct_desc *sd, bool len_meaningful);
+#endif
+
+/* ISAKMP Header: for all messages
+ * layout from RFC 2408 "ISAKMP" section 3.1
+ * 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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Initiator !
+ * ! Cookie !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Responder !
+ * ! Cookie !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! MjVer ! MnVer ! Exchange Type ! Flags !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Message ID !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * Although the drafts are a little unclear, there are a few
+ * places that specify that messages should be padded with 0x00
+ * octets (bytes) to make the length a multiple of something.
+ *
+ * RFC 2408 "ISAKMP" 3.6 specifies that all messages will be
+ * padded to be a multiple of 4 octets in length.
+ * ??? This looks vestigial, and we ignore this requirement.
+ *
+ * RFC 2409 "IKE" Appedix B specifies:
+ * Each message should be padded up to the nearest block size
+ * using bytes containing 0x00.
+ * ??? This does not appear to be limited to encrypted messages,
+ * but it surely must be: the block size is meant to be the encryption
+ * block size, and that is meaningless for a non-encrypted message.
+ *
+ * RFC 2409 "IKE" 5.3 specifies:
+ * Encrypted payloads are padded up to the nearest block size.
+ * All padding bytes, except for the last one, contain 0x00. The
+ * last byte of the padding contains the number of the padding
+ * bytes used, excluding the last one. Note that this means there
+ * will always be padding.
+ * ??? This is nuts since payloads are not padded, messages are.
+ * It also contradicts Appendix B. So we ignore it.
+ *
+ * Summary: we pad encrypted output messages with 0x00 to bring them
+ * up to a multiple of the encryption block size. On input, we require
+ * that any encrypted portion of a message be a multiple of the encryption
+ * block size. After any decryption, we ignore padding (any bytes after
+ * the first payload that specifies a next payload of none; we don't
+ * require them to be zero).
+ */
+
+struct isakmp_hdr
+{
+ u_int8_t isa_icookie[COOKIE_SIZE];
+ u_int8_t isa_rcookie[COOKIE_SIZE];
+ u_int8_t isa_np; /* Next payload */
+ u_int8_t isa_version; /* high-order 4 bits: Major; low order 4: Minor */
+#define ISA_MAJ_SHIFT 4
+#define ISA_MIN_MASK (~((~0u) << ISA_MAJ_SHIFT))
+ u_int8_t isa_xchg; /* Exchange type */
+ u_int8_t isa_flags;
+ u_int32_t isa_msgid; /* Message ID (RAW) */
+ u_int32_t isa_length; /* Length of message */
+};
+
+extern struct_desc isakmp_hdr_desc;
+
+/* Generic portion of all ISAKMP payloads.
+ * layout from RFC 2408 "ISAKMP" section 3.2
+ * This describes the first 32-bit chunk of all payloads.
+ * The previous next payload depends on the actual payload type.
+ * 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 ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct isakmp_generic
+{
+ u_int8_t isag_np;
+ u_int8_t isag_reserved;
+ u_int16_t isag_length;
+};
+
+extern struct_desc isakmp_generic_desc;
+
+/* ISAKMP Data Attribute (generic representation within payloads)
+ * layout from RFC 2408 "ISAKMP" section 3.3
+ * This is not a payload type.
+ * In TLV format, this is followed by a value field.
+ * 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 .
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct isakmp_attribute
+{
+ /* The high order bit of isaat_af_type is the Attribute Format
+ * If it is off, the format is TLV: lv is the length of the following
+ * attribute value.
+ * If it is on, the format is TV: lv is the value of the attribute.
+ * ISAKMP_ATTR_AF_MASK is the mask in host form.
+ *
+ * The low order 15 bits of isaat_af_type is the Attribute Type.
+ * ISAKMP_ATTR_RTYPE_MASK is the mask in host form.
+ */
+ u_int16_t isaat_af_type; /* high order bit: AF; lower 15: rtype */
+ u_int16_t isaat_lv; /* Length or value */
+};
+
+#define ISAKMP_ATTR_AF_MASK 0x8000
+#define ISAKMP_ATTR_AF_TV ISAKMP_ATTR_AF_MASK /* value in lv */
+#define ISAKMP_ATTR_AF_TLV 0 /* length in lv; value follows */
+
+#define ISAKMP_ATTR_RTYPE_MASK 0x7FFF
+
+extern struct_desc
+ isakmp_oakley_attribute_desc,
+ isakmp_ipsec_attribute_desc;
+
+/* ISAKMP Security Association Payload
+ * layout from RFC 2408 "ISAKMP" section 3.4
+ * A variable length Situation follows.
+ * Previous next payload: ISAKMP_NEXT_SA
+ * 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 ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Domain of Interpretation (DOI) !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Situation ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct isakmp_sa
+{
+ u_int8_t isasa_np; /* Next payload */
+ u_int8_t isasa_reserved;
+ u_int16_t isasa_length; /* Payload length */
+ u_int32_t isasa_doi; /* DOI */
+};
+
+extern struct_desc isakmp_sa_desc;
+
+extern struct_desc ipsec_sit_desc;
+
+/* ISAKMP Proposal Payload
+ * layout from RFC 2408 "ISAKMP" section 3.5
+ * A variable length SPI follows.
+ * Previous next payload: ISAKMP_NEXT_P
+ * 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 ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Proposal # ! Protocol-Id ! SPI Size !# of Transforms!
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! SPI (variable) !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct isakmp_proposal
+{
+ u_int8_t isap_np;
+ u_int8_t isap_reserved;
+ u_int16_t isap_length;
+ u_int8_t isap_proposal;
+ u_int8_t isap_protoid;
+ u_int8_t isap_spisize;
+ u_int8_t isap_notrans; /* Number of transforms */
+};
+
+extern struct_desc isakmp_proposal_desc;
+
+/* ISAKMP Transform Payload
+ * layout from RFC 2408 "ISAKMP" section 3.6
+ * Variable length SA Attributes follow.
+ * Previous next payload: ISAKMP_NEXT_T
+ * 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 ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Transform # ! Transform-Id ! RESERVED2 !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ SA Attributes ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct isakmp_transform
+{
+ u_int8_t isat_np;
+ u_int8_t isat_reserved;
+ u_int16_t isat_length;
+ u_int8_t isat_transnum; /* Number of the transform */
+ u_int8_t isat_transid;
+ u_int16_t isat_reserved2;
+};
+
+extern struct_desc
+ isakmp_isakmp_transform_desc,
+ isakmp_ah_transform_desc,
+ isakmp_esp_transform_desc,
+ isakmp_ipcomp_transform_desc;
+
+/* ISAKMP Key Exchange Payload: no fixed fields beyond the generic ones.
+ * layout from RFC 2408 "ISAKMP" section 3.7
+ * Variable Key Exchange Data follow the generic fields.
+ * Previous next payload: ISAKMP_NEXT_KE
+ * 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 ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Key Exchange Data ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+extern struct_desc isakmp_keyex_desc;
+
+/* ISAKMP Identification Payload
+ * layout from RFC 2408 "ISAKMP" section 3.8
+ * See "struct identity" declared later.
+ * Variable length Identification Data follow.
+ * Previous next payload: ISAKMP_NEXT_ID
+ * 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 ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! ID Type ! DOI Specific ID Data !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Identification Data ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct isakmp_id
+{
+ u_int8_t isaid_np;
+ u_int8_t isaid_reserved;
+ u_int16_t isaid_length;
+ u_int8_t isaid_idtype;
+ u_int8_t isaid_doi_specific_a;
+ u_int16_t isaid_doi_specific_b;
+};
+
+extern struct_desc isakmp_identification_desc;
+
+/* IPSEC Identification Payload Content
+ * layout from RFC 2407 "IPsec DOI" section 4.6.2
+ * See struct isakmp_id declared earlier.
+ * Note: Hashing skips the ISAKMP generic payload header
+ * Variable length Identification Data follow.
+ * 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 ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! ID Type ! Protocol ID ! Port !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ~ Identification Data ~
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct isakmp_ipsec_id
+{
+ u_int8_t isaiid_np;
+ u_int8_t isaiid_reserved;
+ u_int16_t isaiid_length;
+ u_int8_t isaiid_idtype;
+ u_int8_t isaiid_protoid;
+ u_int16_t isaiid_port;
+};
+
+extern struct_desc isakmp_ipsec_identification_desc;
+
+/* ISAKMP Certificate Payload: no fixed fields beyond the generic ones.
+ * layout from RFC 2408 "ISAKMP" section 3.9
+ * Variable length Certificate Data follow the generic fields.
+ * Previous next payload: ISAKMP_NEXT_CERT.
+ * 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 ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Cert Encoding ! !
+ * +-+-+-+-+-+-+-+-+ !
+ * ~ Certificate Data ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct isakmp_cert
+{
+ u_int8_t isacert_np;
+ u_int8_t isacert_reserved;
+ u_int16_t isacert_length;
+ u_int8_t isacert_type;
+};
+
+/* NOTE: this packet type has a fixed portion that is not a
+ * multiple of 4 octets. This means that sizeof(struct isakmp_cert)
+ * yields the wrong value for the length.
+ */
+#define ISAKMP_CERT_SIZE 5
+
+extern struct_desc isakmp_ipsec_certificate_desc;
+
+/* ISAKMP Certificate Request Payload: no fixed fields beyond the generic ones.
+ * layout from RFC 2408 "ISAKMP" section 3.10
+ * Variable length Certificate Types and Certificate Authorities follow.
+ * Previous next payload: ISAKMP_NEXT_CR.
+ * 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 ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Cert. Type ! !
+ * +-+-+-+-+-+-+-+-+ !
+ * ~ Certificate Authority ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct isakmp_cr
+{
+ u_int8_t isacr_np;
+ u_int8_t isacr_reserved;
+ u_int16_t isacr_length;
+ u_int8_t isacr_type;
+};
+
+/* NOTE: this packet type has a fixed portion that is not a
+ * multiple of 4 octets. This means that sizeof(struct isakmp_cr)
+ * yields the wrong value for the length.
+ */
+#define ISAKMP_CR_SIZE 5
+
+extern struct_desc isakmp_ipsec_cert_req_desc;
+
+/* ISAKMP Hash Payload: no fixed fields beyond the generic ones.
+ * layout from RFC 2408 "ISAKMP" section 3.11
+ * Variable length Hash Data follow.
+ * Previous next payload: ISAKMP_NEXT_HASH.
+ * 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 ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Hash Data ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+extern struct_desc isakmp_hash_desc;
+
+/* ISAKMP Signature Payload: no fixed fields beyond the generic ones.
+ * layout from RFC 2408 "ISAKMP" section 3.12
+ * Variable length Signature Data follow.
+ * Previous next payload: ISAKMP_NEXT_SIG.
+ * 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 ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Signature Data ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+extern struct_desc isakmp_signature_desc;
+
+/* ISAKMP Nonce Payload: no fixed fields beyond the generic ones.
+ * layout from RFC 2408 "ISAKMP" section 3.13
+ * Variable length Nonce Data follow.
+ * Previous next payload: ISAKMP_NEXT_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 ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Nonce Data ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+extern struct_desc isakmp_nonce_desc;
+
+/* ISAKMP Notification Payload
+ * layout from RFC 2408 "ISAKMP" section 3.14
+ * This is followed by a variable length SPI
+ * and then possibly by variable length Notification Data.
+ * Previous next payload: ISAKMP_NEXT_N
+ * 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 ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Domain of Interpretation (DOI) !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Protocol-ID ! SPI Size ! Notify Message Type !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Security Parameter Index (SPI) ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Notification Data ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct isakmp_notification
+{
+ u_int8_t isan_np;
+ u_int8_t isan_reserved;
+ u_int16_t isan_length;
+ u_int32_t isan_doi;
+ u_int8_t isan_protoid;
+ u_int8_t isan_spisize;
+ u_int16_t isan_type;
+};
+
+extern struct_desc isakmp_notification_desc;
+
+/* ISAKMP Delete Payload
+ * layout from RFC 2408 "ISAKMP" section 3.15
+ * This is followed by a variable length SPI.
+ * Previous next payload: ISAKMP_NEXT_D
+ * 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 ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Domain of Interpretation (DOI) !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Protocol-Id ! SPI Size ! # of SPIs !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Security Parameter Index(es) (SPI) ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct isakmp_delete
+{
+ u_int8_t isad_np;
+ u_int8_t isad_reserved;
+ u_int16_t isad_length;
+ u_int32_t isad_doi;
+ u_int8_t isad_protoid;
+ u_int8_t isad_spisize;
+ u_int16_t isad_nospi;
+};
+
+extern struct_desc isakmp_delete_desc;
+
+/* From draft-dukes-ike-mode-cfg
+3.2. Attribute Payload
+ 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 ! RESERVED ! Payload Length !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Type ! RESERVED ! Identifier !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! !
+ ! !
+ ~ Attributes ~
+ ! !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+struct isakmp_mode_attr
+{
+ u_int8_t isama_np;
+ u_int8_t isama_reserved;
+ u_int16_t isama_length;
+ u_int8_t isama_type;
+ u_int8_t isama_reserved2;
+ u_int16_t isama_identifier;
+};
+
+extern struct_desc isakmp_attr_desc;
+extern struct_desc isakmp_modecfg_attribute_desc;
+
+/* ISAKMP Vendor ID Payload
+ * layout from RFC 2408 "ISAKMP" section 3.15
+ * This is followed by a variable length VID.
+ * Previous next payload: ISAKMP_NEXT_VID
+ * 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 ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Vendor ID (VID) ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+extern struct_desc isakmp_vendor_id_desc;
+
+struct isakmp_nat_oa
+{
+ u_int8_t isanoa_np;
+ u_int8_t isanoa_reserved_1;
+ u_int16_t isanoa_length;
+ u_int8_t isanoa_idtype;
+ u_int8_t isanoa_reserved_2;
+ u_int16_t isanoa_reserved_3;
+};
+
+extern struct_desc isakmp_nat_d;
+extern struct_desc isakmp_nat_oa;
+
+/* union of all payloads */
+
+union payload {
+ struct isakmp_generic generic;
+ struct isakmp_sa sa;
+ struct isakmp_proposal proposal;
+ struct isakmp_transform transform;
+ struct isakmp_id id; /* Main Mode */
+ struct isakmp_cert cert;
+ struct isakmp_cr cr;
+ struct isakmp_ipsec_id ipsec_id; /* Quick Mode */
+ struct isakmp_notification notification;
+ struct isakmp_delete delete;
+ struct isakmp_nat_oa nat_oa;
+ struct isakmp_mode_attr attribute;
+};
+
+/* descriptor for each payload type
+ *
+ * There is a slight problem in that some payloads differ, depending
+ * on the mode. Since this is table only used for top-level payloads,
+ * Proposal and Transform payloads need not be handled.
+ * That leaves only Identification payloads as a problem.
+ * We make all these entries NULL
+ */
+extern struct_desc *const payload_descs[ISAKMP_NEXT_ROOF];
+
+#endif /* _PACKET_H */
diff --git a/src/pluto/pem.c b/src/pluto/pem.c
new file mode 100644
index 000000000..db6d0d7e3
--- /dev/null
+++ b/src/pluto/pem.c
@@ -0,0 +1,463 @@
+/* Loading of PEM encoded files with optional encryption
+ * Copyright (C) 2001-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.
+ *
+ * RCSID $Id: pem.c,v 1.4 2005/08/17 16:31:24 as Exp $
+ */
+
+/* decrypt a PEM encoded data block using DES-EDE3-CBC
+ * see RFC 1423 PEM: Algorithms, Modes and Identifiers
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#include <freeswan.h>
+#define HEADER_DES_LOCL_H /* stupid trick to force prototype decl in <des.h> */
+#include <libdes/des.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "md5.h"
+#include "whack.h"
+#include "pem.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 = empty_chunk;
+
+ 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))
+ {
+ DBG(DBG_PARSING,
+ DBG_log(" -----%s %.*s-----",
+ tag, (int)name.len, name.ptr);
+ )
+ 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 = empty_chunk;
+
+ 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)
+{
+ DBG(DBG_PARSING,
+ DBG_log(" %.*s", (int)line->len, line->ptr);
+ )
+
+ /* 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 bool
+pem_decrypt_3des(chunk_t *blob, chunk_t *iv, const char *passphrase)
+{
+ MD5_CTX context;
+ u_char digest[MD5_DIGEST_SIZE];
+ u_char des_iv[DES_CBC_BLOCK_SIZE];
+ u_char key[24];
+ des_cblock *deskey = (des_cblock *)key;
+ des_key_schedule ks[3];
+ u_char padding, *last_padding_pos, *first_padding_pos;
+
+ /* Convert passphrase to 3des key */
+ MD5Init(&context);
+ MD5Update(&context, passphrase, strlen(passphrase));
+ MD5Update(&context, iv->ptr, iv->len);
+ MD5Final(digest, &context);
+
+ memcpy(key, digest, MD5_DIGEST_SIZE);
+
+ MD5Init(&context);
+ MD5Update(&context, digest, MD5_DIGEST_SIZE);
+ MD5Update(&context, passphrase, strlen(passphrase));
+ MD5Update(&context, iv->ptr, iv->len);
+ MD5Final(digest, &context);
+
+ memcpy(key + MD5_DIGEST_SIZE, digest, 24 - MD5_DIGEST_SIZE);
+
+ (void) des_set_key(&deskey[0], ks[0]);
+ (void) des_set_key(&deskey[1], ks[1]);
+ (void) des_set_key(&deskey[2], ks[2]);
+
+ /* decrypt data block */
+ memcpy(des_iv, iv->ptr, DES_CBC_BLOCK_SIZE);
+ des_ede3_cbc_encrypt((des_cblock *)blob->ptr, (des_cblock *)blob->ptr,
+ blob->len, ks[0], ks[1], ks[2], (des_cblock *)des_iv, FALSE);
+
+ /* 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;
+}
+
+/*
+ * optionally prompts for a passphrase before decryption
+ * currently we support DES-EDE3-CBC, only
+ */
+static err_t
+pem_decrypt(chunk_t *blob, chunk_t *iv, prompt_pass_t *pass, const char* label)
+{
+ DBG(DBG_CRYPT,
+ DBG_log(" decrypting file using 'DES-EDE3-CBC'");
+ )
+ if (iv->len != DES_CBC_BLOCK_SIZE)
+ return "size of DES-EDE3-CBC IV is not 8 bytes";
+
+ if (pass == NULL)
+ return "no passphrase available";
+
+ /* do we prompt for the passphrase? */
+ if (pass->prompt && pass->fd != NULL_FD)
+ {
+ int i;
+ chunk_t blob_copy;
+ err_t ugh = "invalid passphrase, too many trials";
+
+ whack_log(RC_ENTERSECRET, "need passphrase for '%s'", label);
+
+ for (i = 0; i < MAX_PROMPT_PASS_TRIALS; i++)
+ {
+ int n;
+
+ if (i > 0)
+ whack_log(RC_ENTERSECRET, "invalid passphrase, please try again");
+
+ n = read(pass->fd, pass->secret, PROMPT_PASS_LEN);
+
+ if (n == -1)
+ {
+ err_t ugh = "read(whackfd) failed";
+
+ whack_log(RC_LOG_SERIOUS,ugh);
+ return ugh;
+ }
+
+ pass->secret[n-1] = '\0';
+
+ if (strlen(pass->secret) == 0)
+ {
+ err_t ugh = "no passphrase entered, aborted";
+
+ whack_log(RC_LOG_SERIOUS, ugh);
+ return ugh;
+ }
+
+ clonetochunk(blob_copy, blob->ptr, blob->len, "blob copy");
+
+ if (pem_decrypt_3des(blob, iv, pass->secret))
+ {
+ whack_log(RC_SUCCESS, "valid passphrase");
+ pfree(blob_copy.ptr);
+ return NULL;
+ }
+
+ /* blob is useless after wrong decryption, restore the original */
+ pfree(blob->ptr);
+ *blob = blob_copy;
+ }
+ whack_log(RC_LOG_SERIOUS, ugh);
+ return ugh;
+ }
+ else
+ {
+ if (pem_decrypt_3des(blob, iv, pass->secret))
+ return NULL;
+ else
+ return "invalid passphrase";
+ }
+}
+
+/* Converts a PEM encoded file into its binary form
+ *
+ * RFC 1421 Privacy Enhancement for Electronic Mail, February 1993
+ * RFC 934 Message Encapsulation, January 1985
+ */
+err_t
+pemtobin(chunk_t *blob, prompt_pass_t *pass, const char* label, bool *pgp)
+{
+ 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 = empty_chunk;
+ chunk_t iv = empty_chunk;
+
+ u_char iv_buf[MAX_DIGEST_LEN];
+
+ /* 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))
+ {
+ *pgp = FALSE;
+ 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 = empty_chunk;
+ chunk_t value = empty_chunk;
+
+ /* 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 "we support DES-EDE3-CBC encrypted files, only";
+
+ eat_whitespace(&value);
+ ugh = ttodata(value.ptr, value.len, 16,
+ iv.ptr, MAX_DIGEST_LEN, &len);
+ if (ugh)
+ return "error in IV";
+
+ 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;
+
+ /* check for PGP armor checksum */
+ if (*data.ptr == '=')
+ {
+ *pgp = TRUE;
+ data.ptr++;
+ data.len--;
+ DBG(DBG_PARSING,
+ DBG_log(" Armor checksum: %.*s", (int)data.len, data.ptr);
+ )
+ continue;
+ }
+
+ ugh = ttodata(data.ptr, data.len, 64,
+ dst.ptr, blob->len - dst.len, &len);
+ if (ugh)
+ {
+ DBG(DBG_PARSING,
+ DBG_log(" %s", 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 "file coded in unknown format, discarded";
+
+ if (encrypted)
+ return pem_decrypt(blob, &iv, pass, label);
+ else
+ return NULL;
+}
diff --git a/src/pluto/pem.h b/src/pluto/pem.h
new file mode 100644
index 000000000..815b5d85b
--- /dev/null
+++ b/src/pluto/pem.h
@@ -0,0 +1,18 @@
+/* Loading of PEM encoded files with optional encryption
+ * Copyright (C) 2001-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.
+ *
+ * RCSID $Id: pem.h,v 1.1 2004/03/15 20:35:28 as Exp $
+ */
+
+extern err_t pemtobin(chunk_t *blob, prompt_pass_t *pass, const char* label
+ , bool *pgp);
diff --git a/src/pluto/pgp.c b/src/pluto/pgp.c
new file mode 100644
index 000000000..307303f6b
--- /dev/null
+++ b/src/pluto/pgp.c
@@ -0,0 +1,647 @@
+/* Support of OpenPGP certificates
+ * Copyright (C) 2002-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.
+ *
+ * RCSID $Id: pgp.c,v 1.7 2006/01/04 21:00:43 as Exp $
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <freeswan.h>
+#include <ipsec_policy.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "mp_defs.h"
+#include "log.h"
+#include "id.h"
+#include "pgp.h"
+#include "certs.h"
+#include "md5.h"
+#include "whack.h"
+#include "pkcs1.h"
+#include "keys.h"
+
+/*
+ * chained list of OpenPGP end certificates
+ */
+static pgpcert_t *pgpcerts = NULL;
+
+/*
+ * OpenPGP packet tags defined in section 4.3 of RFC 2440
+ */
+#define PGP_PKT_RESERVED 0
+#define PGP_PKT_PUBKEY_ENC_SESSION_KEY 1
+#define PGP_PKT_SIGNATURE 2
+#define PGP_PKT_SYMKEY_ENC_SESSION_KEY 3
+#define PGP_PKT_ONE_PASS_SIGNATURE_PKT 4
+#define PGP_PKT_SECRET_KEY 5
+#define PGP_PKT_PUBLIC_KEY 6
+#define PGP_PKT_SECRET_SUBKEY 7
+#define PGP_PKT_COMPRESSED_DATA 8
+#define PGP_PKT_SYMKEY_ENC_DATA 9
+#define PGP_PKT_MARKER 10
+#define PGP_PKT_LITERAL_DATA 11
+#define PGP_PKT_TRUST 12
+#define PGP_PKT_USER_ID 13
+#define PGP_PKT_PUBLIC_SUBKEY 14
+#define PGP_PKT_ROOF 15
+
+static const char *const pgp_packet_type_name[] = {
+ "Reserved",
+ "Public-Key Encrypted Session Key Packet",
+ "Signature Packet",
+ "Symmetric-Key Encrypted Session Key Packet",
+ "One-Pass Signature Packet",
+ "Secret Key Packet",
+ "Public Key Packet",
+ "Secret Subkey Packet",
+ "Compressed Data Packet",
+ "Symmetrically Encrypted Data Packet",
+ "Marker Packet",
+ "Literal Data Packet",
+ "Trust Packet",
+ "User ID Packet",
+ "Public Subkey Packet"
+};
+
+/*
+ * OpenPGP public key algorithms defined in section 9.1 of RFC 2440
+ */
+#define PGP_PUBKEY_ALG_RSA 1
+#define PGP_PUBKEY_ALG_RSA_ENC_ONLY 2
+#define PGP_PUBKEY_ALG_RSA_SIGN_ONLY 3
+#define PGP_PUBKEY_ALG_ELGAMAL_ENC_ONLY 16
+#define PGP_PUBKEY_ALG_DSA 17
+#define PGP_PUBKEY_ALG_ECC 18
+#define PGP_PUBKEY_ALG_ECDSA 19
+#define PGP_PUBKEY_ALG_ELGAMAL 20
+
+/*
+ * OpenPGP symmetric key algorithms defined in section 9.2 of RFC 2440
+ */
+#define PGP_SYM_ALG_PLAIN 0
+#define PGP_SYM_ALG_IDEA 1
+#define PGP_SYM_ALG_3DES 2
+#define PGP_SYM_ALG_CAST5 3
+#define PGP_SYM_ALG_BLOWFISH 4
+#define PGP_SYM_ALG_SAFER 5
+#define PGP_SYM_ALG_DES 6
+#define PGP_SYM_ALG_AES 7
+#define PGP_SYM_ALG_AES_192 8
+#define PGP_SYM_ALG_AES_256 9
+#define PGP_SYM_ALG_TWOFISH 10
+#define PGP_SYM_ALG_ROOF 11
+
+static const char *const pgp_sym_alg_name[] = {
+ "Plaintext",
+ "IDEA",
+ "3DES",
+ "CAST5",
+ "Blowfish",
+ "SAFER",
+ "DES",
+ "AES",
+ "AES-192",
+ "AES-256",
+ "Twofish"
+};
+
+/*
+ * Size of PGP Key ID
+ */
+#define PGP_KEYID_SIZE 8
+
+const pgpcert_t empty_pgpcert = {
+ NULL , /* *next */
+ 0 , /* installed */
+ 0 , /* count */
+ { NULL, 0 }, /* certificate */
+ 0 , /* created */
+ 0 , /* until */
+ 0 , /* pubkeyAlgorithm */
+ { NULL, 0 }, /* modulus */
+ { NULL, 0 }, /* publicExponent */
+ "" /* fingerprint */
+};
+
+static size_t
+pgp_size(chunk_t *blob, int len)
+{
+ size_t size = 0;
+
+ blob->len -= len;
+ while (len-- > 0)
+ size = 256*size + *blob->ptr++;
+ return size;
+}
+
+/*
+ * extracts the length of a PGP packet
+ */
+static size_t
+pgp_old_packet_length(chunk_t *blob)
+{
+ /* bits 0 and 1 define the packet length type */
+ int len_type = 0x03 & *blob->ptr++;
+
+ blob->len--;
+
+ /* len_type: 0 -> 1 byte, 1 -> 2 bytes, 2 -> 4 bytes */
+ return pgp_size(blob, (len_type == 0)? 1: len_type << 1);
+}
+
+/*
+ * extracts PGP packet version (V3 or V4)
+ */
+static u_char
+pgp_version(chunk_t *blob)
+{
+ u_char version = *blob->ptr++;
+ blob->len--;
+ DBG(DBG_PARSING,
+ DBG_log("L3 - version:");
+ DBG_log(" V%d", version)
+ )
+ return version;
+}
+
+/*
+ * Parse OpenPGP public key packet defined in section 5.5.2 of RFC 2440
+ */
+static bool
+parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert)
+{
+ u_char version = pgp_version(packet);
+
+ if (version < 3 || version > 4)
+ {
+ plog("PGP packet version V%d not supported", version);
+ return FALSE;
+ }
+
+ /* creation date - 4 bytes */
+ cert->created = (time_t)pgp_size(packet, 4);
+ DBG(DBG_PARSING,
+ DBG_log("L3 - created:");
+ DBG_log(" %s", timetoa(&cert->created, TRUE))
+ )
+
+ if (version == 3)
+ {
+ /* validity in days - 2 bytes */
+ cert->until = (time_t)pgp_size(packet, 2);
+
+ /* validity of 0 days means that the key never expires */
+ if (cert->until > 0)
+ cert->until = cert->created + 24*3600*cert->until;
+
+ DBG(DBG_PARSING,
+ DBG_log("L3 - until:");
+ DBG_log(" %s", timetoa(&cert->until, TRUE));
+ )
+ }
+
+ /* public key algorithm - 1 byte */
+ DBG(DBG_PARSING,
+ DBG_log("L3 - public key algorithm:")
+ )
+
+ switch (pgp_size(packet, 1))
+ {
+ case PGP_PUBKEY_ALG_RSA:
+ case PGP_PUBKEY_ALG_RSA_SIGN_ONLY:
+ cert->pubkeyAlg = PUBKEY_ALG_RSA;
+ DBG(DBG_PARSING,
+ DBG_log(" RSA")
+ )
+ /* modulus n */
+ cert->modulus.len = (pgp_size(packet, 2)+7) / BITS_PER_BYTE;
+ cert->modulus.ptr = packet->ptr;
+ packet->ptr += cert->modulus.len;
+ packet->len -= cert->modulus.len;
+ DBG(DBG_PARSING,
+ DBG_log("L3 - modulus:")
+ )
+ DBG_cond_dump_chunk(DBG_RAW, "", cert->modulus);
+
+ /* public exponent e */
+ cert->publicExponent.len = (pgp_size(packet, 2)+7) / BITS_PER_BYTE;
+ cert->publicExponent.ptr = packet->ptr;
+ packet->ptr += cert->publicExponent.len;
+ packet->len -= cert->publicExponent.len;
+ DBG(DBG_PARSING,
+ DBG_log("L3 - public exponent:")
+ )
+ DBG_cond_dump_chunk(DBG_RAW, "", cert->publicExponent);
+
+ if (version == 3)
+ {
+ /* a V3 fingerprint is the MD5 hash of modulus and public exponent */
+ MD5_CTX context;
+ MD5Init(&context);
+ MD5Update(&context, cert->modulus.ptr, cert->modulus.len);
+ MD5Update(&context, cert->publicExponent.ptr, cert->publicExponent.len);
+ MD5Final(cert->fingerprint, &context);
+ }
+ else
+ {
+ plog(" computation of V4 key ID not implemented yet");
+ }
+ break;
+ case PGP_PUBKEY_ALG_DSA:
+ cert->pubkeyAlg = PUBKEY_ALG_DSA;
+ DBG(DBG_PARSING,
+ DBG_log(" DSA")
+ )
+ plog(" DSA public keys not supported");
+ return FALSE;
+ default:
+ cert->pubkeyAlg = 0;
+ DBG(DBG_PARSING,
+ DBG_log(" other")
+ )
+ plog(" exotic not RSA public keys not supported");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ * Parse OpenPGP secret key packet defined in section 5.5.3 of RFC 2440
+ */
+static bool
+parse_pgp_secretkey_packet(chunk_t *packet, RSA_private_key_t *key)
+{
+ int i, s2k;
+ pgpcert_t cert = empty_pgpcert;
+
+ if (!parse_pgp_pubkey_packet(packet, &cert))
+ return FALSE;
+
+ init_RSA_public_key((RSA_public_key_t *)key, cert.publicExponent
+ , cert.modulus);
+
+ /* string-to-key usage */
+ s2k = pgp_size(packet, 1);
+
+ DBG(DBG_PARSING,
+ DBG_log("L3 - string-to-key: %d", s2k)
+ )
+
+ if (s2k == 255)
+ {
+ plog(" string-to-key specifiers not supported");
+ return FALSE;
+ }
+
+ if (s2k >= PGP_SYM_ALG_ROOF)
+ {
+ plog(" undefined symmetric key algorithm");
+ return FALSE;
+ }
+
+ /* a known symmetric key algorithm is specified*/
+ DBG(DBG_PARSING,
+ DBG_log(" %s", pgp_sym_alg_name[s2k])
+ )
+
+ /* private key is unencrypted */
+ if (s2k == PGP_SYM_ALG_PLAIN)
+ {
+ for (i = 2; i < RSA_PRIVATE_FIELD_ELEMENTS; i++)
+ {
+ mpz_t u; /* auxiliary variable */
+
+ /* compute offset to private key component i*/
+ MP_INT *n = (MP_INT*)((char *)key + RSA_private_field[i].offset);
+
+ switch (i)
+ {
+ case 2:
+ case 3:
+ case 4:
+ {
+ size_t len = (pgp_size(packet, 2)+7) / BITS_PER_BYTE;
+
+ n_to_mpz(n, packet->ptr, len);
+ DBG(DBG_PARSING,
+ DBG_log("L3 - %s:", RSA_private_field[i].name)
+ )
+ DBG_cond_dump(DBG_PRIVATE, "", packet->ptr, len);
+ packet->ptr += len;
+ packet->len -= len;
+ }
+ break;
+ case 5: /* dP = d mod (p-1) */
+ mpz_init(u);
+ mpz_sub_ui(u, &key->p, 1);
+ mpz_mod(n, &key->d, u);
+ mpz_clear(u);
+ break;
+ case 6: /* dQ = d mod (q-1) */
+ mpz_init(u);
+ mpz_sub_ui(u, &key->q, 1);
+ mpz_mod(n, &key->d, u);
+ mpz_clear(u);
+ break;
+ case 7: /* qInv = (q^-1) mod p */
+ mpz_invert(n, &key->q, &key->p);
+ if (mpz_cmp_ui(n, 0) < 0)
+ mpz_add(n, n, &key->p);
+ passert(mpz_cmp(n, &key->p) < 0);
+ break;
+ }
+ }
+ return TRUE;
+ }
+
+ plog(" %s encryption not supported", pgp_sym_alg_name[s2k]);
+ return FALSE;
+}
+
+/*
+ * Parse OpenPGP signature packet defined in section 5.2.2 of RFC 2440
+ */
+static bool
+parse_pgp_signature_packet(chunk_t *packet, pgpcert_t *cert)
+{
+ time_t created;
+ chunk_t keyid;
+ u_char sig_type;
+ u_char version = pgp_version(packet);
+
+ /* we parse only V3 signature packets */
+ if (version != 3)
+ return TRUE;
+
+ /* size byte must have the value 5 */
+ if (pgp_size(packet, 1) != 5)
+ {
+ plog(" size must be 5");
+ return FALSE;
+ }
+
+ /* signature type - 1 byte */
+ sig_type = (u_char)pgp_size(packet, 1);
+ DBG(DBG_PARSING,
+ DBG_log("L3 - signature type: 0x%2x", sig_type)
+ )
+
+ /* creation date - 4 bytes */
+ created = (time_t)pgp_size(packet, 4);
+ DBG(DBG_PARSING,
+ DBG_log("L3 - created:");
+ DBG_log(" %s", timetoa(&cert->created, TRUE))
+ )
+
+ /* key ID of signer - 8 bytes */
+ keyid.ptr = packet->ptr;
+ keyid.len = PGP_KEYID_SIZE;
+ DBG_cond_dump_chunk(DBG_PARSING, "L3 - key ID of signer", keyid);
+
+ return TRUE;
+}
+
+bool
+parse_pgp(chunk_t blob, pgpcert_t *cert, RSA_private_key_t *key)
+{
+ DBG(DBG_PARSING,
+ DBG_log("L0 - PGP file:")
+ )
+ DBG_cond_dump_chunk(DBG_RAW, "", blob);
+
+ if (cert != NULL)
+ {
+ /* parse a PGP certificate file */
+ cert->certificate = blob;
+ time(&cert->installed);
+ }
+ else if (key == NULL)
+ {
+ /* should not occur, nothing to parse */
+ return FALSE;
+ }
+
+ while (blob.len > 0)
+ {
+ chunk_t packet = empty_chunk;
+ u_char packet_tag = *blob.ptr;
+
+ DBG(DBG_PARSING,
+ DBG_log("L1 - PGP packet: tag= 0x%2x", packet_tag)
+ )
+
+ /* bit 7 must be set */
+ if (!(packet_tag & 0x80))
+ {
+ plog(" incorrect Packet Tag");
+ return FALSE;
+ }
+
+ /* bit 6 set defines new packet format */
+ if (packet_tag & 0x40)
+ {
+ plog(" new PGP packet format not supported");
+ return FALSE;
+ }
+ else
+ {
+ int packet_type = (packet_tag & 0x3C) >> 2;
+
+ packet.len = pgp_old_packet_length(&blob);
+ packet.ptr = blob.ptr;
+ blob.ptr += packet.len;
+ blob.len -= packet.len;
+ DBG(DBG_PARSING,
+ DBG_log(" %s (%d), old format, %d bytes",
+ (packet_type < PGP_PKT_ROOF) ?
+ pgp_packet_type_name[packet_type] :
+ "Undefined Packet Type", packet_type, (int)packet.len);
+ DBG_log("L2 - body:")
+ )
+ DBG_cond_dump_chunk(DBG_RAW, "", packet);
+
+ if (cert != NULL)
+ {
+ /* parse a PGP certificate */
+ switch (packet_type)
+ {
+ case PGP_PKT_PUBLIC_KEY:
+ if (!parse_pgp_pubkey_packet(&packet, cert))
+ return FALSE;
+ break;
+ case PGP_PKT_SIGNATURE:
+ if (!parse_pgp_signature_packet(&packet, cert))
+ return FALSE;
+ break;
+ case PGP_PKT_USER_ID:
+ DBG(DBG_PARSING,
+ DBG_log("L3 - user ID:");
+ DBG_log(" '%.*s'", (int)packet.len, packet.ptr)
+ )
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ /* parse a PGP private key file */
+ switch (packet_type)
+ {
+ case PGP_PKT_SECRET_KEY:
+ if (!parse_pgp_secretkey_packet(&packet, key))
+ return FALSE;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ return TRUE;
+}
+
+/*
+ * compare two OpenPGP certificates
+ */
+static bool
+same_pgpcert(pgpcert_t *a, pgpcert_t *b)
+{
+ return a->certificate.len == b->certificate.len &&
+ memcmp(a->certificate.ptr, b->certificate.ptr, b->certificate.len) == 0;
+}
+
+/*
+ * for each link pointing to the certificate increase the count by one
+ */
+void
+share_pgpcert(pgpcert_t *cert)
+{
+ if (cert != NULL)
+ cert->count++;
+}
+
+/*
+ * select the OpenPGP keyid as ID
+ */
+void
+select_pgpcert_id(pgpcert_t *cert, struct id *end_id)
+{
+ end_id->kind = ID_KEY_ID;
+ end_id->name.len = PGP_FINGERPRINT_SIZE;
+ end_id->name.ptr = cert->fingerprint;
+ end_id->name.ptr = temporary_cyclic_buffer();
+ memcpy(end_id->name.ptr, cert->fingerprint, PGP_FINGERPRINT_SIZE);
+}
+
+/*
+ * add an OpenPGP user/host certificate to the chained list
+ */
+pgpcert_t*
+add_pgpcert(pgpcert_t *cert)
+{
+ pgpcert_t *c = pgpcerts;
+
+ while (c != NULL)
+ {
+ if (same_pgpcert(c, cert)) /* already in chain, free cert */
+ {
+ free_pgpcert(cert);
+ return c;
+ }
+ c = c->next;
+ }
+
+ /* insert new cert at the root of the chain */
+ cert->next = pgpcerts;
+ pgpcerts = cert;
+ DBG(DBG_CONTROL | DBG_PARSING,
+ DBG_log(" pgp cert inserted")
+ )
+ return cert;
+}
+
+/* release of a certificate decreases the count by one
+ " the certificate is freed when the counter reaches zero
+ */
+void
+release_pgpcert(pgpcert_t *cert)
+{
+ if (cert != NULL && --cert->count == 0)
+ {
+ pgpcert_t **pp = &pgpcerts;
+ while (*pp != cert)
+ pp = &(*pp)->next;
+ *pp = cert->next;
+ free_pgpcert(cert);
+ }
+}
+
+/*
+ * free a PGP certificate
+ */
+void
+free_pgpcert(pgpcert_t *cert)
+{
+ if (cert != NULL)
+ {
+ if (cert->certificate.ptr != NULL)
+ pfree(cert->certificate.ptr);
+ pfree(cert);
+ }
+}
+
+/*
+ * list all PGP end certificates in a chained list
+ */
+void
+list_pgp_end_certs(bool utc)
+{
+ pgpcert_t *cert = pgpcerts;
+ time_t now;
+
+ /* determine the current time */
+ time(&now);
+
+ if (cert != NULL)
+ {
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of PGP End certificates:");
+ whack_log(RC_COMMENT, " ");
+ }
+
+ while (cert != NULL)
+ {
+ unsigned keysize;
+ char buf[BUF_LEN];
+ cert_t c;
+
+ c.type = CERT_PGP;
+ c.u.pgp = cert;
+
+ whack_log(RC_COMMENT, "%s, count: %d", timetoa(&cert->installed, utc), cert->count);
+ datatot(cert->fingerprint, PGP_FINGERPRINT_SIZE, 'x', buf, BUF_LEN);
+ whack_log(RC_COMMENT, " fingerprint: %s", buf);
+ form_keyid(cert->publicExponent, cert->modulus, buf, &keysize);
+ whack_log(RC_COMMENT, " pubkey: %4d RSA Key %s%s", 8*keysize, buf,
+ (has_private_key(c))? ", has private key" : "");
+ whack_log(RC_COMMENT, " created: %s", timetoa(&cert->created, utc));
+ whack_log(RC_COMMENT, " until: %s %s", timetoa(&cert->until, utc),
+ check_expiry(cert->until, CA_CERT_WARNING_INTERVAL, TRUE));
+ cert = cert->next;
+ }
+}
+
diff --git a/src/pluto/pgp.h b/src/pluto/pgp.h
new file mode 100644
index 000000000..4f34debc9
--- /dev/null
+++ b/src/pluto/pgp.h
@@ -0,0 +1,54 @@
+/* Support of OpenPGP certificates
+ * Copyright (C) 2002-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.
+ *
+ * RCSID $Id: pgp.h,v 1.3 2005/08/07 07:50:09 as Exp $
+ */
+
+#ifndef _PGP_H
+#define _PGP_H
+
+#include "pkcs1.h"
+/*
+ * Length of PGP V3 fingerprint
+ */
+#define PGP_FINGERPRINT_SIZE MD5_DIGEST_SIZE
+
+typedef char fingerprint_t[PGP_FINGERPRINT_SIZE];
+
+/* access structure for an OpenPGP certificate */
+
+typedef struct pgpcert pgpcert_t;
+
+struct pgpcert {
+ pgpcert_t *next;
+ time_t installed;
+ int count;
+ chunk_t certificate;
+ time_t created;
+ time_t until;
+ enum pubkey_alg pubkeyAlg;
+ chunk_t modulus;
+ chunk_t publicExponent;
+ fingerprint_t fingerprint;
+};
+
+extern const pgpcert_t empty_pgpcert;
+extern bool parse_pgp(chunk_t blob, pgpcert_t *cert, RSA_private_key_t *key);
+extern void share_pgpcert(pgpcert_t *cert);
+extern void select_pgpcert_id(pgpcert_t *cert, struct id *end_id);
+extern pgpcert_t* add_pgpcert(pgpcert_t *cert);
+extern void list_pgp_end_certs(bool utc);
+extern void release_pgpcert(pgpcert_t *cert);
+extern void free_pgpcert(pgpcert_t *cert);
+
+#endif /* _PGP_H */
diff --git a/src/pluto/pkcs1.c b/src/pluto/pkcs1.c
new file mode 100644
index 000000000..ade5fdd94
--- /dev/null
+++ b/src/pluto/pkcs1.c
@@ -0,0 +1,674 @@
+/* Support of PKCS#1 private key data structures
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Copyright (C) 2002-2005 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil, Switzerland
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: pkcs1.c,v 1.17 2006/01/04 21:00:43 as Exp $
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <freeswan.h>
+#include <libsha2/sha2.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "mp_defs.h"
+#include "asn1.h"
+#include "oid.h"
+#include "log.h"
+#include "pkcs1.h"
+#include "md2.h"
+#include "md5.h"
+#include "sha1.h"
+#include "rnd.h"
+
+const struct fld RSA_private_field[] =
+{
+ { "Modulus", offsetof(RSA_private_key_t, pub.n) },
+ { "PublicExponent", offsetof(RSA_private_key_t, pub.e) },
+
+ { "PrivateExponent", offsetof(RSA_private_key_t, d) },
+ { "Prime1", offsetof(RSA_private_key_t, p) },
+ { "Prime2", offsetof(RSA_private_key_t, q) },
+ { "Exponent1", offsetof(RSA_private_key_t, dP) },
+ { "Exponent2", offsetof(RSA_private_key_t, dQ) },
+ { "Coefficient", offsetof(RSA_private_key_t, qInv) },
+};
+
+/* ASN.1 definition of a PKCS#1 RSA private key */
+
+static const asn1Object_t privkeyObjects[] = {
+ { 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 PKCS1_PRIV_KEY_VERSION 1
+#define PKCS1_PRIV_KEY_MODULUS 2
+#define PKCS1_PRIV_KEY_PUB_EXP 3
+#define PKCS1_PRIV_KEY_COEFF 9
+#define PKCS1_PRIV_KEY_ROOF 16
+
+
+/*
+ * forms the FreeS/WAN keyid from the public exponent e and modulus n
+ */
+void
+form_keyid(chunk_t e, chunk_t n, char* keyid, unsigned *keysize)
+{
+ /* eliminate leading zero bytes in modulus from ASN.1 coding */
+ while (n.len > 1 && *n.ptr == 0x00)
+ {
+ n.ptr++; n.len--;
+ }
+
+ /* form the FreeS/WAN keyid */
+ keyid[0] = '\0'; /* in case of splitkeytoid failure */
+ splitkeytoid(e.ptr, e.len, n.ptr, n.len, keyid, KEYID_BUF);
+
+ /* return the RSA modulus size in octets */
+ *keysize = n.len;
+}
+
+/*
+ * initialize an RSA_public_key_t object
+ */
+void
+init_RSA_public_key(RSA_public_key_t *rsa, chunk_t e, chunk_t n)
+{
+ n_to_mpz(&rsa->e, e.ptr, e.len);
+ n_to_mpz(&rsa->n, n.ptr, n.len);
+
+ form_keyid(e, n, rsa->keyid, &rsa->k);
+}
+
+#ifdef DEBUG
+static void
+RSA_show_key_fields(RSA_private_key_t *k, int fieldcnt)
+{
+ const struct fld *p;
+
+ DBG_log(" keyid: *%s", k->pub.keyid);
+
+ for (p = RSA_private_field; p < &RSA_private_field[fieldcnt]; p++)
+ {
+ MP_INT *n = (MP_INT *) ((char *)k + p->offset);
+ size_t sz = mpz_sizeinbase(n, 16);
+ char buf[RSA_MAX_OCTETS * 2 + 2]; /* ought to be big enough */
+
+ passert(sz <= sizeof(buf));
+ mpz_get_str(buf, 16, n);
+
+ DBG_log(" %s: 0x%s", p->name, buf);
+ }
+}
+
+/* debugging info that compromises security! */
+void
+RSA_show_private_key(RSA_private_key_t *k)
+{
+ RSA_show_key_fields(k, elemsof(RSA_private_field));
+}
+
+void
+RSA_show_public_key(RSA_public_key_t *k)
+{
+ /* Kludge: pretend that it is a private key, but only display the
+ * first two fields (which are the public key).
+ */
+ passert(offsetof(RSA_private_key_t, pub) == 0);
+ RSA_show_key_fields((RSA_private_key_t *)k, 2);
+}
+#endif
+
+err_t
+RSA_private_key_sanity(RSA_private_key_t *k)
+{
+ /* note that the *last* error found is reported */
+ err_t ugh = NULL;
+ mpz_t t, u, q1;
+
+#ifdef DEBUG /* debugging info that compromises security */
+ DBG(DBG_PRIVATE, RSA_show_private_key(k));
+#endif
+
+ /* PKCS#1 1.5 section 6 requires modulus to have at least 12 octets.
+ * We actually require more (for security).
+ */
+ if (k->pub.k < RSA_MIN_OCTETS)
+ return RSA_MIN_OCTETS_UGH;
+
+ /* we picked a max modulus size to simplify buffer allocation */
+ if (k->pub.k > RSA_MAX_OCTETS)
+ return RSA_MAX_OCTETS_UGH;
+
+ mpz_init(t);
+ mpz_init(u);
+ mpz_init(q1);
+
+ /* check that n == p * q */
+ mpz_mul(u, &k->p, &k->q);
+ if (mpz_cmp(u, &k->pub.n) != 0)
+ ugh = "n != p * q";
+
+ /* check that e divides neither p-1 nor q-1 */
+ mpz_sub_ui(t, &k->p, 1);
+ mpz_mod(t, t, &k->pub.e);
+ if (mpz_cmp_ui(t, 0) == 0)
+ ugh = "e divides p-1";
+
+ mpz_sub_ui(t, &k->q, 1);
+ mpz_mod(t, t, &k->pub.e);
+ if (mpz_cmp_ui(t, 0) == 0)
+ ugh = "e divides q-1";
+
+ /* 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, &k->q, 1);
+ mpz_sub_ui(u, &k->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, &k->d, &k->pub.e);
+ mpz_mod(t, t, u);
+ if (mpz_cmp_ui(t, 1) != 0)
+ ugh = "(d * e) mod (lcm(p-1, q-1)) != 1";
+
+ /* check that dP is d mod (p-1) */
+ mpz_sub_ui(u, &k->p, 1);
+ mpz_mod(t, &k->d, u);
+ if (mpz_cmp(t, &k->dP) != 0)
+ ugh = "dP is not congruent to d mod (p-1)";
+
+ /* check that dQ is d mod (q-1) */
+ mpz_sub_ui(u, &k->q, 1);
+ mpz_mod(t, &k->d, u);
+ if (mpz_cmp(t, &k->dQ) != 0)
+ ugh = "dQ is not congruent to d mod (q-1)";
+
+ /* check that qInv is (q^-1) mod p */
+ mpz_mul(t, &k->qInv, &k->q);
+ mpz_mod(t, t, &k->p);
+ if (mpz_cmp_ui(t, 1) != 0)
+ ugh = "qInv is not conguent ot (q^-1) mod p";
+
+ mpz_clear(t);
+ mpz_clear(u);
+ mpz_clear(q1);
+ return ugh;
+}
+
+/*
+ * Check the equality of two RSA public keys
+ */
+bool
+same_RSA_public_key(const RSA_public_key_t *a, const RSA_public_key_t *b)
+{
+ return a == b
+ || (a->k == b->k && mpz_cmp(&a->n, &b->n) == 0 && mpz_cmp(&a->e, &b->e) == 0);
+}
+
+/*
+ * Parses a PKCS#1 private key
+ */
+bool
+pkcs1_parse_private_key(chunk_t blob, RSA_private_key_t *key)
+{
+ err_t ugh = NULL;
+ asn1_ctx_t ctx;
+ chunk_t object, modulus, exp;
+ u_int level;
+ int objectID = 0;
+
+ asn1_init(&ctx, blob, 0, FALSE, DBG_PRIVATE);
+
+ while (objectID < PKCS1_PRIV_KEY_ROOF) {
+
+ if (!extract_object(privkeyObjects, &objectID, &object, &level, &ctx))
+ return FALSE;
+
+ if (objectID == PKCS1_PRIV_KEY_VERSION)
+ {
+ if (object.len > 0 && *object.ptr != 0)
+ {
+ plog(" wrong PKCS#1 private key version");
+ return FALSE;
+ }
+ }
+ else if (objectID >= PKCS1_PRIV_KEY_MODULUS &&
+ objectID <= PKCS1_PRIV_KEY_COEFF)
+ {
+ MP_INT *u = (MP_INT *) ((char *)key
+ + RSA_private_field[objectID - PKCS1_PRIV_KEY_MODULUS].offset);
+
+ n_to_mpz(u, object.ptr, object.len);
+
+ if (objectID == PKCS1_PRIV_KEY_MODULUS)
+ modulus = object;
+ else if (objectID == PKCS1_PRIV_KEY_PUB_EXP)
+ exp = object;
+ }
+ objectID++;
+ }
+ form_keyid(exp, modulus, key->pub.keyid, &key->pub.k);
+ ugh = RSA_private_key_sanity(key);
+ return (ugh == NULL);
+}
+
+/*
+ * compute a digest over a binary blob
+ */
+bool
+compute_digest(chunk_t tbs, int alg, chunk_t *digest)
+{
+ switch (alg)
+ {
+ case OID_MD2:
+ case OID_MD2_WITH_RSA:
+ {
+ MD2_CTX context;
+
+ MD2Init(&context);
+ MD2Update(&context, tbs.ptr, tbs.len);
+ MD2Final(digest->ptr, &context);
+ digest->len = MD2_DIGEST_SIZE;
+ return TRUE;
+ }
+ case OID_MD5:
+ case OID_MD5_WITH_RSA:
+ {
+ MD5_CTX context;
+
+ MD5Init(&context);
+ MD5Update(&context, tbs.ptr, tbs.len);
+ MD5Final(digest->ptr, &context);
+ digest->len = MD5_DIGEST_SIZE;
+ return TRUE;
+ }
+ case OID_SHA1:
+ case OID_SHA1_WITH_RSA:
+ case OID_SHA1_WITH_RSA_OIW:
+ {
+ SHA1_CTX context;
+
+ SHA1Init(&context);
+ SHA1Update(&context, tbs.ptr, tbs.len);
+ SHA1Final(digest->ptr, &context);
+ digest->len = SHA1_DIGEST_SIZE;
+ return TRUE;
+ }
+ case OID_SHA256:
+ case OID_SHA256_WITH_RSA:
+ {
+ sha256_context context;
+
+ sha256_init(&context);
+ sha256_write(&context, tbs.ptr, tbs.len);
+ sha256_final(&context);
+ memcpy(digest->ptr, context.sha_out, SHA2_256_DIGEST_SIZE);
+ digest->len = SHA2_256_DIGEST_SIZE;
+ return TRUE;
+ }
+ case OID_SHA384:
+ case OID_SHA384_WITH_RSA:
+ {
+ sha512_context context;
+
+ sha384_init(&context);
+ sha512_write(&context, tbs.ptr, tbs.len);
+ sha512_final(&context);
+ memcpy(digest->ptr, context.sha_out, SHA2_384_DIGEST_SIZE);
+ digest->len = SHA2_384_DIGEST_SIZE;
+ return TRUE;
+ }
+ case OID_SHA512:
+ case OID_SHA512_WITH_RSA:
+ {
+ sha512_context context;
+
+ sha512_init(&context);
+ sha512_write(&context, tbs.ptr, tbs.len);
+ sha512_final(&context);
+ memcpy(digest->ptr, context.sha_out, SHA2_512_DIGEST_SIZE);
+ digest->len = SHA2_512_DIGEST_SIZE;
+ return TRUE;
+ }
+ default:
+ digest->len = 0;
+ return FALSE;
+ }
+}
+
+/*
+ * compute an RSA signature with PKCS#1 padding
+ */
+void
+sign_hash(const RSA_private_key_t *k, const u_char *hash_val, size_t hash_len
+ , u_char *sig_val, size_t sig_len)
+{
+ chunk_t ch;
+ mpz_t t1, t2;
+ size_t padlen;
+ u_char *p = sig_val;
+
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ DBG_log("signing hash with RSA Key *%s", k->pub.keyid)
+ )
+ /* PKCS#1 v1.5 8.1 encryption-block formatting */
+ *p++ = 0x00;
+ *p++ = 0x01; /* BT (block type) 01 */
+ padlen = sig_len - 3 - hash_len;
+ memset(p, 0xFF, padlen);
+ p += padlen;
+ *p++ = 0x00;
+ memcpy(p, hash_val, hash_len);
+ passert(p + hash_len - sig_val == (ptrdiff_t)sig_len);
+
+ /* PKCS#1 v1.5 8.2 octet-string-to-integer conversion */
+ n_to_mpz(t1, sig_val, sig_len); /* (could skip leading 0x00) */
+
+ /* PKCS#1 v1.5 8.3 RSA computation y = x^c mod n
+ * Better described in PKCS#1 v2.0 5.1 RSADP.
+ * There are two methods, depending on the form of the private key.
+ * We use the one based on the Chinese Remainder Theorem.
+ */
+ mpz_init(t2);
+
+ mpz_powm(t2, t1, &k->dP, &k->p); /* m1 = c^dP mod p */
+
+ mpz_powm(t1, t1, &k->dQ, &k->q); /* m2 = c^dQ mod Q */
+
+ mpz_sub(t2, t2, t1); /* h = qInv (m1 - m2) mod p */
+ mpz_mod(t2, t2, &k->p);
+ mpz_mul(t2, t2, &k->qInv);
+ mpz_mod(t2, t2, &k->p);
+
+ mpz_mul(t2, t2, &k->q); /* m = m2 + h q */
+ mpz_add(t1, t1, t2);
+
+ /* PKCS#1 v1.5 8.4 integer-to-octet-string conversion */
+ ch = mpz_to_n(t1, sig_len);
+ memcpy(sig_val, ch.ptr, sig_len);
+ pfree(ch.ptr);
+
+ mpz_clear(t1);
+ mpz_clear(t2);
+}
+
+/*
+ * encrypt data with an RSA public key after padding
+ */
+chunk_t
+RSA_encrypt(const RSA_public_key_t *key, chunk_t in)
+{
+ u_char padded[RSA_MAX_OCTETS];
+ u_char *pos = padded;
+ int padding = key->k - in.len - 3;
+ int i;
+
+ if (padding < 8 || key->k > RSA_MAX_OCTETS)
+ return empty_chunk;
+
+ /* add padding according to PKCS#1 7.2.1 1.+2. */
+ *pos++ = 0x00;
+ *pos++ = 0x02;
+
+ /* pad with pseudo random bytes unequal to zero */
+ get_rnd_bytes(pos, padding);
+ for (i = 0; i < padding; i++)
+ {
+ while (!*pos)
+ get_rnd_bytes(pos, 1);
+ pos++;
+ }
+
+ /* append the padding terminator */
+ *pos++ = 0x00;
+
+ /* now add the data */
+ memcpy(pos, in.ptr, in.len);
+ DBG(DBG_RAW,
+ DBG_dump_chunk("data for rsa encryption:\n", in);
+ DBG_dump("padded data for rsa encryption:\n", padded, key->k)
+ )
+
+ /* convert chunk to integer (PKCS#1 7.2.1 3.a) */
+ {
+ chunk_t out;
+ mpz_t m, c;
+
+ mpz_init(c);
+ n_to_mpz(m, padded, key->k);
+
+ /* encrypt(PKCS#1 7.2.1 3.b) */
+ mpz_powm(c, m, &key->e, &key->n);
+
+ /* convert integer back to a chunk (PKCS#1 7.2.1 3.c) */
+ out = mpz_to_n(c, key->k);
+ mpz_clear(c);
+ mpz_clear(m);
+
+ DBG(DBG_RAW,
+ DBG_dump_chunk("rsa encrypted data:\n", out)
+ )
+ return out;
+ }
+}
+
+/*
+ * decrypt data with an RSA private key and remove padding
+ */
+bool
+RSA_decrypt(const RSA_private_key_t *key, chunk_t in, chunk_t *out)
+{
+ chunk_t padded;
+ u_char *pos;
+ mpz_t t1, t2;
+
+ n_to_mpz(t1, in.ptr,in.len);
+
+ /* PKCS#1 v1.5 8.3 RSA computation y = x^c mod n
+ * Better described in PKCS#1 v2.0 5.1 RSADP.
+ * There are two methods, depending on the form of the private key.
+ * We use the one based on the Chinese Remainder Theorem.
+ */
+ mpz_init(t2);
+
+ mpz_powm(t2, t1, &key->dP, &key->p); /* m1 = c^dP mod p */
+ mpz_powm(t1, t1, &key->dQ, &key->q); /* m2 = c^dQ mod Q */
+
+ mpz_sub(t2, t2, t1); /* h = qInv (m1 - m2) mod p */
+ mpz_mod(t2, t2, &key->p);
+ mpz_mul(t2, t2, &key->qInv);
+ mpz_mod(t2, t2, &key->p);
+
+ mpz_mul(t2, t2, &key->q); /* m = m2 + h q */
+ mpz_add(t1, t1, t2);
+
+ padded = mpz_to_n(t1, key->pub.k);
+ mpz_clear(t1);
+ mpz_clear(t2);
+
+ DBG(DBG_PRIVATE,
+ DBG_dump_chunk("rsa decrypted data with padding:\n", padded)
+ )
+ pos = padded.ptr;
+
+ /* PKCS#1 v1.5 8.1 encryption-block formatting (EB = 00 || 02 || PS || 00 || D) */
+
+ /* check for hex pattern 00 02 in decrypted message */
+ if ((*pos++ != 0x00) || (*(pos++) != 0x02))
+ {
+ plog("incorrect padding - probably wrong RSA key");
+ freeanychunk(padded);
+ return FALSE;
+ }
+ padded.len -= 2;
+
+ /* the plaintext data starts after first 0x00 byte */
+ while (padded.len-- > 0 && *pos++ != 0x00)
+
+ if (padded.len == 0)
+ {
+ plog("no plaintext data");
+ freeanychunk(padded);
+ return FALSE;
+ }
+
+ clonetochunk(*out, pos, padded.len, "decrypted data");
+ freeanychunk(padded);
+ return TRUE;
+}
+
+/*
+ * build signatureValue
+ */
+chunk_t
+pkcs1_build_signature(chunk_t tbs, int hash_alg, const RSA_private_key_t *key
+, bool bit_string)
+{
+
+ size_t siglen = key->pub.k;
+
+ u_char digest_buf[MAX_DIGEST_LEN];
+ chunk_t digest = { digest_buf, MAX_DIGEST_LEN };
+ chunk_t digestInfo, alg_id, signatureValue;
+ u_char *pos;
+
+ switch (hash_alg)
+ {
+ case OID_MD5:
+ case OID_MD5_WITH_RSA:
+ alg_id = ASN1_md5_id;
+ break;
+ case OID_SHA1:
+ case OID_SHA1_WITH_RSA:
+ alg_id = ASN1_sha1_id;
+ break;
+ default:
+ return empty_chunk;
+ }
+ compute_digest(tbs, hash_alg, &digest);
+
+ /* according to PKCS#1 v2.1 digest must be packaged into
+ * an ASN.1 structure for encryption
+ */
+ digestInfo = asn1_wrap(ASN1_SEQUENCE, "cm"
+ , alg_id
+ , asn1_simple_object(ASN1_OCTET_STRING, digest));
+
+ /* generate the RSA signature */
+ if (bit_string)
+ {
+ pos = build_asn1_object(&signatureValue, ASN1_BIT_STRING, 1 + siglen);
+ *pos++ = 0x00;
+ }
+ else
+ {
+ pos = build_asn1_object(&signatureValue, ASN1_OCTET_STRING, siglen);
+ }
+ sign_hash(key, digestInfo.ptr, digestInfo.len, pos, siglen);
+ pfree(digestInfo.ptr);
+
+ return signatureValue;
+}
+
+/*
+ * build a DER-encoded PKCS#1 private key object
+ */
+chunk_t
+pkcs1_build_private_key(const RSA_private_key_t *key)
+{
+ chunk_t pkcs1 = asn1_wrap(ASN1_SEQUENCE, "cmmmmmmmm"
+ , ASN1_INTEGER_0
+ , asn1_integer_from_mpz(&key->pub.n)
+ , asn1_integer_from_mpz(&key->pub.e)
+ , asn1_integer_from_mpz(&key->d)
+ , asn1_integer_from_mpz(&key->p)
+ , asn1_integer_from_mpz(&key->q)
+ , asn1_integer_from_mpz(&key->dP)
+ , asn1_integer_from_mpz(&key->dQ)
+ , asn1_integer_from_mpz(&key->qInv));
+
+ DBG(DBG_PRIVATE,
+ DBG_dump_chunk("PKCS#1 encoded private key:", pkcs1)
+ )
+ return pkcs1;
+}
+
+/*
+ * build a DER-encoded PKCS#1 public key object
+ */
+chunk_t
+pkcs1_build_public_key(const RSA_public_key_t *rsa)
+{
+ return asn1_wrap(ASN1_SEQUENCE, "mm"
+ , asn1_integer_from_mpz(&rsa->n)
+ , asn1_integer_from_mpz(&rsa->e));
+}
+
+/*
+ * build a DER-encoded publicKeyInfo object
+ */
+chunk_t
+pkcs1_build_publicKeyInfo(const RSA_public_key_t *rsa)
+{
+ chunk_t publicKey;
+ chunk_t rawKey = pkcs1_build_public_key(rsa);
+
+ u_char *pos = build_asn1_object(&publicKey, ASN1_BIT_STRING
+ , 1 + rawKey.len);
+ *pos++ = 0x00;
+ mv_chunk(&pos, rawKey);
+
+ return asn1_wrap(ASN1_SEQUENCE, "cm"
+ , ASN1_rsaEncryption_id
+ , publicKey);
+}
+void
+free_RSA_public_content(RSA_public_key_t *rsa)
+{
+ mpz_clear(&rsa->n);
+ mpz_clear(&rsa->e);
+}
+
+void
+free_RSA_private_content(RSA_private_key_t *rsak)
+{
+ free_RSA_public_content(&rsak->pub);
+ mpz_clear(&rsak->d);
+ mpz_clear(&rsak->p);
+ mpz_clear(&rsak->q);
+ mpz_clear(&rsak->dP);
+ mpz_clear(&rsak->dQ);
+ mpz_clear(&rsak->qInv);
+}
+
diff --git a/src/pluto/pkcs1.h b/src/pluto/pkcs1.h
new file mode 100644
index 000000000..c927db0f8
--- /dev/null
+++ b/src/pluto/pkcs1.h
@@ -0,0 +1,88 @@
+/* Support of PKCS#1 private key data structures
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Copyright (C) 2002-2005 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil, Switzerland
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: pkcs1.h,v 1.14 2005/12/06 22:52:12 as Exp $
+ */
+
+#ifndef _PKCS1_H
+#define _PKCS1_H
+
+#include <gmp.h> /* GNU Multi Precision library */
+
+#include "defs.h"
+
+typedef struct RSA_public_key RSA_public_key_t;
+
+struct RSA_public_key
+{
+ char keyid[KEYID_BUF]; /* see ipsec_keyblobtoid(3) */
+
+ /* length of modulus n in octets: [RSA_MIN_OCTETS, RSA_MAX_OCTETS] */
+ unsigned k;
+
+ /* public: */
+ MP_INT
+ n, /* modulus: p * q */
+ e; /* exponent: relatively prime to (p-1) * (q-1) [probably small] */
+};
+
+typedef struct RSA_private_key RSA_private_key_t;
+
+struct RSA_private_key {
+ struct RSA_public_key pub; /* must be at start for RSA_show_public_key */
+
+ MP_INT
+ d, /* private exponent: (e^-1) mod ((p-1) * (q-1)) */
+ /* help for Chinese Remainder Theorem speedup: */
+ p, /* first secret prime */
+ q, /* second secret prime */
+ dP, /* first factor's exponent: (e^-1) mod (p-1) == d mod (p-1) */
+ dQ, /* second factor's exponent: (e^-1) mod (q-1) == d mod (q-1) */
+ qInv; /* (q^-1) mod p */
+};
+
+struct fld {
+ const char *name;
+ size_t offset;
+};
+
+extern const struct fld RSA_private_field[];
+#define RSA_PRIVATE_FIELD_ELEMENTS 8
+
+extern void init_RSA_public_key(RSA_public_key_t *rsa, chunk_t e, chunk_t n);
+extern bool pkcs1_parse_private_key(chunk_t blob, RSA_private_key_t *key);
+extern chunk_t pkcs1_build_private_key(const RSA_private_key_t *key);
+extern chunk_t pkcs1_build_public_key(const RSA_public_key_t *rsa);
+extern chunk_t pkcs1_build_publicKeyInfo(const RSA_public_key_t *rsa);
+extern chunk_t pkcs1_build_signature(chunk_t tbs, int hash_alg
+ , const RSA_private_key_t *key, bool bit_string);
+extern bool compute_digest(chunk_t tbs, int alg, chunk_t *digest);
+extern void sign_hash(const RSA_private_key_t *k, const u_char *hash_val
+ , size_t hash_len, u_char *sig_val, size_t sig_len);
+extern chunk_t RSA_encrypt(const RSA_public_key_t *key, chunk_t in);
+extern bool RSA_decrypt(const RSA_private_key_t *key, chunk_t in
+ , chunk_t *out);
+extern bool same_RSA_public_key(const RSA_public_key_t *a
+ , const RSA_public_key_t *b);
+extern void form_keyid(chunk_t e, chunk_t n, char* keyid, unsigned *keysize);
+extern err_t RSA_private_key_sanity(RSA_private_key_t *k);
+#ifdef DEBUG
+extern void RSA_show_public_key(RSA_public_key_t *k);
+extern void RSA_show_private_key(RSA_private_key_t *k);
+#endif
+extern void free_RSA_public_content(RSA_public_key_t *rsa);
+extern void free_RSA_private_content(RSA_private_key_t *rsak);
+
+#endif /* _PKCS1_H */
diff --git a/src/pluto/pkcs7.c b/src/pluto/pkcs7.c
new file mode 100644
index 000000000..3068c0c94
--- /dev/null
+++ b/src/pluto/pkcs7.c
@@ -0,0 +1,862 @@
+/* Support of PKCS#7 data structures
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Copyright (C) 2002-2005 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil, Switzerland
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: pkcs7.c,v 1.13 2005/12/22 22:11:24 as Exp $
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <libdes/des.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "asn1.h"
+#include "oid.h"
+#include "log.h"
+#include "x509.h"
+#include "certs.h"
+#include "pkcs7.h"
+#include "rnd.h"
+
+const contentInfo_t empty_contentInfo = {
+ OID_UNKNOWN , /* type */
+ { NULL, 0 } /* content */
+};
+
+/* ASN.1 definition of the PKCS#7 ContentInfo type */
+
+static const asn1Object_t contentInfoObjects[] = {
+ { 0, "contentInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "contentType", ASN1_OID, ASN1_BODY }, /* 1 */
+ { 1, "content", ASN1_CONTEXT_C_0, ASN1_OPT |
+ ASN1_BODY }, /* 2 */
+ { 1, "end opt", ASN1_EOC, ASN1_END } /* 3 */
+};
+
+#define PKCS7_INFO_TYPE 1
+#define PKCS7_INFO_CONTENT 2
+#define PKCS7_INFO_ROOF 4
+
+/* ASN.1 definition of the PKCS#7 signedData type */
+
+static const asn1Object_t signedDataObjects[] = {
+ { 0, "signedData", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */
+ { 1, "digestAlgorithms", ASN1_SET, ASN1_LOOP }, /* 2 */
+ { 2, "algorithm", ASN1_EOC, ASN1_RAW }, /* 3 */
+ { 1, "end loop", ASN1_EOC, ASN1_END }, /* 4 */
+ { 1, "contentInfo", ASN1_EOC, ASN1_RAW }, /* 5 */
+ { 1, "certificates", ASN1_CONTEXT_C_0, ASN1_OPT |
+ ASN1_LOOP }, /* 6 */
+ { 2, "certificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 7 */
+ { 1, "end opt or loop", ASN1_EOC, ASN1_END }, /* 8 */
+ { 1, "crls", ASN1_CONTEXT_C_1, ASN1_OPT |
+ ASN1_LOOP }, /* 9 */
+ { 2, "crl", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */
+ { 1, "end opt or loop", ASN1_EOC, ASN1_END }, /* 11 */
+ { 1, "signerInfos", ASN1_SET, ASN1_LOOP }, /* 12 */
+ { 2, "signerInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */
+ { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 14 */
+ { 3, "issuerAndSerialNumber", ASN1_SEQUENCE, ASN1_BODY }, /* 15 */
+ { 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 16 */
+ { 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 17 */
+ { 3, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 18 */
+ { 3, "authenticatedAttributes", ASN1_CONTEXT_C_0, ASN1_OPT |
+ ASN1_OBJ }, /* 19 */
+ { 3, "end opt", ASN1_EOC, ASN1_END }, /* 20 */
+ { 3, "digestEncryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 21 */
+ { 3, "encryptedDigest", ASN1_OCTET_STRING, ASN1_BODY }, /* 22 */
+ { 3, "unauthenticatedAttributes", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 23 */
+ { 3, "end opt", ASN1_EOC, ASN1_END }, /* 24 */
+ { 1, "end loop", ASN1_EOC, ASN1_END } /* 25 */
+};
+
+#define PKCS7_DIGEST_ALG 3
+#define PKCS7_SIGNED_CONTENT_INFO 5
+#define PKCS7_SIGNED_CERT 7
+#define PKCS7_SIGNER_INFO 13
+#define PKCS7_SIGNED_ISSUER 16
+#define PKCS7_SIGNED_SERIAL_NUMBER 17
+#define PKCS7_DIGEST_ALGORITHM 18
+#define PKCS7_AUTH_ATTRIBUTES 19
+#define PKCS7_DIGEST_ENC_ALGORITHM 21
+#define PKCS7_ENCRYPTED_DIGEST 22
+#define PKCS7_SIGNED_ROOF 26
+
+/* ASN.1 definition of the PKCS#7 envelopedData type */
+
+static const asn1Object_t envelopedDataObjects[] = {
+ { 0, "envelopedData", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */
+ { 1, "recipientInfos", ASN1_SET, ASN1_LOOP }, /* 2 */
+ { 2, "recipientInfo", ASN1_SEQUENCE, ASN1_BODY }, /* 3 */
+ { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 4 */
+ { 3, "issuerAndSerialNumber", ASN1_SEQUENCE, ASN1_BODY }, /* 5 */
+ { 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 6 */
+ { 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 7 */
+ { 3, "encryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 8 */
+ { 3, "encryptedKey", ASN1_OCTET_STRING, ASN1_BODY }, /* 9 */
+ { 1, "end loop", ASN1_EOC, ASN1_END }, /* 10 */
+ { 1, "encryptedContentInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 11 */
+ { 2, "contentType", ASN1_OID, ASN1_BODY }, /* 12 */
+ { 2, "contentEncryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 13 */
+ { 2, "encryptedContent", ASN1_CONTEXT_S_0, ASN1_BODY } /* 14 */
+};
+
+#define PKCS7_ENVELOPED_VERSION 1
+#define PKCS7_RECIPIENT_INFO_VERSION 4
+#define PKCS7_ISSUER 6
+#define PKCS7_SERIAL_NUMBER 7
+#define PKCS7_ENCRYPTION_ALG 8
+#define PKCS7_ENCRYPTED_KEY 9
+#define PKCS7_CONTENT_TYPE 12
+#define PKCS7_CONTENT_ENC_ALGORITHM 13
+#define PKCS7_ENCRYPTED_CONTENT 14
+#define PKCS7_ENVELOPED_ROOF 15
+
+/* PKCS7 contentInfo OIDs */
+
+static u_char ASN1_pkcs7_data_oid_str[] = {
+ 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01
+};
+
+static u_char ASN1_pkcs7_signed_data_oid_str[] = {
+ 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02
+};
+
+static u_char ASN1_pkcs7_enveloped_data_oid_str[] = {
+ 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x03
+};
+
+static u_char ASN1_pkcs7_signed_enveloped_data_oid_str[] = {
+ 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x04
+};
+
+static u_char ASN1_pkcs7_digested_data_oid_str[] = {
+ 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x05
+};
+
+static char ASN1_pkcs7_encrypted_data_oid_str[] = {
+ 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x06
+};
+
+static const chunk_t ASN1_pkcs7_data_oid =
+ strchunk(ASN1_pkcs7_data_oid_str);
+static const chunk_t ASN1_pkcs7_signed_data_oid =
+ strchunk(ASN1_pkcs7_signed_data_oid_str);
+static const chunk_t ASN1_pkcs7_enveloped_data_oid =
+ strchunk(ASN1_pkcs7_enveloped_data_oid_str);
+static const chunk_t ASN1_pkcs7_signed_enveloped_data_oid =
+ strchunk(ASN1_pkcs7_signed_enveloped_data_oid_str);
+static const chunk_t ASN1_pkcs7_digested_data_oid =
+ strchunk(ASN1_pkcs7_digested_data_oid_str);
+static const chunk_t ASN1_pkcs7_encrypted_data_oid =
+ strchunk(ASN1_pkcs7_encrypted_data_oid_str);
+
+/* 3DES and DES encryption OIDs */
+
+static u_char ASN1_3des_ede_cbc_oid_str[] = {
+ 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x03, 0x07
+};
+
+static u_char ASN1_des_cbc_oid_str[] = {
+ 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x07
+};
+
+static const chunk_t ASN1_3des_ede_cbc_oid =
+ strchunk(ASN1_3des_ede_cbc_oid_str);
+static const chunk_t ASN1_des_cbc_oid =
+ strchunk(ASN1_des_cbc_oid_str);
+
+/* PKCS#7 attribute type OIDs */
+
+static u_char ASN1_contentType_oid_str[] = {
+ 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x03
+};
+
+static u_char ASN1_messageDigest_oid_str[] = {
+ 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x04
+};
+
+static const chunk_t ASN1_contentType_oid =
+ strchunk(ASN1_contentType_oid_str);
+static const chunk_t ASN1_messageDigest_oid =
+ strchunk(ASN1_messageDigest_oid_str);
+
+/*
+ * Parse PKCS#7 ContentInfo object
+ */
+bool
+pkcs7_parse_contentInfo(chunk_t blob, u_int level0, contentInfo_t *cInfo)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+
+ asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
+
+ while (objectID < PKCS7_INFO_ROOF)
+ {
+ if (!extract_object(contentInfoObjects, &objectID, &object, &level, &ctx))
+ return FALSE;
+
+ if (objectID == PKCS7_INFO_TYPE)
+ {
+ cInfo->type = known_oid(object);
+ if (cInfo->type < OID_PKCS7_DATA
+ || cInfo->type > OID_PKCS7_ENCRYPTED_DATA)
+ {
+ plog("unknown pkcs7 content type");
+ return FALSE;
+ }
+ }
+ else if (objectID == PKCS7_INFO_CONTENT)
+ {
+ cInfo->content = object;
+ }
+ objectID++;
+ }
+ return TRUE;
+}
+
+/*
+ * Parse a PKCS#7 signedData object
+ */
+bool
+pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, x509cert_t **cert
+, chunk_t *attributes, const x509cert_t *cacert)
+{
+ u_char buf[BUF_LEN];
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int digest_alg = OID_UNKNOWN;
+ int enc_alg = OID_UNKNOWN;
+ int signerInfos = 0;
+ int objectID = 0;
+
+ contentInfo_t cInfo = empty_contentInfo;
+ chunk_t encrypted_digest = empty_chunk;
+
+ if (!pkcs7_parse_contentInfo(blob, 0, &cInfo))
+ return FALSE;
+
+ if (cInfo.type != OID_PKCS7_SIGNED_DATA)
+ {
+ plog("pkcs7 content type is not signedData");
+ return FALSE;
+ }
+
+ asn1_init(&ctx, cInfo.content, 2, FALSE, DBG_RAW);
+
+ while (objectID < PKCS7_SIGNED_ROOF)
+ {
+ if (!extract_object(signedDataObjects, &objectID, &object, &level, &ctx))
+ return FALSE;
+
+ switch (objectID)
+ {
+ case PKCS7_DIGEST_ALG:
+ digest_alg = parse_algorithmIdentifier(object, level, NULL);
+ break;
+ case PKCS7_SIGNED_CONTENT_INFO:
+ if (data != NULL)
+ {
+ pkcs7_parse_contentInfo(object, level, data);
+ }
+ break;
+ case PKCS7_SIGNED_CERT:
+ if (cert != NULL)
+ {
+ chunk_t cert_blob;
+
+ x509cert_t *newcert = alloc_thing(x509cert_t
+ , "pkcs7 wrapped x509cert");
+
+ clonetochunk(cert_blob, object.ptr, object.len
+ , "pkcs7 cert blob");
+ *newcert = empty_x509cert;
+
+ DBG(DBG_CONTROL | DBG_PARSING,
+ DBG_log("parsing pkcs7-wrapped certificate")
+ )
+ if (parse_x509cert(cert_blob, level+1, newcert))
+ {
+ newcert->next = *cert;
+ *cert = newcert;
+ }
+ else
+ {
+ free_x509cert(newcert);
+ }
+ }
+ break;
+ case PKCS7_SIGNER_INFO:
+ signerInfos++;
+ DBG(DBG_PARSING,
+ DBG_log(" signer #%d", signerInfos)
+ )
+ break;
+ case PKCS7_SIGNED_ISSUER:
+ DBG(DBG_PARSING,
+ dntoa(buf, BUF_LEN, object);
+ DBG_log(" '%s'",buf)
+ )
+ break;
+ case PKCS7_AUTH_ATTRIBUTES:
+ if (attributes != NULL)
+ {
+ *attributes = object;
+ *attributes->ptr = ASN1_SET;
+ }
+ break;
+ case PKCS7_DIGEST_ALGORITHM:
+ digest_alg = parse_algorithmIdentifier(object, level, NULL);
+ break;
+ case PKCS7_DIGEST_ENC_ALGORITHM:
+ enc_alg = parse_algorithmIdentifier(object, level, NULL);
+ break;
+ case PKCS7_ENCRYPTED_DIGEST:
+ encrypted_digest = object;
+ }
+ objectID++;
+ }
+
+ /* check the signature only if a cacert is available */
+ if (cacert != NULL)
+ {
+ if (signerInfos == 0)
+ {
+ plog("no signerInfo object found");
+ return FALSE;
+ }
+ else if (signerInfos > 1)
+ {
+ plog("more than one signerInfo object found");
+ return FALSE;
+ }
+ if (attributes->ptr == NULL)
+ {
+ plog("no authenticatedAttributes object found");
+ return FALSE;
+ }
+ if (!check_signature(*attributes, encrypted_digest, digest_alg
+ , enc_alg, cacert))
+ {
+ plog("invalid signature");
+ return FALSE;
+ }
+ else
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("signature is valid")
+ )
+ }
+ }
+ return TRUE;
+}
+
+/*
+ * Parse a PKCS#7 envelopedData object
+ */
+bool
+pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data
+, chunk_t serialNumber, const RSA_private_key_t *key)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ chunk_t iv = empty_chunk;
+ chunk_t symmetric_key = empty_chunk;
+ chunk_t encrypted_content = empty_chunk;
+
+ u_char buf[BUF_LEN];
+ u_int level;
+ u_int total_keys = 3;
+ int enc_alg = OID_UNKNOWN;
+ int content_enc_alg = OID_UNKNOWN;
+ int objectID = 0;
+
+ contentInfo_t cInfo = empty_contentInfo;
+ *data = empty_chunk;
+
+ if (!pkcs7_parse_contentInfo(blob, 0, &cInfo))
+ goto failed;
+
+ if (cInfo.type != OID_PKCS7_ENVELOPED_DATA)
+ {
+ plog("pkcs7 content type is not envelopedData");
+ return FALSE;
+ }
+
+ asn1_init(&ctx, cInfo.content, 2, FALSE, DBG_RAW);
+
+ while (objectID < PKCS7_ENVELOPED_ROOF)
+ {
+ if (!extract_object(envelopedDataObjects, &objectID, &object, &level, &ctx))
+ goto failed;
+
+ switch (objectID)
+ {
+ case PKCS7_ENVELOPED_VERSION:
+ if (*object.ptr != 0)
+ {
+ plog("envelopedData version is not 0");
+ goto failed;
+ }
+ break;
+ case PKCS7_RECIPIENT_INFO_VERSION:
+ if (*object.ptr != 0)
+ {
+ plog("recipient info version is not 0");
+ goto failed;
+ }
+ break;
+ case PKCS7_ISSUER:
+ DBG(DBG_PARSING,
+ dntoa(buf, BUF_LEN, object);
+ DBG_log(" '%s'", buf)
+ )
+ break;
+ case PKCS7_SERIAL_NUMBER:
+ if (!same_chunk(serialNumber, object))
+ {
+ plog("serial numbers do not match");
+ goto failed;
+ }
+ break;
+ case PKCS7_ENCRYPTION_ALG:
+ enc_alg = parse_algorithmIdentifier(object, level, NULL);
+ if (enc_alg != OID_RSA_ENCRYPTION)
+ {
+ plog("only rsa encryption supported");
+ goto failed;
+ }
+ break;
+ case PKCS7_ENCRYPTED_KEY:
+ if (!RSA_decrypt(key, object, &symmetric_key))
+ {
+ plog("symmetric key could not be decrypted with rsa");
+ goto failed;
+ }
+ DBG(DBG_PRIVATE,
+ DBG_dump_chunk("symmetric key :", symmetric_key)
+ )
+ break;
+ case PKCS7_CONTENT_TYPE:
+ if (known_oid(object) != OID_PKCS7_DATA)
+ {
+ plog("encrypted content not of type pkcs7 data");
+ goto failed;
+ }
+ break;
+ case PKCS7_CONTENT_ENC_ALGORITHM:
+ content_enc_alg = parse_algorithmIdentifier(object, level, &iv);
+
+ switch (content_enc_alg)
+ {
+ case OID_DES_CBC:
+ total_keys = 1;
+ break;
+ case OID_3DES_EDE_CBC:
+ total_keys = 3;
+ break;
+ default:
+ plog("Only DES and 3DES supported for symmetric encryption");
+ goto failed;
+ }
+ if (symmetric_key.len != (total_keys * DES_CBC_BLOCK_SIZE))
+ {
+ plog("key length is not %d",(total_keys * DES_CBC_BLOCK_SIZE));
+ goto failed;
+ }
+ if (!parse_asn1_simple_object(&iv, ASN1_OCTET_STRING, level+1, "IV"))
+ {
+ plog("IV could not be parsed");
+ goto failed;
+ }
+ if (iv.len != DES_CBC_BLOCK_SIZE)
+ {
+ plog("IV has wrong length");
+ goto failed;
+ }
+ break;
+ case PKCS7_ENCRYPTED_CONTENT:
+ encrypted_content = object;
+ break;
+ }
+ objectID++;
+ }
+
+ /* decrypt the content */
+ {
+ u_int i;
+ des_cblock des_key[3], des_iv;
+ des_key_schedule key_s[3];
+
+ memcpy((char *)des_key, symmetric_key.ptr, symmetric_key.len);
+ memcpy((char *)des_iv, iv.ptr, iv.len);
+
+ for (i = 0; i < total_keys; i++)
+ {
+ if (des_set_key(&des_key[i], key_s[i]))
+ {
+ plog("des key schedule failed");
+ goto failed;
+ }
+ }
+
+ data->len = encrypted_content.len;
+ data->ptr = alloc_bytes(data->len, "decrypted data");
+
+ switch (content_enc_alg)
+ {
+ case OID_DES_CBC:
+ des_cbc_encrypt((des_cblock*)encrypted_content.ptr
+ , (des_cblock*)data->ptr, data->len
+ , key_s[0], &des_iv, DES_DECRYPT);
+ break;
+ case OID_3DES_EDE_CBC:
+ des_ede3_cbc_encrypt( (des_cblock*)encrypted_content.ptr
+ , (des_cblock*)data->ptr, data->len
+ , key_s[0], key_s[1], key_s[2]
+ , &des_iv, DES_DECRYPT);
+ }
+ DBG(DBG_PRIVATE,
+ DBG_dump_chunk("decrypted content with padding:\n", *data)
+ )
+ }
+
+ /* remove the padding */
+ {
+ u_char *pos = data->ptr + data->len - 1;
+ u_char pattern = *pos;
+ size_t padding = pattern;
+
+ if (padding > data->len)
+ {
+ plog("padding greater than data length");
+ goto failed;
+ }
+ data->len -= padding;
+
+ while (padding-- > 0)
+ {
+ if (*pos-- != pattern)
+ {
+ plog("wrong padding pattern");
+ goto failed;
+ }
+ }
+ }
+ freeanychunk(symmetric_key);
+ return TRUE;
+
+failed:
+ freeanychunk(symmetric_key);
+ pfreeany(data->ptr);
+ return FALSE;
+}
+
+/**
+ * @brief Builds a contentType attribute
+ *
+ * @return ASN.1 encoded contentType attribute
+ */
+chunk_t
+pkcs7_contentType_attribute(void)
+{
+ return asn1_wrap(ASN1_SEQUENCE, "cm"
+ , ASN1_contentType_oid
+ , asn1_simple_object(ASN1_SET, ASN1_pkcs7_data_oid));
+}
+
+/**
+ * @brief Builds a messageDigest attribute
+ *
+ *
+ * @param[in] blob content to create digest of
+ * @param[in] digest_alg digest algorithm to be used
+ * @return ASN.1 encoded messageDigest attribute
+ *
+ */
+chunk_t
+pkcs7_messageDigest_attribute(chunk_t content, int digest_alg)
+{
+ u_char digest_buf[MAX_DIGEST_LEN];
+ chunk_t digest = { digest_buf, MAX_DIGEST_LEN };
+
+ compute_digest(content, digest_alg, &digest);
+
+ return asn1_wrap(ASN1_SEQUENCE, "cm"
+ , ASN1_messageDigest_oid
+ , asn1_wrap(ASN1_SET, "m"
+ , asn1_simple_object(ASN1_OCTET_STRING, digest)
+ )
+ );
+}
+/*
+ * build a DER-encoded contentInfo object
+ */
+static chunk_t
+pkcs7_build_contentInfo(contentInfo_t *cInfo)
+{
+ chunk_t content_type;
+
+ /* select DER-encoded OID for pkcs7 contentInfo type */
+ switch(cInfo->type)
+ {
+ case OID_PKCS7_DATA:
+ content_type = ASN1_pkcs7_data_oid;
+ break;
+ case OID_PKCS7_SIGNED_DATA:
+ content_type = ASN1_pkcs7_signed_data_oid;
+ break;
+ case OID_PKCS7_ENVELOPED_DATA:
+ content_type = ASN1_pkcs7_enveloped_data_oid;
+ break;
+ case OID_PKCS7_SIGNED_ENVELOPED_DATA:
+ content_type = ASN1_pkcs7_signed_enveloped_data_oid;
+ break;
+ case OID_PKCS7_DIGESTED_DATA:
+ content_type = ASN1_pkcs7_digested_data_oid;
+ break;
+ case OID_PKCS7_ENCRYPTED_DATA:
+ content_type = ASN1_pkcs7_encrypted_data_oid;
+ break;
+ case OID_UNKNOWN:
+ default:
+ fprintf(stderr, "invalid pkcs7 contentInfo type");
+ return empty_chunk;
+ }
+
+ return (cInfo->content.ptr == NULL)
+ ? asn1_simple_object(ASN1_SEQUENCE, content_type)
+ : asn1_wrap(ASN1_SEQUENCE, "cm"
+ , content_type
+ , asn1_simple_object(ASN1_CONTEXT_C_0, cInfo->content)
+ );
+}
+
+/*
+ * build issuerAndSerialNumber object
+ */
+chunk_t
+pkcs7_build_issuerAndSerialNumber(const x509cert_t *cert)
+{
+ return asn1_wrap(ASN1_SEQUENCE, "cm"
+ , cert->issuer
+ , asn1_simple_object(ASN1_INTEGER, cert->serialNumber));
+}
+
+/*
+ * create a signed pkcs7 contentInfo object
+ */
+chunk_t
+pkcs7_build_signedData(chunk_t data, chunk_t attributes, const x509cert_t *cert
+, int digest_alg, const RSA_private_key_t *key)
+{
+ contentInfo_t pkcs7Data, signedData;
+ chunk_t authenticatedAttributes, encryptedDigest, signerInfo, cInfo;
+
+ chunk_t digestAlgorithm = asn1_algorithmIdentifier(digest_alg);
+
+ if (attributes.ptr != NULL)
+ {
+ encryptedDigest = pkcs1_build_signature(attributes, digest_alg
+ , key, FALSE);
+ clonetochunk(authenticatedAttributes, attributes.ptr, attributes.len
+ , "authenticatedAttributes");
+ *authenticatedAttributes.ptr = ASN1_CONTEXT_C_0;
+ }
+ else
+ {
+ encryptedDigest = (data.ptr == NULL)? empty_chunk
+ : pkcs1_build_signature(data, digest_alg, key, FALSE);
+ authenticatedAttributes = empty_chunk;
+ }
+
+ signerInfo = asn1_wrap(ASN1_SEQUENCE, "cmcmcm"
+ , ASN1_INTEGER_1
+ , pkcs7_build_issuerAndSerialNumber(cert)
+ , digestAlgorithm
+ , authenticatedAttributes
+ , ASN1_rsaEncryption_id
+ , encryptedDigest);
+
+ pkcs7Data.type = OID_PKCS7_DATA;
+ pkcs7Data.content = (data.ptr == NULL)? empty_chunk
+ : asn1_simple_object(ASN1_OCTET_STRING, data);
+
+ signedData.type = OID_PKCS7_SIGNED_DATA;
+ signedData.content = asn1_wrap(ASN1_SEQUENCE, "cmmmm"
+ , ASN1_INTEGER_1
+ , asn1_simple_object(ASN1_SET, digestAlgorithm)
+ , pkcs7_build_contentInfo(&pkcs7Data)
+ , asn1_simple_object(ASN1_CONTEXT_C_0, cert->certificate)
+ , asn1_wrap(ASN1_SET, "m", signerInfo));
+
+ cInfo = pkcs7_build_contentInfo(&signedData);
+ DBG(DBG_RAW,
+ DBG_dump_chunk("signedData:\n", cInfo)
+ )
+
+ freeanychunk(pkcs7Data.content);
+ freeanychunk(signedData.content);
+ return cInfo;
+}
+
+/*
+ * create a symmetrically encrypted pkcs7 contentInfo object
+ */
+chunk_t
+pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert, int cipher)
+{
+ bool des_check_key_save;
+ des_key_schedule ks[3];
+ des_cblock key[3], des_iv, des_iv_buf;
+
+ chunk_t iv = { (u_char *)des_iv_buf, DES_CBC_BLOCK_SIZE };
+ chunk_t out;
+ chunk_t cipher_oid;
+
+ u_int total_keys, i;
+ size_t padding = pad_up(data.len, DES_CBC_BLOCK_SIZE);
+
+ RSA_public_key_t public_key;
+
+ init_RSA_public_key(&public_key, cert->publicExponent
+ , cert->modulus);
+
+ if (padding == 0)
+ padding += DES_CBC_BLOCK_SIZE;
+
+ out.len = data.len + padding;
+ out.ptr = alloc_bytes(out.len, "DES-encrypted output");
+
+ DBG(DBG_CONTROL,
+ DBG_log("padding %d bytes of data to multiple DES block size of %d bytes"
+ , (int)data.len, (int)out.len)
+ )
+
+ /* copy data */
+ memcpy(out.ptr, data.ptr, data.len);
+ /* append padding */
+ memset(out.ptr + data.len, padding, padding);
+
+ DBG(DBG_RAW,
+ DBG_dump_chunk("Padded unencrypted data:\n", out)
+ )
+
+ /* select OID and keylength for specified cipher */
+ switch (cipher)
+ {
+ case OID_DES_CBC:
+ total_keys = 1;
+ cipher_oid = ASN1_des_cbc_oid;
+ break;
+ case OID_3DES_EDE_CBC:
+ default:
+ total_keys = 3;
+ cipher_oid = ASN1_3des_ede_cbc_oid;
+ }
+ DBG(DBG_CONTROLMORE,
+ DBG_log("pkcs7 encryption cipher: %s", oid_names[cipher].name)
+ )
+
+ /* generate a strong random key for DES/3DES */
+ des_check_key_save = des_check_key;
+ des_check_key = TRUE;
+ for (i = 0; i < total_keys;i++)
+ {
+ for (;;)
+ {
+ get_rnd_bytes((char*)key[i], DES_CBC_BLOCK_SIZE);
+ des_set_odd_parity(&key[i]);
+ if (!des_set_key(&key[i], ks[i]))
+ break;
+ plog("weak DES key discarded - we try again");
+ }
+ DBG(DBG_PRIVATE,
+ DBG_dump("DES key:", key[i], 8)
+ )
+ }
+ des_check_key = des_check_key_save;
+
+ /* generate an iv for DES/3DES CBC */
+ get_rnd_bytes(des_iv, DES_CBC_BLOCK_SIZE);
+ memcpy(iv.ptr, des_iv, DES_CBC_BLOCK_SIZE);
+ DBG(DBG_RAW,
+ DBG_dump_chunk("DES IV :", iv)
+ )
+
+ /* encryption using specified cipher */
+ switch (cipher)
+ {
+ case OID_DES_CBC:
+ des_cbc_encrypt((des_cblock*)out.ptr, (des_cblock*)out.ptr, out.len
+ , ks[0], &des_iv, DES_ENCRYPT);
+ break;
+ case OID_3DES_EDE_CBC:
+ default:
+ des_ede3_cbc_encrypt((des_cblock*)out.ptr, (des_cblock*)out.ptr, out.len
+ , ks[0], ks[1], ks[2], &des_iv, DES_ENCRYPT);
+ }
+ DBG(DBG_RAW,
+ DBG_dump_chunk("Encrypted data:\n", out));
+
+ /* build pkcs7 enveloped data object */
+ {
+ chunk_t contentEncryptionAlgorithm = asn1_wrap(ASN1_SEQUENCE, "cm"
+ , cipher_oid
+ , asn1_simple_object(ASN1_OCTET_STRING, iv));
+
+ chunk_t encryptedContentInfo = asn1_wrap(ASN1_SEQUENCE, "cmm"
+ , ASN1_pkcs7_data_oid
+ , contentEncryptionAlgorithm
+ , asn1_wrap(ASN1_CONTEXT_S_0, "m", out));
+
+ chunk_t plainKey = { (u_char *)key, DES_CBC_BLOCK_SIZE * total_keys };
+
+ chunk_t encryptedKey = asn1_wrap(ASN1_OCTET_STRING, "m"
+ , RSA_encrypt(&public_key, plainKey));
+
+ chunk_t recipientInfo = asn1_wrap(ASN1_SEQUENCE, "cmcm"
+ , ASN1_INTEGER_0
+ , pkcs7_build_issuerAndSerialNumber(cert)
+ , ASN1_rsaEncryption_id
+ , encryptedKey);
+
+ chunk_t cInfo;
+ contentInfo_t envelopedData;
+
+ envelopedData.type = OID_PKCS7_ENVELOPED_DATA;
+ envelopedData.content = asn1_wrap(ASN1_SEQUENCE, "cmm"
+ , ASN1_INTEGER_0
+ , asn1_wrap(ASN1_SET, "m", recipientInfo)
+ , encryptedContentInfo);
+
+ cInfo = pkcs7_build_contentInfo(&envelopedData);
+ DBG(DBG_RAW,
+ DBG_dump_chunk("envelopedData:\n", cInfo)
+ )
+
+ free_RSA_public_content(&public_key);
+ freeanychunk(envelopedData.content);
+ return cInfo;
+ }
+}
diff --git a/src/pluto/pkcs7.h b/src/pluto/pkcs7.h
new file mode 100644
index 000000000..38c633f4e
--- /dev/null
+++ b/src/pluto/pkcs7.h
@@ -0,0 +1,51 @@
+/* Support of PKCS#7 data structures
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Copyright (C) 2002-2005 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil, Switzerland
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: pkcs7.h,v 1.10 2005/12/22 22:11:24 as Exp $
+ */
+
+#ifndef _PKCS7_H
+#define _PKCS7_H
+
+#include "defs.h"
+#include "pkcs1.h"
+#include "x509.h"
+
+/* Access structure for a PKCS#7 ContentInfo object */
+
+typedef struct contentInfo contentInfo_t;
+
+struct contentInfo {
+ int type;
+ chunk_t content;
+};
+
+extern const contentInfo_t empty_contentInfo;
+
+extern bool pkcs7_parse_contentInfo(chunk_t blob, u_int level0
+ , contentInfo_t *cInfo);
+extern bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data
+ , x509cert_t **cert, chunk_t *attributes, const x509cert_t *cacert);
+extern bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data
+ , chunk_t serialNumber, const RSA_private_key_t *key);
+extern chunk_t pkcs7_contentType_attribute(void);
+extern chunk_t pkcs7_messageDigest_attribute(chunk_t content, int digest_alg);
+extern chunk_t pkcs7_build_issuerAndSerialNumber(const x509cert_t *cert);
+extern chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes
+ ,const x509cert_t *cert, int digest_alg, const RSA_private_key_t *key);
+extern chunk_t pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert
+ , int cipher);
+
+#endif /* _PKCS7_H */
diff --git a/src/pluto/pluto.8 b/src/pluto/pluto.8
new file mode 100644
index 000000000..b80d13772
--- /dev/null
+++ b/src/pluto/pluto.8
@@ -0,0 +1,1649 @@
+.TH IPSEC_PLUTO 8 "28 March 1999"
+.SH NAME
+ipsec pluto \- IPsec IKE keying daemon
+.br
+ipsec whack \- control interface for IPSEC keying daemon
+.SH SYNOPSIS
+.na
+.nh
+.HP
+.ft B
+ipsec pluto
+[\-\-help]
+[\-\-version]
+[\-\-optionsfrom\ \c
+\fIfilename\fP]
+[\-\-nofork]
+[\-\-stderrlog]
+[\-\-noklips]
+[\-\-uniqueids]
+[\fB\-\-interface\fP \fIinterfacename\fP]
+[\-\-ikeport\ \c
+\fIportnumber\fP]
+[\-\-ctlbase\ \c
+\fIpath\fP]
+[\-\-secretsfile\ \c
+\fIsecrets\(hyfile\fP]
+[\-\-adns \fIpathname\fP]
+[\-\-lwdnsq \fIpathname\fP]
+[\-\-perpeerlog]
+[\-\-perpeerlogbase\ \c
+\fIdirname\fP]
+[\-\-debug\(hynone]
+[\-\-debug\(hyall]
+[\-\-debug\(hyraw]
+[\-\-debug\(hycrypt]
+[\-\-debug\(hyparsing]
+[\-\-debug\(hyemitting]
+[\-\-debug\(hycontrol]
+[\-\-debug\(hylifecycle]
+[\-\-debug\(hyklips]
+[\-\-debug\(hydns]
+[\-\-debug\(hyoppo]
+[\-\-debug\(hyprivate]
+.HP
+.ft B
+ipsec whack
+[\-\-help]
+[\-\-version]
+.HP
+.ft B
+ipsec whack
+\-\-name\ \c
+\fIconnection-name\fP
+.br
+[\-\-id\ \c
+\fIid\fP] \c
+[\-\-host\ \c
+\fIip\(hyaddress\fP]
+[\-\-ikeport\ \c
+\fIport\(hynumber\fP]
+[\-\-nexthop\ \c
+\fIip\(hyaddress\fP]
+[\-\-client\ \c
+\fIsubnet\fP]
+[\-\-dnskeyondemand]
+[\-\-updown\ \c
+\fIupdown\fP]
+.br
+\-\-to
+.br
+[\-\-id\ \c
+\fIid\fP]
+[\-\-host\ \c
+\fIip\(hyaddress\fP]
+[\-\-ikeport\ \c
+\fIport\(hynumber\fP]
+[\-\-nexthop\ \c
+\fIip\(hyaddress\fP]
+[\-\-client\ \c
+\fIsubnet\fP]
+[\-\-dnskeyondemand]
+[\-\-updown\ \c
+\fIupdown\fP]
+.br
+[\-\-psk]
+[\-\-rsasig]
+[\-\-encrypt]
+[\-\-authenticate]
+[\-\-compress]
+[\-\-tunnel]
+[\-\-pfs]
+[\-\-disablearrivalcheck]
+[\-\-ipv4]
+[\-\-ipv6]
+[\-\-tunnelipv4]
+[\-\-tunnelipv6]
+[\-\-ikelifetime\ \c
+\fIseconds\fP]
+[\-\-ipseclifetime\ \c
+\fIseconds\fP]
+[\-\-rekeymargin\ \c
+\fIseconds\fP]
+[\-\-rekeyfuzz\ \c
+\fIpercentage\fP]
+[\-\-keyingtries\ \c
+\fIcount\fP]
+[\-\-dontrekey]
+[\-\-delete]
+[\-\-ctlbase\ \c
+\fIpath\fP]
+[\-\-optionsfrom\ \c
+\fIfilename\fP]
+[\-\-label\ \c
+\fIstring\fP]
+.HP
+.ft B
+ipsec whack
+\-\-keyid\ \c
+\fIid\fP
+[\-\-addkey]
+[\-\-pubkeyrsa\ \c
+\fIkey\fP]
+[\-\-ctlbase\ \c
+\fIpath\fP]
+[\-\-optionsfrom\ \c
+\fIfilename\fP]
+[\-\-label\ \c
+\fIstring\fP]
+.HP
+.ft B
+ipsec whack
+\-\-myid\ \c
+\fIid\fP
+.HP
+.ft B
+ipsec whack
+\-\-listen|\-\-unlisten
+[\-\-ctlbase\ \c
+\fIpath\fP]
+[\-\-optionsfrom\ \c
+\fIfilename\fP]
+[\-\-label\ \c
+\fIstring\fP]
+.HP
+.ft B
+ipsec whack
+\-\-route|\-\-unroute
+\-\-name\ \c
+\fIconnection-name\fP
+[\-\-ctlbase\ \c
+\fIpath\fP]
+[\-\-optionsfrom\ \c
+\fIfilename\fP]
+[\-\-label\ \c
+\fIstring\fP]
+.HP
+.ft B
+ipsec whack
+\-\-initiate|\-\-terminate
+\-\-name\ \c
+\fIconnection-name\fP
+[\-\-asynchronous]
+[\-\-ctlbase\ \c
+\fIpath\fP]
+[\-\-optionsfrom\ \c
+\fIfilename\fP]
+[\-\-label\ \c
+\fIstring\fP]
+.HP
+.ft B
+ipsec whack
+[\-\-tunnelipv4]
+[\-\-tunnelipv6]
+\-\-oppohere \fIip\(hyaddress\fP
+\-\-oppothere \fIip\(hyaddress\fP
+.HP
+.ft B
+ipsec whack
+\-\-delete
+\-\-name\ \c
+\fIconnection-name\fP
+[\-\-ctlbase\ \c
+\fIpath\fP]
+[\-\-optionsfrom\ \c
+\fIfilename\fP]
+[\-\-label\ \c
+\fIstring\fP]
+.HP
+.ft B
+ipsec whack
+\-\-deletestate\ \c
+\fIstate-number\fP
+[\-\-ctlbase\ \c
+\fIpath\fP]
+[\-\-optionsfrom\ \c
+\fIfilename\fP]
+[\-\-label\ \c
+\fIstring\fP]
+.HP
+.ft B
+ipsec whack
+[\-\-name\ \c
+\fIconnection-name\fP]
+[\-\-debug\(hynone]
+[\-\-debug\(hyall]
+[\-\-debug\(hyraw]
+[\-\-debug\(hycrypt]
+[\-\-debug\(hyparsing]
+[\-\-debug\(hyemitting]
+[\-\-debug\(hycontrol]
+[\-\-debug\(hylifecycle]
+[\-\-debug\(hyklips]
+[\-\-debug\(hydns]
+[\-\-debug\(hyoppo]
+[\-\-debug\(hyprivate]
+[\-\-ctlbase\ \c
+\fIpath\fP]
+[\-\-optionsfrom\ \c
+\fIfilename\fP]
+[\-\-label\ \c
+\fIstring\fP]
+.HP
+.ft B
+ipsec whack
+\-\-status
+[\-\-ctlbase\ \c
+\fIpath\fP]
+[\-\-optionsfrom\ \c
+\fIfilename\fP]
+[\-\-label\ \c
+\fIstring\fP]
+.HP
+.ft B
+ipsec whack
+\-\-shutdown
+[\-\-ctlbase\ \c
+\fIpath\fP]
+[\-\-optionsfrom\ \c
+\fIfilename\fP]
+[\-\-label\ \c
+\fIstring\fP]
+.ft R
+.hy
+.ad
+.SH DESCRIPTION
+.BR pluto
+is an IKE (``IPsec Key Exchange'') daemon.
+.BR whack
+is an auxiliary program to allow requests to be made to a running
+.BR pluto .
+.LP
+.BR pluto
+is used to automatically build shared ``security associations'' on a
+system that has IPsec, the secure IP protocol.
+In other words,
+.BR pluto
+can eliminate much of the work of manual keying.
+The actual
+secure transmission of packets is the responsibility of other parts of
+the system (see
+.BR KLIPS ,
+the companion implementation of IPsec).
+\fIipsec_auto\fP(8) provides a more convenient interface to
+\fBpluto\fP and \fBwhack\fP.
+.SS IKE's Job
+.LP
+A \fISecurity Association\fP (\fISA\fP) is an agreement between two network nodes on
+how to process certain traffic between them. This processing involves
+encapsulation, authentication, encryption, or compression.
+.LP
+IKE can be deployed on a network node to negotiate Security
+Associations for that node. These IKE implementations can only
+negotiate with other IKE implementations, so IKE must be on each node
+that is to be an endpoint of an IKE-negotiated Security Association.
+No other nodes need to be running IKE.
+.LP
+An IKE instance (i.e. an IKE implementation on a particular network
+node) communicates with another IKE instance using UDP IP packets, so
+there must be a route between the nodes in each direction.
+.LP
+The negotiation of Security Associations requires a number of choices
+that involve tradeoffs between security, convenience, trust, and
+efficiency. These are policy issues and are normally specified to the
+IKE instance by the system administrator.
+.LP
+IKE deals with two kinds of Security Associations. The first part of
+a negotiation between IKE instances is to build an ISAKMP SA. An
+ISAKMP SA is used to protect communication between the two IKEs.
+IPsec SAs can then be built by the IKEs \- these are used to carry
+protected IP traffic between the systems.
+.LP
+The negotiation of the ISAKMP SA is known as Phase 1. In theory,
+Phase 1 can be accomplished by a couple of different exchange types,
+but we only implement one called Main Mode (we don't implement
+Aggressive Mode).
+.LP
+Any negotiation under the protection of an ISAKMP SA, including the
+negotiation of IPsec SAs, is part of Phase 2. The exchange type
+that we use to negotiate an IPsec SA is called Quick Mode.
+.LP
+IKE instances must be able to authenticate each other as part of their
+negotiation of an ISAKMP SA. This can be done by several mechanisms
+described in the draft standards.
+.LP
+IKE negotiation can be initiated by any instance with any other. If
+both can find an agreeable set of characteristics for a Security
+Association, and both recognize each others authenticity, they can set
+up a Security Association. The standards do not specify what causes
+an IKE instance to initiate a negotiation.
+.LP
+In summary, an IKE instance is prepared to automate the management of
+Security Associations in an IPsec environment, but a number of issues
+are considered policy and are left in the system administrator's hands.
+.SS Pluto
+.LP
+\fBpluto\fP is an implementation of IKE. It runs as a daemon on a network
+node. Currently, this network node must be a LINUX system running the
+\fBKLIPS\fP implementation of IPsec.
+.LP
+\fBpluto\fP only implements a subset of IKE. This is enough for it to
+interoperate with other instances of \fBpluto\fP, and many other IKE
+implementations. We are working on implementing more of IKE.
+.LP
+The policy for acceptable characteristics for Security Associations is
+mostly hardwired into the code of \fBpluto\fP (spdb.c). Eventually
+this will be moved into a security policy database with reasonable
+expressive power and more convenience.
+.LP
+\fBpluto\fP uses shared secrets or RSA signatures to authenticate
+peers with whom it is negotiating.
+.LP
+\fBpluto\fP initiates negotiation of a Security Association when it is
+manually prodded: the program \fBwhack\fP is run to trigger this.
+It will also initiate a negotiation when \fBKLIPS\fP traps an outbound packet
+for Opportunistic Encryption.
+.LP
+\fBpluto\fP implements ISAKMP SAs itself. After it has negotiated the
+characteristics of an IPsec SA, it directs \fBKLIPS\fP to implement it.
+It also invokes a script to adjust any firewall and issue \fIroute\fP(8)
+commands to direct IP packets through \fBKLIPS\fP.
+.LP
+When \fBpluto\fP shuts down, it closes all Security Associations.
+.SS Before Running Pluto
+.LP
+\fBpluto\fP runs as a daemon with userid root. Before running it, a few
+things must be set up.
+.LP
+\fBpluto\fP requires \fBKLIPS\fP, the FreeS/WAN implementation of IPsec.
+All of the components of \fBKLIPS\fP and \fBpluto\fP should be installed.
+.LP
+\fBpluto\fP supports multiple public networks (that is, networks
+that are considered insecure and thus need to have their traffic
+encrypted or authenticated). It discovers the
+public interfaces to use by looking at all interfaces that are
+configured (the \fB\-\-interface\fP option can be used to limit
+the interfaces considered).
+It does this only when \fBwhack\fP tells it to \-\-listen,
+so the interfaces must be configured by then. Each interface with a name of the form
+\fBipsec\fP[\fB0\fP-\fB9\fP] is taken as a \fBKLIPS\fP virtual public interface.
+Another network interface with the same IP address (there should be only
+one) is taken as the corresponding real public
+interface. \fIifconfig\fP(8) with the \fB\-a\fP flag will show
+the name and status of each network interface.
+.LP
+\fBpluto\fP requires a database of preshared secrets and RSA private keys.
+This is described in the
+.IR ipsec.secrets (5).
+\fBpluto\fP is told of RSA public keys via \fBwhack\fP commands.
+If the connection is Opportunistic, and no RSA public key is known,
+\fBpluto\fP will attempt to fetch RSA keys using the Domain Name System.
+.SS Setting up \fBKLIPS\fP for \fBpluto\fP
+.LP
+The most basic network topology that \fBpluto\fP supports has two security
+gateways negotiating on behalf of client subnets. The diagram of RGB's
+testbed is a good example (see \fIklips/doc/rgb_setup.txt\fP).
+.LP
+The file \fIINSTALL\fP in the base directory of this distribution
+explains how to start setting up the whole system, including \fBKLIPS\fP.
+.LP
+Make sure that the security gateways have routes to each other. This
+is usually covered by the default route, but may require issuing
+.IR route (8)
+commands. The route must go through a particular IP
+interface (we will assume it is \fIeth0\fP, but it need not be). The
+interface that connects the security gateway to its client must be a
+different one.
+.LP
+It is necessary to issue a
+.IR ipsec_tncfg (8)
+command on each gateway. The required command is:
+
+\ \ \ ipsec tncfg \-\-attach\ \-\-virtual\ ipsec0 \-\-physical\ eth0
+
+A command to set up the ipsec0 virtual interface will also need to be
+run. It will have the same parameters as the command used to set up
+the physical interface to which it has just been connected using
+.IR ipsec_tncfg (8).
+.SS ipsec.secrets file
+.LP
+A \fBpluto\fP daemon and another IKE daemon (for example, another instance
+of \fBpluto\fP) must convince each other that they are who they are supposed
+to be before any negotiation can succeed. This authentication is
+accomplished by using either secrets that have been shared beforehand
+(manually) or by using RSA signatures. There are other techniques,
+but they have not been implemented in \fBpluto\fP.
+.LP
+The file \fI/etc/ipsec.secrets\fP is used to keep preshared secret keys
+and RSA private keys for
+authentication with other IKE daemons. For debugging, there is an
+argument to the \fBpluto\fP command to use a different file.
+This file is described in
+.IR ipsec.secrets (5).
+.SS Running Pluto
+.LP
+To fire up the daemon, just type \fBpluto\fP (be sure to be running as
+the superuser).
+The default IKE port number is 500, the UDP port assigned by IANA for IKE Daemons.
+\fBpluto\fP must be run by the superuser to be able to use the UDP 500 port.
+.LP
+\fBpluto\fP attempts to create a lockfile with the name
+\fI/var/run/pluto.pid\fP. If the lockfile cannot be created,
+\fBpluto\fP exits \- this prevents multiple \fBpluto\fPs from
+competing Any ``leftover'' lockfile must be removed before
+\fBpluto\fP will run. \fBpluto\fP writes its pid into this file so
+that scripts can find it. This lock will not function properly if it
+is on an NFS volume (but sharing locks on multiple machines doesn't
+make sense anyway).
+.LP
+\fBpluto\fP then forks and the parent exits. This is the conventional
+``daemon fork''. It can make debugging awkward, so there is an option
+to suppress this fork.
+.LP
+All logging, including diagnostics, is sent to
+.IR syslog (3)
+with facility=authpriv;
+it decides where to put these messages (possibly in /var/log/secure).
+Since this too can make debugging awkward, there is an option to
+steer logging to stderr.
+.LP
+If the \fB\-\-perpeerlog\fP option is given, then pluto will open
+a log file per connection. By default, this is in /var/log/pluto/peer,
+in a subdirectory formed by turning all dot (.) [IPv4} or colon (:)
+[IPv6] into slashes (/).
+.LP
+The base directory can be changed with the \fB\-\-perpeerlogbase\fP.
+.LP
+Once \fBpluto\fP is started, it waits for requests from \fBwhack\fP.
+.SS Pluto's Internal State
+.LP
+To understand how to use \fBpluto\fP, it is helpful to understand a little
+about its internal state. Furthermore, the terminology is needed to decipher
+some of the diagnostic messages.
+.LP
+The \fI(potential) connection\fP database describes attributes of a
+connection. These include the IP addresses of the hosts and client
+subnets and the security characteristics desired. \fBpluto\fP
+requires this information (simply called a connection) before it can
+respond to a request to build an SA. Each connection is given a name
+when it is created, and all references are made using this name.
+.LP
+During the IKE exchange to build an SA, the information about the
+negotiation is represented in a \fIstate object\fP. Each state object
+reflects how far the negotiation has reached. Once the negotiation is
+complete and the SA established, the state object remains to represent
+the SA. When the SA is terminated, the state object is discarded.
+Each State object is given a serial number and this is used to refer
+to the state objects in logged messages.
+.LP
+Each state object corresponds to a connection and can be thought of
+as an instantiation of that connection.
+At any particular time, there may be any number of state objects
+corresponding to a particular connection.
+Often there is one representing an ISAKMP SA and another representing
+an IPsec SA.
+.LP
+\fBKLIPS\fP hooks into the routing code in a LINUX kernel.
+Traffic to be processed by an IPsec SA must be directed through
+\fBKLIPS\fP by routing commands. Furthermore, the processing to be
+done is specified by \fIipsec eroute(8)\fP commands.
+\fBpluto\fP takes the responsibility of managing both of these special
+kinds of routes.
+.LP
+Each connection may be routed, and must be while it has an IPsec SA.
+The connection specifies the characteristics of the route: the
+interface on this machine, the ``gateway'' (the nexthop),
+and the peer's client subnet. Two
+connections may not be simultaneously routed if they are for the same
+peer's client subnet but use different interfaces or gateways
+(\fBpluto\fP's logic does not reflect any advanced routing capabilities).
+.LP
+Each eroute is associated with the state object for an IPsec SA
+because it has the particular characteristics of the SA.
+Two eroutes conflict if they specify the identical local
+and remote clients (unlike for routes, the local clients are
+taken into account).
+.LP
+When \fBpluto\fP needs to install a route for a connection,
+it must make sure that no conflicting route is in use. If another
+connection has a conflicting route, that route will be taken down, as long
+as there is no IPsec SA instantiating that connection.
+If there is such an IPsec SA, the attempt to install a route will fail.
+.LP
+There is an exception. If \fBpluto\fP, as Responder, needs to install
+a route to a fixed client subnet for a connection, and there is
+already a conflicting route, then the SAs using the route are deleted
+to make room for the new SAs. The rationale is that the new
+connection is probably more current. The need for this usually is a
+product of Road Warrior connections (these are explained later; they
+cannot be used to initiate).
+.LP
+When \fBpluto\fP needs to install an eroute for an IPsec SA (for a
+state object), first the state object's connection must be routed (if
+this cannot be done, the eroute and SA will not be installed).
+If a conflicting eroute is already in place for another connection,
+the eroute and SA will not be installed (but note that the routing
+exception mentioned above may have already deleted potentially conflicting SAs).
+If another IPsec
+SA for the same connection already has an eroute, all its outgoing traffic
+is taken over by the new eroute. The incoming traffic will still be
+processed. This characteristic is exploited during rekeying.
+.LP
+All of these routing characteristics are expected change when
+\fBKLIPS\fP is modified to use the firewall hooks in the LINUX 2.4.x
+kernel.
+.SS Using Whack
+.LP
+\fBwhack\fP is used to command a running \fBpluto\fP.
+\fBwhack\fP uses a UNIX domain socket to speak to \fBpluto\fP
+(by default, \fI/var/pluto.ctl\fP).
+.LP
+\fBwhack\fP has an intricate argument syntax.
+This syntax allows many different functions to be specified.
+The help form shows the usage or version information.
+The connection form gives \fBpluto\fP a description of a potential connection.
+The public key form informs \fBpluto\fP of the RSA public key for a potential peer.
+The delete form deletes a connection description and all SAs corresponding
+to it.
+The listen form tells \fBpluto\fP to start or stop listening on the public interfaces
+for IKE requests from peers.
+The route form tells \fBpluto\fP to set up routing for a connection;
+the unroute form undoes this.
+The initiate form tells \fBpluto\fP to negotiate an SA corresponding to a connection.
+The terminate form tells \fBpluto\fP to remove all SAs corresponding to a connection,
+including those being negotiated.
+The status form displays the \fBpluto\fP's internal state.
+The debug form tells \fBpluto\fP to change the selection of debugging output
+``on the fly''. The shutdown form tells
+\fBpluto\fP to shut down, deleting all SAs.
+.LP
+Most options are specific to one of the forms, and will be described
+with that form. There are three options that apply to all forms.
+.TP
+\fB\-\-ctlbase\fP\ \fIpath\fP
+\fIpath\fP.ctl is used as the UNIX domain socket for talking
+to \fBpluto\fP.
+This option facilitates debugging.
+.TP
+\fB\-\-optionsfrom\fP\ \fIfilename\fP
+adds the contents of the file to the argument list.
+.TP
+\fB\-\-label\fP\ \fIstring\fP
+adds the string to all error messages generated by \fBwhack\fP.
+.LP
+The help form of \fBwhack\fP is self-explanatory.
+.TP
+\fB\-\-help\fP
+display the usage message.
+.TP
+\fB\-\-version\fP
+display the version of \fBwhack\fP.
+.LP
+The connection form describes a potential connection to \fBpluto\fP.
+\fBpluto\fP needs to know what connections can and should be negotiated.
+When \fBpluto\fP is the initiator, it needs to know what to propose.
+When \fBpluto\fP is the responder, it needs to know enough to decide whether
+is is willing to set up the proposed connection.
+.LP
+The description of a potential connection can specify a large number
+of details. Each connection has a unique name. This name will appear
+in a updown shell command, so it should not contain punctuation
+that would make the command ill-formed.
+.TP
+\fB\-\-name\fP\ \fIconnection-name\fP
+.LP
+The topology of
+a connection is symmetric, so to save space here is half a picture:
+
+\ \ \ client_subnet<\-\->host:ikeport<\-\->nexthop<\-\-\-
+
+A similar trick is used in the flags. The same flag names are used for
+both ends. Those before the \fB\-\-to\fP flag describe the left side
+and those afterwards describe the right side. When \fBpluto\fP attempts
+to use the connection, it decides whether it is the left side or the right
+side of the connection, based on the IP numbers of its interfaces.
+.TP
+\fB\-\-id\fP\ \fIid\fP
+the identity of the end. Currently, this can be an IP address (specified
+as dotted quad or as a Fully Qualified Domain Name, which will be resolved
+immediately) or as a Fully Qualified Domain Name itself (prefixed by ``@''
+to signify that it should not be resolved), or as user@FQDN, or as the
+magic value \fB%myid\fP.
+\fBPluto\fP only authenticates the identity, and does not use it for
+addressing, so, for example, an IP address need not be the one to which
+packets are to be sent. If the option is absent, the
+identity defaults to the IP address specified by \fB\-\-host\fP.
+\fB%myid\fP allows the identity to be separately specified (by the \fBpluto\fP or \fBwhack\fP option \fB\-\-myid\fP
+or by the \fBipsec.conf\fP(5) \fBconfig setup\fP parameter \fPmyid\fP).
+Otherwise, \fBpluto\fP tries to guess what \fB%myid\fP should stand for:
+the IP address of \fB%defaultroute\fP, if it is supported by a suitable TXT record in the reverse domain for that IP address,
+or the system's hostname, if it is supported by a suitable TXT record in its forward domain.
+.\" The identity is transmitted in the IKE protocol, and is what is authenticated.
+.TP
+\fB\-\-host\fP\ \fIip\(hyaddress\fP
+.TP
+\fB\-\-host\fP\ \fB%any\fP
+.TP
+\fB\-\-host\fP\ \fB%opportunistic\fP
+the IP address of the end (generally the public interface).
+If \fBpluto\fP is to act as a responder
+for IKE negotiations initiated from unknown IP addresses (the
+``Road Warrior'' case), the
+IP address should be specified as \fB%any\fP (currently,
+the obsolete notation \fB0.0.0.0\fP is also accepted for this).
+If \fBpluto\fP is to opportunistically initiate the connection,
+use \fB%opportunistic\fP
+.TP
+\fB\-\-ikeport\fP\ \fIport\(hynumber\fP
+the UDP port that IKE listens to on that host. The default is 500.
+(\fBpluto\fP on this machine uses the port specified by its own command
+line argument, so this only affects where \fBpluto\fP sends messages.)
+.TP
+\fB\-\-nexthop\fP\ \fIip\(hyaddress\fP
+where to route packets for the peer's client (presumably for the peer too,
+but it will not be used for this).
+When \fBpluto\fP installs an IPsec SA, it issues a route command.
+It uses the nexthop as the gateway.
+The default is the peer's IP address (this can be explicitly written as
+\fB%direct\fP; the obsolete notation \fB0.0.0.0\fP is accepted).
+This option is necessary if \fBpluto\fP's host's interface used for sending
+packets to the peer is neither point-to-point nor directly connected to the
+peer.
+.TP
+\fB\-\-client\fP\ \fIsubnet\fP
+the subnet for which the IPsec traffic will be destined. If not specified,
+the host will be the client.
+The subnet can be specified in any of the forms supported by \fIipsec_atosubnet\fP(3).
+The general form is \fIaddress\fP/\fImask\fP. The \fIaddress\fP can be either
+a domain name or four decimal numbers (specifying octets) separated by dots.
+The most convenient form of the \fImask\fP is a decimal integer, specifying
+the number of leading one bits in the mask. So, for example, 10.0.0.0/8
+would specify the class A network ``Net 10''.
+.TP
+\fB\-\-dnskeyondemand]\fP
+specifies that when an RSA public key is needed to authenticate this
+host, and it isn't already known, fetch it from DNS.
+.TP
+\fB\-\-updown\fP\ \fIupdown\fP
+specifies an external shell command to be run whenever \fBpluto\fP
+brings up or down a connection.
+The script is used to build a shell command, so it may contain positional
+parameters, but ought not to have punctuation that would cause the
+resulting command to be ill-formed.
+The default is \fIipsec _updown\fP.
+.TP
+\fB\-\-to\fP
+separates the specification of the left and right ends of the connection.
+.LP
+The potential connection description also specifies characteristics of
+rekeying and security.
+.TP
+\fB\-\-psk\fP
+Propose and allow preshared secret authentication for IKE peers. This authentication
+requires that each side use the same secret. May be combined with \fB\-\-rsasig\fP;
+at least one must be specified.
+.TP
+\fB\-\-rsasig\fP
+Propose and allow RSA signatures for authentication of IKE peers. This authentication
+requires that each side have have a private key of its own and know the
+public key of its peer. May be combined with \fB\-\-psk\fP;
+at least one must be specified.
+.TP
+\fB\-\-encrypt\fP
+All proposed or accepted IPsec SAs will include non-null ESP.
+The actual choices of transforms are wired into \fBpluto\fP.
+.TP
+\fB\-\-authenticate\fP
+All proposed IPsec SAs will include AH.
+All accepted IPsec SAs will include AH or ESP with authentication.
+The actual choices of transforms are wired into \fBpluto\fP.
+Note that this has nothing to do with IKE authentication.
+.TP
+\fB\-\-compress\fP
+All proposed IPsec SAs will include IPCOMP (compression).
+This will be ignored if KLIPS is not configured with IPCOMP support.
+.TP
+\fB\-\-tunnel\fP
+the IPsec SA should use tunneling. Implicit if the SA is for clients.
+Must only be used with \fB\-\-authenticate\fP or \fB\-\-encrypt\fP.
+.TP
+\fB\-\-ipv4\fP
+The host addresses will be interpreted as IPv4 addresses. This is the
+default. Note that for a connection, all host addresses must be of
+the same Address Family (IPv4 and IPv6 use different Address Families).
+.TP
+\fB\-\-ipv6\fP
+The host addresses (including nexthop) will be interpreted as IPv6 addresses.
+Note that for a connection, all host addresses must be of
+the same Address Family (IPv4 and IPv6 use different Address Families).
+.TP
+\fB\-\-tunnelipv4\fP
+The client addresses will be interpreted as IPv4 addresses. The default is
+to match what the host will be. This does not imply \fB\-\-tunnel\fP so the
+flag can be safely used when no tunnel is actually specified.
+Note that for a connection, all tunnel addresses must be of the same
+Address Family.
+.TP
+\fB\-\-tunnelipv6\fP
+The client addresses will be interpreted as IPv6 addresses. The default is
+to match what the host will be. This does not imply \fB\-\-tunnel\fP so the
+flag can be safely used when no tunnel is actually specified.
+Note that for a connection, all tunnel addresses must be of the same
+Address Family.
+.TP
+\fB\-\-pfs\fP
+There should be Perfect Forward Secrecy \- new keying material will
+be generated for each IPsec SA rather than being derived from the ISAKMP
+SA keying material.
+Since the group to be used cannot be negotiated (a dubious feature of the
+standard), \fBpluto\fP will propose the same group that was used during Phase 1.
+We don't implement a stronger form of PFS which would require that the
+ISAKMP SA be deleted after the IPSEC SA is negotiated.
+.TP
+\fB\-\-disablearrivalcheck\fP
+If the connection is a tunnel, allow packets arriving through the tunnel
+to have any source and destination addresses.
+.LP
+If none of the \fB\-\-encrypt\fP, \fB\-\-authenticate\fP, \fB\-\-compress\fP,
+or \fB\-\-pfs\fP flags is given, the initiating the connection will
+only build an ISAKMP SA. For such a connection, client subnets have
+no meaning and must not be specified.
+.LP
+More work is needed to allow for flexible policies. Currently
+policy is hardwired in the source file spdb.c. The ISAKMP SAs may use
+Oakley groups MODP1024 and MODP1536; 3DES encryption; SHA1-96
+and MD5-96 authentication. The IPsec SAs may use 3DES and
+MD5-96 or SHA1-96 for ESP, or just MD5-96 or SHA1-96 for AH.
+IPCOMP Compression is always Deflate.
+.TP
+\fB\-\-ikelifetime\fP\ \fIseconds\fP
+how long \fBpluto\fP will propose that an ISAKMP SA be allowed to live.
+The default is 10800 (three hours) and the maximum is 86400 (one day).
+This option will not affect what is accepted.
+\fBpluto\fP will reject proposals that exceed the maximum.
+.TP
+\fB\-\-ipseclifetime\fP\ \fIseconds\fP
+how long \fBpluto\fP will propose that an IPsec SA be allowed to live.
+The default is 3600 (one hour) and the maximum is 86400 (one day).
+This option will not affect what is accepted.
+\fBpluto\fP will reject proposals that exceed the maximum.
+.TP
+\fB\-\-rekeymargin\fP\ \fIseconds\fP
+how long before an SA's expiration should \fBpluto\fP try to negotiate
+a replacement SA. This will only happen if \fBpluto\fP was the initiator.
+The default is 540 (nine minutes).
+.TP
+\fB\-\-rekeyfuzz\fP\ \fIpercentage\fP
+maximum size of random component to add to rekeymargin, expressed as
+a percentage of rekeymargin. \fBpluto\fP will select a delay uniformly
+distributed within this range. By default, the percentage will be 100.
+If greater determinism is desired, specify 0. It may be appropriate
+for the percentage to be much larger than 100.
+.TP
+\fB\-\-keyingtries\fP\ \fIcount\fP
+how many times \fBpluto\fP should try to negotiate an SA,
+either for the first time or for rekeying.
+A value of 0 is interpreted as a very large number: never give up.
+The default is three.
+.TP
+\fB\-\-dontrekey\fP
+A misnomer.
+Only rekey a connection if we were the Initiator and there was recent
+traffic on the existing connection.
+This applies to Phase 1 and Phase 2.
+This is currently the only automatic way for a connection to terminate.
+It may be useful with Road Warrior or Opportunistic connections.
+.br
+Since SA lifetime negotiation is take-it-or-leave it, a Responder
+normally uses the shorter of the negotiated or the configured lifetime.
+This only works because if the lifetime is shorter than negotiated,
+the Responder will rekey in time so that everything works.
+This interacts badly with \fB\-\-dontrekey\fP. In this case,
+the Responder will end up rekeying to rectify a shortfall in an IPsec SA
+lifetime; for an ISAKMP SA, the Responder will accept the negotiated
+lifetime.
+.TP
+\fB\-\-delete\fP
+when used in the connection form, it causes any previous connection
+with this name to be deleted before this one is added. Unlike a
+normal delete, no diagnostic is produced if there was no previous
+connection to delete. Any routing in place for the connection is undone.
+.LP
+The delete form deletes a named connection description and any
+SAs established or negotiations initiated using this connection.
+Any routing in place for the connection is undone.
+.TP
+\fB\-\-delete\fP
+.TP
+\fB\-\-name\fP\ \fIconnection-name\fP
+.LP
+The deletestate form deletes the state object with the specified serial number.
+This is useful for selectively deleting instances of connections.
+.TP
+\fB\-\-deletestate\fP\ \fIstate-number\fP
+.LP
+The route form of the \fBwhack\fP command tells \fBpluto\fP to set up
+routing for a connection.
+Although like a traditional route, it uses an ipsec device as a
+virtual interface.
+Once routing is set up, no packets will be
+sent ``in the clear'' to the peer's client specified in the connection.
+A TRAP shunt eroute will be installed; if outbound traffic is caught,
+Pluto will initiate the connection.
+An explicit \fBwhack\fP route is not always needed: if it hasn't been
+done when an IPsec SA is being installed, one will be automatically attempted.
+.LP
+When a routing is attempted for a connection, there must not already
+be a routing for a different connection with the same subnet but different
+interface or destination, or if
+there is, it must not be being used by an IPsec SA. Otherwise the
+attempt will fail.
+.TP
+\fB\-\-route\fP
+.TP
+\fB\-\-name\fP\ \fIconnection-name\fP
+.LP
+The unroute form of the \fBwhack\fP command tells \fBpluto\fP to undo
+a routing. \fBpluto\fP will refuse if an IPsec SA is using the connection.
+If another connection is sharing the same routing, it will be left in place.
+Without a routing, packets will be sent without encryption or authentication.
+.TP
+\fB\-\-unroute\fP
+.TP
+\fB\-\-name\fP\ \fIconnection-name\fP
+.LP
+The initiate form tells \fBpluto\fP to initiate a negotiation with another
+\fBpluto\fP (or other IKE daemon) according to the named connection.
+Initiation requires a route that \fB\-\-route\fP would provide;
+if none is in place at the time an IPsec SA is being installed,
+\fBpluto\fP attempts to set one up.
+.TP
+\fB\-\-initiate\fP
+.TP
+\fB\-\-name\fP\ \fIconnection-name\fP
+.TP
+\fB\-\-asynchronous
+.LP
+The initiate form of the \fBwhack\fP command will relay back from
+\fBpluto\fP status information via the UNIX domain socket (unless
+\-\-asynchronous is specified). The status information is meant to
+look a bit like that from \fBFTP\fP. Currently \fBwhack\fP simply
+copies this to stderr. When the request is finished (eg. the SAs are
+established or \fBpluto\fP gives up), \fBpluto\fP closes the channel,
+causing \fBwhack\fP to terminate.
+.LP
+The opportunistic initiate form is mainly used for debugging.
+.TP
+\fB\-\-tunnelipv4\fP
+.TP
+\fB\-\-tunnelipv6\fP
+.TP
+\fB\-\-oppohere\fP\ \fIip-address\fP
+.TP
+\fB\-\-oppothere\fP\ \fIip-address\fP
+.LP
+This will cause \fBpluto\fP to attempt to opportunistically initiate a
+connection from here to the there, even if a previous attempt
+had been made.
+The whack log will show the progress of this attempt.
+.LP
+The terminate form tells \fBpluto\fP to delete any SAs that use the specified
+connection and to stop any negotiations in process.
+It does not prevent new negotiations from starting (the delete form
+has this effect).
+.TP
+\fB\-\-terminate\fP
+.TP
+\fB\-\-name\fP\ \fIconnection-name\fP
+.LP
+The public key for informs \fBpluto\fP of the RSA public key for a potential peer.
+Private keys must be kept secret, so they are kept in
+.IR ipsec.secrets (5).
+.TP
+\fB\-\-keyid\ \fP\fIid\fP
+specififies the identity of the peer for which a public key should be used.
+Its form is identical to the identity in the connection.
+If no public key is specified, \fBpluto\fP attempts to find KEY records
+from DNS for the id (if a FQDN) or through reverse lookup (if an IP address).
+Note that there several interesting ways in which this is not secure.
+.TP
+\fB\-\-addkey\fP
+specifies that the new key is added to the collection; otherwise the
+new key replaces any old ones.
+.TP
+\fB\-\-pubkeyrsa\ \fP\fIkey\fP
+specifies the value of the RSA public key. It is a sequence of bytes
+as described in RFC 2537 ``RSA/MD5 KEYs and SIGs in the Domain Name System (DNS)''.
+It is denoted in a way suitable for \fIipsec_ttodata\fP(3).
+For example, a base 64 numeral starts with 0s.
+.LP
+The listen form tells \fBpluto\fP to start listening for IKE requests
+on its public interfaces. To avoid race conditions, it is normal to
+load the appropriate connections into \fBpluto\fP before allowing it
+to listen. If \fBpluto\fP isn't listening, it is pointless to
+initiate negotiations, so it will refuse requests to do so. Whenever
+the listen form is used, \fBpluto\fP looks for public interfaces and
+will notice when new ones have been added and when old ones have been
+removed. This is also the trigger for \fBpluto\fP to read the
+\fIipsec.secrets\fP file. So listen may useful more than once.
+.TP
+\fB\-\-listen\fP
+start listening for IKE traffic on public interfaces.
+.TP
+\fB\-\-unlisten\fP
+stop listening for IKE traffic on public interfaces.
+.LP
+The status form will display information about the internal state of
+\fBpluto\fP: information about each potential connection, about
+each state object, and about each shunt that \fBpluto\fP is managing
+without an associated connection.
+.TP
+\fB\-\-status\fP
+.LP
+The shutdown form is the proper way to shut down \fBpluto\fP.
+It will tear down the SAs on this machine that \fBpluto\fP has negotiated.
+It does not inform its peers, so the SAs on their machines remain.
+.TP
+\fB\-\-shutdown\fP
+.SS Examples
+.LP
+It would be normal to start \fBpluto\fP in one of the system initialization
+scripts. It needs to be run by the superuser. Generally, no arguments are needed.
+To run in manually, the superuser can simply type
+
+\ \ \ ipsec pluto
+
+The command will immediately return, but a \fBpluto\fP process will be left
+running, waiting for requests from \fBwhack\fP or a peer.
+.LP
+Using \fBwhack\fP, several potential connections would be described:
+.HP
+.na
+\ \ \ ipsec whack \-\-name\ silly
+\-\-host\ 127.0.0.1 \-\-to \-\-host\ 127.0.0.2
+\-\-ikelifetime\ 900 \-\-ipseclifetime\ 800 \-\-keyingtries\ 3
+.ad
+.LP
+Since this silly connection description specifies neither encryption,
+authentication, nor tunneling, it could only be used to establish
+an ISAKMP SA.
+.HP
+.na
+\ \ \ ipsec whack \-\-name\ secret \-\-host\ 10.0.0.1 \-\-client\ 10.0.1.0/24
+\-\-to \-\-host\ 10.0.0.2 \-\-client\ 10.0.2.0/24
+\-\-encrypt
+.ad
+.LP
+This is something that must be done on both sides. If the other
+side is \fBpluto\fP, the same \fBwhack\fP command could be used on it
+(the command syntax is designed to not distinguish which end is ours).
+.LP
+Now that the connections are specified, \fBpluto\fP is ready to handle
+requests and replies via the public interfaces. We must tell it to discover
+those interfaces and start accepting messages from peers:
+
+\ \ \ ipsec whack \-\-listen
+.LP
+If we don't immediately wish to bring up a secure connection between
+the two clients, we might wish to prevent insecure traffic.
+The routing form asks \fBpluto\fP to cause the packets sent from
+our client to the peer's client to be routed through the ipsec0
+device; if there is no SA, they will be discarded:
+
+\ \ \ ipsec whack \-\-route secret
+.LP
+Finally, we are ready to get \fBpluto\fP to initiate negotiation
+for an IPsec SA (and implicitly, an ISAKMP SA):
+
+\ \ \ ipsec whack \-\-initiate\ \-\-name\ secret
+
+A small log of interesting events will appear on standard output
+(other logging is sent to syslog).
+.LP
+\fBwhack\fP can also be used to terminate \fBpluto\fP cleanly, tearing down
+all SAs that it has negotiated.
+
+\ \ \ ipsec whack \-\-shutdown
+
+Notification of any IPSEC SA deletion, but not ISAKMP SA deletion
+is sent to the peer. Unfortunately, such Notification is not reliable.
+Furthermore, \fBpluto\fP itself ignores Notifications.
+.SS The updown command
+.LP
+Whenever \fBpluto\fP brings a connection up or down, it invokes
+the updown command. This command is specified using the \fB\-\-updown\fP
+option. This allows for customized control over routing and firewall manipulation.
+.LP
+The updown is invoked for five different operations. Each of
+these operations can be for our client subnet or for our host itself.
+.TP
+\fBprepare-host\fP or \fBprepare-client\fP
+is run before bringing up a new connection if no other connection
+with the same clients is up. Generally, this is useful for deleting a
+route that might have been set up before \fBpluto\fP was run or
+perhaps by some agent not known to \fBpluto\fP.
+.TP
+\fBroute-host\fP or \fBroute-client\fP
+is run when bringing up a connection for a new peer client subnet
+(even if \fBprepare-host\fP or \fBprepare-client\fP was run). The
+command should install a suitable route. Routing decisions are based
+only on the destination (peer's client) subnet address, unlike eroutes
+which discriminate based on source too.
+.TP
+\fBunroute-host\fP or \fBunroute-client\fP
+is run when bringing down the last connection for a particular peer
+client subnet. It should undo what the \fBroute-host\fP or \fBroute-client\fP
+did.
+.TP
+\fBup-host\fP or \fBup-client\fP
+is run when bringing up a tunnel eroute with a pair of client subnets
+that does not already have a tunnel eroute.
+This command should install firewall rules as appropriate.
+It is generally a good idea to allow IKE messages (UDP port 500)
+travel between the hosts.
+.TP
+\fBdown-host\fP or \fBdown-client\fP
+is run when bringing down the eroute for a pair of client subnets.
+This command should delete firewall rules as appropriate. Note that
+there may remain some inbound IPsec SAs with these client subnets.
+.LP
+The script is passed a large number of environment variables to specify
+what needs to be done.
+.TP
+\fBPLUTO_VERSION\fP
+indicates what version of this interface is being used. This document
+describes version 1.1. This is upwardly compatible with version 1.0.
+.TP
+\fBPLUTO_VERB\fP
+specifies the name of the operation to be performed
+(\fBprepare-host\fP,r \fBprepare-client\fP,
+\fBup-host\fP, \fBup-client\fP,
+\fBdown-host\fP, or \fBdown-client\fP). If the address family for
+security gateway to security gateway communications is IPv6, then
+a suffix of -v6 is added to the verb.
+.TP
+\fBPLUTO_CONNECTION\fP
+is the name of the connection for which we are routing.
+.TP
+\fBPLUTO_NEXT_HOP\fP
+is the next hop to which packets bound for the peer must be sent.
+.TP
+\fBPLUTO_INTERFACE\fP
+is the name of the ipsec interface to be used.
+.TP
+\fBPLUTO_ME\fP
+is the IP address of our host.
+.TP
+\fBPLUTO_MY_CLIENT\fP
+is the IP address / count of our client subnet.
+If the client is just the host, this will be the host's own IP address / max
+(where max is 32 for IPv4 and 128 for IPv6).
+.TP
+\fBPLUTO_MY_CLIENT_NET\fP
+is the IP address of our client net.
+If the client is just the host, this will be the host's own IP address.
+.TP
+\fBPLUTO_MY_CLIENT_MASK\fP
+is the mask for our client net.
+If the client is just the host, this will be 255.255.255.255.
+.TP
+\fBPLUTO_PEER\fP
+is the IP address of our peer.
+.TP
+\fBPLUTO_PEER_CLIENT\fP
+is the IP address / count of the peer's client subnet.
+If the client is just the peer, this will be the peer's own IP address / max
+(where max is 32 for IPv4 and 128 for IPv6).
+.TP
+\fBPLUTO_PEER_CLIENT_NET\fP
+is the IP address of the peer's client net.
+If the client is just the peer, this will be the peer's own IP address.
+.TP
+\fBPLUTO_PEER_CLIENT_MASK\fP
+is the mask for the peer's client net.
+If the client is just the peer, this will be 255.255.255.255.
+.LP
+All output sent by the script to stderr or stdout is logged. The
+script should return an exit status of 0 if and only if it succeeds.
+.LP
+\fBPluto\fP waits for the script to finish and will not do any other
+processing while it is waiting.
+The script may assume that \fBpluto\fP will not change anything
+while the script runs.
+The script should avoid doing anything that takes much time and it
+should not issue any command that requires processing by \fBpluto\fP.
+Either of these activities could be performed by a background
+subprocess of the script.
+.SS Rekeying
+.LP
+When an SA that was initiated by \fBpluto\fP has only a bit of
+lifetime left,
+\fBpluto\fP will initiate the creation of a new SA. This applies to
+ISAKMP and IPsec SAs.
+The rekeying will be initiated when the SA's remaining lifetime is
+less than the rekeymargin plus a random percentage, between 0 and
+rekeyfuzz, of the rekeymargin.
+.LP
+Similarly, when an SA that was initiated by the peer has only a bit of
+lifetime left, \fBpluto\fP will try to initiate the creation of a
+replacement.
+To give preference to the initiator, this rekeying will only be initiated
+when the SA's remaining lifetime is half of rekeymargin.
+If rekeying is done by the responder, the roles will be reversed: the
+responder for the old SA will be the initiator for the replacement.
+The former initiator might also initiate rekeying, so there may
+be redundant SAs created.
+To avoid these complications, make sure that rekeymargin is generous.
+.LP
+One risk of having the former responder initiate is that perhaps
+none of its proposals is acceptable to the former initiator
+(they have not been used in a successful negotiation).
+To reduce the chances of this happening, and to prevent loss of security,
+the policy settings are taken from the old SA (this is the case even if
+the former initiator is initiating).
+These may be stricter than those of the connection.
+.LP
+\fBpluto\fP will not rekey an SA if that SA is not the most recent of its
+type (IPsec or ISAKMP) for its potential connection.
+This avoids creating redundant SAs.
+.LP
+The random component in the rekeying time (rekeyfuzz) is intended to
+make certain pathological patterns of rekeying unstable. If both
+sides decide to rekey at the same time, twice as many SAs as necessary
+are created. This could become a stable pattern without the
+randomness.
+.LP
+Another more important case occurs when a security gateway has SAs
+with many other security gateways. Each of these connections might
+need to be rekeyed at the same time. This would cause a high peek
+requirement for resources (network bandwidth, CPU time, entropy for
+random numbers). The rekeyfuzz can be used to stagger the rekeying
+times.
+.LP
+Once a new set of SAs has been negotiated, \fBpluto\fP will never send
+traffic on a superseded one. Traffic will be accepted on an old SA
+until it expires.
+.SS Selecting a Connection When Responding: Road Warrior Support
+.LP
+When \fBpluto\fP receives an initial Main Mode message, it needs to
+decide which connection this message is for. It picks based solely on
+the source and destination IP addresses of the message. There might
+be several connections with suitable IP addresses, in which case one
+of them is arbitrarily chosen. (The ISAKMP SA proposal contained in
+the message could be taken into account, but it is not.)
+.LP
+The ISAKMP SA is negotiated before the parties pass further
+identifying information, so all ISAKMP SA characteristics specified in
+the connection description should be the same for every connection
+with the same two host IP addresses. At the moment, the only
+characteristic that might differ is authentication method.
+.LP
+Up to this point,
+all configuring has presumed that the IP addresses
+are known to all parties ahead of time. This will not work
+when either end is mobile (or assigned a dynamic IP address for other
+reasons). We call this situation ``Road Warrior''. It is fairly tricky
+and has some important limitations, most of which are features of
+the IKE protocol.
+.LP
+Only the initiator may be mobile:
+the initiator may have an IP number unknown to the responder. When
+the responder doesn't recognize the IP address on the first Main Mode
+packet, it looks for a connection with itself as one end and \fB%any\fP
+as the other.
+If it cannot find one, it refuses to negotiate. If it
+does find one, it creates a temporary connection that is a duplicate
+except with the \fB%any\fP replaced by the source IP address from the
+packet; if there was no identity specified for the peer, the new IP
+address will be used.
+.LP
+When \fBpluto\fP is using one of these temporary connections and
+needs to find the preshared secret or RSA private key in \fIipsec.secrets\fP,
+and and the connection specified no identity for the peer, \fB%any\fP
+is used as its identity. After all, the real IP address was apparently
+unknown to the configuration, so it is unreasonable to require that
+it be used in this table.
+.LP
+Part way into the Phase 1 (Main Mode) negotiation using one of these
+temporary connection descriptions, \fBpluto\fP will be receive an
+Identity Payload. At this point, \fBpluto\fP checks for a more
+appropriate connection, one with an identity for the peer that matches
+the payload but which would use the same keys so-far used for
+authentication. If it finds one, it will switch to using this better
+connection (or a temporary derived from this, if it has \fB%any\fP
+for the peer's IP address). It may even turn out that no connection
+matches the newly discovered identity, including the current connection;
+if so, \fBpluto\fP terminates negotiation.
+.LP
+Unfortunately, if preshared secret authentication is being used, the
+Identity Payload is encrypted using this secret, so the secret must be
+selected by the responder without knowing this payload. This
+limits there to being at most one preshared secret for all Road Warrior
+systems connecting to a host. RSA Signature authentications does not
+require that the responder know how to select the initiator's public key
+until after the initiator's Identity Payload is decoded (using the
+responder's private key, so that must be preselected).
+.LP
+When \fBpluto\fP is responding to a Quick Mode negotiation via one of these
+temporary connection descriptions, it may well find that the subnets
+specified by the initiator don't match those in the temporary
+connection description. If so, it will look for a connection with
+matching subnets, its own host address, a peer address of \fB%any\fP
+and matching identities.
+If it finds one, a new temporary connection is derived from this one
+and used for the Quick Mode negotiation of IPsec SAs. If it does not
+find one, \fBpluto\fP terminates negotiation.
+.LP
+Be sure to specify an appropriate nexthop for the responder
+to send a message to the initiator: \fBpluto\fP has no way of guessing
+it (if forwarding isn't required, use an explicit \fB%direct\fP as the nexthop
+and the IP address of the initiator will be filled in; the obsolete
+notation \fB0.0.0.0\fP is still accepted).
+.LP
+\fBpluto\fP has no special provision for the initiator side. The current
+(possibly dynamic) IP address and nexthop must be used in defining
+connections. These must be
+properly configured each time the initiator's IP address changes.
+\fBpluto\fP has no mechanism to do this automatically.
+.LP
+Although we call this Road Warrior Support, it could also be used to
+support encrypted connections with anonymous initiators. The
+responder's organization could announce the preshared secret that would be used
+with unrecognized initiators and let anyone connect. Of course the initiator's
+identity would not be authenticated.
+.LP
+If any Road Warrior connections are supported, \fBpluto\fP cannot
+reject an exchange initiated by an unknown host until it has
+determined that the secret is not shared or the signature is invalid.
+This must await the
+third Main Mode message from the initiator. If no Road Warrior
+connection is supported, the first message from an unknown source
+would be rejected. This has implications for ease of debugging
+configurations and for denial of service attacks.
+.LP
+Although a Road Warrior connection must be initiated by the mobile
+side, the other side can and will rekey using the temporary connection
+it has created. If the Road Warrior wishes to be able to disconnect,
+it is probably wise to set \fB\-\-keyingtries\fP to 1 in the
+connection on the non-mobile side to prevent it trying to rekey the
+connection. Unfortunately, there is no mechanism to unroute the
+connection automatically.
+.SS Debugging
+.LP
+\fBpluto\fP accepts several optional arguments, useful mostly for debugging.
+Except for \fB\-\-interface\fP, each should appear at most once.
+.TP
+\fB\-\-interface\fP \fIinterfacename\fP
+specifies that the named real public network interface should be considered.
+The interface name specified should not be \fBipsec\fP\fIN\fP.
+If the option doesn't appear, all interfaces are considered.
+To specify several interfaces, use the option once for each.
+One use of this option is to specify which interface should be used
+when two or more share the same IP address.
+.TP
+\fB\-\-ikeport\fP \fIport-number\fP
+changes the UDP port that \fBpluto\fP will use
+(default, specified by IANA: 500)
+.TP
+\fB\-\-ctlbase\fP \fIpath\fP
+basename for control files.
+\fIpath\fP.ctl is the socket through which \fBwhack\fP communicates with
+\fBpluto\fP.
+\fIpath\fP.pid is the lockfile to prevent multiple \fBpluto\fP instances.
+The default is \fI/var/run/pluto\fP).
+.TP
+\fB\-\-secretsfile\fP \fIfile\fP
+specifies the file for authentication secrets
+(default: \fI/etc/ipsec.secrets\fP).
+This name is subject to ``globbing'' as in \fIsh\fP(1),
+so every file with a matching name is processed.
+Quoting is generally needed to prevent the shell from doing the globbing.
+.TP
+\fB\-\-adns\fP \fIpathname\fP
+.TP
+\fB\-\-lwdnsq\fP \fIpathname\fP
+specifies where to find \fBpluto\fP's helper program for asynchronous DNS lookup.
+\fBpluto\fP can be built to use one of two helper programs: \fB_pluto_adns\fP
+or \fBlwdnsq\fP. You must use the program for which it was built.
+By default, \fBpluto\fP will look for the program in
+\fB$IPSEC_DIR\fP (if that environment variable is defined) or, failing that,
+in the same directory as \fBpluto\fP.
+.TP
+\fB\-\-nofork\fP
+disable ``daemon fork'' (default is to fork). In addition, after the
+lock file and control socket are created, print the line ``Pluto
+initialized'' to standard out.
+.TP
+\fB\-\-noklips\fP
+don't actually implement negotiated IPsec SAs
+.TP
+\fB\-\-uniqueids\fP
+if this option has been selected, whenever a new ISAKMP SA is
+established, any connection with the same Peer ID but a different
+Peer IP address is unoriented (causing all its SAs to be deleted).
+This helps clean up dangling SAs when a connection is lost and
+then regained at another IP address.
+.TP
+\fB\-\-stderrlog\fP
+log goes to standard out {default is to use \fIsyslogd\fP(8))
+.LP
+For example
+.TP
+pluto \-\-secretsfile\ ipsec.secrets \-\-ctlbase\ pluto.base \-\-ikeport\ 8500 \-\-nofork \-\-noklips \-\-stderrlog
+.LP
+lets one test \fBpluto\fP without using the superuser account.
+.LP
+\fBpluto\fP is willing to produce a prodigious amount of debugging
+information. To do so, it must be compiled with \-DDEBUG. There are
+several classes of debugging output, and \fBpluto\fP may be directed to
+produce a selection of them. All lines of
+debugging output are prefixed with ``|\ '' to distinguish them from error
+messages.
+.LP
+When \fBpluto\fP is invoked, it may be given arguments to specify
+which classes to output. The current options are:
+.TP
+\fB\-\-debug-raw\fP
+show the raw bytes of messages
+.TP
+\fB\-\-debug-crypt\fP
+show the encryption and decryption of messages
+.TP
+\fB\-\-debug-parsing\fP
+show the structure of input messages
+.TP
+\fB\-\-debug-emitting\fP
+show the structure of output messages
+.TP
+\fB\-\-debug-control\fP
+show \fBpluto\fP's decision making
+.TP
+\fB\-\-debug-lifecycle\fP
+[this option is temporary] log more detail of lifecycle of SAs
+.TP
+\fB\-\-debug-klips\fP
+show \fBpluto\fP's interaction with \fBKLIPS\fP
+.TP
+\fB\-\-debug-dns\fP
+show \fBpluto\fP's interaction with \fBDNS\fP for KEY and TXT records
+.TP
+\fB\-\-debug-oppo\fP
+show why \fBpluto\fP didn't find a suitable DNS TXT record to authorize opportunistic initiation
+.TP
+\fB\-\-debug-all\fP
+all of the above
+.TP
+\fB\-\-debug-private\fP
+allow debugging output with private keys.
+.TP
+\fB\-\-debug-none\fP
+none of the above
+.LP
+The debug form of the
+\fBwhack\fP command will change the selection in a running
+\fBpluto\fP.
+If a connection name is specified, the flags are added whenever
+\fBpluto\fP has identified that it is dealing with that connection.
+Unfortunately, this is often part way into the operation being observed.
+.LP
+For example, to start a \fBpluto\fP with a display of the structure of input
+and output:
+.IP
+pluto \-\-debug-emitting \-\-debug-parsing
+.LP
+To later change this \fBpluto\fP to only display raw bytes:
+.IP
+whack \-\-debug-raw
+.LP
+For testing, SSH's IKE test page is quite useful:
+.IP
+\fIhttp://isakmp-test.ssh.fi/\fP
+.LP
+Hint: ISAKMP SAs are often kept alive by IKEs even after the IPsec SA
+is established. This allows future IPsec SA's to be negotiated
+directly. If one of the IKEs is restarted, the other may try to use
+the ISAKMP SA but the new IKE won't know about it. This can lead to
+much confusion. \fBpluto\fP is not yet smart enough to get out of such a
+mess.
+.SS Pluto's Behaviour When Things Go Wrong
+.LP
+When \fBpluto\fP doesn't understand or accept a message, it just
+ignores the message. It is not yet capable of communicating the
+problem to the other IKE daemon (in the future it might use
+Notifications to accomplish this in many cases). It does log a diagnostic.
+.LP
+When \fBpluto\fP gets no response from a message, it resends the same
+message (a message will be sent at most three times). This is
+appropriate: UDP is unreliable.
+.LP
+When pluto gets a message that it has already seen, there are many
+cases when it notices and discards it. This too is appropriate for UDP.
+.LP
+Combine these three rules, and you can explain many apparently
+mysterious behaviours. In a \fBpluto\fP log, retrying isn't usually the
+interesting event. The critical thing is either earlier (\fBpluto\fP
+got a message which it didn't like and so ignored, so it was still
+awaiting an acceptable message and got impatient) or on the other
+system (\fBpluto\fP didn't send a reply because it wasn't happy with
+the previous message).
+.SS Notes
+.LP
+If \fBpluto\fP is compiled without \-DKLIPS, it negotiates Security
+Associations but never ask the kernel to put them in place and never
+makes routing changes. This allows \fBpluto\fP to be tested on systems
+without \fBKLIPS\fP, but makes it rather useless.
+.LP
+Each IPsec SA is assigned an SPI, a 32-bit number used to refer to the SA.
+The IKE protocol lets the destination of the SA choose the SPI.
+The range 0 to 0xFF is reserved for IANA.
+\fBPluto\fP also avoids choosing an SPI in the range 0x100 to 0xFFF,
+leaving these SPIs free for manual keying.
+Remember that the peer, if not \fBpluto\fP, may well chose
+SPIs in this range.
+.SS Policies
+.LP
+This catalogue of policies may be of use when trying to configure
+\fBPluto\fP and another IKE implementation to interoperate.
+.LP
+In Phase 1, only Main Mode is supported. We are not sure that
+Aggressive Mode is secure. For one thing, it does not support
+identity protection. It may allow more severe Denial Of Service
+attacks.
+.LP
+No Informational Exchanges are supported. These are optional and
+since their delivery is not assured, they must not matter.
+It is the case that some IKE implementations won't interoperate
+without Informational Exchanges, but we feel they are broken.
+.LP
+No Informational Payloads are supported. These are optional, but
+useful. It is of concern that these payloads are not authenticated in
+Phase 1, nor in those Phase 2 messages authenticated with HASH(3).
+.IP \(bu \w'\(bu\ 'u
+Diffie Hellman Groups MODP 1024 and MODP 1536 (2 and 5)
+are supported.
+Group MODP768 (1) is not supported because it is too weak.
+.IP \(bu
+Host authetication can be done by RSA Signatures or Pre-Shared
+Secrets.
+.IP \(bu
+3DES CBC (Cypher Block Chaining mode) is the only encryption
+supported, both for ISAKMP SAs and IPSEC SAs.
+.IP \(bu
+MD5 and SHA1 hashing are supported for packet authentication in both
+kinds of SAs.
+.IP \(bu
+The ESP, AH, or AH plus ESP are supported. If, and only if, AH and
+ESP are combined, the ESP need not have its own authentication
+component. The selection is controlled by the \-\-encrypt and
+\-\-authenticate flags.
+.IP \(bu
+Each of these may be combined with IPCOMP Deflate compression,
+but only if the potential connection specifies compression and only
+if KLIPS is configured with IPCOMP support.
+.IP \(bu
+The IPSEC SAs may be tunnel or transport mode, where appropriate.
+The \-\-tunnel flag controls this when \fBpluto\fP is initiating.
+.IP \(bu
+When responding to an ISAKMP SA proposal, the maximum acceptable
+lifetime is eight hours. The default is one hour. There is no
+minimum. The \-\-ikelifetime flag controls this when \fBpluto\fP
+is initiating.
+.IP \(bu
+When responding to an IPSEC SA proposal, the maximum acceptable
+lifetime is one day. The default is eight hours. There is no
+minimum. The \-\-ipseclifetime flag controls this when \fBpluto\fP
+is initiating.
+.IP \(bu
+PFS is acceptable, and will be proposed if the \-\-pfs flag was
+specified. The DH group proposed will be the same as negotiated for
+Phase 1.
+.SH SIGNALS
+.LP
+\fBPluto\fP responds to \fBSIGHUP\fP by issuing a suggestion that ``\fBwhack\fP
+\-\-listen'' might have been intended.
+.LP
+\fBPluto\fP exits when it recieves \fBSIGTERM\fP.
+.SH EXIT STATUS
+.LP
+\fBpluto\fP normally forks a daemon process, so the exit status is
+normally a very preliminary result.
+.TP
+0
+means that all is OK so far.
+.TP
+1
+means that something was wrong.
+.TP
+10
+means that the lock file already exists.
+.LP
+If \fBwhack\fP detects a problem, it will return an exit status of 1.
+If it received progress messages from \fBpluto\fP, it returns as status
+the value of the numeric prefix from the last such message
+that was not a message sent to syslog or a comment
+(but the prefix for success is treated as 0).
+Otherwise, the exit status is 0.
+.SH FILES
+\fI/var/run/pluto.pid\fP
+.br
+\fI/var/run/pluto.ctl\fP
+.br
+\fI/etc/ipsec.secrets\fP
+.br
+\fI$IPSEC_LIBDIR/_pluto_adns\fP
+.br
+\fI$IPSEC_EXECDIR/lwdnsq\fP
+.br
+\fI/dev/urandom\fP
+.SH ENVIRONMENT
+\fIIPSEC_LIBDIR\fP
+.br
+\fIIPSEC_EXECDIR\fP
+.br
+\fIIPSECmyid\fP
+.SH SEE ALSO
+.LP
+The rest of the FreeS/WAN distribution, in particular \fIipsec\fP(8).
+.LP
+\fIipsec_auto\fP(8) is designed to make using \fBpluto\fP more pleasant.
+Use it!
+.LP
+.IR ipsec.secrets (5)
+describes the format of the secrets file.
+.LP
+\fIipsec_atoaddr\fP(3), part of the FreeS/WAN distribution, describes the
+forms that IP addresses may take.
+\fIipsec_atosubnet\fP(3), part of the FreeS/WAN distribution, describes the
+forms that subnet specifications.
+.LP
+For more information on IPsec, the mailing list, and the relevant
+documents, see:
+.IP
+.nh
+\fIhttp://www.ietf.cnri.reston.va.us/html.charters/ipsec-charter.html\fP
+.hy
+.LP
+At the time of writing, the most relevant IETF RFCs are:
+.IP
+RFC2409 The Internet Key Exchange (IKE)
+.IP
+RFC2408 Internet Security Association and Key Management Protocol (ISAKMP)
+.IP
+RFC2407 The Internet IP Security Domain of Interpretation for ISAKMP
+.LP
+The FreeS/WAN web site <htp://www.freeswan.org>
+and the mailing lists described there.
+.SH HISTORY
+This code is released under the GPL terms.
+See the accompanying file COPYING-2.0 for more details.
+The GPL does NOT apply to those pieces of code written by others
+which are included in this distribution, except as noted by the
+individual authors.
+.LP
+This software was originally written
+for the FreeS/WAN project
+<http://www.freeswan.org>
+by Angelos D. Keromytis
+(angelos@dsl.cis.upenn.edu), in May/June 1997, in Athens, Greece.
+Thanks go to John Ioannidis for his help.
+.LP
+It is currently (2000)
+being developed and maintained by D. Hugh Redelmeier
+(hugh@mimosa.com), in Canada. The regulations of Greece and Canada
+allow us to make the code freely redistributable.
+.LP
+Kai Martius (admin@imib.med.tu-dresden.de) contributed the initial
+version of the code supporting PFS.
+.LP
+Richard Guy Briggs <rgb@conscoop.ottawa.on.ca> and Peter Onion
+<ponion@srd.bt.co.uk> added the PFKEY2 support.
+.LP
+We gratefully acknowledge that we use parts of Eric Young's \fIlibdes\fP
+package; see \fI../libdes/COPYRIGHT\fP.
+.SH BUGS
+.BR pluto
+is a work-in-progress. It currently has many limitations.
+For example, it ignores notification messages that it receives, and
+it generates only Delete Notifications and those only for IPSEC SAs.
+.LP
+\fBpluto\fP does not support the Commit Flag.
+The Commit Flag is a bad feature of the IKE protocol.
+It isn't protected -- neither encrypted nor authenticated.
+A man in the middle could turn it on, leading to DoS.
+We just ignore it, with a warning.
+This should let us interoperate with
+implementations that insist on it, with minor damage.
+.LP
+\fBpluto\fP does not check that the SA returned by the Responder
+is actually one that was proposed. It only checks that the SA is
+acceptable. The difference is not large, but can show up in attributes
+such as SA lifetime.
+.LP
+There is no good way for a connection to be automatically terminated.
+This is a problem for Road Warrior and Opportunistic connections.
+The \fB\-\-dontrekey\fP option does prevent the SAs from
+being rekeyed on expiry.
+Additonally, if a Road Warrior connection has a client subnet with a fixed IP
+address, a negotiation with that subnet will cause any other
+connection instantiations with that same subnet to be unoriented
+(deleted, in effect).
+See also the \-\-uniqueids option for an extension of this.
+.LP
+When \fBpluto\fP sends a message to a peer that has disappeared,
+\fBpluto\fP receives incomplete information from the kernel, so it
+logs the unsatisfactory message ``some IKE message we sent has been
+rejected with ECONNREFUSED (kernel supplied no details)''. John
+Denker suggests that this command is useful for tracking down the
+source of these problems:
+.br
+ tcpdump -i eth0 icmp[0] != 8 and icmp[0] != 0
+.br
+Substitute your public interface for eth0 if it is different.
+.LP
+The word ``authenticate'' is used for two different features. We must
+authenticate each IKE peer to the other. This is an important task of
+Phase 1. Each packet must be authenticated, both in IKE and in IPsec,
+and the method for IPsec is negotiated as an AH SA or part of an ESP SA.
+Unfortunately, the protocol has no mechanism for authenticating the Phase 2
+identities.
+.LP
+Bugs should be reported to the <users@lists.freeswan.org> mailing list.
+Caution: we cannot accept
+actual code from US residents, or even US citizens living outside the
+US, because that would bring FreeS/WAN under US export law. Some
+other countries cause similar problems. In general, we would prefer
+that you send detailed problem reports rather than code: we want
+FreeS/WAN to be unquestionably freely exportable, which means being
+very careful about where the code comes from, and for a small bug fix,
+that is often more time-consuming than just reinventing the fix
+ourselves.
diff --git a/src/pluto/plutomain.c b/src/pluto/plutomain.c
new file mode 100644
index 000000000..e235ff765
--- /dev/null
+++ b/src/pluto/plutomain.c
@@ -0,0 +1,655 @@
+/* Pluto main program
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: plutomain.c,v 1.16 2005/09/25 21:30:52 as Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <resolv.h>
+#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */
+#include <sys/queue.h>
+
+#include <freeswan.h>
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "id.h"
+#include "ca.h"
+#include "certs.h"
+#include "ac.h"
+#include "connections.h"
+#include "foodgroups.h"
+#include "packet.h"
+#include "demux.h" /* needs packet.h */
+#include "server.h"
+#include "kernel.h"
+#include "log.h"
+#include "keys.h"
+#include "adns.h" /* needs <resolv.h> */
+#include "dnskey.h" /* needs keys.h and adns.h */
+#include "rnd.h"
+#include "state.h"
+#include "ipsec_doi.h" /* needs demux.h and state.h */
+#include "ocsp.h"
+#include "crl.h"
+#include "fetch.h"
+#include "xauth.h"
+#include "sha1.h"
+#include "md5.h"
+#include "crypto.h" /* requires sha1.h and md5.h */
+#include "nat_traversal.h"
+#include "virtual.h"
+
+static void
+usage(const char *mess)
+{
+ if (mess != NULL && *mess != '\0')
+ fprintf(stderr, "%s\n", mess);
+ fprintf(stderr
+ , "Usage: pluto"
+ " [--help]"
+ " [--version]"
+ " [--optionsfrom <filename>]"
+ " \\\n\t"
+ "[--nofork]"
+ " [--stderrlog]"
+ " [--noklips]"
+ " [--nocrsend]"
+ " \\\n\t"
+ "[--strictcrlpolicy]"
+ " [--crlcheckinterval <interval>]"
+ " [--cachecrls]"
+ " [--uniqueids]"
+ " \\\n\t"
+ "[--interface <ifname>]"
+ " [--ikeport <port-number>]"
+ " \\\n\t"
+ "[--ctlbase <path>]"
+ " \\\n\t"
+ "[--perpeerlogbase <path>] [--perpeerlog]"
+ " \\\n\t"
+ "[--secretsfile <secrets-file>]"
+ " [--policygroupsdir <policygroups-dir>]"
+ " \\\n\t"
+ "[--adns <pathname>]"
+ "[--pkcs11module <path>]"
+ "[--pkcs11keepstate"
+#ifdef DEBUG
+ " \\\n\t"
+ "[--debug-none]"
+ " [--debug-all]"
+ " \\\n\t"
+ "[--debug-raw]"
+ " [--debug-crypt]"
+ " [--debug-parsing]"
+ " [--debug-emitting]"
+ " \\\n\t"
+ "[--debug-control]"
+ " [--debug-lifecycle]"
+ " [--debug-klips]"
+ " [--debug-dns]"
+ " \\\n\t"
+ "[--debug-oppo]"
+ " [--debug-controlmore]"
+ " [--debug-private]"
+#endif
+ " [ --debug-natt]"
+ " \\\n\t"
+ "[--nat_traversal] [--keep_alive <delay_sec>]"
+ " \\\n\t"
+ "[--force_keepalive] [--disable_port_floating]"
+ " \\\n\t"
+ "[--virtual_private <network_list>]"
+ "\n"
+ "strongSwan %s\n"
+ , ipsec_version_code());
+ exit_pluto(mess == NULL? 0 : 1);
+}
+
+
+/* lock file support
+ * - provides convenient way for scripts to find Pluto's pid
+ * - prevents multiple Plutos competing for the same port
+ * - same basename as unix domain control socket
+ * NOTE: will not take account of sharing LOCK_DIR with other systems.
+ */
+
+static char pluto_lock[sizeof(ctl_addr.sun_path)] = DEFAULT_CTLBASE LOCK_SUFFIX;
+static bool pluto_lock_created = FALSE;
+
+/* create lockfile, or die in the attempt */
+static int
+create_lock(void)
+{
+ int fd = open(pluto_lock, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC
+ , S_IRUSR | S_IRGRP | S_IROTH);
+
+ if (fd < 0)
+ {
+ if (errno == EEXIST)
+ {
+ fprintf(stderr, "pluto: lock file \"%s\" already exists\n"
+ , pluto_lock);
+ exit_pluto(10);
+ }
+ else
+ {
+ fprintf(stderr
+ , "pluto: unable to create lock file \"%s\" (%d %s)\n"
+ , pluto_lock, errno, strerror(errno));
+ exit_pluto(1);
+ }
+ }
+ pluto_lock_created = TRUE;
+ return fd;
+}
+
+static bool
+fill_lock(int lockfd, pid_t pid)
+{
+ char buf[30]; /* holds "<pid>\n" */
+ int len = snprintf(buf, sizeof(buf), "%u\n", (unsigned int) pid);
+ bool ok = len > 0 && write(lockfd, buf, len) == len;
+
+ close(lockfd);
+ return ok;
+}
+
+static void
+delete_lock(void)
+{
+ if (pluto_lock_created)
+ {
+ delete_ctl_socket();
+ unlink(pluto_lock); /* is noting failure useful? */
+ }
+}
+
+/* by default pluto sends certificate requests to its peers */
+bool no_cr_send = FALSE;
+
+/* by default the CRL policy is lenient */
+bool strict_crl_policy = FALSE;
+
+/* by default CRLs are cached locally as files */
+bool cache_crls = FALSE;
+
+/* by default pluto does not check crls dynamically */
+long crl_check_interval = 0;
+
+/* path to the PKCS#11 module */
+char *pkcs11_module_path = NULL;
+
+/* by default pluto logs out after every smartcard use */
+bool pkcs11_keep_state = FALSE;
+
+/* by default pluto does not allow pkcs11 proxy access via whack */
+bool pkcs11_proxy = FALSE;
+
+int
+main(int argc, char **argv)
+{
+ bool fork_desired = TRUE;
+ bool log_to_stderr_desired = FALSE;
+ bool nat_traversal = FALSE;
+ bool nat_t_spf = TRUE; /* support port floating */
+ unsigned int keep_alive = 0;
+ bool force_keepalive = FALSE;
+ char *virtual_private = NULL;
+ int lockfd;
+
+ /* handle arguments */
+ for (;;)
+ {
+# define DBG_OFFSET 256
+ static const struct option long_opts[] = {
+ /* name, has_arg, flag, val */
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'v' },
+ { "optionsfrom", required_argument, NULL, '+' },
+ { "nofork", no_argument, NULL, 'd' },
+ { "stderrlog", no_argument, NULL, 'e' },
+ { "noklips", no_argument, NULL, 'n' },
+ { "nocrsend", no_argument, NULL, 'c' },
+ { "strictcrlpolicy", no_argument, NULL, 'r' },
+ { "crlcheckinterval", required_argument, NULL, 'x'},
+ { "cachecrls", no_argument, NULL, 'C' },
+ { "uniqueids", no_argument, NULL, 'u' },
+ { "interface", required_argument, NULL, 'i' },
+ { "ikeport", required_argument, NULL, 'p' },
+ { "ctlbase", required_argument, NULL, 'b' },
+ { "secretsfile", required_argument, NULL, 's' },
+ { "foodgroupsdir", required_argument, NULL, 'f' },
+ { "perpeerlogbase", required_argument, NULL, 'P' },
+ { "perpeerlog", no_argument, NULL, 'l' },
+ { "policygroupsdir", required_argument, NULL, 'f' },
+#ifdef USE_LWRES
+ { "lwdnsq", required_argument, NULL, 'a' },
+#else /* !USE_LWRES */
+ { "adns", required_argument, NULL, 'a' },
+#endif /* !USE_LWRES */
+ { "pkcs11module", required_argument, NULL, 'm' },
+ { "pkcs11keepstate", no_argument, NULL, 'k' },
+ { "pkcs11proxy", no_argument, NULL, 'y' },
+ { "nat_traversal", no_argument, NULL, '1' },
+ { "keep_alive", required_argument, NULL, '2' },
+ { "force_keepalive", no_argument, NULL, '3' },
+ { "disable_port_floating", no_argument, NULL, '4' },
+ { "debug-natt", no_argument, NULL, '5' },
+ { "virtual_private", required_argument, NULL, '6' },
+#ifdef DEBUG
+ { "debug-none", no_argument, NULL, 'N' },
+ { "debug-all", no_argument, NULL, 'A' },
+ { "debug-raw", no_argument, NULL, DBG_RAW + DBG_OFFSET },
+ { "debug-crypt", no_argument, NULL, DBG_CRYPT + DBG_OFFSET },
+ { "debug-parsing", no_argument, NULL, DBG_PARSING + DBG_OFFSET },
+ { "debug-emitting", no_argument, NULL, DBG_EMITTING + DBG_OFFSET },
+ { "debug-control", no_argument, NULL, DBG_CONTROL + DBG_OFFSET },
+ { "debug-lifecycle", no_argument, NULL, DBG_LIFECYCLE + DBG_OFFSET },
+ { "debug-klips", no_argument, NULL, DBG_KLIPS + DBG_OFFSET },
+ { "debug-dns", no_argument, NULL, DBG_DNS + DBG_OFFSET },
+ { "debug-oppo", no_argument, NULL, DBG_OPPO + DBG_OFFSET },
+ { "debug-controlmore", no_argument, NULL, DBG_CONTROLMORE + DBG_OFFSET },
+ { "debug-private", no_argument, NULL, DBG_PRIVATE + DBG_OFFSET },
+
+ { "impair-delay-adns-key-answer", no_argument, NULL, IMPAIR_DELAY_ADNS_KEY_ANSWER + DBG_OFFSET },
+ { "impair-delay-adns-txt-answer", no_argument, NULL, IMPAIR_DELAY_ADNS_TXT_ANSWER + DBG_OFFSET },
+ { "impair-bust-mi2", no_argument, NULL, IMPAIR_BUST_MI2 + DBG_OFFSET },
+ { "impair-bust-mr2", no_argument, NULL, IMPAIR_BUST_MR2 + DBG_OFFSET },
+#endif
+ { 0,0,0,0 }
+ };
+ /* Note: we don't like the way short options get parsed
+ * by getopt_long, so we simply pass an empty string as
+ * the list. It could be "hvdenp:l:s:" "NARXPECK".
+ */
+ int c = getopt_long(argc, argv, "", long_opts, NULL);
+
+ /* Note: "breaking" from case terminates loop */
+ switch (c)
+ {
+ case EOF: /* end of flags */
+ break;
+
+ case 0: /* long option already handled */
+ continue;
+
+ case ':': /* diagnostic already printed by getopt_long */
+ case '?': /* diagnostic already printed by getopt_long */
+ usage("");
+ break; /* not actually reached */
+
+ case 'h': /* --help */
+ usage(NULL);
+ break; /* not actually reached */
+
+ case 'v': /* --version */
+ {
+ const char **sp = ipsec_copyright_notice();
+
+ printf("%s%s\n", ipsec_version_string(),
+ compile_time_interop_options);
+ for (; *sp != NULL; sp++)
+ puts(*sp);
+ }
+ exit_pluto(0);
+ break; /* not actually reached */
+
+ case '+': /* --optionsfrom <filename> */
+ optionsfrom(optarg, &argc, &argv, optind, stderr);
+ /* does not return on error */
+ continue;
+
+ case 'd': /* --nofork*/
+ fork_desired = FALSE;
+ continue;
+
+ case 'e': /* --stderrlog */
+ log_to_stderr_desired = TRUE;
+ continue;
+
+ case 'n': /* --noklips */
+ no_klips = TRUE;
+ continue;
+
+ case 'c': /* --nocrsend */
+ no_cr_send = TRUE;
+ continue;
+
+ case 'r': /* --strictcrlpolicy */
+ strict_crl_policy = TRUE;
+ continue;
+
+ case 'x': /* --crlcheckinterval <time>*/
+ if (optarg == NULL || !isdigit(optarg[0]))
+ usage("missing interval time");
+
+ {
+ char *endptr;
+ long interval = strtol(optarg, &endptr, 0);
+
+ if (*endptr != '\0' || endptr == optarg
+ || interval <= 0)
+ usage("<interval-time> must be a positive number");
+ crl_check_interval = interval;
+ }
+ continue;
+
+ case 'C': /* --cachecrls */
+ cache_crls = TRUE;
+ continue;
+
+ case 'u': /* --uniqueids */
+ uniqueIDs = TRUE;
+ continue;
+
+ case 'i': /* --interface <ifname> */
+ if (!use_interface(optarg))
+ usage("too many --interface specifications");
+ continue;
+
+ case 'p': /* --port <portnumber> */
+ if (optarg == NULL || !isdigit(optarg[0]))
+ usage("missing port number");
+
+ {
+ char *endptr;
+ long port = strtol(optarg, &endptr, 0);
+
+ if (*endptr != '\0' || endptr == optarg
+ || port <= 0 || port > 0x10000)
+ usage("<port-number> must be a number between 1 and 65535");
+ pluto_port = port;
+ }
+ continue;
+
+ case 'b': /* --ctlbase <path> */
+ if (snprintf(ctl_addr.sun_path, sizeof(ctl_addr.sun_path)
+ , "%s%s", optarg, CTL_SUFFIX) == -1)
+ usage("<path>" CTL_SUFFIX " too long for sun_path");
+ if (snprintf(info_addr.sun_path, sizeof(info_addr.sun_path)
+ , "%s%s", optarg, INFO_SUFFIX) == -1)
+ usage("<path>" INFO_SUFFIX " too long for sun_path");
+ if (snprintf(pluto_lock, sizeof(pluto_lock)
+ , "%s%s", optarg, LOCK_SUFFIX) == -1)
+ usage("<path>" LOCK_SUFFIX " must fit");
+ continue;
+
+ case 's': /* --secretsfile <secrets-file> */
+ shared_secrets_file = optarg;
+ continue;
+
+ case 'f': /* --policygroupsdir <policygroups-dir> */
+ policygroups_dir = optarg;
+ continue;
+
+ case 'a': /* --adns <pathname> */
+ pluto_adns_option = optarg;
+ continue;
+
+ case 'm': /* --pkcs11module <pathname> */
+ pkcs11_module_path = optarg;
+ continue;
+
+ case 'k': /* --pkcs11keepstate */
+ pkcs11_keep_state = TRUE;
+ continue;
+
+ case 'y': /* --pkcs11proxy */
+ pkcs11_proxy = TRUE;
+ continue;
+
+#ifdef DEBUG
+ case 'N': /* --debug-none */
+ base_debugging = DBG_NONE;
+ continue;
+
+ case 'A': /* --debug-all */
+ base_debugging = DBG_ALL;
+ continue;
+#endif
+
+ case 'P': /* --perpeerlogbase */
+ base_perpeer_logdir = optarg;
+ continue;
+
+ case 'l':
+ log_to_perpeer = TRUE;
+ continue;
+
+ case '1': /* --nat_traversal */
+ nat_traversal = TRUE;
+ continue;
+ case '2': /* --keep_alive */
+ keep_alive = atoi(optarg);
+ continue;
+ case '3': /* --force_keepalive */
+ force_keepalive = TRUE;
+ continue;
+ case '4': /* --disable_port_floating */
+ nat_t_spf = FALSE;
+ continue;
+ case '5': /* --debug-nat_t */
+ base_debugging |= DBG_NATT;
+ continue;
+ case '6': /* --virtual_private */
+ virtual_private = optarg;
+ continue;
+
+ default:
+#ifdef DEBUG
+ if (c >= DBG_OFFSET)
+ {
+ base_debugging |= c - DBG_OFFSET;
+ continue;
+ }
+# undef DBG_OFFSET
+#endif
+ bad_case(c);
+ }
+ break;
+ }
+ if (optind != argc)
+ usage("unexpected argument");
+ reset_debugging();
+ lockfd = create_lock();
+
+ /* select between logging methods */
+
+ if (log_to_stderr_desired)
+ log_to_syslog = FALSE;
+ else
+ log_to_stderr = FALSE;
+
+ /* set the logging function of pfkey debugging */
+#ifdef DEBUG
+ pfkey_debug_func = DBG_log;
+#else
+ pfkey_debug_func = NULL;
+#endif
+
+ /* create control socket.
+ * We must create it before the parent process returns so that
+ * there will be no race condition in using it. The easiest
+ * place to do this is before the daemon fork.
+ */
+ {
+ err_t ugh = init_ctl_socket();
+
+ if (ugh != NULL)
+ {
+ fprintf(stderr, "pluto: %s", ugh);
+ exit_pluto(1);
+ }
+ }
+
+ /* If not suppressed, do daemon fork */
+
+ if (fork_desired)
+ {
+ {
+ pid_t pid = fork();
+
+ if (pid < 0)
+ {
+ int e = errno;
+
+ fprintf(stderr, "pluto: fork failed (%d %s)\n",
+ errno, strerror(e));
+ exit_pluto(1);
+ }
+
+ if (pid != 0)
+ {
+ /* parent: die, after filling PID into lock file.
+ * must not use exit_pluto: lock would be removed!
+ */
+ exit(fill_lock(lockfd, pid)? 0 : 1);
+ }
+ }
+
+ if (setsid() < 0)
+ {
+ int e = errno;
+
+ fprintf(stderr, "setsid() failed in main(). Errno %d: %s\n",
+ errno, strerror(e));
+ exit_pluto(1);
+ }
+ }
+ else
+ {
+ /* no daemon fork: we have to fill in lock file */
+ (void) fill_lock(lockfd, getpid());
+ fprintf(stdout, "Pluto initialized\n");
+ fflush(stdout);
+ }
+
+ /* Close everything but ctl_fd and (if needed) stderr.
+ * There is some danger that a library that we don't know
+ * about is using some fd that we don't know about.
+ * I guess we'll soon find out.
+ */
+ {
+ int i;
+
+ for (i = getdtablesize() - 1; i >= 0; i--) /* Bad hack */
+ {
+ if ((!log_to_stderr || i != 2) && i != ctl_fd)
+ close(i);
+ }
+
+ /* make sure that stdin, stdout, stderr are reserved */
+ if (open("/dev/null", O_RDONLY) != 0)
+ abort();
+ if (dup2(0, 1) != 1)
+ abort();
+ if (!log_to_stderr && dup2(0, 2) != 2)
+ abort();
+ }
+
+ init_constants();
+ init_log("pluto");
+
+ /* Note: some scripts may look for this exact message -- don't change
+ * ipsec barf was one, but it no longer does.
+ */
+ plog("Starting Pluto (strongSwan Version %s%s)"
+ , ipsec_version_code()
+ , compile_time_interop_options);
+
+ init_nat_traversal(nat_traversal, keep_alive, force_keepalive, nat_t_spf);
+ init_virtual_ip(virtual_private);
+ scx_init(pkcs11_module_path); /* load and initialize PKCS #11 module */
+ xauth_init(); /* load and initialize XAUTH module */
+ init_rnd_pool();
+ init_secret();
+ init_states();
+ init_crypto();
+ init_demux();
+ init_kernel();
+ init_adns();
+ init_id();
+ init_fetch();
+
+ /* loading X.509 CA certificates */
+ load_authcerts("CA cert", CA_CERT_PATH, AUTH_CA);
+ /* loading X.509 AA certificates */
+ load_authcerts("AA cert", AA_CERT_PATH, AUTH_AA);
+ /* loading X.509 OCSP certificates */
+ load_authcerts("OCSP cert", OCSP_CERT_PATH, AUTH_OCSP);
+ /* loading X.509 CRLs */
+ load_crls();
+ /* loading attribute certificates (experimental) */
+ load_acerts();
+
+ daily_log_event();
+ call_server();
+ return -1; /* Shouldn't ever reach this */
+}
+
+/* leave pluto, with status.
+ * Once child is launched, parent must not exit this way because
+ * the lock would be released.
+ *
+ * 0 OK
+ * 1 general discomfort
+ * 10 lock file exists
+ */
+void
+exit_pluto(int status)
+{
+ reset_globals(); /* needed because we may be called in odd state */
+ free_preshared_secrets();
+ free_remembered_public_keys();
+ delete_every_connection();
+ free_crl_fetch(); /* free chain of crl fetch requests */
+ free_ocsp_fetch(); /* free chain of ocsp fetch requests */
+ free_authcerts(); /* free chain of X.509 authority certificates */
+ free_crls(); /* free chain of X.509 CRLs */
+ free_acerts(); /* free chain of X.509 attribute certificates */
+ free_ca_infos(); /* free chain of X.509 CA information records */
+ free_ocsp(); /* free ocsp cache */
+ free_ifaces();
+ scx_finalize(); /* finalize and unload PKCS #11 module */
+ xauth_finalize(); /* finalize and unload XAUTH module */
+ stop_adns();
+ free_md_pool();
+ delete_lock();
+#ifdef LEAK_DETECTIVE
+ report_leaks();
+#endif /* LEAK_DETECTIVE */
+ close_log();
+ exit(status);
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset:4
+ * c-style: pluto
+ * End:
+ */
diff --git a/src/pluto/primegen.c b/src/pluto/primegen.c
new file mode 100644
index 000000000..159490345
--- /dev/null
+++ b/src/pluto/primegen.c
@@ -0,0 +1,593 @@
+/* primegen.c - prime number generator
+ * Copyright (C) 1998 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * ***********************************************************************
+ * The algorithm used to generate practically save primes is due to
+ * Lim and Lee as described in the CRYPTO '97 proceedings (ISBN3540633847)
+ * page 260.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef PLUTO
+#include <gmp.h>
+#include <freeswan.h>
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "rnd.h"
+#include "gcryptfix.h"
+#else /*! PLUTO */
+/* #include <assert.h> */
+/* #include <config.h> */
+/* #include "util.h" */
+/* #include "mpi.h" */
+/* #include "cipher.h" */
+#endif /* !PLUTO */
+
+static int no_of_small_prime_numbers;
+static MPI gen_prime( unsigned nbits, int mode, int randomlevel );
+static int check_prime( MPI prime, MPI val_2 );
+static int is_prime( MPI n, unsigned steps, int *count );
+static void m_out_of_n( char *array, int m, int n );
+
+
+static void
+progress( int c )
+{
+ fputc( c, stderr );
+}
+
+
+/****************
+ * Generate a prime number (stored in secure memory)
+ */
+MPI
+generate_secret_prime( unsigned nbits )
+{
+ MPI prime;
+
+ prime = gen_prime( nbits, 1, 2 );
+ progress('\n');
+ return prime;
+}
+
+MPI
+generate_public_prime( unsigned nbits )
+{
+ MPI prime;
+
+ prime = gen_prime( nbits, 0, 2 );
+ progress('\n');
+ return prime;
+}
+
+
+/****************
+ * We do not need to use the strongest RNG because we gain no extra
+ * security from it - The prime number is public and we could also
+ * offer the factors for those who are willing to check that it is
+ * indeed a strong prime.
+ *
+ * mode 0: Standard
+ * 1: Make sure that at least one factor is of size qbits.
+ */
+MPI
+generate_elg_prime( int mode, unsigned pbits, unsigned qbits,
+ MPI g, MPI **ret_factors )
+{
+ int n; /* number of factors */
+ int m; /* number of primes in pool */
+ unsigned fbits; /* length of prime factors */
+ MPI *factors; /* current factors */
+ MPI *pool; /* pool of primes */
+ MPI q; /* first prime factor (variable)*/
+ MPI prime; /* prime test value */
+ MPI q_factor; /* used for mode 1 */
+ byte *perms = NULL;
+ int i, j;
+ int count1, count2;
+ unsigned nprime;
+ unsigned req_qbits = qbits; /* the requested q bits size */
+ MPI val_2 = mpi_alloc_set_ui( 2 );
+
+ /* find number of needed prime factors */
+ for(n=1; (pbits - qbits - 1) / n >= qbits; n++ )
+ ;
+ n--;
+ if( !n || (mode==1 && n < 2) )
+ log_fatal("can't gen prime with pbits=%u qbits=%u\n", pbits, qbits );
+ if( mode == 1 ) {
+ n--;
+ fbits = (pbits - 2*req_qbits -1) / n;
+ qbits = pbits - req_qbits - n*fbits;
+ }
+ else {
+ fbits = (pbits - req_qbits -1) / n;
+ qbits = pbits - n*fbits;
+ }
+ if( DBG_CIPHER )
+ log_debug("gen prime: pbits=%u qbits=%u fbits=%u/%u n=%d\n",
+ pbits, req_qbits, qbits, fbits, n );
+ prime = mpi_alloc( (pbits + BITS_PER_MPI_LIMB - 1) / BITS_PER_MPI_LIMB );
+ q = gen_prime( qbits, 0, 1 );
+ q_factor = mode==1? gen_prime( req_qbits, 0, 1 ) : NULL;
+
+ /* allocate an array to hold the factors + 2 for later usage */
+#ifdef PLUTO
+ m_alloc_ptrs_clear(factors, n+2);
+#else
+ factors = m_alloc_clear( (n+2) * sizeof *factors );
+#endif
+
+ /* make a pool of 3n+5 primes (this is an arbitrary value) */
+ m = n*3+5;
+ if( mode == 1 )
+ m += 5; /* need some more for DSA */
+ if( m < 25 )
+ m = 25;
+#ifdef PLUTO
+ m_alloc_ptrs_clear(pool, m);
+#else
+ pool = m_alloc_clear( m * sizeof *pool );
+#endif
+
+ /* permutate over the pool of primes */
+ count1=count2=0;
+ do {
+ next_try:
+ if( !perms ) {
+ /* allocate new primes */
+ for(i=0; i < m; i++ ) {
+ mpi_free(pool[i]);
+ pool[i] = NULL;
+ }
+ /* init m_out_of_n() */
+#ifdef PLUTO
+ perms = alloc_bytes( m, "perms" );
+#else
+ perms = m_alloc_clear( m );
+#endif
+ for(i=0; i < n; i++ ) {
+ perms[i] = 1;
+ pool[i] = gen_prime( fbits, 0, 1 );
+ factors[i] = pool[i];
+ }
+ }
+ else {
+ m_out_of_n( perms, n, m );
+ for(i=j=0; i < m && j < n ; i++ )
+ if( perms[i] ) {
+ if( !pool[i] )
+ pool[i] = gen_prime( fbits, 0, 1 );
+ factors[j++] = pool[i];
+ }
+ if( i == n ) {
+ m_free(perms); perms = NULL;
+ progress('!');
+ goto next_try; /* allocate new primes */
+ }
+ }
+
+ mpi_set( prime, q );
+ mpi_mul_ui( prime, prime, 2 );
+ if( mode == 1 )
+ mpi_mul( prime, prime, q_factor );
+ for(i=0; i < n; i++ )
+ mpi_mul( prime, prime, factors[i] );
+ mpi_add_ui( prime, prime, 1 );
+ nprime = mpi_get_nbits(prime);
+ if( nprime < pbits ) {
+ if( ++count1 > 20 ) {
+ count1 = 0;
+ qbits++;
+ progress('>');
+ q = gen_prime( qbits, 0, 1 );
+ goto next_try;
+ }
+ }
+ else
+ count1 = 0;
+ if( nprime > pbits ) {
+ if( ++count2 > 20 ) {
+ count2 = 0;
+ qbits--;
+ progress('<');
+ q = gen_prime( qbits, 0, 1 );
+ goto next_try;
+ }
+ }
+ else
+ count2 = 0;
+ } while( !(nprime == pbits && check_prime( prime, val_2 )) );
+
+ if( DBG_CIPHER ) {
+ progress('\n');
+ log_mpidump( "prime : ", prime );
+ log_mpidump( "factor q: ", q );
+ if( mode == 1 )
+ log_mpidump( "factor q0: ", q_factor );
+ for(i=0; i < n; i++ )
+ log_mpidump( "factor pi: ", factors[i] );
+ log_debug("bit sizes: prime=%u, q=%u", mpi_get_nbits(prime), mpi_get_nbits(q) );
+ if( mode == 1 )
+ fprintf(stderr, ", q0=%u", mpi_get_nbits(q_factor) );
+ for(i=0; i < n; i++ )
+ fprintf(stderr, ", p%d=%u", i, mpi_get_nbits(factors[i]) );
+ progress('\n');
+ }
+
+ if( ret_factors ) { /* caller wants the factors */
+#ifdef PLUTO
+ m_alloc_ptrs_clear(*ret_factors, n+2);
+#else
+ *ret_factors = m_alloc_clear( (n+2) * sizeof **ret_factors);
+#endif
+ if( mode == 1 ) {
+ i = 0;
+ (*ret_factors)[i++] = mpi_copy( q_factor );
+ for(; i <= n; i++ )
+ (*ret_factors)[i] = mpi_copy( factors[i] );
+ }
+ else {
+ for(; i < n; i++ )
+ (*ret_factors)[i] = mpi_copy( factors[i] );
+ }
+ }
+
+ if( g ) { /* create a generator (start with 3)*/
+ MPI tmp = mpi_alloc( mpi_get_nlimbs(prime) );
+ MPI b = mpi_alloc( mpi_get_nlimbs(prime) );
+ MPI pmin1 = mpi_alloc( mpi_get_nlimbs(prime) );
+
+ if( mode == 1 )
+ BUG(); /* not yet implemented */
+ factors[n] = q;
+ factors[n+1] = mpi_alloc_set_ui(2);
+ mpi_sub_ui( pmin1, prime, 1 );
+ mpi_set_ui(g,2);
+ do {
+ mpi_add_ui(g, g, 1);
+ if( DBG_CIPHER ) {
+#ifdef PLUTO
+ log_mpidump("checking g: ", g);
+#else
+ log_debug("checking g: ");
+ mpi_print( stderr, g, 1 );
+#endif
+ }
+ else
+ progress('^');
+ for(i=0; i < n+2; i++ ) {
+ /*fputc('~', stderr);*/
+ mpi_fdiv_q(tmp, pmin1, factors[i] );
+ /* (no mpi_pow(), but it is okay to use this with mod prime) */
+ mpi_powm(b, g, tmp, prime );
+ if( !mpi_cmp_ui(b, 1) )
+ break;
+ }
+ if( DBG_CIPHER )
+ progress('\n');
+ } while( i < n+2 );
+ mpi_free(factors[n+1]);
+ mpi_free(tmp);
+ mpi_free(b);
+ mpi_free(pmin1);
+ }
+ if( !DBG_CIPHER )
+ progress('\n');
+
+ m_free( factors ); /* (factors are shallow copies) */
+ for(i=0; i < m; i++ )
+ mpi_free( pool[i] );
+ m_free( pool );
+ m_free(perms);
+ mpi_free(val_2);
+ return prime;
+}
+
+
+
+static MPI
+gen_prime( unsigned nbits, int secret, int randomlevel )
+{
+ unsigned nlimbs;
+ MPI prime, ptest, pminus1, val_2, val_3, result;
+ int i;
+ unsigned x, step;
+ unsigned count1, count2;
+ int *mods;
+
+ if( 0 && DBG_CIPHER )
+ log_debug("generate a prime of %u bits ", nbits );
+
+ if( !no_of_small_prime_numbers ) {
+ for(i=0; small_prime_numbers[i]; i++ )
+ no_of_small_prime_numbers++;
+ }
+ mods = m_alloc( no_of_small_prime_numbers * sizeof *mods );
+ /* make nbits fit into MPI implementation */
+ nlimbs = (nbits + BITS_PER_MPI_LIMB - 1) / BITS_PER_MPI_LIMB;
+ val_2 = mpi_alloc_set_ui( 2 );
+ val_3 = mpi_alloc_set_ui( 3);
+ prime = secret? mpi_alloc_secure( nlimbs ): mpi_alloc( nlimbs );
+ result = mpi_alloc_like( prime );
+ pminus1= mpi_alloc_like( prime );
+ ptest = mpi_alloc_like( prime );
+ count1 = count2 = 0;
+ for(;;) { /* try forvever */
+ int dotcount=0;
+
+ /* generate a random number */
+ { char *p = get_random_bits( nbits, randomlevel, secret );
+ mpi_set_buffer( prime, p, (nbits+7)/8, 0 );
+ m_free(p);
+ }
+
+ /* set high order bit to 1, set low order bit to 1 */
+ mpi_set_highbit( prime, nbits-1 );
+ mpi_set_bit( prime, 0 );
+
+ /* calculate all remainders */
+ for(i=0; (x = small_prime_numbers[i]); i++ )
+ mods[i] = mpi_fdiv_r_ui(NULL, prime, x);
+
+ /* now try some primes starting with prime */
+ for(step=0; step < 20000; step += 2 ) {
+ /* check against all the small primes we have in mods */
+ count1++;
+ for(i=0; (x = small_prime_numbers[i]); i++ ) {
+ while( mods[i] + step >= x )
+ mods[i] -= x;
+ if( !(mods[i] + step) )
+ break;
+ }
+ if( x )
+ continue; /* found a multiple of an already known prime */
+
+ mpi_add_ui( ptest, prime, step );
+
+ /* do a faster Fermat test */
+ count2++;
+ mpi_sub_ui( pminus1, ptest, 1);
+ mpi_powm( result, val_2, pminus1, ptest );
+ if( !mpi_cmp_ui( result, 1 ) ) { /* not composite */
+ /* perform stronger tests */
+ if( is_prime(ptest, 5, &count2 ) ) {
+ if( !mpi_test_bit( ptest, nbits-1 ) ) {
+ progress('\n');
+ log_debug("overflow in prime generation\n");
+ break; /* step loop, continue with a new prime */
+ }
+
+ mpi_free(val_2);
+ mpi_free(val_3);
+ mpi_free(result);
+ mpi_free(pminus1);
+ mpi_free(prime);
+ m_free(mods);
+ return ptest;
+ }
+ }
+ if( ++dotcount == 10 ) {
+ progress('.');
+ dotcount = 0;
+ }
+ }
+ progress(':'); /* restart with a new random value */
+ }
+}
+
+/****************
+ * Returns: true if this may be a prime
+ */
+static int
+check_prime( MPI prime, MPI val_2 )
+{
+ int i;
+ unsigned x;
+ int count=0;
+
+ /* check against small primes */
+ for(i=0; (x = small_prime_numbers[i]); i++ ) {
+ if( mpi_divisible_ui( prime, x ) )
+ return 0;
+ }
+
+ /* a quick fermat test */
+ {
+ MPI result = mpi_alloc_like( prime );
+ MPI pminus1 = mpi_alloc_like( prime );
+ mpi_sub_ui( pminus1, prime, 1);
+ mpi_powm( result, val_2, pminus1, prime );
+ mpi_free( pminus1 );
+ if( mpi_cmp_ui( result, 1 ) ) { /* if composite */
+ mpi_free( result );
+ progress('.');
+ return 0;
+ }
+ mpi_free( result );
+ }
+
+ /* perform stronger tests */
+ if( is_prime(prime, 5, &count ) )
+ return 1; /* is probably a prime */
+ progress('.');
+ return 0;
+}
+
+
+/****************
+ * Return true if n is probably a prime
+ */
+static int
+is_prime( MPI n, unsigned steps, int *count )
+{
+ MPI x = mpi_alloc( mpi_get_nlimbs( n ) );
+ MPI y = mpi_alloc( mpi_get_nlimbs( n ) );
+ MPI z = mpi_alloc( mpi_get_nlimbs( n ) );
+ MPI nminus1 = mpi_alloc( mpi_get_nlimbs( n ) );
+ MPI a2 = mpi_alloc_set_ui( 2 );
+ MPI q;
+ unsigned i, j, k;
+ int rc = 0;
+ unsigned nbits = mpi_get_nbits( n );
+
+ mpi_sub_ui( nminus1, n, 1 );
+
+ /* find q and k, so that n = 1 + 2^k * q */
+ q = mpi_copy( nminus1 );
+ k = mpi_trailing_zeros( q );
+ mpi_tdiv_q_2exp(q, q, k);
+
+ for(i=0 ; i < steps; i++ ) {
+ ++*count;
+ if( !i ) {
+ mpi_set_ui( x, 2 );
+ }
+ else {
+ /*mpi_set_bytes( x, nbits-1, get_random_byte, 0 );*/
+ { char *p = get_random_bits( nbits, 0, 0 );
+ mpi_set_buffer( x, p, (nbits+7)/8, 0 );
+ m_free(p);
+ }
+ /* make sure that the number is smaller than the prime
+ * and keep the randomness of the high bit */
+ if( mpi_test_bit( x, nbits-2 ) ) {
+ mpi_set_highbit( x, nbits-2 ); /* clear all higher bits */
+ }
+ else {
+ mpi_set_highbit( x, nbits-2 );
+ mpi_clear_bit( x, nbits-2 );
+ }
+ assert( mpi_cmp( x, nminus1 ) < 0 && mpi_cmp_ui( x, 1 ) > 0 );
+ }
+ mpi_powm( y, x, q, n);
+ if( mpi_cmp_ui(y, 1) && mpi_cmp( y, nminus1 ) ) {
+ for( j=1; j < k && mpi_cmp( y, nminus1 ); j++ ) {
+ mpi_powm(y, y, a2, n);
+ if( !mpi_cmp_ui( y, 1 ) )
+ goto leave; /* not a prime */
+ }
+ if( mpi_cmp( y, nminus1 ) )
+ goto leave; /* not a prime */
+ }
+ progress('+');
+ }
+ rc = 1; /* may be a prime */
+
+ leave:
+ mpi_free( x );
+ mpi_free( y );
+ mpi_free( z );
+ mpi_free( nminus1 );
+ mpi_free( q );
+
+ return rc;
+}
+
+
+static void
+m_out_of_n( char *array, int m, int n )
+{
+ int i=0, i1=0, j=0, jp=0, j1=0, k1=0, k2=0;
+
+ if( !m || m >= n )
+ return;
+
+ if( m == 1 ) { /* special case */
+ for(i=0; i < n; i++ )
+ if( array[i] ) {
+ array[i++] = 0;
+ if( i >= n )
+ i = 0;
+ array[i] = 1;
+ return;
+ }
+ BUG();
+ }
+
+ for(j=1; j < n; j++ ) {
+ if( array[n-1] == array[n-j-1] )
+ continue;
+ j1 = j;
+ break;
+ }
+
+ if( m & 1 ) { /* m is odd */
+ if( array[n-1] ) {
+ if( j1 & 1 ) {
+ k1 = n - j1;
+ k2 = k1+2;
+ if( k2 > n )
+ k2 = n;
+ goto leave;
+ }
+ goto scan;
+ }
+ k2 = n - j1 - 1;
+ if( k2 == 0 ) {
+ k1 = i;
+ k2 = n - j1;
+ }
+ else if( array[k2] && array[k2-1] )
+ k1 = n;
+ else
+ k1 = k2 + 1;
+ }
+ else { /* m is even */
+ if( !array[n-1] ) {
+ k1 = n - j1;
+ k2 = k1 + 1;
+ goto leave;
+ }
+
+ if( !(j1 & 1) ) {
+ k1 = n - j1;
+ k2 = k1+2;
+ if( k2 > n )
+ k2 = n;
+ goto leave;
+ }
+ scan:
+ jp = n - j1 - 1;
+ for(i=1; i <= jp; i++ ) {
+ i1 = jp + 2 - i;
+ if( array[i1-1] ) {
+ if( array[i1-2] ) {
+ k1 = i1 - 1;
+ k2 = n - j1;
+ }
+ else {
+ k1 = i1 - 1;
+ k2 = n + 1 - j1;
+ }
+ goto leave;
+ }
+ }
+ k1 = 1;
+ k2 = n + 1 - m;
+ }
+ leave:
+ array[k1-1] = !array[k1-1];
+ array[k2-1] = !array[k2-1];
+}
+
diff --git a/src/pluto/rcv_whack.c b/src/pluto/rcv_whack.c
new file mode 100644
index 000000000..6a39e7c1f
--- /dev/null
+++ b/src/pluto/rcv_whack.c
@@ -0,0 +1,685 @@
+/* whack communicating routines
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: rcv_whack.c,v 1.18 2006/05/25 11:33:57 as Exp $
+ */
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */
+#include <sys/queue.h>
+#include <fcntl.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "id.h"
+#include "ca.h"
+#include "certs.h"
+#include "ac.h"
+#include "smartcard.h"
+#include "connections.h"
+#include "foodgroups.h"
+#include "whack.h" /* needs connections.h */
+#include "packet.h"
+#include "demux.h" /* needs packet.h */
+#include "state.h"
+#include "ipsec_doi.h" /* needs demux.h and state.h */
+#include "kernel.h"
+#include "rcv_whack.h"
+#include "log.h"
+#include "keys.h"
+#include "adns.h" /* needs <resolv.h> */
+#include "dnskey.h" /* needs keys.h and adns.h */
+#include "server.h"
+#include "fetch.h"
+#include "ocsp.h"
+#include "crl.h"
+
+#include "kernel_alg.h"
+#include "ike_alg.h"
+/* helper variables and function to decode strings from whack message */
+
+static char *next_str
+ , *str_roof;
+
+static bool
+unpack_str(char **p)
+{
+ char *end = memchr(next_str, '\0', str_roof - next_str);
+
+ if (end == NULL)
+ {
+ return FALSE; /* fishy: no end found */
+ }
+ else
+ {
+ *p = next_str == end? NULL : next_str;
+ next_str = end + 1;
+ return TRUE;
+ }
+}
+
+/* bits loading keys from asynchronous DNS */
+
+enum key_add_attempt {
+ ka_TXT,
+#ifdef USE_KEYRR
+ ka_KEY,
+#endif
+ ka_roof /* largest value + 1 */
+};
+
+struct key_add_common {
+ int refCount;
+ char *diag[ka_roof];
+ int whack_fd;
+ bool success;
+};
+
+struct key_add_continuation {
+ struct adns_continuation ac; /* common prefix */
+ struct key_add_common *common; /* common data */
+ enum key_add_attempt lookingfor;
+};
+
+static void
+key_add_ugh(const struct id *keyid, err_t ugh)
+{
+ char name[BUF_LEN]; /* longer IDs will be truncated in message */
+
+ (void)idtoa(keyid, name, sizeof(name));
+ loglog(RC_NOKEY
+ , "failure to fetch key for %s from DNS: %s", name, ugh);
+}
+
+/* last one out: turn out the lights */
+static void
+key_add_merge(struct key_add_common *oc, const struct id *keyid)
+{
+ if (oc->refCount == 0)
+ {
+ enum key_add_attempt kaa;
+
+ /* if no success, print all diagnostics */
+ if (!oc->success)
+ for (kaa = ka_TXT; kaa != ka_roof; kaa++)
+ key_add_ugh(keyid, oc->diag[kaa]);
+
+ for (kaa = ka_TXT; kaa != ka_roof; kaa++)
+ pfreeany(oc->diag[kaa]);
+
+ close(oc->whack_fd);
+ pfree(oc);
+ }
+}
+
+static void
+key_add_continue(struct adns_continuation *ac, err_t ugh)
+{
+ struct key_add_continuation *kc = (void *) ac;
+ struct key_add_common *oc = kc->common;
+
+ passert(whack_log_fd == NULL_FD);
+ whack_log_fd = oc->whack_fd;
+
+ if (ugh != NULL)
+ {
+ oc->diag[kc->lookingfor] = clone_str(ugh, "key add error");
+ }
+ else
+ {
+ oc->success = TRUE;
+ transfer_to_public_keys(kc->ac.gateways_from_dns
+#ifdef USE_KEYRR
+ , &kc->ac.keys_from_dns
+#endif /* USE_KEYRR */
+ );
+ }
+
+ oc->refCount--;
+ key_add_merge(oc, &ac->id);
+ whack_log_fd = NULL_FD;
+}
+
+static void
+key_add_request(const whack_message_t *msg)
+{
+ struct id keyid;
+ err_t ugh = atoid(msg->keyid, &keyid, FALSE);
+
+ if (ugh != NULL)
+ {
+ loglog(RC_BADID, "bad --keyid \"%s\": %s", msg->keyid, ugh);
+ }
+ else
+ {
+ if (!msg->whack_addkey)
+ delete_public_keys(&keyid, msg->pubkey_alg
+ , empty_chunk, empty_chunk);
+
+ if (msg->keyval.len == 0)
+ {
+ struct key_add_common *oc
+ = alloc_thing(struct key_add_common
+ , "key add common things");
+ enum key_add_attempt kaa;
+
+ /* initialize state shared by queries */
+ oc->refCount = 0;
+ oc->whack_fd = dup_any(whack_log_fd);
+ oc->success = FALSE;
+
+ for (kaa = ka_TXT; kaa != ka_roof; kaa++)
+ {
+ struct key_add_continuation *kc
+ = alloc_thing(struct key_add_continuation
+ , "key add continuation");
+
+ oc->diag[kaa] = NULL;
+ oc->refCount++;
+ kc->common = oc;
+ kc->lookingfor = kaa;
+ switch (kaa)
+ {
+ case ka_TXT:
+ ugh = start_adns_query(&keyid
+ , &keyid /* same */
+ , T_TXT
+ , key_add_continue
+ , &kc->ac);
+ break;
+#ifdef USE_KEYRR
+ case ka_KEY:
+ ugh = start_adns_query(&keyid
+ , NULL
+ , T_KEY
+ , key_add_continue
+ , &kc->ac);
+ break;
+#endif /* USE_KEYRR */
+ default:
+ bad_case(kaa); /* suppress gcc warning */
+ }
+ if (ugh != NULL)
+ {
+ oc->diag[kaa] = clone_str(ugh, "early key add failure");
+ oc->refCount--;
+ }
+ }
+
+ /* Done launching queries.
+ * Handle total failure case.
+ */
+ key_add_merge(oc, &keyid);
+ }
+ else
+ {
+ ugh = add_public_key(&keyid, DAL_LOCAL, msg->pubkey_alg
+ , &msg->keyval, &pubkeys);
+ if (ugh != NULL)
+ loglog(RC_LOG_SERIOUS, "%s", ugh);
+ }
+ }
+}
+
+/* Handle a kernel request. Supposedly, there's a message in
+ * the kernelsock socket.
+ */
+void
+whack_handle(int whackctlfd)
+{
+ whack_message_t msg;
+ struct sockaddr_un whackaddr;
+ int whackaddrlen = sizeof(whackaddr);
+ int whackfd = accept(whackctlfd, (struct sockaddr *)&whackaddr, &whackaddrlen);
+ /* Note: actual value in n should fit in int. To print, cast to int. */
+ ssize_t n;
+
+ if (whackfd < 0)
+ {
+ log_errno((e, "accept() failed in whack_handle()"));
+ return;
+ }
+ if (fcntl(whackfd, F_SETFD, FD_CLOEXEC) < 0)
+ {
+ log_errno((e, "failed to set CLOEXEC in whack_handle()"));
+ close(whackfd);
+ return;
+ }
+
+ n = read(whackfd, &msg, sizeof(msg));
+
+ if (n == -1)
+ {
+ log_errno((e, "read() failed in whack_handle()"));
+ close(whackfd);
+ return;
+ }
+
+ whack_log_fd = whackfd;
+
+ /* sanity check message */
+ {
+ err_t ugh = NULL;
+
+ next_str = msg.string;
+ str_roof = (char *)&msg + n;
+
+ if ((size_t)n < offsetof(whack_message_t, whack_shutdown) + sizeof(msg.whack_shutdown))
+ {
+ ugh = builddiag("ignoring runt message from whack: got %d bytes", (int)n);
+ }
+ else if (msg.magic != WHACK_MAGIC)
+ {
+ if (msg.magic == WHACK_BASIC_MAGIC)
+ {
+ /* Only shutdown command. Simpler inter-version compatability. */
+ if (msg.whack_shutdown)
+ {
+ plog("shutting down");
+ exit_pluto(0); /* delete lock and leave, with 0 status */
+ }
+ ugh = ""; /* bail early, but without complaint */
+ }
+ else
+ {
+ ugh = builddiag("ignoring message from whack with bad magic %d; should be %d; probably wrong version"
+ , msg.magic, WHACK_MAGIC);
+ }
+ }
+ else if (next_str > str_roof)
+ {
+ ugh = builddiag("ignoring truncated message from whack: got %d bytes; expected %u"
+ , (int) n, (unsigned) sizeof(msg));
+ }
+ else if (!unpack_str(&msg.name) /* string 1 */
+ || !unpack_str(&msg.left.id) /* string 2 */
+ || !unpack_str(&msg.left.cert) /* string 3 */
+ || !unpack_str(&msg.left.ca) /* string 4 */
+ || !unpack_str(&msg.left.groups) /* string 5 */
+ || !unpack_str(&msg.left.updown) /* string 6 */
+ || !unpack_str(&msg.left.virt) /* string 7 */
+ || !unpack_str(&msg.right.id) /* string 8 */
+ || !unpack_str(&msg.right.cert) /* string 9 */
+ || !unpack_str(&msg.right.ca) /* string 10 */
+ || !unpack_str(&msg.right.groups) /* string 11 */
+ || !unpack_str(&msg.right.updown) /* string 12 */
+ || !unpack_str(&msg.right.virt) /* string 13 */
+ || !unpack_str(&msg.keyid) /* string 14 */
+ || !unpack_str(&msg.myid) /* string 15 */
+ || !unpack_str(&msg.cacert) /* string 16 */
+ || !unpack_str(&msg.ldaphost) /* string 17 */
+ || !unpack_str(&msg.ldapbase) /* string 18 */
+ || !unpack_str(&msg.crluri) /* string 19 */
+ || !unpack_str(&msg.crluri2) /* string 20 */
+ || !unpack_str(&msg.ocspuri) /* string 21 */
+ || !unpack_str(&msg.ike) /* string 22 */
+ || !unpack_str(&msg.esp) /* string 23 */
+ || !unpack_str(&msg.sc_data) /* string 24 */
+ || str_roof - next_str != (ptrdiff_t)msg.keyval.len) /* check chunk */
+ {
+ ugh = "message from whack contains bad string";
+ }
+ else
+ {
+ msg.keyval.ptr = next_str; /* grab chunk */
+ }
+
+ if (ugh != NULL)
+ {
+ if (*ugh != '\0')
+ loglog(RC_BADWHACKMESSAGE, "%s", ugh);
+ whack_log_fd = NULL_FD;
+ close(whackfd);
+ return;
+ }
+ }
+
+ if (msg.whack_options)
+ {
+#ifdef DEBUG
+ if (msg.name == NULL)
+ {
+ /* we do a two-step so that if either old or new would
+ * cause the message to print, it will be printed.
+ */
+ cur_debugging |= msg.debugging;
+ DBG(DBG_CONTROL
+ , DBG_log("base debugging = %s"
+ , bitnamesof(debug_bit_names, msg.debugging)));
+ cur_debugging = base_debugging = msg.debugging;
+ }
+ else if (!msg.whack_connection)
+ {
+ struct connection *c = con_by_name(msg.name, TRUE);
+
+ if (c != NULL)
+ {
+ c->extra_debugging = msg.debugging;
+ DBG(DBG_CONTROL
+ , DBG_log("\"%s\" extra_debugging = %s"
+ , c->name
+ , bitnamesof(debug_bit_names, c->extra_debugging)));
+ }
+ }
+#endif
+ }
+
+ if (msg.whack_myid)
+ set_myid(MYID_SPECIFIED, msg.myid);
+
+ /* Deleting combined with adding a connection works as replace.
+ * To make this more useful, in only this combination,
+ * delete will silently ignore the lack of the connection.
+ */
+ if (msg.whack_delete)
+ {
+ if (msg.whack_ca)
+ find_ca_info_by_name(msg.name, TRUE);
+ else
+ delete_connections_by_name(msg.name, !msg.whack_connection);
+ }
+
+ if (msg.whack_deletestate)
+ {
+ struct state *st = state_with_serialno(msg.whack_deletestateno);
+
+ if (st == NULL)
+ {
+ loglog(RC_UNKNOWN_NAME, "no state #%lu to delete"
+ , msg.whack_deletestateno);
+ }
+ else
+ {
+ delete_state(st);
+ }
+ }
+
+ if (msg.whack_crash)
+ delete_states_by_peer(&msg.whack_crash_peer);
+
+ if (msg.whack_connection)
+ add_connection(&msg);
+
+ if (msg.whack_ca && msg.cacert != NULL)
+ add_ca_info(&msg);
+
+ /* process "listen" before any operation that could require it */
+ if (msg.whack_listen)
+ {
+ close_peerlog(); /* close any open per-peer logs */
+ plog("listening for IKE messages");
+ listening = TRUE;
+ daily_log_reset();
+ reset_adns_restart_count();
+ set_myFQDN();
+ find_ifaces();
+ load_preshared_secrets(NULL_FD);
+ load_groups();
+ }
+ if (msg.whack_unlisten)
+ {
+ plog("no longer listening for IKE messages");
+ listening = FALSE;
+ }
+
+ if (msg.whack_reread & REREAD_SECRETS)
+ {
+ load_preshared_secrets(whackfd);
+ }
+
+ if (msg.whack_reread & REREAD_CACERTS)
+ {
+ load_authcerts("CA cert", CA_CERT_PATH, AUTH_CA);
+ }
+
+ if (msg.whack_reread & REREAD_AACERTS)
+ {
+ load_authcerts("AA cert", AA_CERT_PATH, AUTH_AA);
+ }
+
+ if (msg.whack_reread & REREAD_OCSPCERTS)
+ {
+ load_authcerts("OCSP cert", OCSP_CERT_PATH, AUTH_OCSP);
+ }
+
+ if (msg.whack_reread & REREAD_ACERTS)
+ {
+ load_acerts();
+ }
+
+ if (msg.whack_reread & REREAD_CRLS)
+ {
+ load_crls();
+ }
+
+ if (msg.whack_purgeocsp)
+ {
+ free_ocsp_fetch();
+ free_ocsp_cache();
+ }
+
+ if (msg.whack_list & LIST_ALGS)
+ {
+ ike_alg_list();
+ kernel_alg_list();
+ }
+ if (msg.whack_list & LIST_PUBKEYS)
+ {
+ list_public_keys(msg.whack_utc);
+ }
+
+ if (msg.whack_list & LIST_CERTS)
+ {
+ list_certs(msg.whack_utc);
+ }
+
+ if (msg.whack_list & LIST_CACERTS)
+ {
+ list_authcerts("CA", AUTH_CA, msg.whack_utc);
+ }
+
+ if (msg.whack_list & LIST_AACERTS)
+ {
+ list_authcerts("AA", AUTH_AA, msg.whack_utc);
+ }
+
+ if (msg.whack_list & LIST_OCSPCERTS)
+ {
+ list_authcerts("OCSP", AUTH_OCSP, msg.whack_utc);
+ }
+
+ if (msg.whack_list & LIST_ACERTS)
+ {
+ list_acerts(msg.whack_utc);
+ }
+
+ if (msg.whack_list & LIST_GROUPS)
+ {
+ list_groups(msg.whack_utc);
+ }
+
+ if (msg.whack_list & LIST_CAINFOS)
+ {
+ list_ca_infos(msg.whack_utc);
+ }
+
+ if (msg.whack_list & LIST_CRLS)
+ {
+ list_crls(msg.whack_utc, strict_crl_policy);
+ list_crl_fetch_requests(msg.whack_utc);
+ }
+
+ if (msg.whack_list & LIST_OCSP)
+ {
+ list_ocsp_cache(msg.whack_utc, strict_crl_policy);
+ list_ocsp_fetch_requests(msg.whack_utc);
+ }
+
+ if (msg.whack_list & LIST_CARDS)
+ {
+ scx_list(msg.whack_utc);
+ }
+
+ if (msg.whack_key)
+ {
+ /* add a public key */
+ key_add_request(&msg);
+ }
+
+ if (msg.whack_route)
+ {
+ if (!listening)
+ {
+ whack_log(RC_DEAF, "need --listen before --route");
+ }
+ if (msg.name == NULL)
+ {
+ whack_log(RC_UNKNOWN_NAME
+ , "whack --route requires a connection name");
+ }
+ else
+ {
+ struct connection *c = con_by_name(msg.name, TRUE);
+
+ if (c != NULL && c->ikev1)
+ {
+ set_cur_connection(c);
+ if (!oriented(*c))
+ whack_log(RC_ORIENT
+ , "we have no ipsecN interface for either end of this connection");
+ else if (c->policy & POLICY_GROUP)
+ route_group(c);
+ else if (!trap_connection(c))
+ whack_log(RC_ROUTE, "could not route");
+ reset_cur_connection();
+ }
+ }
+ }
+
+ if (msg.whack_unroute)
+ {
+ if (msg.name == NULL)
+ {
+ whack_log(RC_UNKNOWN_NAME
+ , "whack --unroute requires a connection name");
+ }
+ else
+ {
+ struct connection *c = con_by_name(msg.name, TRUE);
+
+ if (c != NULL && c->ikev1)
+ {
+ struct spd_route *sr;
+ int fail = 0;
+
+ set_cur_connection(c);
+
+ for (sr = &c->spd; sr != NULL; sr = sr->next)
+ {
+ if (sr->routing >= RT_ROUTED_TUNNEL)
+ fail++;
+ }
+ if (fail > 0)
+ whack_log(RC_RTBUSY, "cannot unroute: route busy");
+ else if (c->policy & POLICY_GROUP)
+ unroute_group(c);
+ else
+ unroute_connection(c);
+ reset_cur_connection();
+ }
+ }
+ }
+
+ if (msg.whack_initiate)
+ {
+ if (!listening)
+ {
+ whack_log(RC_DEAF, "need --listen before --initiate");
+ }
+ else if (msg.name == NULL)
+ {
+ whack_log(RC_UNKNOWN_NAME
+ , "whack --initiate requires a connection name");
+ }
+ else
+ {
+ initiate_connection(msg.name
+ , msg.whack_async? NULL_FD : dup_any(whackfd));
+ }
+ }
+
+ if (msg.whack_oppo_initiate)
+ {
+ if (!listening)
+ whack_log(RC_DEAF, "need --listen before opportunistic initiation");
+ else
+ initiate_opportunistic(&msg.oppo_my_client, &msg.oppo_peer_client, 0
+ , FALSE
+ , msg.whack_async? NULL_FD : dup_any(whackfd));
+ }
+
+ if (msg.whack_terminate)
+ {
+ if (msg.name == NULL)
+ {
+ whack_log(RC_UNKNOWN_NAME
+ , "whack --terminate requires a connection name");
+ }
+ else
+ {
+ terminate_connection(msg.name);
+ }
+ }
+
+ if (msg.whack_status)
+ show_status(msg.whack_statusall, msg.name);
+
+ if (msg.whack_shutdown)
+ {
+ plog("shutting down");
+ exit_pluto(0); /* delete lock and leave, with 0 status */
+ }
+
+ if (msg.whack_sc_op != SC_OP_NONE)
+ {
+ if (pkcs11_proxy)
+ scx_op_via_whack(msg.sc_data, msg.inbase, msg.outbase
+ , msg.whack_sc_op, msg.keyid, whackfd);
+ else
+ plog("pkcs11 access to smartcard not allowed (set pkcs11proxy=yes)");
+ }
+
+ whack_log_fd = NULL_FD;
+ close(whackfd);
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset:4
+ * c-style: pluto
+ * End:
+ */
diff --git a/src/pluto/rcv_whack.h b/src/pluto/rcv_whack.h
new file mode 100644
index 000000000..f42761c51
--- /dev/null
+++ b/src/pluto/rcv_whack.h
@@ -0,0 +1,17 @@
+/* whack communicating routines
+ * Copyright (C) 1998, 1999 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: rcv_whack.h,v 1.1 2004/03/15 20:35:29 as Exp $
+ */
+
+extern void whack_handle(int kernelfd);
diff --git a/src/pluto/rnd.c b/src/pluto/rnd.c
new file mode 100644
index 000000000..812882c6b
--- /dev/null
+++ b/src/pluto/rnd.c
@@ -0,0 +1,250 @@
+/* randomness machinery
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: rnd.c,v 1.3 2005/09/08 16:26:30 as Exp $
+ */
+
+/* A true random number generator (we hope)
+ *
+ * Under LINUX ("linux" predefined), use /dev/urandom.
+ * Under OpenBSD ("__OpenBSD__" predefined), use arc4random().
+ * Otherwise use our own random number generator based on clock skew.
+ * I (ADK) first heard of the idea from John Ioannidis, who heard it
+ * from Matt Blaze and/or Jack Lacy.
+ * ??? Why is mixing need for linux but not OpenBSD?
+ */
+
+/* Pluto's uses of randomness:
+ *
+ * - Setting up the "secret_of_the_day". This changes every hour! 20
+ * bytes a shot. It is used in building responder cookies.
+ *
+ * - generating initiator cookies (8 bytes, once per Phase 1 initiation).
+ *
+ * - 32 bytes per DH local secret. Once per Main Mode exchange and once
+ * per Quick Mode Exchange with PFS. (Size is our choice, with
+ * tradeoffs.)
+ *
+ * - 16 bytes per nonce we generate. Once per Main Mode exchange and
+ * once per Quick Mode exchange. (Again, we choose the size.)
+ *
+ * - 4 bytes per SPI number that we generate. We choose the SPIs for all
+ * inbound SPIs, one to three per IPSEC SA (one for AH (rare, probably)
+ * one for ESP (almost always), and one for tunnel (very common)).
+ * I don't actually know how the kernel would generate these numbers --
+ * currently Pluto generates them; this isn't the way things will be
+ * done in the future.
+ *
+ * - 4 bytes per Message ID we need to generate. One per Quick Mode
+ * exchange. Eventually, one per informational exchange.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <fcntl.h>
+
+#include <freeswan.h>
+
+#include "sha1.h"
+#include "constants.h"
+#include "defs.h"
+#include "rnd.h"
+#include "log.h"
+#include "timer.h"
+
+#ifdef linux
+# define USE_DEV_RANDOM 1
+# define RANDOM_PATH DEV_URANDOM
+#else
+# ifdef __OpenBSD__
+# define USE_ARC4RANDOM
+# else
+# define USE_CLOCK_SLEW
+# endif
+#endif
+
+#ifdef USE_ARC4RANDOM
+
+#define get_rnd_byte() (arc4random() % 256)
+
+#else /**** start of large #else ****/
+
+#ifdef USE_DEV_RANDOM
+static int random_fd = NULL_FD;
+#endif
+
+#define RANDOM_POOL_SIZE SHA1_DIGEST_SIZE
+static u_char random_pool[RANDOM_POOL_SIZE];
+
+#ifdef USE_DEV_RANDOM
+
+/* Generate (what we hope is) a true random byte using /dev/urandom */
+static u_char
+generate_rnd_byte(void)
+{
+ u_char c;
+
+ if (read(random_fd, &c, sizeof(c)) == -1)
+ exit_log_errno((e, "read() failed in get_rnd_byte()"));
+
+ return c;
+}
+
+#else /* !USE_DEV_RANDOM */
+
+/* Generate (what we hope is) a true random byte using the clock skew trick.
+ * Note: this code is not maintained! In particular, LINUX signal(2)
+ * semantics changed with glibc2 (and not for the better). It isn't clear
+ * that this code will work. We keep the code because someday it might
+ * come in handy.
+ */
+# error "This code is not maintained. Please define USE_DEV_RANDOM."
+
+static volatile sig_atomic_t i, j, k;
+
+/* timer signal handler */
+static void
+rnd_handler(int ignore_me UNUSED)
+{
+ k <<= 1; /* Shift left by 1 */
+ j++;
+ k |= (i & 0x1); /* Get lsbit of counter */
+
+ if (j != 8)
+ signal(SIGVTALRM, rnd_handler);
+}
+
+static u_char
+generate_rnd_byte(void)
+{
+ struct itimerval tmval, ntmval;
+
+# ifdef NEVER /* ??? */
+# ifdef linux
+ int mask = siggetmask();
+
+ mask |= SIGVTALRM;
+ sigsetmask(mask);
+# endif
+# endif
+
+ i = 0;
+ j = 0;
+
+ ntmval.it_interval.tv_sec = 0;
+ ntmval.it_interval.tv_usec = 1;
+ ntmval.it_value.tv_sec = 0;
+ ntmval.it_value.tv_usec = 1;
+ signal(SIGVTALRM, rnd_handler);
+ setitimer(ITIMER_VIRTUAL, &ntmval, &tmval);
+
+ while (j != 8)
+ i++;
+
+ setitimer(ITIMER_VIRTUAL, &tmval, &ntmval);
+ signal(SIGVTALRM, SIG_IGN);
+
+# ifdef NEVER /* ??? */
+# ifdef linux
+ mask ^= SIGVTALRM;
+ sigsetmask(mask);
+# endif
+# endif
+
+ return k;
+}
+
+#endif /* !USE_DEV_RANDOM */
+
+static void
+mix_pool(void)
+{
+ SHA1_CTX ctx;
+
+ SHA1Init(&ctx);
+ SHA1Update(&ctx, random_pool, RANDOM_POOL_SIZE);
+ SHA1Final(random_pool, &ctx);
+}
+
+/*
+ * Get a single random byte.
+ */
+static u_char
+get_rnd_byte(void)
+{
+ random_pool[RANDOM_POOL_SIZE - 1] = generate_rnd_byte();
+ random_pool[0] = generate_rnd_byte();
+ mix_pool();
+ return random_pool[0];
+}
+
+#endif /* !USE_ARC4RANDOM */ /**** end of large #else ****/
+
+void
+get_rnd_bytes(u_char *buffer, int length)
+{
+ int i;
+
+ for (i = 0; i < length; i++)
+ buffer[i] = get_rnd_byte();
+}
+
+/*
+ * Initialize the random pool.
+ */
+void
+init_rnd_pool(void)
+{
+#ifndef USE_ARC4RANDOM
+# ifdef USE_DEV_RANDOM
+ DBG(DBG_KLIPS, DBG_log("opening %s", RANDOM_PATH));
+ random_fd = open(RANDOM_PATH, O_RDONLY);
+ if (random_fd == -1)
+ exit_log_errno((e, "open of %s failed in init_rnd_pool()", RANDOM_PATH));
+ fcntl(random_fd, F_SETFD, FD_CLOEXEC);
+# endif
+
+ get_rnd_bytes(random_pool, RANDOM_POOL_SIZE);
+ mix_pool();
+#endif /* !USE_ARC4RANDOM */
+
+ /* start of rand(3) on the right foot */
+ {
+ unsigned int seed;
+
+ get_rnd_bytes((void *)&seed, sizeof(seed));
+ srand(seed);
+ }
+}
+
+u_char secret_of_the_day[SHA1_DIGEST_SIZE];
+
+#ifndef NO_PLUTO
+
+void
+init_secret(void)
+{
+ /*
+ * Generate the secret value for responder cookies, and
+ * schedule an event for refresh.
+ */
+ get_rnd_bytes(secret_of_the_day, sizeof(secret_of_the_day));
+ event_schedule(EVENT_REINIT_SECRET, EVENT_REINIT_SECRET_DELAY, NULL);
+}
+
+#endif /* NO_PLUTO */
diff --git a/src/pluto/rnd.h b/src/pluto/rnd.h
new file mode 100644
index 000000000..0bd168039
--- /dev/null
+++ b/src/pluto/rnd.h
@@ -0,0 +1,21 @@
+/* randomness machinery
+ * Copyright (C) 1998, 1999 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: rnd.h,v 1.1 2004/03/15 20:35:29 as Exp $
+ */
+
+extern u_char secret_of_the_day[SHA1_DIGEST_SIZE];
+
+extern void get_rnd_bytes(u_char *buffer, int length);
+extern void init_rnd_pool(void);
+extern void init_secret(void);
diff --git a/src/pluto/rsaref/pkcs11.h b/src/pluto/rsaref/pkcs11.h
new file mode 100644
index 000000000..9261e1e4c
--- /dev/null
+++ b/src/pluto/rsaref/pkcs11.h
@@ -0,0 +1,299 @@
+/* pkcs11.h include file for PKCS #11. */
+/* $Revision: 1.2 $ */
+
+/* License to copy and use this software is granted provided that it is
+ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
+ * (Cryptoki)" in all material mentioning or referencing this software.
+
+ * License is also granted to make and use derivative works provided that
+ * such works are identified as "derived from the RSA Security Inc. PKCS #11
+ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or
+ * referencing the derived work.
+
+ * RSA Security Inc. makes no representations concerning either the
+ * merchantability of this software or the suitability of this software for
+ * any particular purpose. It is provided "as is" without express or implied
+ * warranty of any kind.
+ */
+
+#ifndef _PKCS11_H_
+#define _PKCS11_H_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Before including this file (pkcs11.h) (or pkcs11t.h by
+ * itself), 6 platform-specific macros must be defined. These
+ * macros are described below, and typical definitions for them
+ * are also given. Be advised that these definitions can depend
+ * on both the platform and the compiler used (and possibly also
+ * on whether a Cryptoki library is linked statically or
+ * dynamically).
+ *
+ * In addition to defining these 6 macros, the packing convention
+ * for Cryptoki structures should be set. The Cryptoki
+ * convention on packing is that structures should be 1-byte
+ * aligned.
+ *
+ * If you're using Microsoft Developer Studio 5.0 to produce
+ * Win32 stuff, this might be done by using the following
+ * preprocessor directive before including pkcs11.h or pkcs11t.h:
+ *
+ * #pragma pack(push, cryptoki, 1)
+ *
+ * and using the following preprocessor directive after including
+ * pkcs11.h or pkcs11t.h:
+ *
+ * #pragma pack(pop, cryptoki)
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to produce Win16 stuff, this might be done by using
+ * the following preprocessor directive before including
+ * pkcs11.h or pkcs11t.h:
+ *
+ * #pragma pack(1)
+ *
+ * In a UNIX environment, you're on your own for this. You might
+ * not need to do (or be able to do!) anything.
+ *
+ *
+ * Now for the macros:
+ *
+ *
+ * 1. CK_PTR: The indirection string for making a pointer to an
+ * object. It can be used like this:
+ *
+ * typedef CK_BYTE CK_PTR CK_BYTE_PTR;
+ *
+ * If you're using Microsoft Developer Studio 5.0 to produce
+ * Win32 stuff, it might be defined by:
+ *
+ * #define CK_PTR *
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to produce Win16 stuff, it might be defined by:
+ *
+ * #define CK_PTR far *
+ *
+ * In a typical UNIX environment, it might be defined by:
+ *
+ * #define CK_PTR *
+ *
+ *
+ * 2. CK_DEFINE_FUNCTION(returnType, name): A macro which makes
+ * an exportable Cryptoki library function definition out of a
+ * return type and a function name. It should be used in the
+ * following fashion to define the exposed Cryptoki functions in
+ * a Cryptoki library:
+ *
+ * CK_DEFINE_FUNCTION(CK_RV, C_Initialize)(
+ * CK_VOID_PTR pReserved
+ * )
+ * {
+ * ...
+ * }
+ *
+ * If you're using Microsoft Developer Studio 5.0 to define a
+ * function in a Win32 Cryptoki .dll, it might be defined by:
+ *
+ * #define CK_DEFINE_FUNCTION(returnType, name) \
+ * returnType __declspec(dllexport) name
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to define a function in a Win16 Cryptoki .dll, it
+ * might be defined by:
+ *
+ * #define CK_DEFINE_FUNCTION(returnType, name) \
+ * returnType __export _far _pascal name
+ *
+ * In a UNIX environment, it might be defined by:
+ *
+ * #define CK_DEFINE_FUNCTION(returnType, name) \
+ * returnType name
+ *
+ *
+ * 3. CK_DECLARE_FUNCTION(returnType, name): A macro which makes
+ * an importable Cryptoki library function declaration out of a
+ * return type and a function name. It should be used in the
+ * following fashion:
+ *
+ * extern CK_DECLARE_FUNCTION(CK_RV, C_Initialize)(
+ * CK_VOID_PTR pReserved
+ * );
+ *
+ * If you're using Microsoft Developer Studio 5.0 to declare a
+ * function in a Win32 Cryptoki .dll, it might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION(returnType, name) \
+ * returnType __declspec(dllimport) name
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to declare a function in a Win16 Cryptoki .dll, it
+ * might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION(returnType, name) \
+ * returnType __export _far _pascal name
+ *
+ * In a UNIX environment, it might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION(returnType, name) \
+ * returnType name
+ *
+ *
+ * 4. CK_DECLARE_FUNCTION_POINTER(returnType, name): A macro
+ * which makes a Cryptoki API function pointer declaration or
+ * function pointer type declaration out of a return type and a
+ * function name. It should be used in the following fashion:
+ *
+ * // Define funcPtr to be a pointer to a Cryptoki API function
+ * // taking arguments args and returning CK_RV.
+ * CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtr)(args);
+ *
+ * or
+ *
+ * // Define funcPtrType to be the type of a pointer to a
+ * // Cryptoki API function taking arguments args and returning
+ * // CK_RV, and then define funcPtr to be a variable of type
+ * // funcPtrType.
+ * typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtrType)(args);
+ * funcPtrType funcPtr;
+ *
+ * If you're using Microsoft Developer Studio 5.0 to access
+ * functions in a Win32 Cryptoki .dll, in might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ * returnType __declspec(dllimport) (* name)
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to access functions in a Win16 Cryptoki .dll, it might
+ * be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ * returnType __export _far _pascal (* name)
+ *
+ * In a UNIX environment, it might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ * returnType (* name)
+ *
+ *
+ * 5. CK_CALLBACK_FUNCTION(returnType, name): A macro which makes
+ * a function pointer type for an application callback out of
+ * a return type for the callback and a name for the callback.
+ * It should be used in the following fashion:
+ *
+ * CK_CALLBACK_FUNCTION(CK_RV, myCallback)(args);
+ *
+ * to declare a function pointer, myCallback, to a callback
+ * which takes arguments args and returns a CK_RV. It can also
+ * be used like this:
+ *
+ * typedef CK_CALLBACK_FUNCTION(CK_RV, myCallbackType)(args);
+ * myCallbackType myCallback;
+ *
+ * If you're using Microsoft Developer Studio 5.0 to do Win32
+ * Cryptoki development, it might be defined by:
+ *
+ * #define CK_CALLBACK_FUNCTION(returnType, name) \
+ * returnType (* name)
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to do Win16 development, it might be defined by:
+ *
+ * #define CK_CALLBACK_FUNCTION(returnType, name) \
+ * returnType _far _pascal (* name)
+ *
+ * In a UNIX environment, it might be defined by:
+ *
+ * #define CK_CALLBACK_FUNCTION(returnType, name) \
+ * returnType (* name)
+ *
+ *
+ * 6. NULL_PTR: This macro is the value of a NULL pointer.
+ *
+ * In any ANSI/ISO C environment (and in many others as well),
+ * this should best be defined by
+ *
+ * #ifndef NULL_PTR
+ * #define NULL_PTR 0
+ * #endif
+ */
+
+
+/* All the various Cryptoki types and #define'd values are in the
+ * file pkcs11t.h. */
+#include "pkcs11t.h"
+
+#define __PASTE(x,y) x##y
+
+
+/* ==============================================================
+ * Define the "extern" form of all the entry points.
+ * ==============================================================
+ */
+
+#define CK_NEED_ARG_LIST 1
+#define CK_PKCS11_FUNCTION_INFO(name) \
+ extern CK_DECLARE_FUNCTION(CK_RV, name)
+
+/* pkcs11f.h has all the information about the Cryptoki
+ * function prototypes. */
+#include "pkcs11f.h"
+
+#undef CK_NEED_ARG_LIST
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+/* ==============================================================
+ * Define the typedef form of all the entry points. That is, for
+ * each Cryptoki function C_XXX, define a type CK_C_XXX which is
+ * a pointer to that kind of function.
+ * ==============================================================
+ */
+
+#define CK_NEED_ARG_LIST 1
+#define CK_PKCS11_FUNCTION_INFO(name) \
+ typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, __PASTE(CK_,name))
+
+/* pkcs11f.h has all the information about the Cryptoki
+ * function prototypes. */
+#include "pkcs11f.h"
+
+#undef CK_NEED_ARG_LIST
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+/* ==============================================================
+ * Define structed vector of entry points. A CK_FUNCTION_LIST
+ * contains a CK_VERSION indicating a library's Cryptoki version
+ * and then a whole slew of function pointers to the routines in
+ * the library. This type was declared, but not defined, in
+ * pkcs11t.h.
+ * ==============================================================
+ */
+
+#define CK_PKCS11_FUNCTION_INFO(name) \
+ __PASTE(CK_,name) name;
+
+struct CK_FUNCTION_LIST {
+
+ CK_VERSION version; /* Cryptoki version */
+
+/* Pile all the function pointers into the CK_FUNCTION_LIST. */
+/* pkcs11f.h has all the information about the Cryptoki
+ * function prototypes. */
+#include "pkcs11f.h"
+
+};
+
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+#undef __PASTE
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/pluto/rsaref/pkcs11f.h b/src/pluto/rsaref/pkcs11f.h
new file mode 100644
index 000000000..dec6315dd
--- /dev/null
+++ b/src/pluto/rsaref/pkcs11f.h
@@ -0,0 +1,912 @@
+/* pkcs11f.h include file for PKCS #11. */
+/* $Revision: 1.2 $ */
+
+/* License to copy and use this software is granted provided that it is
+ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
+ * (Cryptoki)" in all material mentioning or referencing this software.
+
+ * License is also granted to make and use derivative works provided that
+ * such works are identified as "derived from the RSA Security Inc. PKCS #11
+ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or
+ * referencing the derived work.
+
+ * RSA Security Inc. makes no representations concerning either the
+ * merchantability of this software or the suitability of this software for
+ * any particular purpose. It is provided "as is" without express or implied
+ * warranty of any kind.
+ */
+
+/* This header file contains pretty much everything about all the */
+/* Cryptoki function prototypes. Because this information is */
+/* used for more than just declaring function prototypes, the */
+/* order of the functions appearing herein is important, and */
+/* should not be altered. */
+
+/* General-purpose */
+
+/* C_Initialize initializes the Cryptoki library. */
+CK_PKCS11_FUNCTION_INFO(C_Initialize)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_VOID_PTR pInitArgs /* if this is not NULL_PTR, it gets
+ * cast to CK_C_INITIALIZE_ARGS_PTR
+ * and dereferenced */
+);
+#endif
+
+
+/* C_Finalize indicates that an application is done with the
+ * Cryptoki library. */
+CK_PKCS11_FUNCTION_INFO(C_Finalize)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_VOID_PTR pReserved /* reserved. Should be NULL_PTR */
+);
+#endif
+
+
+/* C_GetInfo returns general information about Cryptoki. */
+CK_PKCS11_FUNCTION_INFO(C_GetInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_INFO_PTR pInfo /* location that receives information */
+);
+#endif
+
+
+/* C_GetFunctionList returns the function list. */
+CK_PKCS11_FUNCTION_INFO(C_GetFunctionList)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_FUNCTION_LIST_PTR_PTR ppFunctionList /* receives pointer to
+ * function list */
+);
+#endif
+
+
+
+/* Slot and token management */
+
+/* C_GetSlotList obtains a list of slots in the system. */
+CK_PKCS11_FUNCTION_INFO(C_GetSlotList)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_BBOOL tokenPresent, /* only slots with tokens? */
+ CK_SLOT_ID_PTR pSlotList, /* receives array of slot IDs */
+ CK_ULONG_PTR pulCount /* receives number of slots */
+);
+#endif
+
+
+/* C_GetSlotInfo obtains information about a particular slot in
+ * the system. */
+CK_PKCS11_FUNCTION_INFO(C_GetSlotInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* the ID of the slot */
+ CK_SLOT_INFO_PTR pInfo /* receives the slot information */
+);
+#endif
+
+
+/* C_GetTokenInfo obtains information about a particular token
+ * in the system. */
+CK_PKCS11_FUNCTION_INFO(C_GetTokenInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* ID of the token's slot */
+ CK_TOKEN_INFO_PTR pInfo /* receives the token information */
+);
+#endif
+
+
+/* C_GetMechanismList obtains a list of mechanism types
+ * supported by a token. */
+CK_PKCS11_FUNCTION_INFO(C_GetMechanismList)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* ID of token's slot */
+ CK_MECHANISM_TYPE_PTR pMechanismList, /* gets mech. array */
+ CK_ULONG_PTR pulCount /* gets # of mechs. */
+);
+#endif
+
+
+/* C_GetMechanismInfo obtains information about a particular
+ * mechanism possibly supported by a token. */
+CK_PKCS11_FUNCTION_INFO(C_GetMechanismInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* ID of the token's slot */
+ CK_MECHANISM_TYPE type, /* type of mechanism */
+ CK_MECHANISM_INFO_PTR pInfo /* receives mechanism info */
+);
+#endif
+
+
+/* C_InitToken initializes a token. */
+CK_PKCS11_FUNCTION_INFO(C_InitToken)
+#ifdef CK_NEED_ARG_LIST
+/* pLabel changed from CK_CHAR_PTR to CK_UTF8CHAR_PTR for v2.10 */
+(
+ CK_SLOT_ID slotID, /* ID of the token's slot */
+ CK_UTF8CHAR_PTR pPin, /* the SO's initial PIN */
+ CK_ULONG ulPinLen, /* length in bytes of the PIN */
+ CK_UTF8CHAR_PTR pLabel /* 32-byte token label (blank padded) */
+);
+#endif
+
+
+/* C_InitPIN initializes the normal user's PIN. */
+CK_PKCS11_FUNCTION_INFO(C_InitPIN)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_UTF8CHAR_PTR pPin, /* the normal user's PIN */
+ CK_ULONG ulPinLen /* length in bytes of the PIN */
+);
+#endif
+
+
+/* C_SetPIN modifies the PIN of the user who is logged in. */
+CK_PKCS11_FUNCTION_INFO(C_SetPIN)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_UTF8CHAR_PTR pOldPin, /* the old PIN */
+ CK_ULONG ulOldLen, /* length of the old PIN */
+ CK_UTF8CHAR_PTR pNewPin, /* the new PIN */
+ CK_ULONG ulNewLen /* length of the new PIN */
+);
+#endif
+
+
+
+/* Session management */
+
+/* C_OpenSession opens a session between an application and a
+ * token. */
+CK_PKCS11_FUNCTION_INFO(C_OpenSession)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* the slot's ID */
+ CK_FLAGS flags, /* from CK_SESSION_INFO */
+ CK_VOID_PTR pApplication, /* passed to callback */
+ CK_NOTIFY Notify, /* callback function */
+ CK_SESSION_HANDLE_PTR phSession /* gets session handle */
+);
+#endif
+
+
+/* C_CloseSession closes a session between an application and a
+ * token. */
+CK_PKCS11_FUNCTION_INFO(C_CloseSession)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+/* C_CloseAllSessions closes all sessions with a token. */
+CK_PKCS11_FUNCTION_INFO(C_CloseAllSessions)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID /* the token's slot */
+);
+#endif
+
+
+/* C_GetSessionInfo obtains information about the session. */
+CK_PKCS11_FUNCTION_INFO(C_GetSessionInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_SESSION_INFO_PTR pInfo /* receives session info */
+);
+#endif
+
+
+/* C_GetOperationState obtains the state of the cryptographic operation
+ * in a session. */
+CK_PKCS11_FUNCTION_INFO(C_GetOperationState)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pOperationState, /* gets state */
+ CK_ULONG_PTR pulOperationStateLen /* gets state length */
+);
+#endif
+
+
+/* C_SetOperationState restores the state of the cryptographic
+ * operation in a session. */
+CK_PKCS11_FUNCTION_INFO(C_SetOperationState)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pOperationState, /* holds state */
+ CK_ULONG ulOperationStateLen, /* holds state length */
+ CK_OBJECT_HANDLE hEncryptionKey, /* en/decryption key */
+ CK_OBJECT_HANDLE hAuthenticationKey /* sign/verify key */
+);
+#endif
+
+
+/* C_Login logs a user into a token. */
+CK_PKCS11_FUNCTION_INFO(C_Login)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_USER_TYPE userType, /* the user type */
+ CK_UTF8CHAR_PTR pPin, /* the user's PIN */
+ CK_ULONG ulPinLen /* the length of the PIN */
+);
+#endif
+
+
+/* C_Logout logs a user out from a token. */
+CK_PKCS11_FUNCTION_INFO(C_Logout)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+
+/* Object management */
+
+/* C_CreateObject creates a new object. */
+CK_PKCS11_FUNCTION_INFO(C_CreateObject)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* the object's template */
+ CK_ULONG ulCount, /* attributes in template */
+ CK_OBJECT_HANDLE_PTR phObject /* gets new object's handle. */
+);
+#endif
+
+
+/* C_CopyObject copies an object, creating a new object for the
+ * copy. */
+CK_PKCS11_FUNCTION_INFO(C_CopyObject)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject, /* the object's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* template for new object */
+ CK_ULONG ulCount, /* attributes in template */
+ CK_OBJECT_HANDLE_PTR phNewObject /* receives handle of copy */
+);
+#endif
+
+
+/* C_DestroyObject destroys an object. */
+CK_PKCS11_FUNCTION_INFO(C_DestroyObject)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject /* the object's handle */
+);
+#endif
+
+
+/* C_GetObjectSize gets the size of an object in bytes. */
+CK_PKCS11_FUNCTION_INFO(C_GetObjectSize)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject, /* the object's handle */
+ CK_ULONG_PTR pulSize /* receives size of object */
+);
+#endif
+
+
+/* C_GetAttributeValue obtains the value of one or more object
+ * attributes. */
+CK_PKCS11_FUNCTION_INFO(C_GetAttributeValue)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject, /* the object's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* specifies attrs; gets vals */
+ CK_ULONG ulCount /* attributes in template */
+);
+#endif
+
+
+/* C_SetAttributeValue modifies the value of one or more object
+ * attributes */
+CK_PKCS11_FUNCTION_INFO(C_SetAttributeValue)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject, /* the object's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* specifies attrs and values */
+ CK_ULONG ulCount /* attributes in template */
+);
+#endif
+
+
+/* C_FindObjectsInit initializes a search for token and session
+ * objects that match a template. */
+CK_PKCS11_FUNCTION_INFO(C_FindObjectsInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* attribute values to match */
+ CK_ULONG ulCount /* attrs in search template */
+);
+#endif
+
+
+/* C_FindObjects continues a search for token and session
+ * objects that match a template, obtaining additional object
+ * handles. */
+CK_PKCS11_FUNCTION_INFO(C_FindObjects)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_OBJECT_HANDLE_PTR phObject, /* gets obj. handles */
+ CK_ULONG ulMaxObjectCount, /* max handles to get */
+ CK_ULONG_PTR pulObjectCount /* actual # returned */
+);
+#endif
+
+
+/* C_FindObjectsFinal finishes a search for token and session
+ * objects. */
+CK_PKCS11_FUNCTION_INFO(C_FindObjectsFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+
+/* Encryption and decryption */
+
+/* C_EncryptInit initializes an encryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_EncryptInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the encryption mechanism */
+ CK_OBJECT_HANDLE hKey /* handle of encryption key */
+);
+#endif
+
+
+/* C_Encrypt encrypts single-part data. */
+CK_PKCS11_FUNCTION_INFO(C_Encrypt)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pData, /* the plaintext data */
+ CK_ULONG ulDataLen, /* bytes of plaintext */
+ CK_BYTE_PTR pEncryptedData, /* gets ciphertext */
+ CK_ULONG_PTR pulEncryptedDataLen /* gets c-text size */
+);
+#endif
+
+
+/* C_EncryptUpdate continues a multiple-part encryption
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_EncryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pPart, /* the plaintext data */
+ CK_ULONG ulPartLen, /* plaintext data len */
+ CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */
+ CK_ULONG_PTR pulEncryptedPartLen /* gets c-text size */
+);
+#endif
+
+
+/* C_EncryptFinal finishes a multiple-part encryption
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_EncryptFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session handle */
+ CK_BYTE_PTR pLastEncryptedPart, /* last c-text */
+ CK_ULONG_PTR pulLastEncryptedPartLen /* gets last size */
+);
+#endif
+
+
+/* C_DecryptInit initializes a decryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the decryption mechanism */
+ CK_OBJECT_HANDLE hKey /* handle of decryption key */
+);
+#endif
+
+
+/* C_Decrypt decrypts encrypted data in a single part. */
+CK_PKCS11_FUNCTION_INFO(C_Decrypt)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pEncryptedData, /* ciphertext */
+ CK_ULONG ulEncryptedDataLen, /* ciphertext length */
+ CK_BYTE_PTR pData, /* gets plaintext */
+ CK_ULONG_PTR pulDataLen /* gets p-text size */
+);
+#endif
+
+
+/* C_DecryptUpdate continues a multiple-part decryption
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pEncryptedPart, /* encrypted data */
+ CK_ULONG ulEncryptedPartLen, /* input length */
+ CK_BYTE_PTR pPart, /* gets plaintext */
+ CK_ULONG_PTR pulPartLen /* p-text size */
+);
+#endif
+
+
+/* C_DecryptFinal finishes a multiple-part decryption
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pLastPart, /* gets plaintext */
+ CK_ULONG_PTR pulLastPartLen /* p-text size */
+);
+#endif
+
+
+
+/* Message digesting */
+
+/* C_DigestInit initializes a message-digesting operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism /* the digesting mechanism */
+);
+#endif
+
+
+/* C_Digest digests data in a single part. */
+CK_PKCS11_FUNCTION_INFO(C_Digest)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pData, /* data to be digested */
+ CK_ULONG ulDataLen, /* bytes of data to digest */
+ CK_BYTE_PTR pDigest, /* gets the message digest */
+ CK_ULONG_PTR pulDigestLen /* gets digest length */
+);
+#endif
+
+
+/* C_DigestUpdate continues a multiple-part message-digesting
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pPart, /* data to be digested */
+ CK_ULONG ulPartLen /* bytes of data to be digested */
+);
+#endif
+
+
+/* C_DigestKey continues a multi-part message-digesting
+ * operation, by digesting the value of a secret key as part of
+ * the data already digested. */
+CK_PKCS11_FUNCTION_INFO(C_DigestKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hKey /* secret key to digest */
+);
+#endif
+
+
+/* C_DigestFinal finishes a multiple-part message-digesting
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pDigest, /* gets the message digest */
+ CK_ULONG_PTR pulDigestLen /* gets byte count of digest */
+);
+#endif
+
+
+
+/* Signing and MACing */
+
+/* C_SignInit initializes a signature (private key encryption)
+ * operation, where the signature is (will be) an appendix to
+ * the data, and plaintext cannot be recovered from the
+ *signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the signature mechanism */
+ CK_OBJECT_HANDLE hKey /* handle of signature key */
+);
+#endif
+
+
+/* C_Sign signs (encrypts with private key) data in a single
+ * part, where the signature is (will be) an appendix to the
+ * data, and plaintext cannot be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_Sign)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pData, /* the data to sign */
+ CK_ULONG ulDataLen, /* count of bytes to sign */
+ CK_BYTE_PTR pSignature, /* gets the signature */
+ CK_ULONG_PTR pulSignatureLen /* gets signature length */
+);
+#endif
+
+
+/* C_SignUpdate continues a multiple-part signature operation,
+ * where the signature is (will be) an appendix to the data,
+ * and plaintext cannot be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pPart, /* the data to sign */
+ CK_ULONG ulPartLen /* count of bytes to sign */
+);
+#endif
+
+
+/* C_SignFinal finishes a multiple-part signature operation,
+ * returning the signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pSignature, /* gets the signature */
+ CK_ULONG_PTR pulSignatureLen /* gets signature length */
+);
+#endif
+
+
+/* C_SignRecoverInit initializes a signature operation, where
+ * the data can be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignRecoverInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the signature mechanism */
+ CK_OBJECT_HANDLE hKey /* handle of the signature key */
+);
+#endif
+
+
+/* C_SignRecover signs data in a single operation, where the
+ * data can be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignRecover)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pData, /* the data to sign */
+ CK_ULONG ulDataLen, /* count of bytes to sign */
+ CK_BYTE_PTR pSignature, /* gets the signature */
+ CK_ULONG_PTR pulSignatureLen /* gets signature length */
+);
+#endif
+
+
+
+/* Verifying signatures and MACs */
+
+/* C_VerifyInit initializes a verification operation, where the
+ * signature is an appendix to the data, and plaintext cannot
+ * cannot be recovered from the signature (e.g. DSA). */
+CK_PKCS11_FUNCTION_INFO(C_VerifyInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the verification mechanism */
+ CK_OBJECT_HANDLE hKey /* verification key */
+);
+#endif
+
+
+/* C_Verify verifies a signature in a single-part operation,
+ * where the signature is an appendix to the data, and plaintext
+ * cannot be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_Verify)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pData, /* signed data */
+ CK_ULONG ulDataLen, /* length of signed data */
+ CK_BYTE_PTR pSignature, /* signature */
+ CK_ULONG ulSignatureLen /* signature length*/
+);
+#endif
+
+
+/* C_VerifyUpdate continues a multiple-part verification
+ * operation, where the signature is an appendix to the data,
+ * and plaintext cannot be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_VerifyUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pPart, /* signed data */
+ CK_ULONG ulPartLen /* length of signed data */
+);
+#endif
+
+
+/* C_VerifyFinal finishes a multiple-part verification
+ * operation, checking the signature. */
+CK_PKCS11_FUNCTION_INFO(C_VerifyFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pSignature, /* signature to verify */
+ CK_ULONG ulSignatureLen /* signature length */
+);
+#endif
+
+
+/* C_VerifyRecoverInit initializes a signature verification
+ * operation, where the data is recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_VerifyRecoverInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the verification mechanism */
+ CK_OBJECT_HANDLE hKey /* verification key */
+);
+#endif
+
+
+/* C_VerifyRecover verifies a signature in a single-part
+ * operation, where the data is recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_VerifyRecover)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pSignature, /* signature to verify */
+ CK_ULONG ulSignatureLen, /* signature length */
+ CK_BYTE_PTR pData, /* gets signed data */
+ CK_ULONG_PTR pulDataLen /* gets signed data len */
+);
+#endif
+
+
+
+/* Dual-function cryptographic operations */
+
+/* C_DigestEncryptUpdate continues a multiple-part digesting
+ * and encryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestEncryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pPart, /* the plaintext data */
+ CK_ULONG ulPartLen, /* plaintext length */
+ CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */
+ CK_ULONG_PTR pulEncryptedPartLen /* gets c-text length */
+);
+#endif
+
+
+/* C_DecryptDigestUpdate continues a multiple-part decryption and
+ * digesting operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptDigestUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pEncryptedPart, /* ciphertext */
+ CK_ULONG ulEncryptedPartLen, /* ciphertext length */
+ CK_BYTE_PTR pPart, /* gets plaintext */
+ CK_ULONG_PTR pulPartLen /* gets plaintext len */
+);
+#endif
+
+
+/* C_SignEncryptUpdate continues a multiple-part signing and
+ * encryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_SignEncryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pPart, /* the plaintext data */
+ CK_ULONG ulPartLen, /* plaintext length */
+ CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */
+ CK_ULONG_PTR pulEncryptedPartLen /* gets c-text length */
+);
+#endif
+
+
+/* C_DecryptVerifyUpdate continues a multiple-part decryption and
+ * verify operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptVerifyUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pEncryptedPart, /* ciphertext */
+ CK_ULONG ulEncryptedPartLen, /* ciphertext length */
+ CK_BYTE_PTR pPart, /* gets plaintext */
+ CK_ULONG_PTR pulPartLen /* gets p-text length */
+);
+#endif
+
+
+
+/* Key management */
+
+/* C_GenerateKey generates a secret key, creating a new key
+ * object. */
+CK_PKCS11_FUNCTION_INFO(C_GenerateKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* key generation mech. */
+ CK_ATTRIBUTE_PTR pTemplate, /* template for new key */
+ CK_ULONG ulCount, /* # of attrs in template */
+ CK_OBJECT_HANDLE_PTR phKey /* gets handle of new key */
+);
+#endif
+
+
+/* C_GenerateKeyPair generates a public-key/private-key pair,
+ * creating new key objects. */
+CK_PKCS11_FUNCTION_INFO(C_GenerateKeyPair)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session
+ * handle */
+ CK_MECHANISM_PTR pMechanism, /* key-gen
+ * mech. */
+ CK_ATTRIBUTE_PTR pPublicKeyTemplate, /* template
+ * for pub.
+ * key */
+ CK_ULONG ulPublicKeyAttributeCount, /* # pub.
+ * attrs. */
+ CK_ATTRIBUTE_PTR pPrivateKeyTemplate, /* template
+ * for priv.
+ * key */
+ CK_ULONG ulPrivateKeyAttributeCount, /* # priv.
+ * attrs. */
+ CK_OBJECT_HANDLE_PTR phPublicKey, /* gets pub.
+ * key
+ * handle */
+ CK_OBJECT_HANDLE_PTR phPrivateKey /* gets
+ * priv. key
+ * handle */
+);
+#endif
+
+
+/* C_WrapKey wraps (i.e., encrypts) a key. */
+CK_PKCS11_FUNCTION_INFO(C_WrapKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the wrapping mechanism */
+ CK_OBJECT_HANDLE hWrappingKey, /* wrapping key */
+ CK_OBJECT_HANDLE hKey, /* key to be wrapped */
+ CK_BYTE_PTR pWrappedKey, /* gets wrapped key */
+ CK_ULONG_PTR pulWrappedKeyLen /* gets wrapped key size */
+);
+#endif
+
+
+/* C_UnwrapKey unwraps (decrypts) a wrapped key, creating a new
+ * key object. */
+CK_PKCS11_FUNCTION_INFO(C_UnwrapKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_MECHANISM_PTR pMechanism, /* unwrapping mech. */
+ CK_OBJECT_HANDLE hUnwrappingKey, /* unwrapping key */
+ CK_BYTE_PTR pWrappedKey, /* the wrapped key */
+ CK_ULONG ulWrappedKeyLen, /* wrapped key len */
+ CK_ATTRIBUTE_PTR pTemplate, /* new key template */
+ CK_ULONG ulAttributeCount, /* template length */
+ CK_OBJECT_HANDLE_PTR phKey /* gets new handle */
+);
+#endif
+
+
+/* C_DeriveKey derives a key from a base key, creating a new key
+ * object. */
+CK_PKCS11_FUNCTION_INFO(C_DeriveKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_MECHANISM_PTR pMechanism, /* key deriv. mech. */
+ CK_OBJECT_HANDLE hBaseKey, /* base key */
+ CK_ATTRIBUTE_PTR pTemplate, /* new key template */
+ CK_ULONG ulAttributeCount, /* template length */
+ CK_OBJECT_HANDLE_PTR phKey /* gets new handle */
+);
+#endif
+
+
+
+/* Random number generation */
+
+/* C_SeedRandom mixes additional seed material into the token's
+ * random number generator. */
+CK_PKCS11_FUNCTION_INFO(C_SeedRandom)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pSeed, /* the seed material */
+ CK_ULONG ulSeedLen /* length of seed material */
+);
+#endif
+
+
+/* C_GenerateRandom generates random data. */
+CK_PKCS11_FUNCTION_INFO(C_GenerateRandom)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR RandomData, /* receives the random data */
+ CK_ULONG ulRandomLen /* # of bytes to generate */
+);
+#endif
+
+
+
+/* Parallel function management */
+
+/* C_GetFunctionStatus is a legacy function; it obtains an
+ * updated status of a function running in parallel with an
+ * application. */
+CK_PKCS11_FUNCTION_INFO(C_GetFunctionStatus)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+/* C_CancelFunction is a legacy function; it cancels a function
+ * running in parallel. */
+CK_PKCS11_FUNCTION_INFO(C_CancelFunction)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+
+/* Functions added in for Cryptoki Version 2.01 or later */
+
+/* C_WaitForSlotEvent waits for a slot event (token insertion,
+ * removal, etc.) to occur. */
+CK_PKCS11_FUNCTION_INFO(C_WaitForSlotEvent)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_FLAGS flags, /* blocking/nonblocking flag */
+ CK_SLOT_ID_PTR pSlot, /* location that receives the slot ID */
+ CK_VOID_PTR pRserved /* reserved. Should be NULL_PTR */
+);
+#endif
diff --git a/src/pluto/rsaref/pkcs11t.h b/src/pluto/rsaref/pkcs11t.h
new file mode 100644
index 000000000..3da20b215
--- /dev/null
+++ b/src/pluto/rsaref/pkcs11t.h
@@ -0,0 +1,1685 @@
+/* pkcs11t.h include file for PKCS #11. */
+/* $Revision: 1.2 $ */
+
+/* License to copy and use this software is granted provided that it is
+ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
+ * (Cryptoki)" in all material mentioning or referencing this software.
+
+ * License is also granted to make and use derivative works provided that
+ * such works are identified as "derived from the RSA Security Inc. PKCS #11
+ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or
+ * referencing the derived work.
+
+ * RSA Security Inc. makes no representations concerning either the
+ * merchantability of this software or the suitability of this software for
+ * any particular purpose. It is provided "as is" without express or implied
+ * warranty of any kind.
+ */
+
+/* See top of pkcs11.h for information about the macros that
+ * must be defined and the structure-packing conventions that
+ * must be set before including this file. */
+
+#ifndef _PKCS11T_H_
+#define _PKCS11T_H_ 1
+
+#define CK_TRUE 1
+#define CK_FALSE 0
+
+#ifndef CK_DISABLE_TRUE_FALSE
+#ifndef FALSE
+#define FALSE CK_FALSE
+#endif
+
+#ifndef TRUE
+#define TRUE CK_TRUE
+#endif
+#endif
+
+/* an unsigned 8-bit value */
+typedef unsigned char CK_BYTE;
+
+/* an unsigned 8-bit character */
+typedef CK_BYTE CK_CHAR;
+
+/* an 8-bit UTF-8 character */
+typedef CK_BYTE CK_UTF8CHAR;
+
+/* a BYTE-sized Boolean flag */
+typedef CK_BYTE CK_BBOOL;
+
+/* an unsigned value, at least 32 bits long */
+typedef unsigned long int CK_ULONG;
+
+/* a signed value, the same size as a CK_ULONG */
+/* CK_LONG is new for v2.0 */
+typedef long int CK_LONG;
+
+/* at least 32 bits; each bit is a Boolean flag */
+typedef CK_ULONG CK_FLAGS;
+
+
+/* some special values for certain CK_ULONG variables */
+#define CK_UNAVAILABLE_INFORMATION (~0UL)
+#define CK_EFFECTIVELY_INFINITE 0
+
+
+typedef CK_BYTE CK_PTR CK_BYTE_PTR;
+typedef CK_CHAR CK_PTR CK_CHAR_PTR;
+typedef CK_UTF8CHAR CK_PTR CK_UTF8CHAR_PTR;
+typedef CK_ULONG CK_PTR CK_ULONG_PTR;
+typedef void CK_PTR CK_VOID_PTR;
+
+/* Pointer to a CK_VOID_PTR-- i.e., pointer to pointer to void */
+typedef CK_VOID_PTR CK_PTR CK_VOID_PTR_PTR;
+
+
+/* The following value is always invalid if used as a session */
+/* handle or object handle */
+#define CK_INVALID_HANDLE 0
+
+
+typedef struct CK_VERSION {
+ CK_BYTE major; /* integer portion of version number */
+ CK_BYTE minor; /* 1/100ths portion of version number */
+} CK_VERSION;
+
+typedef CK_VERSION CK_PTR CK_VERSION_PTR;
+
+
+typedef struct CK_INFO {
+ /* manufacturerID and libraryDecription have been changed from
+ * CK_CHAR to CK_UTF8CHAR for v2.10 */
+ CK_VERSION cryptokiVersion; /* Cryptoki interface ver */
+ CK_UTF8CHAR manufacturerID[32]; /* blank padded */
+ CK_FLAGS flags; /* must be zero */
+
+ /* libraryDescription and libraryVersion are new for v2.0 */
+ CK_UTF8CHAR libraryDescription[32]; /* blank padded */
+ CK_VERSION libraryVersion; /* version of library */
+} CK_INFO;
+
+typedef CK_INFO CK_PTR CK_INFO_PTR;
+
+
+/* CK_NOTIFICATION enumerates the types of notifications that
+ * Cryptoki provides to an application */
+/* CK_NOTIFICATION has been changed from an enum to a CK_ULONG
+ * for v2.0 */
+typedef CK_ULONG CK_NOTIFICATION;
+#define CKN_SURRENDER 0
+
+
+typedef CK_ULONG CK_SLOT_ID;
+
+typedef CK_SLOT_ID CK_PTR CK_SLOT_ID_PTR;
+
+
+/* CK_SLOT_INFO provides information about a slot */
+typedef struct CK_SLOT_INFO {
+ /* slotDescription and manufacturerID have been changed from
+ * CK_CHAR to CK_UTF8CHAR for v2.10 */
+ CK_UTF8CHAR slotDescription[64]; /* blank padded */
+ CK_UTF8CHAR manufacturerID[32]; /* blank padded */
+ CK_FLAGS flags;
+
+ /* hardwareVersion and firmwareVersion are new for v2.0 */
+ CK_VERSION hardwareVersion; /* version of hardware */
+ CK_VERSION firmwareVersion; /* version of firmware */
+} CK_SLOT_INFO;
+
+/* flags: bit flags that provide capabilities of the slot
+ * Bit Flag Mask Meaning
+ */
+#define CKF_TOKEN_PRESENT 0x00000001 /* a token is there */
+#define CKF_REMOVABLE_DEVICE 0x00000002 /* removable devices*/
+#define CKF_HW_SLOT 0x00000004 /* hardware slot */
+
+typedef CK_SLOT_INFO CK_PTR CK_SLOT_INFO_PTR;
+
+
+/* CK_TOKEN_INFO provides information about a token */
+typedef struct CK_TOKEN_INFO {
+ /* label, manufacturerID, and model have been changed from
+ * CK_CHAR to CK_UTF8CHAR for v2.10 */
+ CK_UTF8CHAR label[32]; /* blank padded */
+ CK_UTF8CHAR manufacturerID[32]; /* blank padded */
+ CK_UTF8CHAR model[16]; /* blank padded */
+ CK_CHAR serialNumber[16]; /* blank padded */
+ CK_FLAGS flags; /* see below */
+
+ /* ulMaxSessionCount, ulSessionCount, ulMaxRwSessionCount,
+ * ulRwSessionCount, ulMaxPinLen, and ulMinPinLen have all been
+ * changed from CK_USHORT to CK_ULONG for v2.0 */
+ CK_ULONG ulMaxSessionCount; /* max open sessions */
+ CK_ULONG ulSessionCount; /* sess. now open */
+ CK_ULONG ulMaxRwSessionCount; /* max R/W sessions */
+ CK_ULONG ulRwSessionCount; /* R/W sess. now open */
+ CK_ULONG ulMaxPinLen; /* in bytes */
+ CK_ULONG ulMinPinLen; /* in bytes */
+ CK_ULONG ulTotalPublicMemory; /* in bytes */
+ CK_ULONG ulFreePublicMemory; /* in bytes */
+ CK_ULONG ulTotalPrivateMemory; /* in bytes */
+ CK_ULONG ulFreePrivateMemory; /* in bytes */
+
+ /* hardwareVersion, firmwareVersion, and time are new for
+ * v2.0 */
+ CK_VERSION hardwareVersion; /* version of hardware */
+ CK_VERSION firmwareVersion; /* version of firmware */
+ CK_CHAR utcTime[16]; /* time */
+} CK_TOKEN_INFO;
+
+/* The flags parameter is defined as follows:
+ * Bit Flag Mask Meaning
+ */
+#define CKF_RNG 0x00000001 /* has random #
+ * generator */
+#define CKF_WRITE_PROTECTED 0x00000002 /* token is
+ * write-
+ * protected */
+#define CKF_LOGIN_REQUIRED 0x00000004 /* user must
+ * login */
+#define CKF_USER_PIN_INITIALIZED 0x00000008 /* normal user's
+ * PIN is set */
+
+/* CKF_RESTORE_KEY_NOT_NEEDED is new for v2.0. If it is set,
+ * that means that *every* time the state of cryptographic
+ * operations of a session is successfully saved, all keys
+ * needed to continue those operations are stored in the state */
+#define CKF_RESTORE_KEY_NOT_NEEDED 0x00000020
+
+/* CKF_CLOCK_ON_TOKEN is new for v2.0. If it is set, that means
+ * that the token has some sort of clock. The time on that
+ * clock is returned in the token info structure */
+#define CKF_CLOCK_ON_TOKEN 0x00000040
+
+/* CKF_PROTECTED_AUTHENTICATION_PATH is new for v2.0. If it is
+ * set, that means that there is some way for the user to login
+ * without sending a PIN through the Cryptoki library itself */
+#define CKF_PROTECTED_AUTHENTICATION_PATH 0x00000100
+
+/* CKF_DUAL_CRYPTO_OPERATIONS is new for v2.0. If it is true,
+ * that means that a single session with the token can perform
+ * dual simultaneous cryptographic operations (digest and
+ * encrypt; decrypt and digest; sign and encrypt; and decrypt
+ * and sign) */
+#define CKF_DUAL_CRYPTO_OPERATIONS 0x00000200
+
+/* CKF_TOKEN_INITIALIZED if new for v2.10. If it is true, the
+ * token has been initialized using C_InitializeToken or an
+ * equivalent mechanism outside the scope of PKCS #11.
+ * Calling C_InitializeToken when this flag is set will cause
+ * the token to be reinitialized. */
+#define CKF_TOKEN_INITIALIZED 0x00000400
+
+/* CKF_SECONDARY_AUTHENTICATION if new for v2.10. If it is
+ * true, the token supports secondary authentication for
+ * private key objects. This flag is deprecated in v2.11 and
+ onwards. */
+#define CKF_SECONDARY_AUTHENTICATION 0x00000800
+
+/* CKF_USER_PIN_COUNT_LOW if new for v2.10. If it is true, an
+ * incorrect user login PIN has been entered at least once
+ * since the last successful authentication. */
+#define CKF_USER_PIN_COUNT_LOW 0x00010000
+
+/* CKF_USER_PIN_FINAL_TRY if new for v2.10. If it is true,
+ * supplying an incorrect user PIN will it to become locked. */
+#define CKF_USER_PIN_FINAL_TRY 0x00020000
+
+/* CKF_USER_PIN_LOCKED if new for v2.10. If it is true, the
+ * user PIN has been locked. User login to the token is not
+ * possible. */
+#define CKF_USER_PIN_LOCKED 0x00040000
+
+/* CKF_USER_PIN_TO_BE_CHANGED if new for v2.10. If it is true,
+ * the user PIN value is the default value set by token
+ * initialization or manufacturing, or the PIN has been
+ * expired by the card. */
+#define CKF_USER_PIN_TO_BE_CHANGED 0x00080000
+
+/* CKF_SO_PIN_COUNT_LOW if new for v2.10. If it is true, an
+ * incorrect SO login PIN has been entered at least once since
+ * the last successful authentication. */
+#define CKF_SO_PIN_COUNT_LOW 0x00100000
+
+/* CKF_SO_PIN_FINAL_TRY if new for v2.10. If it is true,
+ * supplying an incorrect SO PIN will it to become locked. */
+#define CKF_SO_PIN_FINAL_TRY 0x00200000
+
+/* CKF_SO_PIN_LOCKED if new for v2.10. If it is true, the SO
+ * PIN has been locked. SO login to the token is not possible.
+ */
+#define CKF_SO_PIN_LOCKED 0x00400000
+
+/* CKF_SO_PIN_TO_BE_CHANGED if new for v2.10. If it is true,
+ * the SO PIN value is the default value set by token
+ * initialization or manufacturing, or the PIN has been
+ * expired by the card. */
+#define CKF_SO_PIN_TO_BE_CHANGED 0x00800000
+
+typedef CK_TOKEN_INFO CK_PTR CK_TOKEN_INFO_PTR;
+
+
+/* CK_SESSION_HANDLE is a Cryptoki-assigned value that
+ * identifies a session */
+typedef CK_ULONG CK_SESSION_HANDLE;
+
+typedef CK_SESSION_HANDLE CK_PTR CK_SESSION_HANDLE_PTR;
+
+
+/* CK_USER_TYPE enumerates the types of Cryptoki users */
+/* CK_USER_TYPE has been changed from an enum to a CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG CK_USER_TYPE;
+/* Security Officer */
+#define CKU_SO 0
+/* Normal user */
+#define CKU_USER 1
+/* Context specific (added in v2.20) */
+#define CKU_CONTEXT_SPECIFIC 2
+
+/* CK_STATE enumerates the session states */
+/* CK_STATE has been changed from an enum to a CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG CK_STATE;
+#define CKS_RO_PUBLIC_SESSION 0
+#define CKS_RO_USER_FUNCTIONS 1
+#define CKS_RW_PUBLIC_SESSION 2
+#define CKS_RW_USER_FUNCTIONS 3
+#define CKS_RW_SO_FUNCTIONS 4
+
+
+/* CK_SESSION_INFO provides information about a session */
+typedef struct CK_SESSION_INFO {
+ CK_SLOT_ID slotID;
+ CK_STATE state;
+ CK_FLAGS flags; /* see below */
+
+ /* ulDeviceError was changed from CK_USHORT to CK_ULONG for
+ * v2.0 */
+ CK_ULONG ulDeviceError; /* device-dependent error code */
+} CK_SESSION_INFO;
+
+/* The flags are defined in the following table:
+ * Bit Flag Mask Meaning
+ */
+#define CKF_RW_SESSION 0x00000002 /* session is r/w */
+#define CKF_SERIAL_SESSION 0x00000004 /* no parallel */
+
+typedef CK_SESSION_INFO CK_PTR CK_SESSION_INFO_PTR;
+
+
+/* CK_OBJECT_HANDLE is a token-specific identifier for an
+ * object */
+typedef CK_ULONG CK_OBJECT_HANDLE;
+
+typedef CK_OBJECT_HANDLE CK_PTR CK_OBJECT_HANDLE_PTR;
+
+
+/* CK_OBJECT_CLASS is a value that identifies the classes (or
+ * types) of objects that Cryptoki recognizes. It is defined
+ * as follows: */
+/* CK_OBJECT_CLASS was changed from CK_USHORT to CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG CK_OBJECT_CLASS;
+
+/* The following classes of objects are defined: */
+/* CKO_HW_FEATURE is new for v2.10 */
+/* CKO_DOMAIN_PARAMETERS is new for v2.11 */
+/* CKO_MECHANISM is new for v2.20 */
+#define CKO_DATA 0x00000000
+#define CKO_CERTIFICATE 0x00000001
+#define CKO_PUBLIC_KEY 0x00000002
+#define CKO_PRIVATE_KEY 0x00000003
+#define CKO_SECRET_KEY 0x00000004
+#define CKO_HW_FEATURE 0x00000005
+#define CKO_DOMAIN_PARAMETERS 0x00000006
+#define CKO_MECHANISM 0x00000007
+#define CKO_VENDOR_DEFINED 0x80000000
+
+typedef CK_OBJECT_CLASS CK_PTR CK_OBJECT_CLASS_PTR;
+
+/* CK_HW_FEATURE_TYPE is new for v2.10. CK_HW_FEATURE_TYPE is a
+ * value that identifies the hardware feature type of an object
+ * with CK_OBJECT_CLASS equal to CKO_HW_FEATURE. */
+typedef CK_ULONG CK_HW_FEATURE_TYPE;
+
+/* The following hardware feature types are defined */
+/* CKH_USER_INTERFACE is new for v2.20 */
+#define CKH_MONOTONIC_COUNTER 0x00000001
+#define CKH_CLOCK 0x00000002
+#define CKH_USER_INTERFACE 0x00000003
+#define CKH_VENDOR_DEFINED 0x80000000
+
+/* CK_KEY_TYPE is a value that identifies a key type */
+/* CK_KEY_TYPE was changed from CK_USHORT to CK_ULONG for v2.0 */
+typedef CK_ULONG CK_KEY_TYPE;
+
+/* the following key types are defined: */
+#define CKK_RSA 0x00000000
+#define CKK_DSA 0x00000001
+#define CKK_DH 0x00000002
+
+/* CKK_ECDSA and CKK_KEA are new for v2.0 */
+/* CKK_ECDSA is deprecated in v2.11, CKK_EC is preferred. */
+#define CKK_ECDSA 0x00000003
+#define CKK_EC 0x00000003
+#define CKK_X9_42_DH 0x00000004
+#define CKK_KEA 0x00000005
+
+#define CKK_GENERIC_SECRET 0x00000010
+#define CKK_RC2 0x00000011
+#define CKK_RC4 0x00000012
+#define CKK_DES 0x00000013
+#define CKK_DES2 0x00000014
+#define CKK_DES3 0x00000015
+
+/* all these key types are new for v2.0 */
+#define CKK_CAST 0x00000016
+#define CKK_CAST3 0x00000017
+/* CKK_CAST5 is deprecated in v2.11, CKK_CAST128 is preferred. */
+#define CKK_CAST5 0x00000018
+#define CKK_CAST128 0x00000018
+#define CKK_RC5 0x00000019
+#define CKK_IDEA 0x0000001A
+#define CKK_SKIPJACK 0x0000001B
+#define CKK_BATON 0x0000001C
+#define CKK_JUNIPER 0x0000001D
+#define CKK_CDMF 0x0000001E
+#define CKK_AES 0x0000001F
+
+/* BlowFish and TwoFish are new for v2.20 */
+#define CKK_BLOWFISH 0x00000020
+#define CKK_TWOFISH 0x00000021
+
+#define CKK_VENDOR_DEFINED 0x80000000
+
+
+/* CK_CERTIFICATE_TYPE is a value that identifies a certificate
+ * type */
+/* CK_CERTIFICATE_TYPE was changed from CK_USHORT to CK_ULONG
+ * for v2.0 */
+typedef CK_ULONG CK_CERTIFICATE_TYPE;
+
+/* The following certificate types are defined: */
+/* CKC_X_509_ATTR_CERT is new for v2.10 */
+/* CKC_WTLS is new for v2.20 */
+#define CKC_X_509 0x00000000
+#define CKC_X_509_ATTR_CERT 0x00000001
+#define CKC_WTLS 0x00000002
+#define CKC_VENDOR_DEFINED 0x80000000
+
+
+/* CK_ATTRIBUTE_TYPE is a value that identifies an attribute
+ * type */
+/* CK_ATTRIBUTE_TYPE was changed from CK_USHORT to CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG CK_ATTRIBUTE_TYPE;
+
+/* The CKF_ARRAY_ATTRIBUTE flag identifies an attribute which
+ consists of an array of values. */
+#define CKF_ARRAY_ATTRIBUTE 0x40000000
+
+/* The following attribute types are defined: */
+#define CKA_CLASS 0x00000000
+#define CKA_TOKEN 0x00000001
+#define CKA_PRIVATE 0x00000002
+#define CKA_LABEL 0x00000003
+#define CKA_APPLICATION 0x00000010
+#define CKA_VALUE 0x00000011
+
+/* CKA_OBJECT_ID is new for v2.10 */
+#define CKA_OBJECT_ID 0x00000012
+
+#define CKA_CERTIFICATE_TYPE 0x00000080
+#define CKA_ISSUER 0x00000081
+#define CKA_SERIAL_NUMBER 0x00000082
+
+/* CKA_AC_ISSUER, CKA_OWNER, and CKA_ATTR_TYPES are new
+ * for v2.10 */
+#define CKA_AC_ISSUER 0x00000083
+#define CKA_OWNER 0x00000084
+#define CKA_ATTR_TYPES 0x00000085
+
+/* CKA_TRUSTED is new for v2.11 */
+#define CKA_TRUSTED 0x00000086
+
+/* CKA_CERTIFICATE_CATEGORY ...
+ * CKA_CHECK_VALUE are new for v2.20 */
+#define CKA_CERTIFICATE_CATEGORY 0x00000087
+#define CKA_JAVA_MIDP_SECURITY_DOMAIN 0x00000088
+#define CKA_URL 0x00000089
+#define CKA_HASH_OF_SUBJECT_PUBLIC_KEY 0x0000008A
+#define CKA_HASH_OF_ISSUER_PUBLIC_KEY 0x0000008B
+#define CKA_CHECK_VALUE 0x00000090
+
+#define CKA_KEY_TYPE 0x00000100
+#define CKA_SUBJECT 0x00000101
+#define CKA_ID 0x00000102
+#define CKA_SENSITIVE 0x00000103
+#define CKA_ENCRYPT 0x00000104
+#define CKA_DECRYPT 0x00000105
+#define CKA_WRAP 0x00000106
+#define CKA_UNWRAP 0x00000107
+#define CKA_SIGN 0x00000108
+#define CKA_SIGN_RECOVER 0x00000109
+#define CKA_VERIFY 0x0000010A
+#define CKA_VERIFY_RECOVER 0x0000010B
+#define CKA_DERIVE 0x0000010C
+#define CKA_START_DATE 0x00000110
+#define CKA_END_DATE 0x00000111
+#define CKA_MODULUS 0x00000120
+#define CKA_MODULUS_BITS 0x00000121
+#define CKA_PUBLIC_EXPONENT 0x00000122
+#define CKA_PRIVATE_EXPONENT 0x00000123
+#define CKA_PRIME_1 0x00000124
+#define CKA_PRIME_2 0x00000125
+#define CKA_EXPONENT_1 0x00000126
+#define CKA_EXPONENT_2 0x00000127
+#define CKA_COEFFICIENT 0x00000128
+#define CKA_PRIME 0x00000130
+#define CKA_SUBPRIME 0x00000131
+#define CKA_BASE 0x00000132
+
+/* CKA_PRIME_BITS and CKA_SUB_PRIME_BITS are new for v2.11 */
+#define CKA_PRIME_BITS 0x00000133
+#define CKA_SUBPRIME_BITS 0x00000134
+#define CKA_SUB_PRIME_BITS CKA_SUBPRIME_BITS
+/* (To retain backwards-compatibility) */
+
+#define CKA_VALUE_BITS 0x00000160
+#define CKA_VALUE_LEN 0x00000161
+
+/* CKA_EXTRACTABLE, CKA_LOCAL, CKA_NEVER_EXTRACTABLE,
+ * CKA_ALWAYS_SENSITIVE, CKA_MODIFIABLE, CKA_ECDSA_PARAMS,
+ * and CKA_EC_POINT are new for v2.0 */
+#define CKA_EXTRACTABLE 0x00000162
+#define CKA_LOCAL 0x00000163
+#define CKA_NEVER_EXTRACTABLE 0x00000164
+#define CKA_ALWAYS_SENSITIVE 0x00000165
+
+/* CKA_KEY_GEN_MECHANISM is new for v2.11 */
+#define CKA_KEY_GEN_MECHANISM 0x00000166
+
+#define CKA_MODIFIABLE 0x00000170
+
+/* CKA_ECDSA_PARAMS is deprecated in v2.11,
+ * CKA_EC_PARAMS is preferred. */
+#define CKA_ECDSA_PARAMS 0x00000180
+#define CKA_EC_PARAMS 0x00000180
+
+#define CKA_EC_POINT 0x00000181
+
+/* CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS,
+ * are new for v2.10. Deprecated in v2.11 and onwards. */
+#define CKA_SECONDARY_AUTH 0x00000200
+#define CKA_AUTH_PIN_FLAGS 0x00000201
+
+/* CKA_ALWAYS_AUTHENTICATE ...
+ * CKA_UNWRAP_TEMPLATE are new for v2.20 */
+#define CKA_ALWAYS_AUTHENTICATE 0x00000202
+
+#define CKA_WRAP_WITH_TRUSTED 0x00000210
+#define CKA_WRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x00000211)
+#define CKA_UNWRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x00000212)
+
+/* CKA_HW_FEATURE_TYPE, CKA_RESET_ON_INIT, and CKA_HAS_RESET
+ * are new for v2.10 */
+#define CKA_HW_FEATURE_TYPE 0x00000300
+#define CKA_RESET_ON_INIT 0x00000301
+#define CKA_HAS_RESET 0x00000302
+
+/* The following attributes are new for v2.20 */
+#define CKA_PIXEL_X 0x00000400
+#define CKA_PIXEL_Y 0x00000401
+#define CKA_RESOLUTION 0x00000402
+#define CKA_CHAR_ROWS 0x00000403
+#define CKA_CHAR_COLUMNS 0x00000404
+#define CKA_COLOR 0x00000405
+#define CKA_BITS_PER_PIXEL 0x00000406
+#define CKA_CHAR_SETS 0x00000480
+#define CKA_ENCODING_METHODS 0x00000481
+#define CKA_MIME_TYPES 0x00000482
+#define CKA_MECHANISM_TYPE 0x00000500
+#define CKA_REQUIRED_CMS_ATTRIBUTES 0x00000501
+#define CKA_DEFAULT_CMS_ATTRIBUTES 0x00000502
+#define CKA_SUPPORTED_CMS_ATTRIBUTES 0x00000503
+#define CKA_ALLOWED_MECHANISMS (CKF_ARRAY_ATTRIBUTE|0x00000600)
+
+#define CKA_VENDOR_DEFINED 0x80000000
+
+
+/* CK_ATTRIBUTE is a structure that includes the type, length
+ * and value of an attribute */
+typedef struct CK_ATTRIBUTE {
+ CK_ATTRIBUTE_TYPE type;
+ CK_VOID_PTR pValue;
+
+ /* ulValueLen went from CK_USHORT to CK_ULONG for v2.0 */
+ CK_ULONG ulValueLen; /* in bytes */
+} CK_ATTRIBUTE;
+
+typedef CK_ATTRIBUTE CK_PTR CK_ATTRIBUTE_PTR;
+
+
+/* CK_DATE is a structure that defines a date */
+typedef struct CK_DATE{
+ CK_CHAR year[4]; /* the year ("1900" - "9999") */
+ CK_CHAR month[2]; /* the month ("01" - "12") */
+ CK_CHAR day[2]; /* the day ("01" - "31") */
+} CK_DATE;
+
+
+/* CK_MECHANISM_TYPE is a value that identifies a mechanism
+ * type */
+/* CK_MECHANISM_TYPE was changed from CK_USHORT to CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG CK_MECHANISM_TYPE;
+
+/* the following mechanism types are defined: */
+#define CKM_RSA_PKCS_KEY_PAIR_GEN 0x00000000
+#define CKM_RSA_PKCS 0x00000001
+#define CKM_RSA_9796 0x00000002
+#define CKM_RSA_X_509 0x00000003
+
+/* CKM_MD2_RSA_PKCS, CKM_MD5_RSA_PKCS, and CKM_SHA1_RSA_PKCS
+ * are new for v2.0. They are mechanisms which hash and sign */
+#define CKM_MD2_RSA_PKCS 0x00000004
+#define CKM_MD5_RSA_PKCS 0x00000005
+#define CKM_SHA1_RSA_PKCS 0x00000006
+
+/* CKM_RIPEMD128_RSA_PKCS, CKM_RIPEMD160_RSA_PKCS, and
+ * CKM_RSA_PKCS_OAEP are new for v2.10 */
+#define CKM_RIPEMD128_RSA_PKCS 0x00000007
+#define CKM_RIPEMD160_RSA_PKCS 0x00000008
+#define CKM_RSA_PKCS_OAEP 0x00000009
+
+/* CKM_RSA_X9_31_KEY_PAIR_GEN, CKM_RSA_X9_31, CKM_SHA1_RSA_X9_31,
+ * CKM_RSA_PKCS_PSS, and CKM_SHA1_RSA_PKCS_PSS are new for v2.11 */
+#define CKM_RSA_X9_31_KEY_PAIR_GEN 0x0000000A
+#define CKM_RSA_X9_31 0x0000000B
+#define CKM_SHA1_RSA_X9_31 0x0000000C
+#define CKM_RSA_PKCS_PSS 0x0000000D
+#define CKM_SHA1_RSA_PKCS_PSS 0x0000000E
+
+#define CKM_DSA_KEY_PAIR_GEN 0x00000010
+#define CKM_DSA 0x00000011
+#define CKM_DSA_SHA1 0x00000012
+#define CKM_DH_PKCS_KEY_PAIR_GEN 0x00000020
+#define CKM_DH_PKCS_DERIVE 0x00000021
+
+/* CKM_X9_42_DH_KEY_PAIR_GEN, CKM_X9_42_DH_DERIVE,
+ * CKM_X9_42_DH_HYBRID_DERIVE, and CKM_X9_42_MQV_DERIVE are new for
+ * v2.11 */
+#define CKM_X9_42_DH_KEY_PAIR_GEN 0x00000030
+#define CKM_X9_42_DH_DERIVE 0x00000031
+#define CKM_X9_42_DH_HYBRID_DERIVE 0x00000032
+#define CKM_X9_42_MQV_DERIVE 0x00000033
+
+/* CKM_SHA256/384/512 are new for v2.20 */
+#define CKM_SHA256_RSA_PKCS 0x00000040
+#define CKM_SHA384_RSA_PKCS 0x00000041
+#define CKM_SHA512_RSA_PKCS 0x00000042
+#define CKM_SHA256_RSA_PKCS_PSS 0x00000043
+#define CKM_SHA384_RSA_PKCS_PSS 0x00000044
+#define CKM_SHA512_RSA_PKCS_PSS 0x00000045
+
+#define CKM_RC2_KEY_GEN 0x00000100
+#define CKM_RC2_ECB 0x00000101
+#define CKM_RC2_CBC 0x00000102
+#define CKM_RC2_MAC 0x00000103
+
+/* CKM_RC2_MAC_GENERAL and CKM_RC2_CBC_PAD are new for v2.0 */
+#define CKM_RC2_MAC_GENERAL 0x00000104
+#define CKM_RC2_CBC_PAD 0x00000105
+
+#define CKM_RC4_KEY_GEN 0x00000110
+#define CKM_RC4 0x00000111
+#define CKM_DES_KEY_GEN 0x00000120
+#define CKM_DES_ECB 0x00000121
+#define CKM_DES_CBC 0x00000122
+#define CKM_DES_MAC 0x00000123
+
+/* CKM_DES_MAC_GENERAL and CKM_DES_CBC_PAD are new for v2.0 */
+#define CKM_DES_MAC_GENERAL 0x00000124
+#define CKM_DES_CBC_PAD 0x00000125
+
+#define CKM_DES2_KEY_GEN 0x00000130
+#define CKM_DES3_KEY_GEN 0x00000131
+#define CKM_DES3_ECB 0x00000132
+#define CKM_DES3_CBC 0x00000133
+#define CKM_DES3_MAC 0x00000134
+
+/* CKM_DES3_MAC_GENERAL, CKM_DES3_CBC_PAD, CKM_CDMF_KEY_GEN,
+ * CKM_CDMF_ECB, CKM_CDMF_CBC, CKM_CDMF_MAC,
+ * CKM_CDMF_MAC_GENERAL, and CKM_CDMF_CBC_PAD are new for v2.0 */
+#define CKM_DES3_MAC_GENERAL 0x00000135
+#define CKM_DES3_CBC_PAD 0x00000136
+#define CKM_CDMF_KEY_GEN 0x00000140
+#define CKM_CDMF_ECB 0x00000141
+#define CKM_CDMF_CBC 0x00000142
+#define CKM_CDMF_MAC 0x00000143
+#define CKM_CDMF_MAC_GENERAL 0x00000144
+#define CKM_CDMF_CBC_PAD 0x00000145
+
+/* the following four DES mechanisms are new for v2.20 */
+#define CKM_DES_OFB64 0x00000150
+#define CKM_DES_OFB8 0x00000151
+#define CKM_DES_CFB64 0x00000152
+#define CKM_DES_CFB8 0x00000153
+
+#define CKM_MD2 0x00000200
+
+/* CKM_MD2_HMAC and CKM_MD2_HMAC_GENERAL are new for v2.0 */
+#define CKM_MD2_HMAC 0x00000201
+#define CKM_MD2_HMAC_GENERAL 0x00000202
+
+#define CKM_MD5 0x00000210
+
+/* CKM_MD5_HMAC and CKM_MD5_HMAC_GENERAL are new for v2.0 */
+#define CKM_MD5_HMAC 0x00000211
+#define CKM_MD5_HMAC_GENERAL 0x00000212
+
+#define CKM_SHA_1 0x00000220
+
+/* CKM_SHA_1_HMAC and CKM_SHA_1_HMAC_GENERAL are new for v2.0 */
+#define CKM_SHA_1_HMAC 0x00000221
+#define CKM_SHA_1_HMAC_GENERAL 0x00000222
+
+/* CKM_RIPEMD128, CKM_RIPEMD128_HMAC,
+ * CKM_RIPEMD128_HMAC_GENERAL, CKM_RIPEMD160, CKM_RIPEMD160_HMAC,
+ * and CKM_RIPEMD160_HMAC_GENERAL are new for v2.10 */
+#define CKM_RIPEMD128 0x00000230
+#define CKM_RIPEMD128_HMAC 0x00000231
+#define CKM_RIPEMD128_HMAC_GENERAL 0x00000232
+#define CKM_RIPEMD160 0x00000240
+#define CKM_RIPEMD160_HMAC 0x00000241
+#define CKM_RIPEMD160_HMAC_GENERAL 0x00000242
+
+/* CKM_SHA256/384/512 are new for v2.20 */
+#define CKM_SHA256 0x00000250
+#define CKM_SHA256_HMAC 0x00000251
+#define CKM_SHA256_HMAC_GENERAL 0x00000252
+#define CKM_SHA384 0x00000260
+#define CKM_SHA384_HMAC 0x00000261
+#define CKM_SHA384_HMAC_GENERAL 0x00000262
+#define CKM_SHA512 0x00000270
+#define CKM_SHA512_HMAC 0x00000271
+#define CKM_SHA512_HMAC_GENERAL 0x00000272
+
+/* All of the following mechanisms are new for v2.0 */
+/* Note that CAST128 and CAST5 are the same algorithm */
+#define CKM_CAST_KEY_GEN 0x00000300
+#define CKM_CAST_ECB 0x00000301
+#define CKM_CAST_CBC 0x00000302
+#define CKM_CAST_MAC 0x00000303
+#define CKM_CAST_MAC_GENERAL 0x00000304
+#define CKM_CAST_CBC_PAD 0x00000305
+#define CKM_CAST3_KEY_GEN 0x00000310
+#define CKM_CAST3_ECB 0x00000311
+#define CKM_CAST3_CBC 0x00000312
+#define CKM_CAST3_MAC 0x00000313
+#define CKM_CAST3_MAC_GENERAL 0x00000314
+#define CKM_CAST3_CBC_PAD 0x00000315
+#define CKM_CAST5_KEY_GEN 0x00000320
+#define CKM_CAST128_KEY_GEN 0x00000320
+#define CKM_CAST5_ECB 0x00000321
+#define CKM_CAST128_ECB 0x00000321
+#define CKM_CAST5_CBC 0x00000322
+#define CKM_CAST128_CBC 0x00000322
+#define CKM_CAST5_MAC 0x00000323
+#define CKM_CAST128_MAC 0x00000323
+#define CKM_CAST5_MAC_GENERAL 0x00000324
+#define CKM_CAST128_MAC_GENERAL 0x00000324
+#define CKM_CAST5_CBC_PAD 0x00000325
+#define CKM_CAST128_CBC_PAD 0x00000325
+#define CKM_RC5_KEY_GEN 0x00000330
+#define CKM_RC5_ECB 0x00000331
+#define CKM_RC5_CBC 0x00000332
+#define CKM_RC5_MAC 0x00000333
+#define CKM_RC5_MAC_GENERAL 0x00000334
+#define CKM_RC5_CBC_PAD 0x00000335
+#define CKM_IDEA_KEY_GEN 0x00000340
+#define CKM_IDEA_ECB 0x00000341
+#define CKM_IDEA_CBC 0x00000342
+#define CKM_IDEA_MAC 0x00000343
+#define CKM_IDEA_MAC_GENERAL 0x00000344
+#define CKM_IDEA_CBC_PAD 0x00000345
+#define CKM_GENERIC_SECRET_KEY_GEN 0x00000350
+#define CKM_CONCATENATE_BASE_AND_KEY 0x00000360
+#define CKM_CONCATENATE_BASE_AND_DATA 0x00000362
+#define CKM_CONCATENATE_DATA_AND_BASE 0x00000363
+#define CKM_XOR_BASE_AND_DATA 0x00000364
+#define CKM_EXTRACT_KEY_FROM_KEY 0x00000365
+#define CKM_SSL3_PRE_MASTER_KEY_GEN 0x00000370
+#define CKM_SSL3_MASTER_KEY_DERIVE 0x00000371
+#define CKM_SSL3_KEY_AND_MAC_DERIVE 0x00000372
+
+/* CKM_SSL3_MASTER_KEY_DERIVE_DH, CKM_TLS_PRE_MASTER_KEY_GEN,
+ * CKM_TLS_MASTER_KEY_DERIVE, CKM_TLS_KEY_AND_MAC_DERIVE, and
+ * CKM_TLS_MASTER_KEY_DERIVE_DH are new for v2.11 */
+#define CKM_SSL3_MASTER_KEY_DERIVE_DH 0x00000373
+#define CKM_TLS_PRE_MASTER_KEY_GEN 0x00000374
+#define CKM_TLS_MASTER_KEY_DERIVE 0x00000375
+#define CKM_TLS_KEY_AND_MAC_DERIVE 0x00000376
+#define CKM_TLS_MASTER_KEY_DERIVE_DH 0x00000377
+
+/* CKM_TLS_PRF is new for v2.20 */
+#define CKM_TLS_PRF 0x00000378
+
+#define CKM_SSL3_MD5_MAC 0x00000380
+#define CKM_SSL3_SHA1_MAC 0x00000381
+#define CKM_MD5_KEY_DERIVATION 0x00000390
+#define CKM_MD2_KEY_DERIVATION 0x00000391
+#define CKM_SHA1_KEY_DERIVATION 0x00000392
+
+/* CKM_SHA256/384/512 are new for v2.20 */
+#define CKM_SHA256_KEY_DERIVATION 0x00000393
+#define CKM_SHA384_KEY_DERIVATION 0x00000394
+#define CKM_SHA512_KEY_DERIVATION 0x00000395
+
+#define CKM_PBE_MD2_DES_CBC 0x000003A0
+#define CKM_PBE_MD5_DES_CBC 0x000003A1
+#define CKM_PBE_MD5_CAST_CBC 0x000003A2
+#define CKM_PBE_MD5_CAST3_CBC 0x000003A3
+#define CKM_PBE_MD5_CAST5_CBC 0x000003A4
+#define CKM_PBE_MD5_CAST128_CBC 0x000003A4
+#define CKM_PBE_SHA1_CAST5_CBC 0x000003A5
+#define CKM_PBE_SHA1_CAST128_CBC 0x000003A5
+#define CKM_PBE_SHA1_RC4_128 0x000003A6
+#define CKM_PBE_SHA1_RC4_40 0x000003A7
+#define CKM_PBE_SHA1_DES3_EDE_CBC 0x000003A8
+#define CKM_PBE_SHA1_DES2_EDE_CBC 0x000003A9
+#define CKM_PBE_SHA1_RC2_128_CBC 0x000003AA
+#define CKM_PBE_SHA1_RC2_40_CBC 0x000003AB
+
+/* CKM_PKCS5_PBKD2 is new for v2.10 */
+#define CKM_PKCS5_PBKD2 0x000003B0
+
+#define CKM_PBA_SHA1_WITH_SHA1_HMAC 0x000003C0
+
+/* WTLS mechanisms are new for v2.20 */
+#define CKM_WTLS_PRE_MASTER_KEY_GEN 0x000003D0
+#define CKM_WTLS_MASTER_KEY_DERIVE 0x000003D1
+#define CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC 0x000003D2
+#define CKM_WTLS_PRF 0x000003D3
+#define CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE 0x000003D4
+#define CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE 0x000003D5
+
+#define CKM_KEY_WRAP_LYNKS 0x00000400
+#define CKM_KEY_WRAP_SET_OAEP 0x00000401
+
+/* CKM_CMS_SIG is new for v2.20 */
+#define CKM_CMS_SIG 0x00000500
+
+/* Fortezza mechanisms */
+#define CKM_SKIPJACK_KEY_GEN 0x00001000
+#define CKM_SKIPJACK_ECB64 0x00001001
+#define CKM_SKIPJACK_CBC64 0x00001002
+#define CKM_SKIPJACK_OFB64 0x00001003
+#define CKM_SKIPJACK_CFB64 0x00001004
+#define CKM_SKIPJACK_CFB32 0x00001005
+#define CKM_SKIPJACK_CFB16 0x00001006
+#define CKM_SKIPJACK_CFB8 0x00001007
+#define CKM_SKIPJACK_WRAP 0x00001008
+#define CKM_SKIPJACK_PRIVATE_WRAP 0x00001009
+#define CKM_SKIPJACK_RELAYX 0x0000100a
+#define CKM_KEA_KEY_PAIR_GEN 0x00001010
+#define CKM_KEA_KEY_DERIVE 0x00001011
+#define CKM_FORTEZZA_TIMESTAMP 0x00001020
+#define CKM_BATON_KEY_GEN 0x00001030
+#define CKM_BATON_ECB128 0x00001031
+#define CKM_BATON_ECB96 0x00001032
+#define CKM_BATON_CBC128 0x00001033
+#define CKM_BATON_COUNTER 0x00001034
+#define CKM_BATON_SHUFFLE 0x00001035
+#define CKM_BATON_WRAP 0x00001036
+
+/* CKM_ECDSA_KEY_PAIR_GEN is deprecated in v2.11,
+ * CKM_EC_KEY_PAIR_GEN is preferred */
+#define CKM_ECDSA_KEY_PAIR_GEN 0x00001040
+#define CKM_EC_KEY_PAIR_GEN 0x00001040
+
+#define CKM_ECDSA 0x00001041
+#define CKM_ECDSA_SHA1 0x00001042
+
+/* CKM_ECDH1_DERIVE, CKM_ECDH1_COFACTOR_DERIVE, and CKM_ECMQV_DERIVE
+ * are new for v2.11 */
+#define CKM_ECDH1_DERIVE 0x00001050
+#define CKM_ECDH1_COFACTOR_DERIVE 0x00001051
+#define CKM_ECMQV_DERIVE 0x00001052
+
+#define CKM_JUNIPER_KEY_GEN 0x00001060
+#define CKM_JUNIPER_ECB128 0x00001061
+#define CKM_JUNIPER_CBC128 0x00001062
+#define CKM_JUNIPER_COUNTER 0x00001063
+#define CKM_JUNIPER_SHUFFLE 0x00001064
+#define CKM_JUNIPER_WRAP 0x00001065
+#define CKM_FASTHASH 0x00001070
+
+/* CKM_AES_KEY_GEN, CKM_AES_ECB, CKM_AES_CBC, CKM_AES_MAC,
+ * CKM_AES_MAC_GENERAL, CKM_AES_CBC_PAD, CKM_DSA_PARAMETER_GEN,
+ * CKM_DH_PKCS_PARAMETER_GEN, and CKM_X9_42_DH_PARAMETER_GEN are
+ * new for v2.11 */
+#define CKM_AES_KEY_GEN 0x00001080
+#define CKM_AES_ECB 0x00001081
+#define CKM_AES_CBC 0x00001082
+#define CKM_AES_MAC 0x00001083
+#define CKM_AES_MAC_GENERAL 0x00001084
+#define CKM_AES_CBC_PAD 0x00001085
+
+/* BlowFish and TwoFish are new for v2.20 */
+#define CKM_BLOWFISH_KEY_GEN 0x00001090
+#define CKM_BLOWFISH_CBC 0x00001091
+#define CKM_TWOFISH_KEY_GEN 0x00001092
+#define CKM_TWOFISH_CBC 0x00001093
+
+
+/* CKM_xxx_ENCRYPT_DATA mechanisms are new for v2.20 */
+#define CKM_DES_ECB_ENCRYPT_DATA 0x00001100
+#define CKM_DES_CBC_ENCRYPT_DATA 0x00001101
+#define CKM_DES3_ECB_ENCRYPT_DATA 0x00001102
+#define CKM_DES3_CBC_ENCRYPT_DATA 0x00001103
+#define CKM_AES_ECB_ENCRYPT_DATA 0x00001104
+#define CKM_AES_CBC_ENCRYPT_DATA 0x00001105
+
+#define CKM_DSA_PARAMETER_GEN 0x00002000
+#define CKM_DH_PKCS_PARAMETER_GEN 0x00002001
+#define CKM_X9_42_DH_PARAMETER_GEN 0x00002002
+
+#define CKM_VENDOR_DEFINED 0x80000000
+
+typedef CK_MECHANISM_TYPE CK_PTR CK_MECHANISM_TYPE_PTR;
+
+
+/* CK_MECHANISM is a structure that specifies a particular
+ * mechanism */
+typedef struct CK_MECHANISM {
+ CK_MECHANISM_TYPE mechanism;
+ CK_VOID_PTR pParameter;
+
+ /* ulParameterLen was changed from CK_USHORT to CK_ULONG for
+ * v2.0 */
+ CK_ULONG ulParameterLen; /* in bytes */
+} CK_MECHANISM;
+
+typedef CK_MECHANISM CK_PTR CK_MECHANISM_PTR;
+
+
+/* CK_MECHANISM_INFO provides information about a particular
+ * mechanism */
+typedef struct CK_MECHANISM_INFO {
+ CK_ULONG ulMinKeySize;
+ CK_ULONG ulMaxKeySize;
+ CK_FLAGS flags;
+} CK_MECHANISM_INFO;
+
+/* The flags are defined as follows:
+ * Bit Flag Mask Meaning */
+#define CKF_HW 0x00000001 /* performed by HW */
+
+/* The flags CKF_ENCRYPT, CKF_DECRYPT, CKF_DIGEST, CKF_SIGN,
+ * CKG_SIGN_RECOVER, CKF_VERIFY, CKF_VERIFY_RECOVER,
+ * CKF_GENERATE, CKF_GENERATE_KEY_PAIR, CKF_WRAP, CKF_UNWRAP,
+ * and CKF_DERIVE are new for v2.0. They specify whether or not
+ * a mechanism can be used for a particular task */
+#define CKF_ENCRYPT 0x00000100
+#define CKF_DECRYPT 0x00000200
+#define CKF_DIGEST 0x00000400
+#define CKF_SIGN 0x00000800
+#define CKF_SIGN_RECOVER 0x00001000
+#define CKF_VERIFY 0x00002000
+#define CKF_VERIFY_RECOVER 0x00004000
+#define CKF_GENERATE 0x00008000
+#define CKF_GENERATE_KEY_PAIR 0x00010000
+#define CKF_WRAP 0x00020000
+#define CKF_UNWRAP 0x00040000
+#define CKF_DERIVE 0x00080000
+
+/* CKF_EC_F_P, CKF_EC_F_2M, CKF_EC_ECPARAMETERS, CKF_EC_NAMEDCURVE,
+ * CKF_EC_UNCOMPRESS, and CKF_EC_COMPRESS are new for v2.11. They
+ * describe a token's EC capabilities not available in mechanism
+ * information. */
+#define CKF_EC_F_P 0x00100000
+#define CKF_EC_F_2M 0x00200000
+#define CKF_EC_ECPARAMETERS 0x00400000
+#define CKF_EC_NAMEDCURVE 0x00800000
+#define CKF_EC_UNCOMPRESS 0x01000000
+#define CKF_EC_COMPRESS 0x02000000
+
+#define CKF_EXTENSION 0x80000000 /* FALSE for this version */
+
+typedef CK_MECHANISM_INFO CK_PTR CK_MECHANISM_INFO_PTR;
+
+
+/* CK_RV is a value that identifies the return value of a
+ * Cryptoki function */
+/* CK_RV was changed from CK_USHORT to CK_ULONG for v2.0 */
+typedef CK_ULONG CK_RV;
+
+#define CKR_OK 0x00000000
+#define CKR_CANCEL 0x00000001
+#define CKR_HOST_MEMORY 0x00000002
+#define CKR_SLOT_ID_INVALID 0x00000003
+
+/* CKR_FLAGS_INVALID was removed for v2.0 */
+
+/* CKR_GENERAL_ERROR and CKR_FUNCTION_FAILED are new for v2.0 */
+#define CKR_GENERAL_ERROR 0x00000005
+#define CKR_FUNCTION_FAILED 0x00000006
+
+/* CKR_ARGUMENTS_BAD, CKR_NO_EVENT, CKR_NEED_TO_CREATE_THREADS,
+ * and CKR_CANT_LOCK are new for v2.01 */
+#define CKR_ARGUMENTS_BAD 0x00000007
+#define CKR_NO_EVENT 0x00000008
+#define CKR_NEED_TO_CREATE_THREADS 0x00000009
+#define CKR_CANT_LOCK 0x0000000A
+
+#define CKR_ATTRIBUTE_READ_ONLY 0x00000010
+#define CKR_ATTRIBUTE_SENSITIVE 0x00000011
+#define CKR_ATTRIBUTE_TYPE_INVALID 0x00000012
+#define CKR_ATTRIBUTE_VALUE_INVALID 0x00000013
+#define CKR_DATA_INVALID 0x00000020
+#define CKR_DATA_LEN_RANGE 0x00000021
+#define CKR_DEVICE_ERROR 0x00000030
+#define CKR_DEVICE_MEMORY 0x00000031
+#define CKR_DEVICE_REMOVED 0x00000032
+#define CKR_ENCRYPTED_DATA_INVALID 0x00000040
+#define CKR_ENCRYPTED_DATA_LEN_RANGE 0x00000041
+#define CKR_FUNCTION_CANCELED 0x00000050
+#define CKR_FUNCTION_NOT_PARALLEL 0x00000051
+
+/* CKR_FUNCTION_NOT_SUPPORTED is new for v2.0 */
+#define CKR_FUNCTION_NOT_SUPPORTED 0x00000054
+
+#define CKR_KEY_HANDLE_INVALID 0x00000060
+
+/* CKR_KEY_SENSITIVE was removed for v2.0 */
+
+#define CKR_KEY_SIZE_RANGE 0x00000062
+#define CKR_KEY_TYPE_INCONSISTENT 0x00000063
+
+/* CKR_KEY_NOT_NEEDED, CKR_KEY_CHANGED, CKR_KEY_NEEDED,
+ * CKR_KEY_INDIGESTIBLE, CKR_KEY_FUNCTION_NOT_PERMITTED,
+ * CKR_KEY_NOT_WRAPPABLE, and CKR_KEY_UNEXTRACTABLE are new for
+ * v2.0 */
+#define CKR_KEY_NOT_NEEDED 0x00000064
+#define CKR_KEY_CHANGED 0x00000065
+#define CKR_KEY_NEEDED 0x00000066
+#define CKR_KEY_INDIGESTIBLE 0x00000067
+#define CKR_KEY_FUNCTION_NOT_PERMITTED 0x00000068
+#define CKR_KEY_NOT_WRAPPABLE 0x00000069
+#define CKR_KEY_UNEXTRACTABLE 0x0000006A
+
+#define CKR_MECHANISM_INVALID 0x00000070
+#define CKR_MECHANISM_PARAM_INVALID 0x00000071
+
+/* CKR_OBJECT_CLASS_INCONSISTENT and CKR_OBJECT_CLASS_INVALID
+ * were removed for v2.0 */
+#define CKR_OBJECT_HANDLE_INVALID 0x00000082
+#define CKR_OPERATION_ACTIVE 0x00000090
+#define CKR_OPERATION_NOT_INITIALIZED 0x00000091
+#define CKR_PIN_INCORRECT 0x000000A0
+#define CKR_PIN_INVALID 0x000000A1
+#define CKR_PIN_LEN_RANGE 0x000000A2
+
+/* CKR_PIN_EXPIRED and CKR_PIN_LOCKED are new for v2.0 */
+#define CKR_PIN_EXPIRED 0x000000A3
+#define CKR_PIN_LOCKED 0x000000A4
+
+#define CKR_SESSION_CLOSED 0x000000B0
+#define CKR_SESSION_COUNT 0x000000B1
+#define CKR_SESSION_HANDLE_INVALID 0x000000B3
+#define CKR_SESSION_PARALLEL_NOT_SUPPORTED 0x000000B4
+#define CKR_SESSION_READ_ONLY 0x000000B5
+#define CKR_SESSION_EXISTS 0x000000B6
+
+/* CKR_SESSION_READ_ONLY_EXISTS and
+ * CKR_SESSION_READ_WRITE_SO_EXISTS are new for v2.0 */
+#define CKR_SESSION_READ_ONLY_EXISTS 0x000000B7
+#define CKR_SESSION_READ_WRITE_SO_EXISTS 0x000000B8
+
+#define CKR_SIGNATURE_INVALID 0x000000C0
+#define CKR_SIGNATURE_LEN_RANGE 0x000000C1
+#define CKR_TEMPLATE_INCOMPLETE 0x000000D0
+#define CKR_TEMPLATE_INCONSISTENT 0x000000D1
+#define CKR_TOKEN_NOT_PRESENT 0x000000E0
+#define CKR_TOKEN_NOT_RECOGNIZED 0x000000E1
+#define CKR_TOKEN_WRITE_PROTECTED 0x000000E2
+#define CKR_UNWRAPPING_KEY_HANDLE_INVALID 0x000000F0
+#define CKR_UNWRAPPING_KEY_SIZE_RANGE 0x000000F1
+#define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT 0x000000F2
+#define CKR_USER_ALREADY_LOGGED_IN 0x00000100
+#define CKR_USER_NOT_LOGGED_IN 0x00000101
+#define CKR_USER_PIN_NOT_INITIALIZED 0x00000102
+#define CKR_USER_TYPE_INVALID 0x00000103
+
+/* CKR_USER_ANOTHER_ALREADY_LOGGED_IN and CKR_USER_TOO_MANY_TYPES
+ * are new to v2.01 */
+#define CKR_USER_ANOTHER_ALREADY_LOGGED_IN 0x00000104
+#define CKR_USER_TOO_MANY_TYPES 0x00000105
+
+#define CKR_WRAPPED_KEY_INVALID 0x00000110
+#define CKR_WRAPPED_KEY_LEN_RANGE 0x00000112
+#define CKR_WRAPPING_KEY_HANDLE_INVALID 0x00000113
+#define CKR_WRAPPING_KEY_SIZE_RANGE 0x00000114
+#define CKR_WRAPPING_KEY_TYPE_INCONSISTENT 0x00000115
+#define CKR_RANDOM_SEED_NOT_SUPPORTED 0x00000120
+
+/* These are new to v2.0 */
+#define CKR_RANDOM_NO_RNG 0x00000121
+
+/* These are new to v2.11 */
+#define CKR_DOMAIN_PARAMS_INVALID 0x00000130
+
+/* These are new to v2.0 */
+#define CKR_BUFFER_TOO_SMALL 0x00000150
+#define CKR_SAVED_STATE_INVALID 0x00000160
+#define CKR_INFORMATION_SENSITIVE 0x00000170
+#define CKR_STATE_UNSAVEABLE 0x00000180
+
+/* These are new to v2.01 */
+#define CKR_CRYPTOKI_NOT_INITIALIZED 0x00000190
+#define CKR_CRYPTOKI_ALREADY_INITIALIZED 0x00000191
+#define CKR_MUTEX_BAD 0x000001A0
+#define CKR_MUTEX_NOT_LOCKED 0x000001A1
+
+/* This is new to v2.20 */
+#define CKR_FUNCTION_REJECTED 0x00000200
+
+#define CKR_VENDOR_DEFINED 0x80000000
+
+
+/* CK_NOTIFY is an application callback that processes events */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_NOTIFY)(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_NOTIFICATION event,
+ CK_VOID_PTR pApplication /* passed to C_OpenSession */
+);
+
+
+/* CK_FUNCTION_LIST is a structure holding a Cryptoki spec
+ * version and pointers of appropriate types to all the
+ * Cryptoki functions */
+/* CK_FUNCTION_LIST is new for v2.0 */
+typedef struct CK_FUNCTION_LIST CK_FUNCTION_LIST;
+
+typedef CK_FUNCTION_LIST CK_PTR CK_FUNCTION_LIST_PTR;
+
+typedef CK_FUNCTION_LIST_PTR CK_PTR CK_FUNCTION_LIST_PTR_PTR;
+
+
+/* CK_CREATEMUTEX is an application callback for creating a
+ * mutex object */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_CREATEMUTEX)(
+ CK_VOID_PTR_PTR ppMutex /* location to receive ptr to mutex */
+);
+
+
+/* CK_DESTROYMUTEX is an application callback for destroying a
+ * mutex object */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_DESTROYMUTEX)(
+ CK_VOID_PTR pMutex /* pointer to mutex */
+);
+
+
+/* CK_LOCKMUTEX is an application callback for locking a mutex */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_LOCKMUTEX)(
+ CK_VOID_PTR pMutex /* pointer to mutex */
+);
+
+
+/* CK_UNLOCKMUTEX is an application callback for unlocking a
+ * mutex */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_UNLOCKMUTEX)(
+ CK_VOID_PTR pMutex /* pointer to mutex */
+);
+
+
+/* CK_C_INITIALIZE_ARGS provides the optional arguments to
+ * C_Initialize */
+typedef struct CK_C_INITIALIZE_ARGS {
+ CK_CREATEMUTEX CreateMutex;
+ CK_DESTROYMUTEX DestroyMutex;
+ CK_LOCKMUTEX LockMutex;
+ CK_UNLOCKMUTEX UnlockMutex;
+ CK_FLAGS flags;
+ CK_VOID_PTR pReserved;
+} CK_C_INITIALIZE_ARGS;
+
+/* flags: bit flags that provide capabilities of the slot
+ * Bit Flag Mask Meaning
+ */
+#define CKF_LIBRARY_CANT_CREATE_OS_THREADS 0x00000001
+#define CKF_OS_LOCKING_OK 0x00000002
+
+typedef CK_C_INITIALIZE_ARGS CK_PTR CK_C_INITIALIZE_ARGS_PTR;
+
+
+/* additional flags for parameters to functions */
+
+/* CKF_DONT_BLOCK is for the function C_WaitForSlotEvent */
+#define CKF_DONT_BLOCK 1
+
+/* CK_RSA_PKCS_OAEP_MGF_TYPE is new for v2.10.
+ * CK_RSA_PKCS_OAEP_MGF_TYPE is used to indicate the Message
+ * Generation Function (MGF) applied to a message block when
+ * formatting a message block for the PKCS #1 OAEP encryption
+ * scheme. */
+typedef CK_ULONG CK_RSA_PKCS_MGF_TYPE;
+
+typedef CK_RSA_PKCS_MGF_TYPE CK_PTR CK_RSA_PKCS_MGF_TYPE_PTR;
+
+/* The following MGFs are defined */
+/* CKG_MGF1_SHA256, CKG_MGF1_SHA384, and CKG_MGF1_SHA512
+ * are new for v2.20 */
+#define CKG_MGF1_SHA1 0x00000001
+#define CKG_MGF1_SHA256 0x00000002
+#define CKG_MGF1_SHA384 0x00000003
+#define CKG_MGF1_SHA512 0x00000004
+
+/* CK_RSA_PKCS_OAEP_SOURCE_TYPE is new for v2.10.
+ * CK_RSA_PKCS_OAEP_SOURCE_TYPE is used to indicate the source
+ * of the encoding parameter when formatting a message block
+ * for the PKCS #1 OAEP encryption scheme. */
+typedef CK_ULONG CK_RSA_PKCS_OAEP_SOURCE_TYPE;
+
+typedef CK_RSA_PKCS_OAEP_SOURCE_TYPE CK_PTR CK_RSA_PKCS_OAEP_SOURCE_TYPE_PTR;
+
+/* The following encoding parameter sources are defined */
+#define CKZ_DATA_SPECIFIED 0x00000001
+
+/* CK_RSA_PKCS_OAEP_PARAMS is new for v2.10.
+ * CK_RSA_PKCS_OAEP_PARAMS provides the parameters to the
+ * CKM_RSA_PKCS_OAEP mechanism. */
+typedef struct CK_RSA_PKCS_OAEP_PARAMS {
+ CK_MECHANISM_TYPE hashAlg;
+ CK_RSA_PKCS_MGF_TYPE mgf;
+ CK_RSA_PKCS_OAEP_SOURCE_TYPE source;
+ CK_VOID_PTR pSourceData;
+ CK_ULONG ulSourceDataLen;
+} CK_RSA_PKCS_OAEP_PARAMS;
+
+typedef CK_RSA_PKCS_OAEP_PARAMS CK_PTR CK_RSA_PKCS_OAEP_PARAMS_PTR;
+
+/* CK_RSA_PKCS_PSS_PARAMS is new for v2.11.
+ * CK_RSA_PKCS_PSS_PARAMS provides the parameters to the
+ * CKM_RSA_PKCS_PSS mechanism(s). */
+typedef struct CK_RSA_PKCS_PSS_PARAMS {
+ CK_MECHANISM_TYPE hashAlg;
+ CK_RSA_PKCS_MGF_TYPE mgf;
+ CK_ULONG sLen;
+} CK_RSA_PKCS_PSS_PARAMS;
+
+typedef CK_RSA_PKCS_PSS_PARAMS CK_PTR CK_RSA_PKCS_PSS_PARAMS_PTR;
+
+/* CK_EC_KDF_TYPE is new for v2.11. */
+typedef CK_ULONG CK_EC_KDF_TYPE;
+
+/* The following EC Key Derivation Functions are defined */
+#define CKD_NULL 0x00000001
+#define CKD_SHA1_KDF 0x00000002
+
+/* CK_ECDH1_DERIVE_PARAMS is new for v2.11.
+ * CK_ECDH1_DERIVE_PARAMS provides the parameters to the
+ * CKM_ECDH1_DERIVE and CKM_ECDH1_COFACTOR_DERIVE mechanisms,
+ * where each party contributes one key pair.
+ */
+typedef struct CK_ECDH1_DERIVE_PARAMS {
+ CK_EC_KDF_TYPE kdf;
+ CK_ULONG ulSharedDataLen;
+ CK_BYTE_PTR pSharedData;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+} CK_ECDH1_DERIVE_PARAMS;
+
+typedef CK_ECDH1_DERIVE_PARAMS CK_PTR CK_ECDH1_DERIVE_PARAMS_PTR;
+
+
+/* CK_ECDH2_DERIVE_PARAMS is new for v2.11.
+ * CK_ECDH2_DERIVE_PARAMS provides the parameters to the
+ * CKM_ECMQV_DERIVE mechanism, where each party contributes two key pairs. */
+typedef struct CK_ECDH2_DERIVE_PARAMS {
+ CK_EC_KDF_TYPE kdf;
+ CK_ULONG ulSharedDataLen;
+ CK_BYTE_PTR pSharedData;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+ CK_ULONG ulPrivateDataLen;
+ CK_OBJECT_HANDLE hPrivateData;
+ CK_ULONG ulPublicDataLen2;
+ CK_BYTE_PTR pPublicData2;
+} CK_ECDH2_DERIVE_PARAMS;
+
+typedef CK_ECDH2_DERIVE_PARAMS CK_PTR CK_ECDH2_DERIVE_PARAMS_PTR;
+
+typedef struct CK_ECMQV_DERIVE_PARAMS {
+ CK_EC_KDF_TYPE kdf;
+ CK_ULONG ulSharedDataLen;
+ CK_BYTE_PTR pSharedData;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+ CK_ULONG ulPrivateDataLen;
+ CK_OBJECT_HANDLE hPrivateData;
+ CK_ULONG ulPublicDataLen2;
+ CK_BYTE_PTR pPublicData2;
+ CK_OBJECT_HANDLE publicKey;
+} CK_ECMQV_DERIVE_PARAMS;
+
+typedef CK_ECMQV_DERIVE_PARAMS CK_PTR CK_ECMQV_DERIVE_PARAMS_PTR;
+
+/* Typedefs and defines for the CKM_X9_42_DH_KEY_PAIR_GEN and the
+ * CKM_X9_42_DH_PARAMETER_GEN mechanisms (new for PKCS #11 v2.11) */
+typedef CK_ULONG CK_X9_42_DH_KDF_TYPE;
+typedef CK_X9_42_DH_KDF_TYPE CK_PTR CK_X9_42_DH_KDF_TYPE_PTR;
+
+/* The following X9.42 DH key derivation functions are defined
+ (besides CKD_NULL already defined : */
+#define CKD_SHA1_KDF_ASN1 0x00000003
+#define CKD_SHA1_KDF_CONCATENATE 0x00000004
+
+/* CK_X9_42_DH1_DERIVE_PARAMS is new for v2.11.
+ * CK_X9_42_DH1_DERIVE_PARAMS provides the parameters to the
+ * CKM_X9_42_DH_DERIVE key derivation mechanism, where each party
+ * contributes one key pair */
+typedef struct CK_X9_42_DH1_DERIVE_PARAMS {
+ CK_X9_42_DH_KDF_TYPE kdf;
+ CK_ULONG ulOtherInfoLen;
+ CK_BYTE_PTR pOtherInfo;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+} CK_X9_42_DH1_DERIVE_PARAMS;
+
+typedef struct CK_X9_42_DH1_DERIVE_PARAMS CK_PTR CK_X9_42_DH1_DERIVE_PARAMS_PTR;
+
+/* CK_X9_42_DH2_DERIVE_PARAMS is new for v2.11.
+ * CK_X9_42_DH2_DERIVE_PARAMS provides the parameters to the
+ * CKM_X9_42_DH_HYBRID_DERIVE and CKM_X9_42_MQV_DERIVE key derivation
+ * mechanisms, where each party contributes two key pairs */
+typedef struct CK_X9_42_DH2_DERIVE_PARAMS {
+ CK_X9_42_DH_KDF_TYPE kdf;
+ CK_ULONG ulOtherInfoLen;
+ CK_BYTE_PTR pOtherInfo;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+ CK_ULONG ulPrivateDataLen;
+ CK_OBJECT_HANDLE hPrivateData;
+ CK_ULONG ulPublicDataLen2;
+ CK_BYTE_PTR pPublicData2;
+} CK_X9_42_DH2_DERIVE_PARAMS;
+
+typedef CK_X9_42_DH2_DERIVE_PARAMS CK_PTR CK_X9_42_DH2_DERIVE_PARAMS_PTR;
+
+typedef struct CK_X9_42_MQV_DERIVE_PARAMS {
+ CK_X9_42_DH_KDF_TYPE kdf;
+ CK_ULONG ulOtherInfoLen;
+ CK_BYTE_PTR pOtherInfo;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+ CK_ULONG ulPrivateDataLen;
+ CK_OBJECT_HANDLE hPrivateData;
+ CK_ULONG ulPublicDataLen2;
+ CK_BYTE_PTR pPublicData2;
+ CK_OBJECT_HANDLE publicKey;
+} CK_X9_42_MQV_DERIVE_PARAMS;
+
+typedef CK_X9_42_MQV_DERIVE_PARAMS CK_PTR CK_X9_42_MQV_DERIVE_PARAMS_PTR;
+
+/* CK_KEA_DERIVE_PARAMS provides the parameters to the
+ * CKM_KEA_DERIVE mechanism */
+/* CK_KEA_DERIVE_PARAMS is new for v2.0 */
+typedef struct CK_KEA_DERIVE_PARAMS {
+ CK_BBOOL isSender;
+ CK_ULONG ulRandomLen;
+ CK_BYTE_PTR pRandomA;
+ CK_BYTE_PTR pRandomB;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+} CK_KEA_DERIVE_PARAMS;
+
+typedef CK_KEA_DERIVE_PARAMS CK_PTR CK_KEA_DERIVE_PARAMS_PTR;
+
+
+/* CK_RC2_PARAMS provides the parameters to the CKM_RC2_ECB and
+ * CKM_RC2_MAC mechanisms. An instance of CK_RC2_PARAMS just
+ * holds the effective keysize */
+typedef CK_ULONG CK_RC2_PARAMS;
+
+typedef CK_RC2_PARAMS CK_PTR CK_RC2_PARAMS_PTR;
+
+
+/* CK_RC2_CBC_PARAMS provides the parameters to the CKM_RC2_CBC
+ * mechanism */
+typedef struct CK_RC2_CBC_PARAMS {
+ /* ulEffectiveBits was changed from CK_USHORT to CK_ULONG for
+ * v2.0 */
+ CK_ULONG ulEffectiveBits; /* effective bits (1-1024) */
+
+ CK_BYTE iv[8]; /* IV for CBC mode */
+} CK_RC2_CBC_PARAMS;
+
+typedef CK_RC2_CBC_PARAMS CK_PTR CK_RC2_CBC_PARAMS_PTR;
+
+
+/* CK_RC2_MAC_GENERAL_PARAMS provides the parameters for the
+ * CKM_RC2_MAC_GENERAL mechanism */
+/* CK_RC2_MAC_GENERAL_PARAMS is new for v2.0 */
+typedef struct CK_RC2_MAC_GENERAL_PARAMS {
+ CK_ULONG ulEffectiveBits; /* effective bits (1-1024) */
+ CK_ULONG ulMacLength; /* Length of MAC in bytes */
+} CK_RC2_MAC_GENERAL_PARAMS;
+
+typedef CK_RC2_MAC_GENERAL_PARAMS CK_PTR \
+ CK_RC2_MAC_GENERAL_PARAMS_PTR;
+
+
+/* CK_RC5_PARAMS provides the parameters to the CKM_RC5_ECB and
+ * CKM_RC5_MAC mechanisms */
+/* CK_RC5_PARAMS is new for v2.0 */
+typedef struct CK_RC5_PARAMS {
+ CK_ULONG ulWordsize; /* wordsize in bits */
+ CK_ULONG ulRounds; /* number of rounds */
+} CK_RC5_PARAMS;
+
+typedef CK_RC5_PARAMS CK_PTR CK_RC5_PARAMS_PTR;
+
+
+/* CK_RC5_CBC_PARAMS provides the parameters to the CKM_RC5_CBC
+ * mechanism */
+/* CK_RC5_CBC_PARAMS is new for v2.0 */
+typedef struct CK_RC5_CBC_PARAMS {
+ CK_ULONG ulWordsize; /* wordsize in bits */
+ CK_ULONG ulRounds; /* number of rounds */
+ CK_BYTE_PTR pIv; /* pointer to IV */
+ CK_ULONG ulIvLen; /* length of IV in bytes */
+} CK_RC5_CBC_PARAMS;
+
+typedef CK_RC5_CBC_PARAMS CK_PTR CK_RC5_CBC_PARAMS_PTR;
+
+
+/* CK_RC5_MAC_GENERAL_PARAMS provides the parameters for the
+ * CKM_RC5_MAC_GENERAL mechanism */
+/* CK_RC5_MAC_GENERAL_PARAMS is new for v2.0 */
+typedef struct CK_RC5_MAC_GENERAL_PARAMS {
+ CK_ULONG ulWordsize; /* wordsize in bits */
+ CK_ULONG ulRounds; /* number of rounds */
+ CK_ULONG ulMacLength; /* Length of MAC in bytes */
+} CK_RC5_MAC_GENERAL_PARAMS;
+
+typedef CK_RC5_MAC_GENERAL_PARAMS CK_PTR \
+ CK_RC5_MAC_GENERAL_PARAMS_PTR;
+
+
+/* CK_MAC_GENERAL_PARAMS provides the parameters to most block
+ * ciphers' MAC_GENERAL mechanisms. Its value is the length of
+ * the MAC */
+/* CK_MAC_GENERAL_PARAMS is new for v2.0 */
+typedef CK_ULONG CK_MAC_GENERAL_PARAMS;
+
+typedef CK_MAC_GENERAL_PARAMS CK_PTR CK_MAC_GENERAL_PARAMS_PTR;
+
+/* CK_DES/AES_ECB/CBC_ENCRYPT_DATA_PARAMS are new for v2.20 */
+typedef struct CK_DES_CBC_ENCRYPT_DATA_PARAMS {
+ CK_BYTE iv[8];
+ CK_BYTE_PTR pData;
+ CK_ULONG length;
+} CK_DES_CBC_ENCRYPT_DATA_PARAMS;
+
+typedef CK_DES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_DES_CBC_ENCRYPT_DATA_PARAMS_PTR;
+
+typedef struct CK_AES_CBC_ENCRYPT_DATA_PARAMS {
+ CK_BYTE iv[16];
+ CK_BYTE_PTR pData;
+ CK_ULONG length;
+} CK_AES_CBC_ENCRYPT_DATA_PARAMS;
+
+typedef CK_AES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_AES_CBC_ENCRYPT_DATA_PARAMS_PTR;
+
+/* CK_SKIPJACK_PRIVATE_WRAP_PARAMS provides the parameters to the
+ * CKM_SKIPJACK_PRIVATE_WRAP mechanism */
+/* CK_SKIPJACK_PRIVATE_WRAP_PARAMS is new for v2.0 */
+typedef struct CK_SKIPJACK_PRIVATE_WRAP_PARAMS {
+ CK_ULONG ulPasswordLen;
+ CK_BYTE_PTR pPassword;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+ CK_ULONG ulPAndGLen;
+ CK_ULONG ulQLen;
+ CK_ULONG ulRandomLen;
+ CK_BYTE_PTR pRandomA;
+ CK_BYTE_PTR pPrimeP;
+ CK_BYTE_PTR pBaseG;
+ CK_BYTE_PTR pSubprimeQ;
+} CK_SKIPJACK_PRIVATE_WRAP_PARAMS;
+
+typedef CK_SKIPJACK_PRIVATE_WRAP_PARAMS CK_PTR \
+ CK_SKIPJACK_PRIVATE_WRAP_PTR;
+
+
+/* CK_SKIPJACK_RELAYX_PARAMS provides the parameters to the
+ * CKM_SKIPJACK_RELAYX mechanism */
+/* CK_SKIPJACK_RELAYX_PARAMS is new for v2.0 */
+typedef struct CK_SKIPJACK_RELAYX_PARAMS {
+ CK_ULONG ulOldWrappedXLen;
+ CK_BYTE_PTR pOldWrappedX;
+ CK_ULONG ulOldPasswordLen;
+ CK_BYTE_PTR pOldPassword;
+ CK_ULONG ulOldPublicDataLen;
+ CK_BYTE_PTR pOldPublicData;
+ CK_ULONG ulOldRandomLen;
+ CK_BYTE_PTR pOldRandomA;
+ CK_ULONG ulNewPasswordLen;
+ CK_BYTE_PTR pNewPassword;
+ CK_ULONG ulNewPublicDataLen;
+ CK_BYTE_PTR pNewPublicData;
+ CK_ULONG ulNewRandomLen;
+ CK_BYTE_PTR pNewRandomA;
+} CK_SKIPJACK_RELAYX_PARAMS;
+
+typedef CK_SKIPJACK_RELAYX_PARAMS CK_PTR \
+ CK_SKIPJACK_RELAYX_PARAMS_PTR;
+
+
+typedef struct CK_PBE_PARAMS {
+ CK_BYTE_PTR pInitVector;
+ CK_UTF8CHAR_PTR pPassword;
+ CK_ULONG ulPasswordLen;
+ CK_BYTE_PTR pSalt;
+ CK_ULONG ulSaltLen;
+ CK_ULONG ulIteration;
+} CK_PBE_PARAMS;
+
+typedef CK_PBE_PARAMS CK_PTR CK_PBE_PARAMS_PTR;
+
+
+/* CK_KEY_WRAP_SET_OAEP_PARAMS provides the parameters to the
+ * CKM_KEY_WRAP_SET_OAEP mechanism */
+/* CK_KEY_WRAP_SET_OAEP_PARAMS is new for v2.0 */
+typedef struct CK_KEY_WRAP_SET_OAEP_PARAMS {
+ CK_BYTE bBC; /* block contents byte */
+ CK_BYTE_PTR pX; /* extra data */
+ CK_ULONG ulXLen; /* length of extra data in bytes */
+} CK_KEY_WRAP_SET_OAEP_PARAMS;
+
+typedef CK_KEY_WRAP_SET_OAEP_PARAMS CK_PTR \
+ CK_KEY_WRAP_SET_OAEP_PARAMS_PTR;
+
+
+typedef struct CK_SSL3_RANDOM_DATA {
+ CK_BYTE_PTR pClientRandom;
+ CK_ULONG ulClientRandomLen;
+ CK_BYTE_PTR pServerRandom;
+ CK_ULONG ulServerRandomLen;
+} CK_SSL3_RANDOM_DATA;
+
+
+typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS {
+ CK_SSL3_RANDOM_DATA RandomInfo;
+ CK_VERSION_PTR pVersion;
+} CK_SSL3_MASTER_KEY_DERIVE_PARAMS;
+
+typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS CK_PTR \
+ CK_SSL3_MASTER_KEY_DERIVE_PARAMS_PTR;
+
+
+typedef struct CK_SSL3_KEY_MAT_OUT {
+ CK_OBJECT_HANDLE hClientMacSecret;
+ CK_OBJECT_HANDLE hServerMacSecret;
+ CK_OBJECT_HANDLE hClientKey;
+ CK_OBJECT_HANDLE hServerKey;
+ CK_BYTE_PTR pIVClient;
+ CK_BYTE_PTR pIVServer;
+} CK_SSL3_KEY_MAT_OUT;
+
+typedef CK_SSL3_KEY_MAT_OUT CK_PTR CK_SSL3_KEY_MAT_OUT_PTR;
+
+
+typedef struct CK_SSL3_KEY_MAT_PARAMS {
+ CK_ULONG ulMacSizeInBits;
+ CK_ULONG ulKeySizeInBits;
+ CK_ULONG ulIVSizeInBits;
+ CK_BBOOL bIsExport;
+ CK_SSL3_RANDOM_DATA RandomInfo;
+ CK_SSL3_KEY_MAT_OUT_PTR pReturnedKeyMaterial;
+} CK_SSL3_KEY_MAT_PARAMS;
+
+typedef CK_SSL3_KEY_MAT_PARAMS CK_PTR CK_SSL3_KEY_MAT_PARAMS_PTR;
+
+/* CK_TLS_PRF_PARAMS is new for version 2.20 */
+typedef struct CK_TLS_PRF_PARAMS {
+ CK_BYTE_PTR pSeed;
+ CK_ULONG ulSeedLen;
+ CK_BYTE_PTR pLabel;
+ CK_ULONG ulLabelLen;
+ CK_BYTE_PTR pOutput;
+ CK_ULONG_PTR pulOutputLen;
+} CK_TLS_PRF_PARAMS;
+
+typedef CK_TLS_PRF_PARAMS CK_PTR CK_TLS_PRF_PARAMS_PTR;
+
+/* WTLS is new for version 2.20 */
+typedef struct CK_WTLS_RANDOM_DATA {
+ CK_BYTE_PTR pClientRandom;
+ CK_ULONG ulClientRandomLen;
+ CK_BYTE_PTR pServerRandom;
+ CK_ULONG ulServerRandomLen;
+} CK_WTLS_RANDOM_DATA;
+
+typedef CK_WTLS_RANDOM_DATA CK_PTR CK_WTLS_RANDOM_DATA_PTR;
+
+typedef struct CK_WTLS_MASTER_KEY_DERIVE_PARAMS {
+ CK_MECHANISM_TYPE DigestMechanism;
+ CK_WTLS_RANDOM_DATA RandomInfo;
+ CK_BYTE_PTR pVersion;
+} CK_WTLS_MASTER_KEY_DERIVE_PARAMS;
+
+typedef CK_WTLS_MASTER_KEY_DERIVE_PARAMS CK_PTR \
+ CK_WTLS_MASTER_KEY_DERIVE_PARAMS_PTR;
+
+typedef struct CK_WTLS_PRF_PARAMS {
+ CK_MECHANISM_TYPE DigestMechanism;
+ CK_BYTE_PTR pSeed;
+ CK_ULONG ulSeedLen;
+ CK_BYTE_PTR pLabel;
+ CK_ULONG ulLabelLen;
+ CK_BYTE_PTR pOutput;
+ CK_ULONG_PTR pulOutputLen;
+} CK_WTLS_PRF_PARAMS;
+
+typedef CK_WTLS_PRF_PARAMS CK_PTR CK_WTLS_PRF_PARAMS_PTR;
+
+typedef struct CK_WTLS_KEY_MAT_OUT {
+ CK_OBJECT_HANDLE hMacSecret;
+ CK_OBJECT_HANDLE hKey;
+ CK_BYTE_PTR pIV;
+} CK_WTLS_KEY_MAT_OUT;
+
+typedef CK_WTLS_KEY_MAT_OUT CK_PTR CK_WTLS_KEY_MAT_OUT_PTR;
+
+typedef struct CK_WTLS_KEY_MAT_PARAMS {
+ CK_MECHANISM_TYPE DigestMechanism;
+ CK_ULONG ulMacSizeInBits;
+ CK_ULONG ulKeySizeInBits;
+ CK_ULONG ulIVSizeInBits;
+ CK_ULONG ulSequenceNumber;
+ CK_BBOOL bIsExport;
+ CK_WTLS_RANDOM_DATA RandomInfo;
+ CK_WTLS_KEY_MAT_OUT_PTR pReturnedKeyMaterial;
+} CK_WTLS_KEY_MAT_PARAMS;
+
+typedef CK_WTLS_KEY_MAT_PARAMS CK_PTR CK_WTLS_KEY_MAT_PARAMS_PTR;
+
+/* CMS is new for version 2.20 */
+typedef struct CK_CMS_SIG_PARAMS {
+ CK_OBJECT_HANDLE certificateHandle;
+ CK_MECHANISM_PTR pSigningMechanism;
+ CK_MECHANISM_PTR pDigestMechanism;
+ CK_UTF8CHAR_PTR pContentType;
+ CK_BYTE_PTR pRequestedAttributes;
+ CK_ULONG ulRequestedAttributesLen;
+ CK_BYTE_PTR pRequiredAttributes;
+ CK_ULONG ulRequiredAttributesLen;
+} CK_CMS_SIG_PARAMS;
+
+typedef CK_CMS_SIG_PARAMS CK_PTR CK_CMS_SIG_PARAMS_PTR;
+
+typedef struct CK_KEY_DERIVATION_STRING_DATA {
+ CK_BYTE_PTR pData;
+ CK_ULONG ulLen;
+} CK_KEY_DERIVATION_STRING_DATA;
+
+typedef CK_KEY_DERIVATION_STRING_DATA CK_PTR \
+ CK_KEY_DERIVATION_STRING_DATA_PTR;
+
+
+/* The CK_EXTRACT_PARAMS is used for the
+ * CKM_EXTRACT_KEY_FROM_KEY mechanism. It specifies which bit
+ * of the base key should be used as the first bit of the
+ * derived key */
+/* CK_EXTRACT_PARAMS is new for v2.0 */
+typedef CK_ULONG CK_EXTRACT_PARAMS;
+
+typedef CK_EXTRACT_PARAMS CK_PTR CK_EXTRACT_PARAMS_PTR;
+
+/* CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE is new for v2.10.
+ * CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE is used to
+ * indicate the Pseudo-Random Function (PRF) used to generate
+ * key bits using PKCS #5 PBKDF2. */
+typedef CK_ULONG CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE;
+
+typedef CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE CK_PTR CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE_PTR;
+
+/* The following PRFs are defined in PKCS #5 v2.0. */
+#define CKP_PKCS5_PBKD2_HMAC_SHA1 0x00000001
+
+
+/* CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE is new for v2.10.
+ * CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE is used to indicate the
+ * source of the salt value when deriving a key using PKCS #5
+ * PBKDF2. */
+typedef CK_ULONG CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE;
+
+typedef CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE CK_PTR CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE_PTR;
+
+/* The following salt value sources are defined in PKCS #5 v2.0. */
+#define CKZ_SALT_SPECIFIED 0x00000001
+
+/* CK_PKCS5_PBKD2_PARAMS is new for v2.10.
+ * CK_PKCS5_PBKD2_PARAMS is a structure that provides the
+ * parameters to the CKM_PKCS5_PBKD2 mechanism. */
+typedef struct CK_PKCS5_PBKD2_PARAMS {
+ CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE saltSource;
+ CK_VOID_PTR pSaltSourceData;
+ CK_ULONG ulSaltSourceDataLen;
+ CK_ULONG iterations;
+ CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE prf;
+ CK_VOID_PTR pPrfData;
+ CK_ULONG ulPrfDataLen;
+ CK_UTF8CHAR_PTR pPassword;
+ CK_ULONG_PTR ulPasswordLen;
+} CK_PKCS5_PBKD2_PARAMS;
+
+typedef CK_PKCS5_PBKD2_PARAMS CK_PTR CK_PKCS5_PBKD2_PARAMS_PTR;
+
+#endif
diff --git a/src/pluto/rsaref/unix.h b/src/pluto/rsaref/unix.h
new file mode 100644
index 000000000..2e7eb6663
--- /dev/null
+++ b/src/pluto/rsaref/unix.h
@@ -0,0 +1,24 @@
+
+
+#ifndef UNIX_H
+#define UNIX_H
+
+#define CK_PTR *
+
+#define CK_DEFINE_FUNCTION(returnType, name) \
+ returnType name
+
+#define CK_DECLARE_FUNCTION(returnType, name) \
+ returnType name
+
+#define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ returnType (* name)
+
+#define CK_CALLBACK_FUNCTION(returnType, name) \
+ returnType (* name)
+
+#ifndef NULL_PTR
+#define NULL_PTR 0
+#endif
+
+#endif
diff --git a/src/pluto/server.c b/src/pluto/server.c
new file mode 100644
index 000000000..1cc221515
--- /dev/null
+++ b/src/pluto/server.c
@@ -0,0 +1,996 @@
+/* get-next-event loop
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: server.c,v 1.9 2005/09/09 14:15:35 as Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#ifdef SOLARIS
+# include <sys/sockio.h> /* for Solaris 2.6: defines SIOCGIFCONF */
+#endif
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/time.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <resolv.h>
+#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */
+#include <sys/queue.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "state.h"
+#include "connections.h"
+#include "kernel.h"
+#include "log.h"
+#include "server.h"
+#include "timer.h"
+#include "packet.h"
+#include "demux.h" /* needs packet.h */
+#include "rcv_whack.h"
+#include "keys.h"
+#include "adns.h" /* needs <resolv.h> */
+#include "dnskey.h" /* needs keys.h and adns.h */
+#include "whack.h" /* for RC_LOG_SERIOUS */
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+#include "kameipsec.h"
+#include "nat_traversal.h"
+
+/*
+ * Server main loop and socket initialization routines.
+ */
+
+static const int on = TRUE; /* by-reference parameter; constant, we hope */
+
+/* control (whack) socket */
+int ctl_fd = NULL_FD; /* file descriptor of control (whack) socket */
+struct sockaddr_un ctl_addr = { AF_UNIX, DEFAULT_CTLBASE CTL_SUFFIX };
+
+/* info (showpolicy) socket */
+int policy_fd = NULL_FD;
+struct sockaddr_un info_addr= { AF_UNIX, DEFAULT_CTLBASE INFO_SUFFIX };
+
+/* Initialize the control socket.
+ * Note: this is called very early, so little infrastructure is available.
+ * It is important that the socket is created before the original
+ * Pluto process returns.
+ */
+err_t
+init_ctl_socket(void)
+{
+ err_t failed = NULL;
+
+ delete_ctl_socket(); /* preventative medicine */
+ ctl_fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (ctl_fd == -1)
+ failed = "create";
+ else if (fcntl(ctl_fd, F_SETFD, FD_CLOEXEC) == -1)
+ failed = "fcntl FD+CLOEXEC";
+ else if (setsockopt(ctl_fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof(on)) < 0)
+ failed = "setsockopt";
+ else
+ {
+ /* to keep control socket secure, use umask */
+ mode_t ou = umask(~S_IRWXU);
+
+ if (bind(ctl_fd, (struct sockaddr *)&ctl_addr
+ , offsetof(struct sockaddr_un, sun_path) + strlen(ctl_addr.sun_path)) < 0)
+ failed = "bind";
+ umask(ou);
+ }
+
+ /* 5 is a haphazardly chosen limit for the backlog.
+ * Rumour has it that this is the max on BSD systems.
+ */
+ if (failed == NULL && listen(ctl_fd, 5) < 0)
+ failed = "listen() on";
+
+ return failed == NULL? NULL : builddiag("could not %s control socket: %d %s"
+ , failed, errno, strerror(errno));
+}
+
+void
+delete_ctl_socket(void)
+{
+ /* Is noting failure useful? Not when used as preventative medicine. */
+ unlink(ctl_addr.sun_path);
+}
+
+bool listening = FALSE; /* should we pay attention to IKE messages? */
+
+struct iface *interfaces = NULL; /* public interfaces */
+
+/* Initialize the interface sockets. */
+
+static void
+mark_ifaces_dead(void)
+{
+ struct iface *p;
+
+ for (p = interfaces; p != NULL; p = p->next)
+ p->change = IFN_DELETE;
+}
+
+static void
+free_dead_ifaces(void)
+{
+ struct iface *p;
+ bool some_dead = FALSE
+ , some_new = FALSE;
+
+ for (p = interfaces; p != NULL; p = p->next)
+ {
+ if (p->change == IFN_DELETE)
+ {
+ plog("shutting down interface %s/%s %s"
+ , p->vname, p->rname, ip_str(&p->addr));
+ some_dead = TRUE;
+ }
+ else if (p->change == IFN_ADD)
+ {
+ some_new = TRUE;
+ }
+ }
+
+ if (some_dead)
+ {
+ struct iface **pp;
+
+ release_dead_interfaces();
+ for (pp = &interfaces; (p = *pp) != NULL; )
+ {
+ if (p->change == IFN_DELETE)
+ {
+ *pp = p->next; /* advance *pp */
+ pfree(p->vname);
+ pfree(p->rname);
+ close(p->fd);
+ pfree(p);
+ }
+ else
+ {
+ pp = &p->next; /* advance pp */
+ }
+ }
+ }
+
+ /* this must be done after the release_dead_interfaces
+ * in case some to the newly unoriented connections can
+ * become oriented here.
+ */
+ if (some_dead || some_new)
+ check_orientations();
+}
+
+void
+free_ifaces(void)
+{
+ mark_ifaces_dead();
+ free_dead_ifaces();
+}
+
+struct raw_iface {
+ ip_address addr;
+ char name[IFNAMSIZ + 20]; /* what would be a safe size? */
+ struct raw_iface *next;
+};
+
+/* Called to handle --interface <ifname>
+ * Semantics: if specified, only these (real) interfaces are considered.
+ */
+static const char *pluto_ifn[10];
+static int pluto_ifn_roof = 0;
+
+bool
+use_interface(const char *rifn)
+{
+ if (pluto_ifn_roof >= (int)elemsof(pluto_ifn))
+ {
+ return FALSE;
+ }
+ else
+ {
+ pluto_ifn[pluto_ifn_roof++] = rifn;
+ return TRUE;
+ }
+}
+
+#ifndef IPSECDEVPREFIX
+# define IPSECDEVPREFIX "ipsec"
+#endif
+
+static struct raw_iface *
+find_raw_ifaces4(void)
+{
+ int j; /* index into buf */
+ struct ifconf ifconf;
+ struct ifreq buf[300]; /* for list of interfaces -- arbitrary limit */
+ struct raw_iface *rifaces = NULL;
+ int master_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); /* Get a UDP socket */
+
+ /* get list of interfaces with assigned IPv4 addresses from system */
+
+ if (master_sock == -1)
+ exit_log_errno((e, "socket() failed in find_raw_ifaces4()"));
+
+ if (setsockopt(master_sock, SOL_SOCKET, SO_REUSEADDR
+ , (const void *)&on, sizeof(on)) < 0)
+ exit_log_errno((e, "setsockopt() in find_raw_ifaces4()"));
+
+ /* bind the socket */
+ {
+ ip_address any;
+
+ happy(anyaddr(AF_INET, &any));
+ setportof(htons(pluto_port), &any);
+ if (bind(master_sock, sockaddrof(&any), sockaddrlenof(&any)) < 0)
+ exit_log_errno((e, "bind() failed in find_raw_ifaces4()"));
+ }
+
+ /* Get local interfaces. See netdevice(7). */
+ ifconf.ifc_len = sizeof(buf);
+ ifconf.ifc_buf = (void *) buf;
+ zero(buf);
+
+ if (ioctl(master_sock, SIOCGIFCONF, &ifconf) == -1)
+ exit_log_errno((e, "ioctl(SIOCGIFCONF) in find_raw_ifaces4()"));
+
+ /* Add an entry to rifaces for each interesting interface. */
+ for (j = 0; (j+1) * sizeof(*buf) <= (size_t)ifconf.ifc_len; j++)
+ {
+ struct raw_iface ri;
+ const struct sockaddr_in *rs = (struct sockaddr_in *) &buf[j].ifr_addr;
+ struct ifreq auxinfo;
+
+ /* ignore all but AF_INET interfaces */
+ if (rs->sin_family != AF_INET)
+ continue; /* not interesting */
+
+ /* build a NUL-terminated copy of the rname field */
+ memcpy(ri.name, buf[j].ifr_name, IFNAMSIZ);
+ ri.name[IFNAMSIZ] = '\0';
+
+ /* ignore if our interface names were specified, and this isn't one */
+ if (pluto_ifn_roof != 0)
+ {
+ int i;
+
+ for (i = 0; i != pluto_ifn_roof; i++)
+ if (streq(ri.name, pluto_ifn[i]))
+ break;
+ if (i == pluto_ifn_roof)
+ continue; /* not found -- skip */
+ }
+
+ /* Find out stuff about this interface. See netdevice(7). */
+ zero(&auxinfo); /* paranoia */
+ memcpy(auxinfo.ifr_name, buf[j].ifr_name, IFNAMSIZ);
+ if (ioctl(master_sock, SIOCGIFFLAGS, &auxinfo) == -1)
+ exit_log_errno((e
+ , "ioctl(SIOCGIFFLAGS) for %s in find_raw_ifaces4()"
+ , ri.name));
+ if (!(auxinfo.ifr_flags & IFF_UP))
+ continue; /* ignore an interface that isn't UP */
+
+ /* ignore unconfigured interfaces */
+ if (rs->sin_addr.s_addr == 0)
+ continue;
+
+ happy(initaddr((const void *)&rs->sin_addr, sizeof(struct in_addr)
+ , AF_INET, &ri.addr));
+
+ DBG(DBG_CONTROL, DBG_log("found %s with address %s"
+ , ri.name, ip_str(&ri.addr)));
+ ri.next = rifaces;
+ rifaces = clone_thing(ri, "struct raw_iface");
+ }
+
+ close(master_sock);
+
+ return rifaces;
+}
+
+static struct raw_iface *
+find_raw_ifaces6(void)
+{
+
+ /* Get list of interfaces with IPv6 addresses from system from /proc/net/if_inet6).
+ *
+ * Documentation of format?
+ * RTFS: linux-2.2.16/net/ipv6/addrconf.c:iface_proc_info()
+ * linux-2.4.9-13/net/ipv6/addrconf.c:iface_proc_info()
+ *
+ * Sample from Gerhard's laptop:
+ * 00000000000000000000000000000001 01 80 10 80 lo
+ * 30490009000000000000000000010002 02 40 00 80 ipsec0
+ * 30490009000000000000000000010002 07 40 00 80 eth0
+ * fe80000000000000025004fffefd5484 02 0a 20 80 ipsec0
+ * fe80000000000000025004fffefd5484 07 0a 20 80 eth0
+ *
+ * Each line contains:
+ * - IPv6 address: 16 bytes, in hex, no punctuation
+ * - ifindex: 1 byte, in hex
+ * - prefix_len: 1 byte, in hex
+ * - scope (e.g. global, link local): 1 byte, in hex
+ * - flags: 1 byte, in hex
+ * - device name: string, followed by '\n'
+ */
+ struct raw_iface *rifaces = NULL;
+ static const char proc_name[] = "/proc/net/if_inet6";
+ FILE *proc_sock = fopen(proc_name, "r");
+
+ if (proc_sock == NULL)
+ {
+ DBG(DBG_CONTROL, DBG_log("could not open %s", proc_name));
+ }
+ else
+ {
+ for (;;)
+ {
+ struct raw_iface ri;
+ unsigned short xb[8]; /* IPv6 address as 8 16-bit chunks */
+ char sb[8*5]; /* IPv6 address as string-with-colons */
+ unsigned int if_idx; /* proc field, not used */
+ unsigned int plen; /* proc field, not used */
+ unsigned int scope; /* proc field, used to exclude link-local */
+ unsigned int dad_status; /* proc field, not used */
+ /* ??? I hate and distrust scanf -- DHR */
+ int r = fscanf(proc_sock
+ , "%4hx%4hx%4hx%4hx%4hx%4hx%4hx%4hx"
+ " %02x %02x %02x %02x %20s\n"
+ , xb+0, xb+1, xb+2, xb+3, xb+4, xb+5, xb+6, xb+7
+ , &if_idx, &plen, &scope, &dad_status, ri.name);
+
+ /* ??? we should diagnose any problems */
+ if (r != 13)
+ break;
+
+ /* ignore addresses with link local scope.
+ * From linux-2.4.9-13/include/net/ipv6.h:
+ * IPV6_ADDR_LINKLOCAL 0x0020U
+ * IPV6_ADDR_SCOPE_MASK 0x00f0U
+ */
+ if ((scope & 0x00f0U) == 0x0020U)
+ continue;
+
+ snprintf(sb, sizeof(sb)
+ , "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
+ , xb[0], xb[1], xb[2], xb[3], xb[4], xb[5], xb[6], xb[7]);
+
+ happy(ttoaddr(sb, 0, AF_INET6, &ri.addr));
+
+ if (!isunspecaddr(&ri.addr))
+ {
+ DBG(DBG_CONTROL
+ , DBG_log("found %s with address %s"
+ , ri.name, sb));
+ ri.next = rifaces;
+ rifaces = clone_thing(ri, "struct raw_iface");
+ }
+ }
+ fclose(proc_sock);
+ }
+
+ return rifaces;
+}
+
+#if 1
+static int
+create_socket(struct raw_iface *ifp, const char *v_name, int port)
+{
+ int fd = socket(addrtypeof(&ifp->addr), SOCK_DGRAM, IPPROTO_UDP);
+ int fcntl_flags;
+
+ if (fd < 0)
+ {
+ log_errno((e, "socket() in process_raw_ifaces()"));
+ return -1;
+ }
+
+#if 1
+ /* Set socket Nonblocking */
+ if ((fcntl_flags=fcntl(fd, F_GETFL)) >= 0) {
+ if (!(fcntl_flags & O_NONBLOCK)) {
+ fcntl_flags |= O_NONBLOCK;
+ fcntl(fd, F_SETFL, fcntl_flags);
+ }
+ }
+#endif
+
+ if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
+ {
+ log_errno((e, "fcntl(,, FD_CLOEXEC) in process_raw_ifaces()"));
+ close(fd);
+ return -1;
+ }
+
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR
+ , (const void *)&on, sizeof(on)) < 0)
+ {
+ log_errno((e, "setsockopt SO_REUSEADDR in process_raw_ifaces()"));
+ close(fd);
+ return -1;
+ }
+
+ /* To improve error reporting. See ip(7). */
+#if defined(IP_RECVERR) && defined(MSG_ERRQUEUE)
+ if (setsockopt(fd, SOL_IP, IP_RECVERR
+ , (const void *)&on, sizeof(on)) < 0)
+ {
+ log_errno((e, "setsockopt IP_RECVERR in process_raw_ifaces()"));
+ close(fd);
+ return -1;
+ }
+#endif
+
+ /* With IPv6, there is no fragmentation after
+ * it leaves our interface. PMTU discovery
+ * is mandatory but doesn't work well with IKE (why?).
+ * So we must set the IPV6_USE_MIN_MTU option.
+ * See draft-ietf-ipngwg-rfc2292bis-01.txt 11.1
+ */
+#ifdef IPV6_USE_MIN_MTU /* YUCK: not always defined */
+ if (addrtypeof(&ifp->addr) == AF_INET6
+ && setsockopt(fd, SOL_SOCKET, IPV6_USE_MIN_MTU
+ , (const void *)&on, sizeof(on)) < 0)
+ {
+ log_errno((e, "setsockopt IPV6_USE_MIN_MTU in process_raw_ifaces()"));
+ close(fd);
+ return -1;
+ }
+#endif
+
+#if defined(linux) && defined(KERNEL26_SUPPORT)
+ if (!no_klips && kernel_ops->type == KERNEL_TYPE_LINUX)
+ {
+ struct sadb_x_policy policy;
+ int level, opt;
+
+ policy.sadb_x_policy_len = sizeof(policy) / IPSEC_PFKEYv2_ALIGN;
+ policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY;
+ policy.sadb_x_policy_type = IPSEC_POLICY_BYPASS;
+ policy.sadb_x_policy_dir = IPSEC_DIR_INBOUND;
+ policy.sadb_x_policy_reserved = 0;
+ policy.sadb_x_policy_id = 0;
+ policy.sadb_x_policy_reserved2 = 0;
+
+ if (addrtypeof(&ifp->addr) == AF_INET6)
+ {
+ level = IPPROTO_IPV6;
+ opt = IPV6_IPSEC_POLICY;
+ }
+ else
+ {
+ level = IPPROTO_IP;
+ opt = IP_IPSEC_POLICY;
+ }
+
+ if (setsockopt(fd, level, opt
+ , &policy, sizeof(policy)) < 0)
+ {
+ log_errno((e, "setsockopt IPSEC_POLICY in process_raw_ifaces()"));
+ close(fd);
+ return -1;
+ }
+
+ policy.sadb_x_policy_dir = IPSEC_DIR_OUTBOUND;
+
+ if (setsockopt(fd, level, opt
+ , &policy, sizeof(policy)) < 0)
+ {
+ log_errno((e, "setsockopt IPSEC_POLICY in process_raw_ifaces()"));
+ close(fd);
+ return -1;
+ }
+ }
+#endif
+
+ setportof(htons(port), &ifp->addr);
+ if (bind(fd, sockaddrof(&ifp->addr), sockaddrlenof(&ifp->addr)) < 0)
+ {
+ log_errno((e, "bind() for %s/%s %s:%u in process_raw_ifaces()"
+ , ifp->name, v_name
+ , ip_str(&ifp->addr), (unsigned) port));
+ close(fd);
+ return -1;
+ }
+ setportof(htons(pluto_port), &ifp->addr);
+ return fd;
+}
+#endif
+
+static void
+process_raw_ifaces(struct raw_iface *rifaces)
+{
+ struct raw_iface *ifp;
+
+ /* Find all virtual/real interface pairs.
+ * For each real interface...
+ */
+ for (ifp = rifaces; ifp != NULL; ifp = ifp->next)
+ {
+ struct raw_iface *v = NULL; /* matching ipsecX interface */
+ struct raw_iface fake_v;
+ bool after = FALSE; /* has vfp passed ifp on the list? */
+ bool bad = FALSE;
+ struct raw_iface *vfp;
+
+ /* ignore if virtual (ipsec*) interface */
+ if (strncmp(ifp->name, IPSECDEVPREFIX, sizeof(IPSECDEVPREFIX)-1) == 0)
+ continue;
+
+ for (vfp = rifaces; vfp != NULL; vfp = vfp->next)
+ {
+ if (vfp == ifp)
+ {
+ after = TRUE;
+ }
+ else if (sameaddr(&ifp->addr, &vfp->addr))
+ {
+ /* Different entries with matching IP addresses.
+ * Many interesting cases.
+ */
+ if (strncmp(vfp->name, IPSECDEVPREFIX, sizeof(IPSECDEVPREFIX)-1) == 0)
+ {
+ if (v != NULL && !streq(v->name, vfp->name))
+ {
+ loglog(RC_LOG_SERIOUS
+ , "ipsec interfaces %s and %s share same address %s"
+ , v->name, vfp->name, ip_str(&ifp->addr));
+ bad = TRUE;
+ }
+ else
+ {
+ v = vfp; /* current winner */
+ }
+ }
+ else
+ {
+ /* ugh: a second real interface with the same IP address
+ * "after" allows us to avoid double reporting.
+ */
+#if defined(linux) && defined(KERNEL26_SUPPORT)
+ if (!no_klips && kernel_ops->type == KERNEL_TYPE_LINUX)
+ {
+ if (after)
+ {
+ bad = TRUE;
+ break;
+ }
+ continue;
+ }
+#endif
+ if (after)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "IP interfaces %s and %s share address %s!"
+ , ifp->name, vfp->name, ip_str(&ifp->addr));
+ }
+ bad = TRUE;
+ }
+ }
+ }
+
+ if (bad)
+ continue;
+
+#if defined(linux) && defined(KERNEL26_SUPPORT)
+ if (!no_klips && kernel_ops->type == KERNEL_TYPE_LINUX)
+ {
+ v = ifp;
+ goto add_entry;
+ }
+#endif
+
+ /* what if we didn't find a virtual interface? */
+ if (v == NULL)
+ {
+ if (no_klips)
+ {
+ /* kludge for testing: invent a virtual device */
+ static const char fvp[] = "virtual";
+ fake_v = *ifp;
+ passert(sizeof(fake_v.name) > sizeof(fvp));
+ strcpy(fake_v.name, fvp);
+ addrtot(&ifp->addr, 0, fake_v.name + sizeof(fvp) - 1
+ , sizeof(fake_v.name) - (sizeof(fvp) - 1));
+ v = &fake_v;
+ }
+ else
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("IP interface %s %s has no matching ipsec* interface -- ignored"
+ , ifp->name, ip_str(&ifp->addr)));
+ continue;
+ }
+ }
+
+ /* We've got all we need; see if this is a new thing:
+ * search old interfaces list.
+ */
+#if defined(linux) && defined(KERNEL26_SUPPORT)
+add_entry:
+#endif
+ {
+ struct iface **p = &interfaces;
+
+ for (;;)
+ {
+ struct iface *q = *p;
+
+ /* search is over if at end of list */
+ if (q == NULL)
+ {
+ /* matches nothing -- create a new entry */
+ int fd = create_socket(ifp, v->name, pluto_port);
+
+ if (fd < 0)
+ break;
+
+ if (nat_traversal_support_non_ike
+ && addrtypeof(&ifp->addr) == AF_INET)
+ {
+ nat_traversal_espinudp_socket(fd, ESPINUDP_WITH_NON_IKE);
+ }
+
+ q = alloc_thing(struct iface, "struct iface");
+ q->rname = clone_str(ifp->name, "real device name");
+ q->vname = clone_str(v->name, "virtual device name");
+ q->addr = ifp->addr;
+ q->fd = fd;
+ q->next = interfaces;
+ q->change = IFN_ADD;
+ interfaces = q;
+ plog("adding interface %s/%s %s:%d"
+ , q->vname, q->rname, ip_str(&q->addr), pluto_port);
+
+ if (nat_traversal_support_port_floating
+ && addrtypeof(&ifp->addr) == AF_INET)
+ {
+ fd = create_socket(ifp, v->name, NAT_T_IKE_FLOAT_PORT);
+ if (fd < 0)
+ break;
+ nat_traversal_espinudp_socket(fd,
+ ESPINUDP_WITH_NON_ESP);
+ q = alloc_thing(struct iface, "struct iface");
+ q->rname = clone_str(ifp->name, "real device name");
+ q->vname = clone_str(v->name, "virtual device name");
+ q->addr = ifp->addr;
+ setportof(htons(NAT_T_IKE_FLOAT_PORT), &q->addr);
+ q->fd = fd;
+ q->next = interfaces;
+ q->change = IFN_ADD;
+ q->ike_float = TRUE;
+ interfaces = q;
+ plog("adding interface %s/%s %s:%d",
+ q->vname, q->rname, ip_str(&q->addr), NAT_T_IKE_FLOAT_PORT);
+ }
+ break;
+ }
+
+ /* search over if matching old entry found */
+ if (streq(q->rname, ifp->name)
+ && streq(q->vname, v->name)
+ && sameaddr(&q->addr, &ifp->addr))
+ {
+ /* matches -- rejuvinate old entry */
+ q->change = IFN_KEEP;
+
+ /* look for other interfaces to keep (due to NAT-T) */
+ for (q = q->next ; q ; q = q->next)
+ {
+ if (streq(q->rname, ifp->name)
+ && streq(q->vname, v->name)
+ && sameaddr(&q->addr, &ifp->addr))
+ {
+ q->change = IFN_KEEP;
+ }
+ }
+ break;
+ }
+
+ /* try again */
+ p = &q->next;
+ } /* for (;;) */
+ }
+ }
+
+ /* delete the raw interfaces list */
+ while (rifaces != NULL)
+ {
+ struct raw_iface *t = rifaces;
+
+ rifaces = t->next;
+ pfree(t);
+ }
+}
+
+void
+find_ifaces(void)
+{
+ mark_ifaces_dead();
+ process_raw_ifaces(find_raw_ifaces4());
+ process_raw_ifaces(find_raw_ifaces6());
+
+ free_dead_ifaces(); /* ditch remaining old entries */
+
+ if (interfaces == NULL)
+ loglog(RC_LOG_SERIOUS, "no public interfaces found");
+}
+
+void
+show_ifaces_status(void)
+{
+ struct iface *p;
+
+ for (p = interfaces; p != NULL; p = p->next)
+ whack_log(RC_COMMENT, "interface %s/%s %s:%d"
+ , p->vname, p->rname, ip_str(&p->addr), ntohs(portof(&p->addr)));
+}
+
+void
+show_debug_status(void)
+{
+#ifdef DEBUG
+ whack_log(RC_COMMENT, "debug %s"
+ , bitnamesof(debug_bit_names, cur_debugging));
+#endif
+}
+
+static volatile sig_atomic_t sighupflag = FALSE;
+
+static void
+huphandler(int sig UNUSED)
+{
+ sighupflag = TRUE;
+}
+
+static volatile sig_atomic_t sigtermflag = FALSE;
+
+static void
+termhandler(int sig UNUSED)
+{
+ sigtermflag = TRUE;
+}
+
+/* call_server listens for incoming ISAKMP packets and Whack messages,
+ * and handles timer events.
+ */
+void
+call_server(void)
+{
+ struct iface *ifp;
+
+ /* catch SIGHUP and SIGTERM */
+ {
+ int r;
+ struct sigaction act;
+
+ act.sa_handler = &huphandler;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0; /* no SA_ONESHOT, no SA_RESTART, no nothing */
+ r = sigaction(SIGHUP, &act, NULL);
+ passert(r == 0);
+
+ act.sa_handler = &termhandler;
+ r = sigaction(SIGTERM, &act, NULL);
+ passert(r == 0);
+ }
+
+ for (;;)
+ {
+ fd_set readfds;
+ fd_set writefds;
+ int ndes;
+
+ /* wait for next interesting thing */
+
+ for (;;)
+ {
+ long next_time = next_event(); /* time to any pending timer event */
+ int maxfd = ctl_fd;
+
+ if (sigtermflag)
+ exit_pluto(0);
+
+ if (sighupflag)
+ {
+ /* Ignorant folks think poking any daemon with SIGHUP
+ * is polite. We catch it and tell them otherwise.
+ * There is one use: unsticking a hung recvfrom.
+ * This sticking happens sometimes -- kernel bug?
+ */
+ sighupflag = FALSE;
+ plog("Pluto ignores SIGHUP -- perhaps you want \"whack --listen\"");
+ }
+
+ FD_ZERO(&readfds);
+ FD_ZERO(&writefds);
+ FD_SET(ctl_fd, &readfds);
+
+ /* the only write file-descriptor of interest */
+ if (adns_qfd != NULL_FD && unsent_ADNS_queries)
+ {
+ if (maxfd < adns_qfd)
+ maxfd = adns_qfd;
+ FD_SET(adns_qfd, &writefds);
+ }
+
+ if (adns_afd != NULL_FD)
+ {
+ if (maxfd < adns_afd)
+ maxfd = adns_afd;
+ FD_SET(adns_afd, &readfds);
+ }
+
+#ifdef KLIPS
+ if (!no_klips)
+ {
+ int fd = *kernel_ops->async_fdp;
+
+ if (kernel_ops->process_queue)
+ kernel_ops->process_queue();
+ if (maxfd < fd)
+ maxfd = fd;
+ passert(!FD_ISSET(fd, &readfds));
+ FD_SET(fd, &readfds);
+ }
+#endif
+
+ if (listening)
+ {
+ for (ifp = interfaces; ifp != NULL; ifp = ifp->next)
+ {
+ if (maxfd < ifp->fd)
+ maxfd = ifp->fd;
+ passert(!FD_ISSET(ifp->fd, &readfds));
+ FD_SET(ifp->fd, &readfds);
+ }
+ }
+
+ if (next_time == -1)
+ {
+ /* select without timer */
+
+ ndes = select(maxfd + 1, &readfds, &writefds, NULL, NULL);
+ }
+ else if (next_time == 0)
+ {
+ /* timer without select: there is a timer event pending,
+ * and it should fire now so don't bother to do the select.
+ */
+ ndes = 0; /* signify timer expiration */
+ }
+ else
+ {
+ /* select with timer */
+
+ struct timeval tm;
+
+ tm.tv_sec = next_time;
+ tm.tv_usec = 0;
+ ndes = select(maxfd + 1, &readfds, &writefds, NULL, &tm);
+ }
+
+ if (ndes != -1)
+ break; /* success */
+
+ if (errno != EINTR)
+ exit_log_errno((e, "select() failed in call_server()"));
+
+ /* retry if terminated by signal */
+ }
+
+ /* figure out what is interesting */
+
+ if (ndes == 0)
+ {
+ /* timer event */
+
+ DBG(DBG_CONTROL,
+ DBG_log(BLANK_FORMAT);
+ DBG_log("*time to handle event"));
+
+ handle_timer_event();
+ passert(GLOBALS_ARE_RESET());
+ }
+ else
+ {
+ /* at least one file descriptor is ready */
+
+ if (adns_qfd != NULL_FD && FD_ISSET(adns_qfd, &writefds))
+ {
+ passert(ndes > 0);
+ send_unsent_ADNS_queries();
+ passert(GLOBALS_ARE_RESET());
+ ndes--;
+ }
+
+ if (adns_afd != NULL_FD && FD_ISSET(adns_afd, &readfds))
+ {
+ passert(ndes > 0);
+ DBG(DBG_CONTROL,
+ DBG_log(BLANK_FORMAT);
+ DBG_log("*received adns message"));
+ handle_adns_answer();
+ passert(GLOBALS_ARE_RESET());
+ ndes--;
+ }
+
+#ifdef KLIPS
+ if (!no_klips && FD_ISSET(*kernel_ops->async_fdp, &readfds))
+ {
+ passert(ndes > 0);
+ DBG(DBG_CONTROL,
+ DBG_log(BLANK_FORMAT);
+ DBG_log("*received kernel message"));
+ kernel_ops->process_msg();
+ passert(GLOBALS_ARE_RESET());
+ ndes--;
+ }
+#endif
+
+ for (ifp = interfaces; ifp != NULL; ifp = ifp->next)
+ {
+ if (FD_ISSET(ifp->fd, &readfds))
+ {
+ /* comm_handle will print DBG_CONTROL intro,
+ * with more info than we have here.
+ */
+
+ passert(ndes > 0);
+ comm_handle(ifp);
+ passert(GLOBALS_ARE_RESET());
+ ndes--;
+ }
+ }
+
+ if (FD_ISSET(ctl_fd, &readfds))
+ {
+ passert(ndes > 0);
+ DBG(DBG_CONTROL,
+ DBG_log(BLANK_FORMAT);
+ DBG_log("*received whack message"));
+ whack_handle(ctl_fd);
+ passert(GLOBALS_ARE_RESET());
+ ndes--;
+ }
+
+ passert(ndes == 0);
+ }
+ }
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset: 4
+ * End Variables:
+ */
diff --git a/src/pluto/server.h b/src/pluto/server.h
new file mode 100644
index 000000000..d90e47c8f
--- /dev/null
+++ b/src/pluto/server.h
@@ -0,0 +1,58 @@
+/* get-next-event loop
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: server.h,v 1.2 2004/03/22 21:53:20 as Exp $
+ */
+
+extern int ctl_fd; /* file descriptor of control (whack) socket */
+extern struct sockaddr_un ctl_addr; /* address of control (whack) socket */
+
+extern int info_fd; /* file descriptor of control (info) socket */
+extern struct sockaddr_un info_addr; /* address of control (info) socket */
+
+extern err_t init_ctl_socket(void);
+extern void delete_ctl_socket(void);
+
+extern bool listening; /* should we pay attention to IKE messages? */
+
+
+/* interface: a terminal point for IKE traffic, IPsec transport mode
+ * and IPsec tunnels.
+ * Essentially:
+ * - an IP device (eg. eth1), and
+ * - its partner, an ipsec device (eg. ipsec0), and
+ * - their shared IP address (eg. 10.7.3.2)
+ * Note: the port for IKE is always implicitly UDP/pluto_port.
+ */
+struct iface {
+ char *vname; /* virtual (ipsec) device name */
+ char *rname; /* real device name */
+ ip_address addr; /* interface IP address */
+ int fd; /* file descriptor of socket for IKE UDP messages */
+ struct iface *next;
+ bool ike_float;
+ enum { IFN_ADD, IFN_KEEP, IFN_DELETE } change;
+};
+
+extern struct iface *interfaces; /* public interfaces */
+
+extern bool use_interface(const char *rifn);
+extern void find_ifaces(void);
+extern void show_ifaces_status(void);
+extern void free_ifaces(void);
+extern void show_debug_status(void);
+extern void call_server(void);
+
+/* in rcv_info.c */
+extern err_t init_info_socket(void);
+extern void delete_info_socket(void);
diff --git a/src/pluto/sha1.c b/src/pluto/sha1.c
new file mode 100644
index 000000000..bbf062876
--- /dev/null
+++ b/src/pluto/sha1.c
@@ -0,0 +1,193 @@
+/*
+SHA-1 in C
+By Steve Reid <steve@edmweb.com>
+100% Public Domain
+
+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
+*/
+
+/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */
+/* #define SHA1HANDSOFF * Copies data before messing with it. */
+
+#define SHA1HANDSOFF
+
+#include <string.h>
+#include <sys/types.h> /* for u_int*_t */
+#include <endian.h> /* sets BYTE_ORDER, LITTLE_ENDIAN, and BIG_ENDIAN */
+
+#include "sha1.h"
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from SSLeay */
+#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);
+
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+
+void SHA1Transform(u_int32_t state[5], const unsigned char buffer[64])
+{
+u_int32_t a, b, c, d, e;
+typedef union {
+ unsigned char c[64];
+ u_int32_t l[16];
+} CHAR64LONG16;
+#ifdef SHA1HANDSOFF
+CHAR64LONG16 block[1]; /* use array to appear as a pointer */
+ memcpy(block, buffer, 64);
+#else
+ /* The following had better never be used because it causes the
+ * pointer-to-const buffer to be cast into a pointer to non-const.
+ * And the result is written through. I threw a "const" in, hoping
+ * this will cause a diagnostic.
+ */
+CHAR64LONG16* block = (const CHAR64LONG16*)buffer;
+#endif
+ /* 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;
+#ifdef SHA1HANDSOFF
+ memset(block, '\0', sizeof(block));
+#endif
+}
+
+
+/* SHA1Init - Initialize new context */
+
+void SHA1Init(SHA1_CTX* context)
+{
+ /* SHA1 initialization constants */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xC3D2E1F0;
+ context->count[0] = context->count[1] = 0;
+}
+
+
+/* Run your data through this. */
+
+void SHA1Update(SHA1_CTX* context, const unsigned char* data, u_int32_t len)
+{
+u_int32_t i;
+u_int32_t j;
+
+ j = context->count[0];
+ if ((context->count[0] += len << 3) < j)
+ context->count[1]++;
+ context->count[1] += (len>>29);
+ j = (j >> 3) & 63;
+ if ((j + len) > 63) {
+ memcpy(&context->buffer[j], data, (i = 64-j));
+ SHA1Transform(context->state, context->buffer);
+ for ( ; i + 63 < len; i += 64) {
+ SHA1Transform(context->state, &data[i]);
+ }
+ j = 0;
+ }
+ else i = 0;
+ memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+
+/* Add padding and return the message digest. */
+
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
+{
+unsigned i;
+unsigned char finalcount[8];
+unsigned char c;
+
+#if 0 /* untested "improvement" by DHR */
+ /* Convert context->count to a sequence of bytes
+ * in finalcount. Second element first, but
+ * big-endian order within element.
+ * But we do it all backwards.
+ */
+ unsigned char *fcp = &finalcount[8];
+
+ for (i = 0; i < 2; i++)
+ {
+ u_int32_t t = context->count[i];
+ int j;
+
+ for (j = 0; j < 4; t >>= 8, j++)
+ *--fcp = (unsigned char) t
+ }
+#else
+ for (i = 0; i < 8; i++) {
+ finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
+ >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
+ }
+#endif
+ c = 0200;
+ SHA1Update(context, &c, 1);
+ while ((context->count[0] & 504) != 448) {
+ c = 0000;
+ SHA1Update(context, &c, 1);
+ }
+ SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
+ for (i = 0; i < 20; i++) {
+ digest[i] = (unsigned char)
+ ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+ }
+ /* Wipe variables */
+ memset(context, '\0', sizeof(*context));
+ memset(&finalcount, '\0', sizeof(finalcount));
+}
diff --git a/src/pluto/sha1.h b/src/pluto/sha1.h
new file mode 100644
index 000000000..64b3d2f5d
--- /dev/null
+++ b/src/pluto/sha1.h
@@ -0,0 +1,16 @@
+/*
+SHA-1 in C
+By Steve Reid <steve@edmweb.com>
+100% Public Domain
+*/
+
+typedef struct {
+ u_int32_t state[5];
+ u_int32_t count[2];
+ unsigned char buffer[64];
+} SHA1_CTX;
+
+void SHA1Transform(u_int32_t state[5], const unsigned char buffer[64]);
+void SHA1Init(SHA1_CTX* context);
+void SHA1Update(SHA1_CTX* context, const unsigned char* data, u_int32_t len);
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
diff --git a/src/pluto/smallprime.c b/src/pluto/smallprime.c
new file mode 100644
index 000000000..87497d096
--- /dev/null
+++ b/src/pluto/smallprime.c
@@ -0,0 +1,122 @@
+/* smallprime.c - List of small primes
+ * Copyright (C) 1998 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef PLUTO
+#include <gmp.h>
+#include <freeswan.h>
+#include "constants.h"
+#include "defs.h"
+#include "gcryptfix.h"
+#else
+/* #include <config.h> */
+/* #include <stdio.h> */
+/* #include <stdlib.h> */
+/* #include "util.h" */
+/* #include "types.h" */
+#endif
+
+/* Note: 2 is not included because it can be tested more easily
+ * by looking at bit 0. The last entry in this list is marked by a zero
+ */
+ushort
+small_prime_numbers[] = {
+ 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43,
+ 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101,
+ 103, 107, 109, 113, 127, 131, 137, 139, 149, 151,
+ 157, 163, 167, 173, 179, 181, 191, 193, 197, 199,
+ 211, 223, 227, 229, 233, 239, 241, 251, 257, 263,
+ 269, 271, 277, 281, 283, 293, 307, 311, 313, 317,
+ 331, 337, 347, 349, 353, 359, 367, 373, 379, 383,
+ 389, 397, 401, 409, 419, 421, 431, 433, 439, 443,
+ 449, 457, 461, 463, 467, 479, 487, 491, 499, 503,
+ 509, 521, 523, 541, 547, 557, 563, 569, 571, 577,
+ 587, 593, 599, 601, 607, 613, 617, 619, 631, 641,
+ 643, 647, 653, 659, 661, 673, 677, 683, 691, 701,
+ 709, 719, 727, 733, 739, 743, 751, 757, 761, 769,
+ 773, 787, 797, 809, 811, 821, 823, 827, 829, 839,
+ 853, 857, 859, 863, 877, 881, 883, 887, 907, 911,
+ 919, 929, 937, 941, 947, 953, 967, 971, 977, 983,
+ 991, 997, 1009, 1013, 1019, 1021, 1031, 1033,
+ 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091,
+ 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151,
+ 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213,
+ 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277,
+ 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307,
+ 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399,
+ 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451,
+ 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493,
+ 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559,
+ 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609,
+ 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667,
+ 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733,
+ 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789,
+ 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871,
+ 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931,
+ 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997,
+ 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053,
+ 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111,
+ 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161,
+ 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243,
+ 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297,
+ 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357,
+ 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411,
+ 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473,
+ 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551,
+ 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633,
+ 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687,
+ 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729,
+ 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791,
+ 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851,
+ 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917,
+ 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999,
+ 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061,
+ 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137,
+ 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209,
+ 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271,
+ 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331,
+ 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391,
+ 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467,
+ 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533,
+ 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583,
+ 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643,
+ 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709,
+ 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779,
+ 3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851,
+ 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917,
+ 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989,
+ 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049,
+ 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111,
+ 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177,
+ 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243,
+ 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297,
+ 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391,
+ 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457,
+ 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519,
+ 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597,
+ 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657,
+ 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729,
+ 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799,
+ 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889,
+ 4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951,
+ 4957, 4967, 4969, 4973, 4987, 4993, 4999,
+ 0
+};
+
+
diff --git a/src/pluto/smartcard.c b/src/pluto/smartcard.c
new file mode 100644
index 000000000..744f8a6f3
--- /dev/null
+++ b/src/pluto/smartcard.c
@@ -0,0 +1,1956 @@
+/* Support of smartcards and cryptotokens
+ * Copyright (C) 2003 Christoph Gysin, Simon Zwahlen
+ * Copyright (C) 2004 David Buechi, Michael Meier
+ * Zuercher Hochschule Winterthur, Switzerland
+ *
+ * Copyright (C) 2005 Michael Joosten
+ *
+ * Copyright (C) 2005 Andreas Steffen
+ * Hochschule für Technik Rapperswil, Switzerland
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: smartcard.c,v 1.41 2006/01/04 21:03:52 as Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+#include <dlfcn.h>
+
+#include <freeswan.h>
+#include <ipsec_policy.h>
+
+#include "constants.h"
+
+#ifdef SMARTCARD
+#include "rsaref/unix.h"
+#include "rsaref/pkcs11.h"
+#endif
+
+#include "defs.h"
+#include "mp_defs.h"
+#include "log.h"
+#include "x509.h"
+#include "ca.h"
+#include "certs.h"
+#include "keys.h"
+#include "smartcard.h"
+#include "whack.h"
+#include "fetch.h"
+
+#define DEFAULT_BASE 16
+
+/* chained list of smartcard records */
+static smartcard_t *smartcards = NULL;
+
+/* number of generated sc objects */
+static int sc_number = 0;
+
+const smartcard_t empty_sc = {
+ NULL , /* next */
+ 0 , /* last_load */
+ { CERT_NONE, {NULL} }, /* last_cert */
+ 0 , /* count */
+ 0 , /* number */
+ 999999 , /* slot */
+ NULL , /* id */
+ NULL , /* label */
+ { NULL, 0 } , /* pin */
+ FALSE , /* pinpad */
+ FALSE , /* valid */
+ FALSE , /* session_opened */
+ FALSE , /* logged_in */
+ TRUE , /* any_slot */
+ 0L , /* session */
+};
+
+#ifdef SMARTCARD /* compile with smartcard support */
+
+#define SCX_MAGIC 0xd00bed00
+
+struct scx_pkcs11_module {
+ u_int _magic;
+ void *handle;
+};
+
+typedef struct scx_pkcs11_module scx_pkcs11_module_t;
+
+/* PKCS #11 cryptoki context */
+static bool scx_initialized = FALSE;
+static scx_pkcs11_module_t *pkcs11_module = NULL_PTR;
+static CK_FUNCTION_LIST_PTR pkcs11_functions = NULL_PTR;
+
+/* crytoki v2.11 - return values of PKCS #11 functions*/
+
+static const char *const pkcs11_return_name[] = {
+ "CKR_OK",
+ "CKR_CANCEL",
+ "CKR_HOST_MEMORY",
+ "CKR_SLOT_ID_INVALID",
+ "CKR_FLAGS_INVALID",
+ "CKR_GENERAL_ERROR",
+ "CKR_FUNCTION_FAILED",
+ "CKR_ARGUMENTS_BAD",
+ "CKR_NO_EVENT",
+ "CKR_NEED_TO_CREATE_THREADS",
+ "CKR_CANT_LOCK"
+ };
+
+static const char *const pkcs11_return_name_10[] = {
+ "CKR_ATTRIBUTE_READ_ONLY",
+ "CKR_ATTRIBUTE_SENSITIVE",
+ "CKR_ATTRIBUTE_TYPE_INVALID",
+ "CKR_ATTRIBUTE_VALUE_INVALID"
+ };
+
+static const char *const pkcs11_return_name_20[] = {
+ "CKR_DATA_INVALID",
+ "CKR_DATA_LEN_RANGE"
+ };
+
+static const char *const pkcs11_return_name_30[] = {
+ "CKR_DEVICE_ERROR",
+ "CKR_DEVICE_MEMORY",
+ "CKR_DEVICE_REMOVED"
+ };
+
+static const char *const pkcs11_return_name_40[] = {
+ "CKR_ENCRYPTED_DATA_INVALID",
+ "CKR_ENCRYPTED_DATA_LEN_RANGE"
+ };
+
+static const char *const pkcs11_return_name_50[] = {
+ "CKR_FUNCTION_CANCELED",
+ "CKR_FUNCTION_NOT_PARALLEL",
+ "CKR_0x52_UNDEFINED",
+ "CKR_0x53_UNDEFINED",
+ "CKR_FUNCTION_NOT_SUPPORTED"
+ };
+
+static const char *const pkcs11_return_name_60[] = {
+ "CKR_KEY_HANDLE_INVALID",
+ "CKR_KEY_SENSITIVE",
+ "CKR_KEY_SIZE_RANGE",
+ "CKR_KEY_TYPE_INCONSISTENT",
+ "CKR_KEY_NOT_NEEDED",
+ "CKR_KEY_CHANGED",
+ "CKR_KEY_NEEDED",
+ "CKR_KEY_INDIGESTIBLE",
+ "CKR_KEY_FUNCTION_NOT_PERMITTED",
+ "CKR_KEY_NOT_WRAPPABLE",
+ "CKR_KEY_UNEXTRACTABLE"
+ };
+
+static const char *const pkcs11_return_name_70[] = {
+ "CKR_MECHANISM_INVALID",
+ "CKR_MECHANISM_PARAM_INVALID"
+ };
+
+static const char *const pkcs11_return_name_80[] = {
+ "CKR_OBJECT_HANDLE_INVALID"
+ };
+
+static const char *const pkcs11_return_name_90[] = {
+ "CKR_OPERATION_ACTIVE",
+ "CKR_OPERATION_NOT_INITIALIZED"
+ };
+
+static const char *const pkcs11_return_name_A0[] = {
+ "CKR_PIN_INCORRECT",
+ "CKR_PIN_INVALID",
+ "CKR_PIN_LEN_RANGE",
+ "CKR_PIN_EXPIRED",
+ "CKR_PIN_LOCKED"
+ };
+
+static const char *const pkcs11_return_name_B0[] = {
+ "CKR_SESSION_CLOSED",
+ "CKR_SESSION_COUNT",
+ "CKR_0xB2_UNDEFINED",
+ "CKR_SESSION_HANDLE_INVALID",
+ "CKR_SESSION_PARALLEL_NOT_SUPPORTED",
+ "CKR_SESSION_READ_ONLY",
+ "CKR_SESSION_EXISTS",
+ "CKR_SESSION_READ_ONLY_EXISTS",
+ "CKR_SESSION_READ_WRITE_SO_EXISTS"
+ };
+
+static const char *const pkcs11_return_name_C0[] = {
+ "CKR_SIGNATURE_INVALID",
+ "CKR_SIGNATURE_LEN_RANGE"
+ };
+
+static const char *const pkcs11_return_name_D0[] = {
+ "CKR_TEMPLATE_INCOMPLETE",
+ "CKR_TEMPLATE_INCONSISTENT"
+ };
+
+static const char *const pkcs11_return_name_E0[] = {
+ "CKR_TOKEN_NOT_PRESENT",
+ "CKR_TOKEN_NOT_RECOGNIZED",
+ "CKR_TOKEN_WRITE_PROTECTED"
+ };
+
+static const char *const pkcs11_return_name_F0[] = {
+ "CKR_UNWRAPPING_KEY_HANDLE_INVALID",
+ "CKR_UNWRAPPING_KEY_SIZE_RANGE",
+ "CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT"
+ };
+
+static const char *const pkcs11_return_name_100[] = {
+ "CKR_USER_ALREADY_LOGGED_IN",
+ "CKR_USER_NOT_LOGGED_IN",
+ "CKR_USER_PIN_NOT_INITIALIZED",
+ "CKR_USER_TYPE_INVALID",
+ "CKR_USER_ANOTHER_ALREADY_LOGGED_IN",
+ "CKR_USER_TOO_MANY_TYPES"
+ };
+
+static const char *const pkcs11_return_name_110[] = {
+ "CKR_WRAPPED_KEY_INVALID",
+ "CKR_0x111_UNDEFINED",
+ "CKR_WRAPPED_KEY_LEN_RANGE",
+ "CKR_WRAPPING_KEY_HANDLE_INVALID",
+ "CKR_WRAPPING_KEY_SIZE_RANGE",
+ "CKR_WRAPPING_KEY_TYPE_INCONSISTENT"
+ };
+
+static const char *const pkcs11_return_name_120[] = {
+ "CKR_RANDOM_SEED_NOT_SUPPORTED",
+ "CKR_RANDOM_NO_RNG"
+ };
+
+static const char *const pkcs11_return_name_130[] = {
+ "CKR_DOMAIN_PARAMS_INVALID"
+ };
+
+static const char *const pkcs11_return_name_150[] = {
+ "CKR_BUFFER_TOO_SMALL"
+ };
+
+static const char *const pkcs11_return_name_160[] = {
+ "CKR_SAVED_STATE_INVALID"
+ };
+
+static const char *const pkcs11_return_name_170[] = {
+ "CKR_INFORMATION_SENSITIVE"
+ };
+
+static const char *const pkcs11_return_name_180[] = {
+ "CKR_STATE_UNSAVEABLE"
+ };
+
+static const char *const pkcs11_return_name_190[] = {
+ "CKR_CRYPTOKI_NOT_INITIALIZED",
+ "CKR_CRYPTOKI_ALREADY_INITIALIZED"
+ };
+
+static const char *const pkcs11_return_name_1A0[] = {
+ "CKR_MUTEX_BAD",
+ "CKR_MUTEX_NOT_LOCKED"
+ };
+
+static const char *const pkcs11_return_name_200[] = {
+ "CKR_FUNCTION_REJECTED"
+ };
+
+static const char *const pkcs11_return_name_vendor[] = {
+ "CKR_VENDOR_DEFINED"
+ };
+
+static enum_names pkcs11_return_names_vendor =
+ { CKR_VENDOR_DEFINED, CKR_VENDOR_DEFINED
+ , pkcs11_return_name_vendor, NULL };
+
+static enum_names pkcs11_return_names_200 =
+ { CKR_FUNCTION_REJECTED, CKR_FUNCTION_REJECTED
+ , pkcs11_return_name_200, &pkcs11_return_names_vendor };
+
+static enum_names pkcs11_return_names_1A0 =
+ { CKR_MUTEX_BAD, CKR_MUTEX_NOT_LOCKED
+ , pkcs11_return_name_1A0, &pkcs11_return_names_200 };
+
+static enum_names pkcs11_return_names_190 =
+ { CKR_CRYPTOKI_NOT_INITIALIZED, CKR_CRYPTOKI_ALREADY_INITIALIZED
+ , pkcs11_return_name_190, &pkcs11_return_names_1A0 };
+
+static enum_names pkcs11_return_names_180 =
+ { CKR_STATE_UNSAVEABLE, CKR_STATE_UNSAVEABLE
+ , pkcs11_return_name_180, &pkcs11_return_names_190 };
+
+static enum_names pkcs11_return_names_170 =
+ { CKR_INFORMATION_SENSITIVE, CKR_INFORMATION_SENSITIVE
+ , pkcs11_return_name_170, &pkcs11_return_names_180 };
+
+static enum_names pkcs11_return_names_160 =
+ { CKR_SAVED_STATE_INVALID, CKR_SAVED_STATE_INVALID
+ , pkcs11_return_name_160, &pkcs11_return_names_170 };
+
+static enum_names pkcs11_return_names_150 =
+ { CKR_BUFFER_TOO_SMALL, CKR_BUFFER_TOO_SMALL
+ , pkcs11_return_name_150, &pkcs11_return_names_160 };
+
+static enum_names pkcs11_return_names_130 =
+ { CKR_DOMAIN_PARAMS_INVALID, CKR_DOMAIN_PARAMS_INVALID
+ , pkcs11_return_name_130, &pkcs11_return_names_150 };
+
+static enum_names pkcs11_return_names_120 =
+ { CKR_RANDOM_SEED_NOT_SUPPORTED, CKR_RANDOM_NO_RNG
+ , pkcs11_return_name_120, &pkcs11_return_names_130 };
+
+static enum_names pkcs11_return_names_110 =
+ { CKR_WRAPPED_KEY_INVALID, CKR_WRAPPING_KEY_TYPE_INCONSISTENT
+ , pkcs11_return_name_110, &pkcs11_return_names_120 };
+
+static enum_names pkcs11_return_names_100 =
+ { CKR_USER_ALREADY_LOGGED_IN, CKR_USER_TOO_MANY_TYPES
+ , pkcs11_return_name_100, &pkcs11_return_names_110 };
+
+static enum_names pkcs11_return_names_F0 =
+ { CKR_UNWRAPPING_KEY_HANDLE_INVALID, CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT
+ , pkcs11_return_name_F0, &pkcs11_return_names_100 };
+
+static enum_names pkcs11_return_names_E0 =
+ { CKR_TOKEN_NOT_PRESENT, CKR_TOKEN_WRITE_PROTECTED
+ , pkcs11_return_name_E0, &pkcs11_return_names_F0 };
+
+static enum_names pkcs11_return_names_D0 =
+ { CKR_TEMPLATE_INCOMPLETE, CKR_TEMPLATE_INCONSISTENT
+ , pkcs11_return_name_D0,&pkcs11_return_names_E0 };
+
+static enum_names pkcs11_return_names_C0 =
+ { CKR_SIGNATURE_INVALID, CKR_SIGNATURE_LEN_RANGE
+ , pkcs11_return_name_C0, &pkcs11_return_names_D0 };
+
+static enum_names pkcs11_return_names_B0 =
+ { CKR_SESSION_CLOSED, CKR_SESSION_READ_WRITE_SO_EXISTS
+ , pkcs11_return_name_B0, &pkcs11_return_names_C0 };
+
+static enum_names pkcs11_return_names_A0 =
+ { CKR_PIN_INCORRECT, CKR_PIN_LOCKED
+ , pkcs11_return_name_A0, &pkcs11_return_names_B0 };
+
+static enum_names pkcs11_return_names_90 =
+ { CKR_OPERATION_ACTIVE, CKR_OPERATION_NOT_INITIALIZED
+ , pkcs11_return_name_90, &pkcs11_return_names_A0 };
+
+static enum_names pkcs11_return_names_80 =
+ { CKR_OBJECT_HANDLE_INVALID, CKR_OBJECT_HANDLE_INVALID
+ , pkcs11_return_name_80, &pkcs11_return_names_90 };
+
+static enum_names pkcs11_return_names_70 =
+ { CKR_MECHANISM_INVALID, CKR_MECHANISM_PARAM_INVALID
+ , pkcs11_return_name_70, &pkcs11_return_names_80 };
+
+static enum_names pkcs11_return_names_60 =
+ { CKR_KEY_HANDLE_INVALID, CKR_KEY_UNEXTRACTABLE
+ , pkcs11_return_name_60, &pkcs11_return_names_70 };
+
+static enum_names pkcs11_return_names_50 =
+ { CKR_FUNCTION_CANCELED, CKR_FUNCTION_NOT_SUPPORTED
+ , pkcs11_return_name_50, &pkcs11_return_names_60 };
+
+static enum_names pkcs11_return_names_40 =
+ { CKR_ENCRYPTED_DATA_INVALID, CKR_ENCRYPTED_DATA_LEN_RANGE
+ , pkcs11_return_name_40, &pkcs11_return_names_50 };
+
+static enum_names pkcs11_return_names_30 =
+ { CKR_DEVICE_ERROR, CKR_DEVICE_REMOVED
+ , pkcs11_return_name_30, &pkcs11_return_names_40 };
+
+static enum_names pkcs11_return_names_20 =
+ { CKR_DATA_INVALID, CKR_DATA_LEN_RANGE
+ , pkcs11_return_name_20, &pkcs11_return_names_30 };
+
+static enum_names pkcs11_return_names_10 =
+ { CKR_ATTRIBUTE_READ_ONLY, CKR_ATTRIBUTE_VALUE_INVALID
+ , pkcs11_return_name_10, &pkcs11_return_names_20};
+
+static enum_names pkcs11_return_names =
+ { CKR_OK, CKR_CANT_LOCK
+ , pkcs11_return_name, &pkcs11_return_names_10};
+
+/*
+ * Unload a PKCS#11 module.
+ * The calling application is responsible for cleaning up
+ * and calling C_Finalize()
+ */
+static CK_RV
+scx_unload_pkcs11_module(scx_pkcs11_module_t *mod)
+{
+ if (!mod || mod->_magic != SCX_MAGIC)
+ return CKR_ARGUMENTS_BAD;
+
+ if (dlclose(mod->handle) < 0)
+ return CKR_FUNCTION_FAILED;
+
+ memset(mod, 0, sizeof(*mod));
+ pfree(mod);
+ return CKR_OK;
+}
+
+static scx_pkcs11_module_t*
+scx_load_pkcs11_module(const char *name, CK_FUNCTION_LIST_PTR_PTR funcs)
+{
+ CK_RV (*c_get_function_list)(CK_FUNCTION_LIST_PTR_PTR);
+ scx_pkcs11_module_t *mod;
+ void *handle;
+ int rv;
+
+ if (name == NULL || *name == '\0')
+ return NULL;
+
+ /* Try to load PKCS#11 library module*/
+ handle = dlopen(name, RTLD_NOW);
+ if (handle == NULL)
+ return NULL;
+
+ mod = alloc_thing(scx_pkcs11_module_t, "scx_pkcs11_module");
+ mod->_magic = SCX_MAGIC;
+ mod->handle = handle;
+
+ /* Get the list of function pointers */
+ c_get_function_list = (CK_RV (*)(CK_FUNCTION_LIST_PTR_PTR))
+ dlsym(mod->handle, "C_GetFunctionList");
+ if (!c_get_function_list)
+ goto failed;
+
+ rv = c_get_function_list(funcs);
+ if (rv == CKR_OK)
+ return mod;
+
+failed: scx_unload_pkcs11_module(mod);
+ return NULL;
+}
+
+/*
+ * retrieve a certificate object
+ */
+static bool
+scx_find_cert_object(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object
+, smartcard_t *sc, cert_t *cert)
+{
+ size_t hex_len, label_len;
+ u_char *hex_id = NULL;
+ chunk_t blob;
+ x509cert_t *x509cert;
+
+ CK_ATTRIBUTE attr[] = {
+ { CKA_ID, NULL_PTR, 0L },
+ { CKA_LABEL, NULL_PTR, 0L },
+ { CKA_VALUE, NULL_PTR, 0L }
+ };
+
+ /* initialize the return argument */
+ *cert = empty_cert;
+
+ /* get the length of the attributes first */
+ CK_RV rv = pkcs11_functions->C_GetAttributeValue(session, object, attr, 3);
+ if (rv != CKR_OK)
+ {
+ plog("couldn't read the attribute sizes: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ return FALSE;
+ }
+
+ pfreeany(sc->label);
+
+ hex_id = alloc_bytes(attr[0].ulValueLen, "hex id");
+ hex_len = attr[0].ulValueLen;
+ sc->label = alloc_bytes(attr[1].ulValueLen + 1, "sc label");
+ label_len = attr[1].ulValueLen;
+ blob.ptr = alloc_bytes(attr[2].ulValueLen, "x509cert blob");
+ blob.len = attr[2].ulValueLen;
+
+ attr[0].pValue = hex_id;
+ attr[1].pValue = sc->label;
+ attr[2].pValue = blob.ptr;
+
+ /* now get the attributes */
+ rv = pkcs11_functions->C_GetAttributeValue(session, object, attr, 3);
+ if (rv != CKR_OK)
+ {
+ plog("couldn't read the attributes: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ pfree(hex_id);
+ pfreeany(sc->label);
+ pfree(blob.ptr);
+ return FALSE;
+ }
+
+ pfreeany(sc->id);
+
+ /* convert id from hex to ASCII */
+ sc->id = alloc_bytes(2*hex_len + 1, " sc id");
+ datatot(hex_id, hex_len, 16, sc->id, 2*hex_len + 1);
+ pfree(hex_id);
+
+ /* safeguard in case the label is not null terminated */
+ sc->label[label_len] = '\0';
+
+ /* parse the retrieved cert */
+ x509cert = alloc_thing(x509cert_t, "x509cert");
+ *x509cert = empty_x509cert;
+ x509cert->smartcard = TRUE;
+
+ if (!parse_x509cert(blob, 0, x509cert))
+ {
+ plog("failed to load cert from smartcard, error in X.509 certificate");
+ free_x509cert(x509cert);
+ return FALSE;
+ }
+ cert->type = CERT_X509_SIGNATURE;
+ cert->u.x509 = x509cert;
+ return TRUE;
+}
+
+/*
+ * search a given slot for PKCS#11 certificate objects
+ */
+static void
+scx_find_cert_objects(CK_SLOT_ID slot, CK_SESSION_HANDLE session)
+{
+ CK_RV rv;
+ CK_OBJECT_CLASS class = CKO_CERTIFICATE;
+ CK_ATTRIBUTE attr[] = {{ CKA_CLASS, &class, sizeof(class) }};
+
+ rv = pkcs11_functions->C_FindObjectsInit(session, attr, 1);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_FindObjectsInit: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ return;
+ }
+
+ for (;;)
+ {
+ CK_OBJECT_HANDLE object;
+ CK_ULONG obj_count = 0;
+ err_t ugh;
+ time_t valid_until;
+ smartcard_t *sc;
+ x509cert_t *cert;
+
+ rv = pkcs11_functions->C_FindObjects(session, &object, 1, &obj_count);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_FindObjects: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ break;
+ }
+
+ /* no objects left */
+ if (obj_count == 0)
+ break;
+
+ /* create and initialize a new smartcard object */
+ sc = alloc_thing(smartcard_t, "smartcard");
+ *sc = empty_sc;
+ sc->any_slot = FALSE;
+ sc->slot = slot;
+
+ if (!scx_find_cert_object(session, object, sc, &sc->last_cert))
+ {
+ scx_free(sc);
+ continue;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("found cert in %s with id: %s, label: '%s'"
+ , scx_print_slot(sc, ""), sc->id, sc->label)
+ )
+
+ /* check validity of certificate */
+ cert = sc->last_cert.u.x509;
+ valid_until = cert->notAfter;
+ ugh = check_validity(cert, &valid_until);
+ if (ugh != NULL)
+ {
+ plog(" %s", ugh);
+ free_x509cert(cert);
+ scx_free(sc);
+ continue;
+ }
+ else
+ {
+ DBG(DBG_CONTROL,
+ DBG_log(" certificate is valid")
+ )
+ }
+
+ sc = scx_add(sc);
+
+ /* put end entity and ca certificates into different chains */
+ if (cert->isCA)
+ add_authcert(cert, AUTH_CA);
+ else
+ {
+ add_x509_public_key(cert, valid_until, DAL_LOCAL);
+ sc->last_cert.u.x509 = add_x509cert(cert);
+ }
+
+ share_cert(sc->last_cert);
+ time(&sc->last_load);
+ }
+
+ rv = pkcs11_functions->C_FindObjectsFinal(session);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_FindObjectsFinal: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ }
+}
+
+/*
+ * search all slots for PKCS#11 certificate objects
+ */
+static void
+scx_find_all_cert_objects(void)
+{
+ CK_RV rv;
+ CK_SLOT_ID_PTR slots = NULL_PTR;
+ CK_ULONG slot_count = 0;
+ CK_ULONG i;
+
+ if (!scx_initialized)
+ {
+ plog("pkcs11 module not initialized");
+ return;
+ }
+
+ /* read size, always returns CKR_OK ! */
+ rv = pkcs11_functions->C_GetSlotList(FALSE, NULL_PTR, &slot_count);
+
+ /* allocate memory for the slots */
+ slots = (CK_SLOT_ID *)alloc_bytes(slot_count * sizeof(CK_SLOT_ID), "slots");
+
+ rv = pkcs11_functions->C_GetSlotList(FALSE, slots, &slot_count);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_GetSlotList: %s", enum_show(&pkcs11_return_names, rv));
+ pfreeany(slots);
+ return;
+ }
+
+ /* look in every slot for certificate objects */
+ for (i = 0; i < slot_count; i++)
+ {
+ CK_SLOT_ID slot = slots[i];
+ CK_SLOT_INFO info;
+ CK_SESSION_HANDLE session;
+
+ rv = pkcs11_functions->C_GetSlotInfo(slot, &info);
+
+ if (rv != CKR_OK)
+ {
+ plog("error in C_GetSlotInfo: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ continue;
+ }
+
+ if (!(info.flags & CKF_TOKEN_PRESENT))
+ {
+ plog("no token present in slot %lu", slot);
+ continue;
+ }
+
+ rv = pkcs11_functions->C_OpenSession(slot
+ , CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &session);
+ if (rv != CKR_OK)
+ {
+ plog("failed to open a session on slot %lu: %s"
+ , slot, enum_show(&pkcs11_return_names, rv));
+ continue;
+ }
+ DBG(DBG_CONTROLMORE,
+ DBG_log("pkcs11 session #%ld for searching slot %lu", session, slot)
+ )
+ scx_find_cert_objects(slot, session);
+
+ rv = pkcs11_functions->C_CloseSession(session);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_CloseSession: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ }
+ }
+ pfreeany(slots);
+}
+#endif
+
+/*
+ * load and initialize PKCS#11 cryptoki module
+ */
+void
+scx_init(const char* module)
+{
+#ifdef SMARTCARD
+ CK_RV rv;
+
+ if (scx_initialized)
+ {
+ plog("weird - pkcs11 module seems already to be initialized");
+ return;
+ }
+
+ if (module == NULL)
+#ifdef PKCS11_DEFAULT_LIB
+ module = PKCS11_DEFAULT_LIB;
+#else
+ {
+ plog("no pkcs11 module defined");
+ return;
+ }
+#endif
+
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ DBG_log("pkcs11 module '%s' loading...", module)
+ )
+ pkcs11_module = scx_load_pkcs11_module(module, &pkcs11_functions);
+ if (pkcs11_module == NULL)
+ {
+ plog("failed to load pkcs11 module '%s'", module);
+ return;
+ }
+
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ DBG_log("pkcs11 module initializing...")
+ )
+ rv = pkcs11_functions->C_Initialize(NULL);
+ if (rv != CKR_OK)
+ {
+ plog("failed to initialize pkcs11 module: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ return;
+ }
+
+ scx_initialized = TRUE;
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ DBG_log("pkcs11 module loaded and initialized")
+ )
+
+ scx_find_all_cert_objects();
+#endif
+}
+
+/*
+ * finalize and unload PKCS#11 cryptoki module
+ */
+void
+scx_finalize(void)
+{
+#ifdef SMARTCARD
+ while (smartcards != NULL)
+ {
+ scx_release(smartcards);
+ }
+
+ if (pkcs11_functions != NULL_PTR)
+ {
+ pkcs11_functions->C_Finalize(NULL_PTR);
+ pkcs11_functions = NULL_PTR;
+ }
+
+ if (pkcs11_module != NULL)
+ {
+ scx_unload_pkcs11_module(pkcs11_module);
+ pkcs11_module = NULL;
+ }
+
+ scx_initialized = FALSE;
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ DBG_log("pkcs11 module finalized and unloaded")
+ )
+#endif
+}
+
+/*
+ * does a filename contain the token %smartcard?
+ */
+bool
+scx_on_smartcard(const char *filename)
+{
+ return strncmp(filename, SCX_TOKEN, strlen(SCX_TOKEN)) == 0;
+}
+
+#ifdef SMARTCARD
+/*
+ * find a specific object on the smartcard
+ */
+static bool
+scx_pkcs11_find_object( CK_SESSION_HANDLE session,
+ CK_OBJECT_HANDLE_PTR object,
+ CK_OBJECT_CLASS class,
+ const char* id)
+{
+ size_t len;
+ char buf[BUF_LEN];
+ CK_RV rv;
+ CK_ULONG obj_count = 0;
+ CK_ULONG attr_count = 1;
+
+ CK_ATTRIBUTE attr[] = {
+ { CKA_CLASS, &class, sizeof(class) },
+ { CKA_ID, &buf, 0L }
+ };
+
+ if (id != NULL)
+ {
+ ttodata(id, strlen(id), 16, buf, BUF_LEN, &len);
+ attr[1].ulValueLen = len;
+ attr_count = 2;
+ }
+
+ /* get info for certificate with id */
+ rv = pkcs11_functions->C_FindObjectsInit(session, attr, attr_count);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_FindObjectsInit: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ return FALSE;
+ }
+
+ rv = pkcs11_functions->C_FindObjects(session, object, 1, &obj_count);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_FindObjects: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ return FALSE;
+ }
+
+ rv = pkcs11_functions->C_FindObjectsFinal(session);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_FindObjectsFinal: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ return FALSE;
+ }
+
+ return (obj_count != 0);
+}
+
+/*
+ * check if a given certificate object id is found in a slot
+ */
+static bool
+scx_find_cert_id_in_slot(smartcard_t *sc, CK_SLOT_ID slot)
+{
+ CK_SESSION_HANDLE session;
+ CK_OBJECT_HANDLE object;
+ CK_SLOT_INFO info;
+
+ CK_RV rv = pkcs11_functions->C_GetSlotInfo(slot, &info);
+
+ if (rv != CKR_OK)
+ {
+ plog("error in C_GetSlotInfo: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ return FALSE;
+ }
+
+ if (!(info.flags & CKF_TOKEN_PRESENT))
+ {
+ plog("no token present in slot %lu", slot);
+ return FALSE;
+ }
+
+ rv = pkcs11_functions->C_OpenSession(slot
+ , CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &session);
+ if (rv != CKR_OK)
+ {
+ plog("failed to open a session on slot %lu: %s"
+ , slot, enum_show(&pkcs11_return_names, rv));
+ return FALSE;
+ }
+ DBG(DBG_CONTROLMORE,
+ DBG_log("pkcs11 session #%ld for searching slot %lu", session, slot)
+ )
+
+ /* check if there is a certificate on the card in the specified slot */
+ if (scx_pkcs11_find_object(session, &object, CKO_CERTIFICATE, sc->id))
+ {
+ sc->slot = slot;
+ sc->any_slot = FALSE;
+ sc->session = session;
+ sc->session_opened = TRUE;
+ return TRUE;
+ }
+
+ rv = pkcs11_functions->C_CloseSession(session);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_CloseSession: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ }
+ return FALSE;
+}
+#endif
+
+/*
+ * Connect to the smart card in the reader and select the correct slot
+ */
+bool
+scx_establish_context(smartcard_t *sc)
+{
+#ifdef SMARTCARD
+ bool id_found = FALSE;
+
+ if (!scx_initialized)
+ {
+ plog("pkcs11 module not initialized");
+ return FALSE;
+ }
+
+ if (sc->session_opened)
+ {
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ DBG_log("pkcs11 session #%ld already open", sc->session)
+ )
+ return TRUE;
+ }
+
+ if (!sc->any_slot)
+ id_found = scx_find_cert_id_in_slot(sc, sc->slot);
+
+ if (!id_found)
+ {
+ CK_RV rv;
+ CK_SLOT_ID slot;
+ CK_SLOT_ID_PTR slots = NULL_PTR;
+ CK_ULONG slot_count = 0;
+ CK_ULONG i;
+
+ /* read size, always returns CKR_OK ! */
+ rv = pkcs11_functions->C_GetSlotList(FALSE, NULL_PTR, &slot_count);
+
+ /* allocate memory for the slots */
+ slots = (CK_SLOT_ID *)alloc_bytes(slot_count * sizeof(CK_SLOT_ID), "slots");
+
+ rv = pkcs11_functions->C_GetSlotList(FALSE, slots, &slot_count);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_GetSlotList: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ pfreeany(slots);
+ return FALSE;
+ }
+
+ /* look in every slot for a certificate with a given object ID */
+ for (i = 0; i < slot_count; i++)
+ {
+ slot = slots[i];
+ id_found = scx_find_cert_id_in_slot(sc, slot);
+ if (id_found)
+ break;
+ }
+ pfreeany(slots)
+ }
+
+ if (id_found)
+ {
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ DBG_log("found token with id %s in slot %lu", sc->id, sc->slot);
+ DBG_log("pkcs11 session #%ld opened", sc->session)
+ )
+ }
+ else
+ {
+ plog(" no certificate with id %s found on smartcard", sc->id);
+ }
+ return id_found;
+#else
+ plog("warning: SMARTCARD support is deactivated in pluto/Makefile!");
+ return FALSE;
+#endif
+}
+
+/*
+ * log in to a session
+ */
+bool
+scx_login(smartcard_t *sc)
+{
+#ifdef SMARTCARD
+ CK_RV rv;
+
+ if (sc->logged_in)
+ {
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ DBG_log("pkcs11 session #%ld login already done", sc->session)
+ )
+ return TRUE;
+ }
+
+ if (sc->pin.ptr == NULL)
+ {
+ plog("unable to log in without PIN!");
+ return FALSE;
+ }
+
+ if (!sc->session_opened)
+ {
+ plog("session not opened");
+ return FALSE;
+ }
+
+ rv = pkcs11_functions->C_Login(sc->session, CKU_USER
+ , (CK_UTF8CHAR *) sc->pin.ptr, sc->pin.len);
+ if (rv != CKR_OK && rv != CKR_USER_ALREADY_LOGGED_IN)
+ {
+ plog("unable to login: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ return FALSE;
+ }
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ DBG_log("pkcs11 session #%ld login successful", sc->session)
+ )
+ sc->logged_in = TRUE;
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+
+#ifdef SMARTCARD
+/*
+ * logout from a session
+ */
+static void
+scx_logout(smartcard_t *sc)
+{
+ CK_RV rv;
+
+ rv = pkcs11_functions->C_Logout(sc->session);
+ if (rv != CKR_OK)
+ plog("error in C_Logout: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ else
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ DBG_log("pkcs11 session #%ld logout", sc->session)
+ )
+ sc->logged_in = FALSE;
+}
+#endif
+
+
+/*
+ * Release context and disconnect from card
+ */
+void
+scx_release_context(smartcard_t *sc)
+{
+#ifdef SMARTCARD
+ CK_RV rv;
+
+ if (!scx_initialized)
+ return;
+
+ if (sc->session_opened)
+ {
+ if (sc->logged_in)
+ scx_logout(sc);
+
+ sc->session_opened = FALSE;
+
+ rv = pkcs11_functions->C_CloseSession(sc->session);
+ if (rv != CKR_OK)
+ plog("error in C_CloseSession: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ else
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ DBG_log("pkcs11 session #%ld closed", sc->session)
+ )
+ }
+#endif
+}
+
+/*
+ * Load host certificate from smartcard
+ */
+bool
+scx_load_cert(const char *filename, smartcard_t **scp, cert_t *cert
+, bool *cached)
+{
+#ifdef SMARTCARD /* compile with smartcard support */
+ CK_OBJECT_HANDLE object;
+
+ const char *number_slot_id = filename + strlen(SCX_TOKEN);
+
+ smartcard_t *sc = scx_add(scx_parse_number_slot_id(number_slot_id));
+
+ /* return the smartcard object */
+ *scp = sc;
+
+ /* is there a cached smartcard certificate? */
+ *cached = sc->last_cert.type != CERT_NONE
+ && (time(NULL) - sc->last_load) < SCX_CERT_CACHE_INTERVAL;
+
+ if (*cached)
+ {
+ *cert = sc->last_cert;
+ plog(" using cached cert from smartcard #%d (%s, id: %s, label: '%s')"
+ , sc->number
+ , scx_print_slot(sc, "")
+ , sc->id
+ , sc->label);
+ return TRUE;
+ }
+
+ if (!scx_establish_context(sc))
+ {
+ scx_release_context(sc);
+ return FALSE;
+ }
+
+ /* find the certificate object */
+ if (!scx_pkcs11_find_object(sc->session, &object, CKO_CERTIFICATE, sc->id))
+ {
+ scx_release_context(sc);
+ return FALSE;
+ }
+
+ /* retrieve the certificate object */
+ if (!scx_find_cert_object(sc->session, object, sc, cert))
+ {
+ scx_release_context(sc);
+ return FALSE;
+ }
+
+ if (!pkcs11_keep_state)
+ scx_release_context(sc);
+
+ plog(" loaded cert from smartcard #%d (%s, id: %s, label: '%s')"
+ , sc->number
+ , scx_print_slot(sc, "")
+ , sc->id
+ , sc->label);
+
+ return TRUE;
+#else
+ plog(" warning: SMARTCARD support is deactivated in pluto/Makefile!");
+ return FALSE;
+#endif
+}
+
+/*
+ * parse slot number and key id
+ * the following syntax is allowed
+ * number slot id
+ * %smartcard 1 - -
+ * %smartcard#2 2 - -
+ * %smartcard0 - 0 -
+ * %smartcard:45 - - 45
+ * %smartcard0:45 - 0 45
+ */
+smartcard_t*
+scx_parse_number_slot_id(const char *number_slot_id)
+{
+ int len = strlen(number_slot_id);
+ smartcard_t *sc = alloc_thing(smartcard_t, "smartcard");
+
+ /* assign default values */
+ *sc = empty_sc;
+
+ if (len == 0) /* default: use certificate #1 */
+ {
+ sc->number = 1;
+ }
+ else if (*number_slot_id == '#') /* #number scheme */
+ {
+ err_t ugh;
+ unsigned long ul;
+
+ ugh = atoul(number_slot_id+1, len-1 , 10, &ul);
+ if (ugh == NULL)
+ sc->number = (int)ul;
+ else
+ plog("error parsing smartcard number: %s", ugh);
+ }
+ else /* slot:id scheme */
+ {
+ int slot_len = len;
+ char *p = strchr(number_slot_id, ':');
+
+ if (p != NULL)
+ {
+ int id_len = len - (p + 1 - number_slot_id);
+ slot_len -= (1 + id_len);
+
+ if (id_len > 0) /* we have an id */
+ sc->id = p + 1;
+ }
+ if (slot_len > 0) /* we have a slot */
+ {
+ err_t ugh = NULL;
+ unsigned long ul;
+
+ ugh = atoul(number_slot_id, slot_len, 10, &ul);
+ if (ugh == NULL)
+ {
+ sc->slot = ul;
+ sc->any_slot = FALSE;
+ }
+ else
+ plog("error parsing smartcard slot number: %s", ugh);
+ }
+ }
+ /* unshare the id string */
+ sc->id = clone_str(sc->id, "key id");
+ return sc;
+}
+
+/*
+ * Verify pin on card
+ */
+bool
+scx_verify_pin(smartcard_t *sc)
+{
+#ifdef SMARTCARD
+ CK_RV rv;
+
+ if (!sc->pinpad)
+ sc->valid = FALSE;
+
+ if (sc->pin.ptr == NULL)
+ {
+ plog("unable to verify without PIN");
+ return FALSE;
+ }
+
+ /* establish context */
+ if (!scx_establish_context(sc))
+ {
+ scx_release_context(sc);
+ return FALSE;
+ }
+
+ rv = pkcs11_functions->C_Login(sc->session, CKU_USER,
+ (CK_UTF8CHAR *) sc->pin.ptr, sc->pin.len);
+ if (rv == CKR_OK || rv == CKR_USER_ALREADY_LOGGED_IN)
+ {
+ sc->valid = TRUE;
+ sc->logged_in = TRUE;
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ DBG_log((rv == CKR_OK)
+ ? "PIN code correct"
+ : "already logged in, no PIN entry required");
+ DBG_log("pkcs11 session #%ld login successful", sc->session)
+ )
+ }
+ else
+ {
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ DBG_log("PIN code incorrect")
+ )
+ }
+ if (!pkcs11_keep_state)
+ scx_release_context(sc);
+#else
+ sc->valid = FALSE;
+#endif
+ return sc->valid;
+}
+
+/*
+ * Sign hash on smartcard
+ */
+bool
+scx_sign_hash(smartcard_t *sc, const u_char *in, size_t inlen
+, u_char *out, size_t outlen)
+{
+#ifdef SMARTCARD
+ CK_RV rv;
+ CK_OBJECT_HANDLE object;
+ CK_ULONG siglen = (CK_ULONG)outlen;
+ CK_BBOOL sign_flag, decrypt_flag;
+ CK_ATTRIBUTE attr[] = {
+ { CKA_SIGN, &sign_flag, sizeof(sign_flag) },
+ { CKA_DECRYPT, &decrypt_flag, sizeof(decrypt_flag) }
+ };
+
+ if (!sc->logged_in)
+ return FALSE;
+
+ if (!scx_pkcs11_find_object(sc->session, &object, CKO_PRIVATE_KEY, sc->id))
+ {
+ plog("unable to find private key with id '%s'", sc->id);
+ return FALSE;
+ }
+
+ rv = pkcs11_functions->C_GetAttributeValue(sc->session, object, attr, 2);
+ if (rv != CKR_OK)
+ {
+ plog("couldn't read the private key attributes: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("RSA key flags: sign = %s, decrypt = %s"
+ , (sign_flag)? "true":"false"
+ , (decrypt_flag)? "true":"false")
+ )
+
+ if (sign_flag)
+ {
+ CK_MECHANISM mech = { CKM_RSA_PKCS, NULL_PTR, 0 };
+
+ rv = pkcs11_functions->C_SignInit(sc->session, &mech, object);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_SignInit: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ return FALSE;
+ }
+
+ rv = pkcs11_functions->C_Sign(sc->session, (CK_BYTE_PTR)in, inlen
+ , out, &siglen);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_Sign: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ return FALSE;
+ }
+ }
+ else if (decrypt_flag)
+ {
+ CK_MECHANISM mech = { CKM_RSA_X_509, NULL_PTR, 0 };
+ size_t padlen;
+ u_char *p = out ;
+
+ /* PKCS#1 v1.5 8.1 encryption-block formatting */
+ *p++ = 0x00;
+ *p++ = 0x01; /* BT (block type) 01 */
+ padlen = outlen - 3 - inlen;
+ memset(p, 0xFF, padlen);
+ p += padlen;
+ *p++ = 0x00;
+ memcpy(p, in, inlen);
+
+ rv = pkcs11_functions->C_DecryptInit(sc->session, &mech, object);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_DecryptInit: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ return FALSE;
+ }
+
+ rv = pkcs11_functions->C_Decrypt(sc->session, out, outlen
+ , out, &siglen);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_Decrypt: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ return FALSE;
+ }
+ }
+ else
+ {
+ plog("private key has neither sign nor decrypt flag set");
+ return FALSE;
+ }
+
+ if (siglen > (CK_ULONG)outlen)
+ {
+ plog("signature length (%lu) larger than allocated buffer (%d)"
+ , siglen, (int)outlen);
+ return FALSE;
+ }
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+
+/*
+ * encrypt data block with an RSA public key
+ */
+bool
+scx_encrypt(smartcard_t *sc, const u_char *in, size_t inlen
+, u_char *out, size_t *outlen)
+{
+#ifdef SMARTCARD
+ CK_RV rv;
+ CK_OBJECT_HANDLE object;
+ CK_ULONG len = (CK_ULONG)(*outlen);
+ CK_BBOOL encrypt_flag;
+ CK_ATTRIBUTE attr[] = {
+ { CKA_MODULUS, NULL_PTR, 0L },
+ { CKA_PUBLIC_EXPONENT, NULL_PTR, 0L },
+ { CKA_ENCRYPT, &encrypt_flag, sizeof(encrypt_flag) }
+ };
+ CK_MECHANISM mech = { CKM_RSA_PKCS, NULL_PTR, 0 };
+
+ if (!scx_establish_context(sc))
+ {
+ scx_release_context(sc);
+ return FALSE;
+ }
+
+ if (!scx_pkcs11_find_object(sc->session, &object, CKO_PUBLIC_KEY, sc->id))
+ {
+ plog("unable to find public key with id '%s'", sc->id);
+ return FALSE;
+ }
+
+ rv = pkcs11_functions->C_GetAttributeValue(sc->session, object, attr, 3);
+ if (rv != CKR_OK)
+ {
+ plog("couldn't read the public key attributes: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ scx_release_context(sc);
+ return FALSE;
+ }
+
+ if (!encrypt_flag)
+ {
+ plog("public key cannot be used for encryption");
+ scx_release_context(sc);
+ return FALSE;
+ }
+
+ /* there must be enough space left for the PKCS#1 v1.5 padding */
+ if (inlen > attr[0].ulValueLen - 11)
+ {
+ plog("smartcard input data length (%d) exceeds maximum of %lu bytes"
+ , (int)inlen, attr[0].ulValueLen - 11);
+ if (!pkcs11_keep_state)
+ scx_release_context(sc);
+ return FALSE;
+ }
+
+ rv = pkcs11_functions->C_EncryptInit(sc->session, &mech, object);
+
+ if (rv != CKR_OK)
+ {
+ if (rv == CKR_FUNCTION_NOT_SUPPORTED)
+ {
+ RSA_public_key_t rsa;
+ chunk_t plain_text = {in, inlen};
+ chunk_t cipher_text;
+
+ DBG(DBG_CONTROL,
+ DBG_log("doing RSA encryption in software")
+ )
+ attr[0].pValue = alloc_bytes(attr[0].ulValueLen, "modulus");
+ attr[1].pValue = alloc_bytes(attr[1].ulValueLen, "exponent");
+
+ rv = pkcs11_functions->C_GetAttributeValue(sc->session, object, attr, 2);
+ if (rv != CKR_OK)
+ {
+ plog("couldn't read modulus and public exponent: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ pfree(attr[0].pValue);
+ pfree(attr[1].pValue);
+ scx_release_context(sc);
+ return FALSE;
+ }
+ rsa.k = attr[0].ulValueLen;
+ n_to_mpz(&rsa.n, attr[0].pValue, attr[0].ulValueLen);
+ n_to_mpz(&rsa.e, attr[1].pValue, attr[1].ulValueLen);
+ pfree(attr[0].pValue);
+ pfree(attr[1].pValue);
+
+ cipher_text = RSA_encrypt(&rsa, plain_text);
+ free_RSA_public_content(&rsa);
+ if (cipher_text.ptr == NULL)
+ {
+ plog("smartcard input data length is too large");
+ if (!pkcs11_keep_state)
+ scx_release_context(sc);
+ return FALSE;
+ }
+
+ memcpy(out, cipher_text.ptr, cipher_text.len);
+ *outlen = cipher_text.len;
+ freeanychunk(cipher_text);
+ if (!pkcs11_keep_state)
+ scx_release_context(sc);
+ return TRUE;
+ }
+ else
+ {
+ plog("error in C_EncryptInit: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ scx_release_context(sc);
+ return FALSE;
+ }
+ }
+
+ DBG(DBG_CONTROL,
+ DBG_log("doing RSA encryption on smartcard")
+ )
+ rv = pkcs11_functions->C_Encrypt(sc->session, in, inlen
+ , out, &len);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_Encrypt: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ scx_release_context(sc);
+ return FALSE;
+ }
+ if (!pkcs11_keep_state)
+ scx_release_context(sc);
+
+ *outlen = (size_t)len;
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+/*
+ * decrypt a data block with an RSA private key
+ */
+bool
+scx_decrypt(smartcard_t *sc, const u_char *in, size_t inlen
+, u_char *out, size_t *outlen)
+{
+#ifdef SMARTCARD
+ CK_RV rv;
+ CK_OBJECT_HANDLE object;
+ CK_ULONG len = (CK_ULONG)(*outlen);
+ CK_BBOOL decrypt_flag;
+ CK_ATTRIBUTE attr[] = {
+ { CKA_DECRYPT, &decrypt_flag, sizeof(decrypt_flag) }
+ };
+ CK_MECHANISM mech = { CKM_RSA_PKCS, NULL_PTR, 0 };
+
+ if (!scx_establish_context(sc) || !scx_login(sc))
+ {
+ scx_release_context(sc);
+ return FALSE;
+ }
+
+ if (!scx_pkcs11_find_object(sc->session, &object, CKO_PRIVATE_KEY, sc->id))
+ {
+ plog("unable to find private key with id '%s'", sc->id);
+ return FALSE;
+ }
+
+ rv = pkcs11_functions->C_GetAttributeValue(sc->session, object, attr, 1);
+ if (rv != CKR_OK)
+ {
+ plog("couldn't read the private key attributes: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ return FALSE;
+ }
+
+ if (!decrypt_flag)
+ {
+ plog("private key cannot be used for decryption");
+ scx_release_context(sc);
+ return FALSE;
+ }
+
+ DBG(DBG_CONTROL,
+ DBG_log("doing RSA decryption on smartcard")
+ )
+ rv = pkcs11_functions->C_DecryptInit(sc->session, &mech, object);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_DecryptInit: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ scx_release_context(sc);
+ return FALSE;
+ }
+
+ rv = pkcs11_functions->C_Decrypt(sc->session, in, inlen
+ , out, &len);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_Decrypt: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ scx_release_context(sc);
+ return FALSE;
+ }
+ if (!pkcs11_keep_state)
+ scx_release_context(sc);
+
+ *outlen = (size_t)len;
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+
+/* receive an encrypted data block via whack,
+ * decrypt it using a private RSA key and
+ * return the decrypted data block via whack
+ */
+bool
+scx_op_via_whack(const char* msg, int inbase, int outbase, sc_op_t op
+, const char* keyid, int whackfd)
+{
+ char inbuf[RSA_MAX_OCTETS];
+ char outbuf[2*RSA_MAX_OCTETS + 1];
+ size_t outlen = sizeof(inbuf);
+ size_t inlen;
+ smartcard_t *sc,*sc_new;
+
+ const char *number_slot_id = "";
+
+ err_t ugh = ttodata(msg, 0, inbase, inbuf, sizeof(inbuf), &inlen);
+
+ /* no prefix - use default base */
+ if (ugh != NULL && inbase == 0)
+ ugh = ttodata(msg, 0, DEFAULT_BASE, inbuf, sizeof(inbuf), &inlen);
+
+ if (ugh != NULL)
+ {
+ plog("format error in smartcard input data: %s", ugh);
+ return FALSE;
+ }
+
+ if (keyid != NULL)
+ {
+ number_slot_id = (strncmp(keyid, SCX_TOKEN, strlen(SCX_TOKEN)) == 0)
+ ? keyid + strlen(SCX_TOKEN) : keyid;
+ }
+
+ sc_new = scx_parse_number_slot_id(number_slot_id);
+ sc = scx_add(sc_new);
+ if (sc == sc_new)
+ scx_share(sc);
+
+ DBG((op == SC_OP_ENCRYPT)? DBG_PRIVATE:DBG_RAW,
+ DBG_dump("smartcard input data:\n", inbuf, inlen)
+ )
+
+ if (op == SC_OP_DECRYPT)
+ {
+ if (!sc->valid && whackfd != NULL_FD)
+ scx_get_pin(sc, whackfd);
+
+ if (!sc->valid)
+ {
+ loglog(RC_NOVALIDPIN, "cannot decrypt without valid PIN");
+ return FALSE;
+ }
+ }
+
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ DBG_log("using RSA key from smartcard (slot: %d, id: %s)"
+ , (int)sc->slot, sc->id)
+ )
+
+ switch (op)
+ {
+ case SC_OP_ENCRYPT:
+ if (!scx_encrypt(sc, inbuf, inlen, inbuf, &outlen))
+ return FALSE;
+ break;
+ case SC_OP_DECRYPT:
+ if (!scx_decrypt(sc, inbuf, inlen, inbuf, &outlen))
+ return FALSE;
+ break;
+ default:
+ break;
+ }
+
+ DBG((op == SC_OP_DECRYPT)? DBG_PRIVATE:DBG_RAW,
+ DBG_dump("smartcard output data:\n", inbuf, outlen)
+ )
+
+ if (outbase == 0) /* use default base */
+ outbase = DEFAULT_BASE;
+
+ if (outbase == 256) /* ascii plain text */
+ whack_log(RC_COMMENT, "%.*s", (int)outlen, inbuf);
+ else
+ {
+ outlen = datatot(inbuf, outlen, outbase, outbuf, sizeof(outbuf));
+ if (outlen == 0)
+ {
+ plog("error in output format conversion");
+ return FALSE;
+ }
+ whack_log(RC_COMMENT, "%s", outbuf);
+ }
+ return TRUE;
+}
+
+ /*
+ * get length of RSA key in bytes
+ */
+size_t
+scx_get_keylength(smartcard_t *sc)
+{
+#ifdef SMARTCARD
+ CK_RV rv;
+ CK_OBJECT_HANDLE object;
+ CK_ATTRIBUTE attr[] = {{ CKA_MODULUS, NULL_PTR, 0}};
+
+ if (!sc->logged_in)
+ return FALSE;
+
+ if (!scx_pkcs11_find_object(sc->session, &object, CKO_PRIVATE_KEY, sc->id))
+ {
+ plog("unable to find private key with id '%s'", sc->id);
+ return FALSE;
+ }
+
+ /* get the length of the private key */
+ rv = pkcs11_functions->C_GetAttributeValue(sc->session, object
+ , (CK_ATTRIBUTE_PTR)&attr, 1);
+ if (rv != CKR_OK)
+ {
+ plog("failed to get key length: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ return FALSE;
+ }
+
+ return attr[0].ulValueLen; /*Return key length in bytes */
+#else
+ return 0;
+#endif
+}
+
+/*
+ * prompt for pin and verify it
+ */
+bool
+scx_get_pin(smartcard_t *sc, int whackfd)
+{
+#ifdef SMARTCARD
+ char pin[BUF_LEN];
+ int i, n;
+
+ whack_log(RC_ENTERSECRET, "need PIN for #%d (%s, id: %s, label: '%s')"
+ , sc->number, scx_print_slot(sc, ""), sc->id, sc->label);
+
+ for (i = 0; i < SCX_MAX_PIN_TRIALS; i++)
+ {
+ if (i > 0)
+ whack_log(RC_ENTERSECRET, "invalid PIN, please try again");
+
+ n = read(whackfd, pin, BUF_LEN);
+
+ if (n == -1)
+ {
+ whack_log(RC_LOG_SERIOUS, "read(whackfd) failed");
+ return FALSE;
+ }
+
+ if (strlen(pin) == 0)
+ {
+ whack_log(RC_LOG_SERIOUS, "no PIN entered, aborted");
+ return FALSE;
+ }
+
+ sc->pin.ptr = pin;
+ sc->pin.len = strlen(pin);
+
+ /* verify the pin */
+ if (scx_verify_pin(sc))
+ {
+ clonetochunk(sc->pin, pin, strlen(pin), "pin");
+ break;
+ }
+
+ /* wrong pin - we try another round */
+ sc->pin = empty_chunk;
+ }
+
+ if (sc->valid)
+ whack_log(RC_SUCCESS, "valid PIN");
+ else
+ whack_log(RC_LOG_SERIOUS, "invalid PIN, too many trials");
+#else
+ sc->valid = FALSE;
+ whack_log(RC_LOG_SERIOUS, "SMARTCARD support is deactivated in pluto/Makefile!");
+#endif
+ return sc->valid;
+}
+
+
+/*
+ * free the pin code
+ */
+void
+scx_free_pin(chunk_t *pin)
+{
+ if (pin->ptr != NULL)
+ {
+ /* clear pin field in memory */
+ memset(pin->ptr, '\0', pin->len);
+ pfree(pin->ptr);
+ *pin = empty_chunk;
+ }
+}
+
+/*
+ * frees a smartcard record
+ */
+void
+scx_free(smartcard_t *sc)
+{
+ if (sc != NULL)
+ {
+ scx_release_context(sc);
+ pfreeany(sc->id);
+ pfreeany(sc->label);
+ scx_free_pin(&sc->pin);
+ pfree(sc);
+ }
+}
+
+/* release of a smartcard record decreases the count by one
+ " the record is freed when the counter reaches zero
+ */
+void
+scx_release(smartcard_t *sc)
+{
+ if (sc != NULL && --sc->count == 0)
+ {
+ smartcard_t **pp = &smartcards;
+ while (*pp != sc)
+ pp = &(*pp)->next;
+ *pp = sc->next;
+ release_cert(sc->last_cert);
+ scx_free(sc);
+ }
+}
+
+/*
+ * compare two smartcard records by comparing their slots and ids
+ */
+static bool
+scx_same(smartcard_t *a, smartcard_t *b)
+{
+ if (a->number && b->number)
+ {
+ /* same number */
+ return a->number == b->number;
+ }
+ else
+ {
+ /* same id and/or same slot */
+ return (!a->id || (b->id && streq(a->id, b->id)))
+ && (a->any_slot || b->any_slot || a->slot == b->slot);
+ }
+}
+
+/* for each link pointing to the smartcard record
+ " increase the count by one
+ */
+void
+scx_share(smartcard_t *sc)
+{
+ if (sc != NULL)
+ sc->count++;
+}
+
+/*
+ * adds a smartcard record to the chained list
+ */
+smartcard_t*
+scx_add(smartcard_t *smartcard)
+{
+ smartcard_t *sc = smartcards;
+ smartcard_t **psc = &smartcards;
+
+ while (sc != NULL)
+ {
+ if (scx_same(smartcard, sc)) /* already in chain, free smartcard record */
+ {
+ scx_free(smartcard);
+ return sc;
+ }
+ psc = &sc->next;
+ sc = sc->next;
+ }
+
+ /* insert new smartcard record at the end of the chain */
+ *psc = smartcard;
+ smartcard->number = ++sc_number;
+ smartcard->count = 1;
+ DBG(DBG_CONTROL | DBG_PARSING,
+ DBG_log(" smartcard #%d added", sc_number)
+ )
+ return smartcard;
+}
+
+/*
+ * get the smartcard that belongs to an X.509 certificate
+ */
+smartcard_t*
+scx_get(x509cert_t *cert)
+{
+ smartcard_t *sc = smartcards;
+
+ while (sc != NULL)
+ {
+ if (sc->last_cert.u.x509 == cert)
+ return sc;
+ sc = sc->next;
+ }
+ return NULL;
+}
+
+/*
+ * prints either the slot number or 'any slot'
+ */
+char *
+scx_print_slot(smartcard_t *sc, const char *whitespace)
+{
+ char *buf = temporary_cyclic_buffer();
+
+ if (sc->any_slot)
+ snprintf(buf, BUF_LEN, "any slot");
+ else
+ snprintf(buf, BUF_LEN, "slot: %s%lu", whitespace, sc->slot);
+ return buf;
+}
+
+/*
+ * list all smartcard info records in a chained list
+ */
+void
+scx_list(bool utc)
+{
+ smartcard_t *sc = smartcards;
+
+ if (sc != NULL)
+ {
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of Smartcard Objects:");
+ whack_log(RC_COMMENT, " ");
+ }
+
+ while (sc != NULL)
+ {
+ whack_log(RC_COMMENT, "%s, #%d, count: %d"
+ , timetoa(&sc->last_load, utc)
+ , sc->number
+ , sc->count);
+ whack_log(RC_COMMENT, " %s, session %s, logged %s, has %s"
+ , scx_print_slot(sc, " ")
+ , sc->session_opened? "opened" : "closed"
+ , sc->logged_in? "in" : "out"
+ , sc->pinpad? "pin pad"
+ : ((sc->pin.ptr == NULL)? "no pin"
+ : sc->valid? "valid pin" : "invalid pin"));
+ if (sc->id != NULL)
+ whack_log(RC_COMMENT, " id: %s", sc->id);
+ if (sc->label != NULL)
+ whack_log(RC_COMMENT, " label: '%s'", sc->label);
+ if (sc->last_cert.type == CERT_X509_SIGNATURE)
+ {
+ char buf[BUF_LEN];
+
+ dntoa(buf, BUF_LEN, sc->last_cert.u.x509->subject);
+ whack_log(RC_COMMENT, " subject: '%s'", buf);
+ }
+ sc = sc->next;
+ }
+}
diff --git a/src/pluto/smartcard.h b/src/pluto/smartcard.h
new file mode 100644
index 000000000..c004ca7dd
--- /dev/null
+++ b/src/pluto/smartcard.h
@@ -0,0 +1,100 @@
+/* Support of smartcards and cryptotokens
+ * Copyright (C) 2003 Christoph Gysin, Simon Zwahlen
+ * Copyright (C) 2004 David Buechi, Michael Meier
+ * 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.
+ *
+ * RCSID $Id: smartcard.h,v 1.14 2005/11/06 22:55:41 as Exp $
+ */
+
+#ifndef _SMARTCARD_H
+#define _SMARTCARD_H
+
+#include "certs.h"
+
+#define SCX_TOKEN "%smartcard"
+#define SCX_CERT_CACHE_INTERVAL 60 /* seconds */
+#define SCX_MAX_PIN_TRIALS 3
+
+/* smartcard operations */
+
+typedef enum {
+ SC_OP_NONE = 0,
+ SC_OP_ENCRYPT = 1,
+ SC_OP_DECRYPT = 2,
+ SC_OP_SIGN = 3,
+} sc_op_t;
+
+/* smartcard record */
+
+typedef struct smartcard smartcard_t;
+
+struct smartcard {
+ smartcard_t *next;
+ time_t last_load;
+ cert_t last_cert;
+ int count;
+ int number;
+ unsigned long slot;
+ char *id;
+ char *label;
+ chunk_t pin;
+ bool pinpad;
+ bool valid;
+ bool session_opened;
+ bool logged_in;
+ bool any_slot;
+ long session;
+};
+
+extern const smartcard_t empty_sc;
+
+/* keep a PKCS#11 login during the lifetime of pluto
+ * flag set in plutomain.c and used in ipsec_doi.c and ocsp.c
+ */
+extern bool pkcs11_keep_state;
+
+/* allow other applications access to pluto's PKCS#11 interface
+ * via whack. Could be used e.g. for disk encryption
+ */
+extern bool pkcs11_proxy;
+
+extern smartcard_t* scx_parse_number_slot_id(const char *number_slot_id);
+extern void scx_init(const char *module);
+extern void scx_finalize(void);
+extern bool scx_establish_context(smartcard_t *sc);
+extern bool scx_login(smartcard_t *sc);
+extern bool scx_on_smartcard(const char *filename);
+extern bool scx_load_cert(const char *filename, smartcard_t **scp
+ , cert_t *cert, bool *cached);
+extern bool scx_verify_pin(smartcard_t *sc);
+extern void scx_share(smartcard_t *sc);
+extern bool scx_sign_hash(smartcard_t *sc, const u_char *in, size_t inlen
+ , u_char *out, size_t outlen);
+extern bool scx_encrypt(smartcard_t *sc, const u_char *in, size_t inlen
+ , u_char *out, size_t *outlen);
+extern bool scx_decrypt(smartcard_t *sc, const u_char *in, size_t inlen
+ , u_char *out, size_t *outlen);
+extern bool scx_op_via_whack(const char* msg, int inbase, int outbase
+ , sc_op_t op, const char *keyid, int whackfd);
+extern bool scx_get_pin(smartcard_t *sc, int whackfd);
+extern size_t scx_get_keylength(smartcard_t *sc);
+extern smartcard_t* scx_add(smartcard_t *sc);
+extern smartcard_t* scx_get(x509cert_t *cert);
+extern void scx_release(smartcard_t *sc);
+extern void scx_release_context(smartcard_t *sc);
+extern void scx_free_pin(chunk_t *pin);
+extern void scx_free(smartcard_t *sc);
+extern void scx_list(bool utc);
+extern char *scx_print_slot(smartcard_t *sc, const char *whitespace);
+
+#endif /* _SMARTCARD_H */
diff --git a/src/pluto/spdb.c b/src/pluto/spdb.c
new file mode 100644
index 000000000..996585135
--- /dev/null
+++ b/src/pluto/spdb.c
@@ -0,0 +1,2314 @@
+/* Security Policy Data Base (such as it is)
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: spdb.c,v 1.9 2006/04/22 21:59:20 as Exp $
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/queue.h>
+
+#include <freeswan.h>
+#include <ipsec_policy.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "id.h"
+#include "connections.h"
+#include "state.h"
+#include "packet.h"
+#include "keys.h"
+#include "kernel.h"
+#include "log.h"
+#include "spdb.h"
+#include "whack.h"
+#include "sha1.h"
+#include "md5.h"
+#include "crypto.h" /* requires sha1.h and md5.h */
+#include "alg_info.h"
+#include "kernel_alg.h"
+#include "ike_alg.h"
+#include "db_ops.h"
+#include "nat_traversal.h"
+
+#define AD(x) x, elemsof(x) /* Array Description */
+#define AD_NULL NULL, 0
+
+/**************** Oakely (main mode) SA database ****************/
+
+/* array of proposals to be conjoined (can only be one for Oakley) */
+
+static struct db_prop oakley_pc[] =
+ { { PROTO_ISAKMP, AD_NULL } };
+
+/* array of proposal conjuncts (can only be one) */
+
+static struct db_prop_conj oakley_props[] = { { AD(oakley_pc) } };
+
+/* the sadb entry */
+struct db_sa oakley_sadb = { AD(oakley_props) };
+
+/**************** IPsec (quick mode) SA database ****************/
+
+/* arrays of attributes for transforms */
+
+static struct db_attr espsha1_attr[] = {
+ { AUTH_ALGORITHM, AUTH_ALGORITHM_HMAC_SHA1 },
+ };
+
+static struct db_attr ah_HMAC_SHA1_attr[] = {
+ { AUTH_ALGORITHM, AUTH_ALGORITHM_HMAC_SHA1 },
+ };
+
+/* arrays of transforms, each in in preference order */
+
+static struct db_trans espa_trans[] = {
+ { ESP_3DES, AD(espsha1_attr) },
+ };
+
+static struct db_trans esp_trans[] = {
+ { ESP_3DES, AD_NULL },
+ };
+
+#ifdef SUPPORT_ESP_NULL
+static struct db_trans espnull_trans[] = {
+ { ESP_NULL, AD(espsha1_attr) },
+ };
+#endif /* SUPPORT_ESP_NULL */
+
+static struct db_trans ah_trans[] = {
+ { AH_SHA, AD(ah_HMAC_SHA1_attr) },
+ };
+
+static struct db_trans ipcomp_trans[] = {
+ { IPCOMP_DEFLATE, AD_NULL },
+ };
+
+/* arrays of proposals to be conjoined */
+
+static struct db_prop ah_pc[] = {
+ { PROTO_IPSEC_AH, AD(ah_trans) },
+ };
+
+#ifdef SUPPORT_ESP_NULL
+static struct db_prop espnull_pc[] = {
+ { PROTO_IPSEC_ESP, AD(espnull_trans) },
+ };
+#endif /* SUPPORT_ESP_NULL */
+
+static struct db_prop esp_pc[] = {
+ { PROTO_IPSEC_ESP, AD(espa_trans) },
+ };
+
+static struct db_prop ah_esp_pc[] = {
+ { PROTO_IPSEC_AH, AD(ah_trans) },
+ { PROTO_IPSEC_ESP, AD(esp_trans) },
+ };
+
+static struct db_prop compress_pc[] = {
+ { PROTO_IPCOMP, AD(ipcomp_trans) },
+ };
+
+static struct db_prop ah_compress_pc[] = {
+ { PROTO_IPSEC_AH, AD(ah_trans) },
+ { PROTO_IPCOMP, AD(ipcomp_trans) },
+ };
+
+#ifdef SUPPORT_ESP_NULL
+static struct db_prop espnull_compress_pc[] = {
+ { PROTO_IPSEC_ESP, AD(espnull_trans) },
+ { PROTO_IPCOMP, AD(ipcomp_trans) },
+ };
+#endif /* SUPPORT_ESP_NULL */
+
+static struct db_prop esp_compress_pc[] = {
+ { PROTO_IPSEC_ESP, AD(espa_trans) },
+ { PROTO_IPCOMP, AD(ipcomp_trans) },
+ };
+
+static struct db_prop ah_esp_compress_pc[] = {
+ { PROTO_IPSEC_AH, AD(ah_trans) },
+ { PROTO_IPSEC_ESP, AD(esp_trans) },
+ { PROTO_IPCOMP, AD(ipcomp_trans) },
+ };
+
+/* arrays of proposal alternatives (each element is a conjunction) */
+
+static struct db_prop_conj ah_props[] = {
+ { AD(ah_pc) },
+#ifdef SUPPORT_ESP_NULL
+ { AD(espnull_pc) }
+#endif
+ };
+
+static struct db_prop_conj esp_props[] =
+ { { AD(esp_pc) } };
+
+static struct db_prop_conj ah_esp_props[] =
+ { { AD(ah_esp_pc) } };
+
+static struct db_prop_conj compress_props[] = {
+ { AD(compress_pc) },
+ };
+
+static struct db_prop_conj ah_compress_props[] = {
+ { AD(ah_compress_pc) },
+#ifdef SUPPORT_ESP_NULL
+ { AD(espnull_compress_pc) }
+#endif
+ };
+
+static struct db_prop_conj esp_compress_props[] =
+ { { AD(esp_compress_pc) } };
+
+static struct db_prop_conj ah_esp_compress_props[] =
+ { { AD(ah_esp_compress_pc) } };
+
+/* The IPsec sadb is subscripted by a bitset (subset of policy)
+ * with members from { POLICY_ENCRYPT, POLICY_AUTHENTICATE, POLICY_COMPRESS }
+ * shifted right by POLICY_IPSEC_SHIFT.
+ */
+struct db_sa ipsec_sadb[1 << 3] = {
+ { AD_NULL }, /* none */
+ { AD(esp_props) }, /* POLICY_ENCRYPT */
+ { AD(ah_props) }, /* POLICY_AUTHENTICATE */
+ { AD(ah_esp_props) }, /* POLICY_ENCRYPT+POLICY_AUTHENTICATE */
+ { AD(compress_props) }, /* POLICY_COMPRESS */
+ { AD(esp_compress_props) }, /* POLICY_ENCRYPT+POLICY_COMPRESS */
+ { AD(ah_compress_props) }, /* POLICY_AUTHENTICATE+POLICY_COMPRESS */
+ { AD(ah_esp_compress_props) }, /* POLICY_ENCRYPT+POLICY_AUTHENTICATE+POLICY_COMPRESS */
+ };
+
+#undef AD
+#undef AD_NULL
+
+/* output an attribute (within an SA) */
+static bool
+out_attr(int type
+, unsigned long val
+, struct_desc *attr_desc
+, enum_names **attr_val_descs USED_BY_DEBUG
+, pb_stream *pbs)
+{
+ struct isakmp_attribute attr;
+
+ if (val >> 16 == 0)
+ {
+ /* short value: use TV form */
+ attr.isaat_af_type = type | ISAKMP_ATTR_AF_TV;
+ attr.isaat_lv = val;
+ if (!out_struct(&attr, attr_desc, pbs, NULL))
+ return FALSE;
+ }
+ else
+ {
+ /* This is a real fudge! Since we rarely use long attributes
+ * and since this is the only place where we can cause an
+ * ISAKMP message length to be other than a multiple of 4 octets,
+ * we force the length of the value to be a multiple of 4 octets.
+ * Furthermore, we only handle values up to 4 octets in length.
+ * Voila: a fixed format!
+ */
+ pb_stream val_pbs;
+ u_int32_t nval = htonl(val);
+
+ attr.isaat_af_type = type | ISAKMP_ATTR_AF_TLV;
+ if (!out_struct(&attr, attr_desc, pbs, &val_pbs)
+ || !out_raw(&nval, sizeof(nval), &val_pbs, "long attribute value"))
+ return FALSE;
+ close_output_pbs(&val_pbs);
+ }
+ DBG(DBG_EMITTING,
+ enum_names *d = attr_val_descs[type];
+
+ if (d != NULL)
+ DBG_log(" [%lu is %s]"
+ , val, enum_show(d, val)));
+ return TRUE;
+}
+#define return_on(var, val) do { var=val;goto return_out; } while(0);
+/* Output an SA, as described by a db_sa.
+ * This has the side-effect of allocating SPIs for us.
+ */
+bool
+out_sa(pb_stream *outs
+, struct db_sa *sadb
+, struct state *st
+, bool oakley_mode
+, u_int8_t np)
+{
+ pb_stream sa_pbs;
+ int pcn;
+ bool ret = FALSE;
+ bool ah_spi_generated = FALSE
+ , esp_spi_generated = FALSE
+ , ipcomp_cpi_generated = FALSE;
+#if !defined NO_KERNEL_ALG || !defined NO_IKE_ALG
+ struct db_context *db_ctx = NULL;
+#endif
+
+ /* SA header out */
+ {
+ struct isakmp_sa sa;
+
+ sa.isasa_np = np;
+ st->st_doi = sa.isasa_doi = ISAKMP_DOI_IPSEC; /* all we know */
+ if (!out_struct(&sa, &isakmp_sa_desc, outs, &sa_pbs))
+ return_on(ret, FALSE);
+ }
+
+ /* within SA: situation out */
+ st->st_situation = SIT_IDENTITY_ONLY;
+ if (!out_struct(&st->st_situation, &ipsec_sit_desc, &sa_pbs, NULL))
+ return_on(ret, FALSE);
+
+ /* within SA: Proposal Payloads
+ *
+ * Multiple Proposals with the same number are simultaneous
+ * (conjuncts) and must deal with different protocols (AH or ESP).
+ * Proposals with different numbers are alternatives (disjuncts),
+ * in preference order.
+ * Proposal numbers must be monotonic.
+ * See RFC 2408 "ISAKMP" 4.2
+ */
+
+ for (pcn = 0; pcn != sadb->prop_conj_cnt; pcn++)
+ {
+ struct db_prop_conj *pc = &sadb->prop_conjs[pcn];
+ int pn;
+
+ for (pn = 0; pn != pc->prop_cnt; pn++)
+ {
+ struct db_prop *p = &pc->props[pn];
+ pb_stream proposal_pbs;
+ struct isakmp_proposal proposal;
+ struct_desc *trans_desc;
+ struct_desc *attr_desc;
+ enum_names **attr_val_descs;
+ int tn;
+ bool tunnel_mode;
+
+ tunnel_mode = (pn == pc->prop_cnt-1)
+ && (st->st_policy & POLICY_TUNNEL);
+
+ /* Proposal header */
+ proposal.isap_np = pcn == sadb->prop_conj_cnt-1 && pn == pc->prop_cnt-1
+ ? ISAKMP_NEXT_NONE : ISAKMP_NEXT_P;
+ proposal.isap_proposal = pcn;
+ proposal.isap_protoid = p->protoid;
+ proposal.isap_spisize = oakley_mode ? 0
+ : p->protoid == PROTO_IPCOMP ? IPCOMP_CPI_SIZE
+ : IPSEC_DOI_SPI_SIZE;
+
+ /* In quick mode ONLY, create proposal for runtime kernel algos.
+ * Replace ESP proposals with runtime created one
+ */
+ if (!oakley_mode && p->protoid == PROTO_IPSEC_ESP)
+ {
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ if (st->st_connection->alg_info_esp)
+ {
+ static char buf[256]="";
+
+ alg_info_snprint(buf, sizeof (buf),
+ (struct alg_info *)st->st_connection->alg_info_esp);
+ DBG_log(buf);
+ }
+ )
+ db_ctx = kernel_alg_db_new(st->st_connection->alg_info_esp, st->st_policy);
+ p = db_prop_get(db_ctx);
+
+ if (!p || p->trans_cnt == 0)
+ {
+ loglog(RC_LOG_SERIOUS,
+ "empty IPSEC SA proposal to send "
+ "(no kernel algorithms for esp selection)");
+ return_on(ret, FALSE);
+ }
+ }
+
+ if (oakley_mode && p->protoid == PROTO_ISAKMP)
+ {
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ if (st->st_connection->alg_info_ike)
+ {
+ static char buf[256]="";
+
+ alg_info_snprint(buf, sizeof (buf),
+ (struct alg_info *)st->st_connection->alg_info_ike);
+ DBG_log(buf);
+ }
+ )
+ db_ctx = ike_alg_db_new(st->st_connection->alg_info_ike, st->st_policy);
+ p = db_prop_get(db_ctx);
+
+ if (!p || p->trans_cnt == 0)
+ {
+ loglog(RC_LOG_SERIOUS,
+ "empty ISAKMP SA proposal to send "
+ "(no algorithms for ike selection?)");
+ return_on(ret, FALSE);
+ }
+ }
+
+ proposal.isap_notrans = p->trans_cnt;
+ if (!out_struct(&proposal, &isakmp_proposal_desc, &sa_pbs, &proposal_pbs))
+ return_on(ret, FALSE);
+
+ /* Per-protocols stuff:
+ * Set trans_desc.
+ * Set attr_desc.
+ * Set attr_val_descs.
+ * If not oakley_mode, emit SPI.
+ * We allocate SPIs on demand.
+ * All ESPs in an SA will share a single SPI.
+ * All AHs in an SAwill share a single SPI.
+ * AHs' SPI will be distinct from ESPs'.
+ * This latter is needed because KLIPS doesn't
+ * use the protocol when looking up a (dest, protocol, spi).
+ * ??? If multiple ESPs are composed, how should their SPIs
+ * be allocated?
+ */
+ {
+ ipsec_spi_t *spi_ptr = NULL;
+ int proto = 0;
+ bool *spi_generated = NULL;
+
+ switch (p->protoid)
+ {
+ case PROTO_ISAKMP:
+ passert(oakley_mode);
+ trans_desc = &isakmp_isakmp_transform_desc;
+ attr_desc = &isakmp_oakley_attribute_desc;
+ attr_val_descs = oakley_attr_val_descs;
+ /* no SPI needed */
+ break;
+ case PROTO_IPSEC_AH:
+ passert(!oakley_mode);
+ trans_desc = &isakmp_ah_transform_desc;
+ attr_desc = &isakmp_ipsec_attribute_desc;
+ attr_val_descs = ipsec_attr_val_descs;
+ spi_ptr = &st->st_ah.our_spi;
+ spi_generated = &ah_spi_generated;
+ proto = IPPROTO_AH;
+ break;
+ case PROTO_IPSEC_ESP:
+ passert(!oakley_mode);
+ trans_desc = &isakmp_esp_transform_desc;
+ attr_desc = &isakmp_ipsec_attribute_desc;
+ attr_val_descs = ipsec_attr_val_descs;
+ spi_ptr = &st->st_esp.our_spi;
+ spi_generated = &esp_spi_generated;
+ proto = IPPROTO_ESP;
+ break;
+ case PROTO_IPCOMP:
+ passert(!oakley_mode);
+ trans_desc = &isakmp_ipcomp_transform_desc;
+ attr_desc = &isakmp_ipsec_attribute_desc;
+ attr_val_descs = ipsec_attr_val_descs;
+
+ /* a CPI isn't quite the same as an SPI
+ * so we use specialized code to emit it.
+ */
+ if (!ipcomp_cpi_generated)
+ {
+ st->st_ipcomp.our_spi = get_my_cpi(
+ &st->st_connection->spd, tunnel_mode);
+ if (st->st_ipcomp.our_spi == 0)
+ return_on(ret, FALSE); /* problem generating CPI */
+
+ ipcomp_cpi_generated = TRUE;
+ }
+ /* CPI is stored in network low order end of an
+ * ipsec_spi_t. So we start a couple of bytes in.
+ */
+ if (!out_raw((u_char *)&st->st_ipcomp.our_spi
+ + IPSEC_DOI_SPI_SIZE - IPCOMP_CPI_SIZE
+ , IPCOMP_CPI_SIZE
+ , &proposal_pbs, "CPI"))
+ return_on(ret, FALSE);
+ break;
+ default:
+ bad_case(p->protoid);
+ }
+ if (spi_ptr != NULL)
+ {
+ if (!*spi_generated)
+ {
+ *spi_ptr = get_ipsec_spi(0
+ , proto
+ , &st->st_connection->spd
+ , tunnel_mode);
+ if (*spi_ptr == 0)
+ return FALSE;
+ *spi_generated = TRUE;
+ }
+ if (!out_raw((u_char *)spi_ptr, IPSEC_DOI_SPI_SIZE
+ , &proposal_pbs, "SPI"))
+ return_on(ret, FALSE);
+ }
+ }
+
+ /* within proposal: Transform Payloads */
+ for (tn = 0; tn != p->trans_cnt; tn++)
+ {
+ struct db_trans *t = &p->trans[tn];
+ pb_stream trans_pbs;
+ struct isakmp_transform trans;
+ int an;
+
+ trans.isat_np = (tn == p->trans_cnt - 1)
+ ? ISAKMP_NEXT_NONE : ISAKMP_NEXT_T;
+ trans.isat_transnum = tn;
+ trans.isat_transid = t->transid;
+ if (!out_struct(&trans, trans_desc, &proposal_pbs, &trans_pbs))
+ return_on(ret, FALSE);
+
+ /* Within tranform: Attributes. */
+
+ /* For Phase 2 / Quick Mode, GROUP_DESCRIPTION is
+ * automatically generated because it must be the same
+ * in every transform. Except IPCOMP.
+ */
+ if (p->protoid != PROTO_IPCOMP
+ && st->st_pfs_group != NULL)
+ {
+ passert(!oakley_mode);
+ passert(st->st_pfs_group != &unset_group);
+ out_attr(GROUP_DESCRIPTION, st->st_pfs_group->group
+ , attr_desc, attr_val_descs
+ , &trans_pbs);
+ }
+
+ /* automatically generate duration
+ * and, for Phase 2 / Quick Mode, encapsulation.
+ */
+ if (oakley_mode)
+ {
+ out_attr(OAKLEY_LIFE_TYPE, OAKLEY_LIFE_SECONDS
+ , attr_desc, attr_val_descs
+ , &trans_pbs);
+ out_attr(OAKLEY_LIFE_DURATION
+ , st->st_connection->sa_ike_life_seconds
+ , attr_desc, attr_val_descs
+ , &trans_pbs);
+ }
+ else
+ {
+ /* RFC 2407 (IPSEC DOI) 4.5 specifies that
+ * the default is "unspecified (host-dependent)".
+ * This makes little sense, so we always specify it.
+ *
+ * Unlike other IPSEC transforms, IPCOMP defaults
+ * to Transport Mode, so we can exploit the default
+ * (draft-shacham-ippcp-rfc2393bis-05.txt 4.1).
+ */
+ if (p->protoid != PROTO_IPCOMP
+ || st->st_policy & POLICY_TUNNEL)
+ {
+#ifndef I_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT
+ if ((st->nat_traversal & NAT_T_DETECTED)
+ && !(st->st_policy & POLICY_TUNNEL))
+ {
+ /* Inform user that we will not respect policy and only
+ * propose Tunnel Mode
+ */
+ loglog(RC_LOG_SERIOUS, "NAT-Traversal: "
+ "Transport Mode not allowed due to security concerns -- "
+ "using Tunnel mode");
+ }
+#endif
+ out_attr(ENCAPSULATION_MODE
+#ifdef I_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT
+ , NAT_T_ENCAPSULATION_MODE(st, st->st_policy)
+#else
+ /* If NAT-T is detected, use UDP_TUNNEL as long as Transport
+ * Mode has security concerns.
+ *
+ * User has been informed of that
+ */
+ , NAT_T_ENCAPSULATION_MODE(st, POLICY_TUNNEL)
+#endif
+ , attr_desc, attr_val_descs
+ , &trans_pbs);
+ }
+ out_attr(SA_LIFE_TYPE, SA_LIFE_TYPE_SECONDS
+ , attr_desc, attr_val_descs
+ , &trans_pbs);
+ out_attr(SA_LIFE_DURATION
+ , st->st_connection->sa_ipsec_life_seconds
+ , attr_desc, attr_val_descs
+ , &trans_pbs);
+ }
+
+ /* spit out attributes from table */
+ for (an = 0; an != t->attr_cnt; an++)
+ {
+ struct db_attr *a = &t->attrs[an];
+
+ out_attr(a->type, a->val
+ , attr_desc, attr_val_descs
+ , &trans_pbs);
+ }
+
+ close_output_pbs(&trans_pbs);
+ }
+ close_output_pbs(&proposal_pbs);
+ }
+ /* end of a conjunction of proposals */
+ }
+ close_output_pbs(&sa_pbs);
+ ret = TRUE;
+
+return_out:
+
+#if !defined NO_KERNEL_ALG || !defined NO_IKE_ALG
+ if (db_ctx)
+ db_destroy(db_ctx);
+#endif
+ return ret;
+}
+
+/* Handle long form of duration attribute.
+ * The code is can only handle values that can fit in unsigned long.
+ * "Clamping" is probably an acceptable way to impose this limitation.
+ */
+static u_int32_t
+decode_long_duration(pb_stream *pbs)
+{
+ u_int32_t val = 0;
+
+ /* ignore leading zeros */
+ while (pbs_left(pbs) != 0 && *pbs->cur == '\0')
+ pbs->cur++;
+
+ if (pbs_left(pbs) > sizeof(val))
+ {
+ /* "clamp" too large value to max representable value */
+ val -= 1; /* portable way to get to maximum value */
+ DBG(DBG_PARSING, DBG_log(" too large duration clamped to: %lu"
+ , (unsigned long)val));
+ }
+ else
+ {
+ /* decode number */
+ while (pbs_left(pbs) != 0)
+ val = (val << BITS_PER_BYTE) | *pbs->cur++;
+ DBG(DBG_PARSING, DBG_log(" long duration: %lu", (unsigned long)val));
+ }
+ return val;
+}
+
+/* Preparse the body of an ISAKMP SA Payload and
+ * return body of ISAKMP Proposal Payload
+ *
+ * Only IPsec DOI is accepted (what is the ISAKMP DOI?).
+ * Error response is rudimentary.
+ */
+notification_t
+preparse_isakmp_sa_body(const struct isakmp_sa *sa
+ , pb_stream *sa_pbs
+ , u_int32_t *ipsecdoisit
+ , pb_stream *proposal_pbs
+ , struct isakmp_proposal *proposal)
+{
+ /* DOI */
+ if (sa->isasa_doi != ISAKMP_DOI_IPSEC)
+ {
+ loglog(RC_LOG_SERIOUS, "Unknown/unsupported DOI %s", enum_show(&doi_names, sa->isasa_doi));
+ /* XXX Could send notification back */
+ return DOI_NOT_SUPPORTED;
+ }
+
+ /* Situation */
+ if (!in_struct(ipsecdoisit, &ipsec_sit_desc, sa_pbs, NULL))
+ return SITUATION_NOT_SUPPORTED;
+
+ if (*ipsecdoisit != SIT_IDENTITY_ONLY)
+ {
+ loglog(RC_LOG_SERIOUS, "unsupported IPsec DOI situation (%s)"
+ , bitnamesof(sit_bit_names, *ipsecdoisit));
+ /* XXX Could send notification back */
+ return SITUATION_NOT_SUPPORTED;
+ }
+
+ /* The rules for ISAKMP SAs are scattered.
+ * RFC 2409 "IKE" section 5 says that there
+ * can only be one SA, and it can have only one proposal in it.
+ * There may well be multiple transforms.
+ */
+ if (!in_struct(proposal, &isakmp_proposal_desc, sa_pbs, proposal_pbs))
+ return PAYLOAD_MALFORMED;
+
+ if (proposal->isap_np != ISAKMP_NEXT_NONE)
+ {
+ loglog(RC_LOG_SERIOUS, "Proposal Payload must be alone in Oakley SA; found %s following Proposal"
+ , enum_show(&payload_names, proposal->isap_np));
+ return PAYLOAD_MALFORMED;
+ }
+
+ if (proposal->isap_protoid != PROTO_ISAKMP)
+ {
+ loglog(RC_LOG_SERIOUS, "unexpected Protocol ID (%s) found in Oakley Proposal"
+ , enum_show(&protocol_names, proposal->isap_protoid));
+ return INVALID_PROTOCOL_ID;
+ }
+
+ /* Just what should we accept for the SPI field?
+ * The RFC is sort of contradictory. We will ignore the SPI
+ * as long as it is of the proper size.
+ *
+ * From RFC2408 2.4 Identifying Security Associations:
+ * During phase 1 negotiations, the initiator and responder cookies
+ * determine the ISAKMP SA. Therefore, the SPI field in the Proposal
+ * payload is redundant and MAY be set to 0 or it MAY contain the
+ * transmitting entity's cookie.
+ *
+ * From RFC2408 3.5 Proposal Payload:
+ * o SPI Size (1 octet) - Length in octets of the SPI as defined by
+ * the Protocol-Id. In the case of ISAKMP, the Initiator and
+ * Responder cookie pair from the ISAKMP Header is the ISAKMP SPI,
+ * therefore, the SPI Size is irrelevant and MAY be from zero (0) to
+ * sixteen (16). If the SPI Size is non-zero, the content of the
+ * SPI field MUST be ignored. If the SPI Size is not a multiple of
+ * 4 octets it will have some impact on the SPI field and the
+ * alignment of all payloads in the message. The Domain of
+ * Interpretation (DOI) will dictate the SPI Size for other
+ * protocols.
+ */
+ if (proposal->isap_spisize == 0)
+ {
+ /* empty (0) SPI -- fine */
+ }
+ else if (proposal->isap_spisize <= MAX_ISAKMP_SPI_SIZE)
+ {
+ u_char junk_spi[MAX_ISAKMP_SPI_SIZE];
+
+ if (!in_raw(junk_spi, proposal->isap_spisize, proposal_pbs, "Oakley SPI"))
+ return PAYLOAD_MALFORMED;
+ }
+ else
+ {
+ loglog(RC_LOG_SERIOUS, "invalid SPI size (%u) in Oakley Proposal"
+ , (unsigned)proposal->isap_spisize);
+ return INVALID_SPI;
+ }
+ return NOTHING_WRONG;
+}
+
+static struct {
+ u_int8_t *start;
+ u_int8_t *cur;
+ u_int8_t *roof;
+} backup;
+
+/*
+ * backup the pointer into a pb_stream
+ */
+void
+backup_pbs(pb_stream *pbs)
+{
+ backup.start = pbs->start;
+ backup.cur = pbs->cur;
+ backup.roof = pbs->roof;
+}
+
+/*
+ * restore the pointer into a pb_stream
+ */
+void
+restore_pbs(pb_stream *pbs)
+{
+ pbs->start = backup.start;
+ pbs->cur = backup.cur;
+ pbs->roof = backup.roof;
+}
+
+/*
+ * Parse an ISAKMP Proposal Payload for RSA and PSK authentication policies
+ */
+notification_t
+parse_isakmp_policy(pb_stream *proposal_pbs
+ , u_int notrans
+ , lset_t *policy)
+{
+ int last_transnum = -1;
+
+ *policy = LEMPTY;
+
+ while (notrans--)
+ {
+ pb_stream trans_pbs;
+ u_char *attr_start;
+ size_t attr_len;
+ struct isakmp_transform trans;
+
+ if (!in_struct(&trans, &isakmp_isakmp_transform_desc, proposal_pbs, &trans_pbs))
+ return BAD_PROPOSAL_SYNTAX;
+
+ if (trans.isat_transnum <= last_transnum)
+ {
+ /* picky, picky, picky */
+ loglog(RC_LOG_SERIOUS, "Transform Numbers are not monotonically increasing"
+ " in Oakley Proposal");
+ return BAD_PROPOSAL_SYNTAX;
+ }
+ last_transnum = trans.isat_transnum;
+
+ if (trans.isat_transid != KEY_IKE)
+ {
+ loglog(RC_LOG_SERIOUS, "expected KEY_IKE but found %s in Oakley Transform"
+ , enum_show(&isakmp_transformid_names, trans.isat_transid));
+ return INVALID_TRANSFORM_ID;
+ }
+
+ attr_start = trans_pbs.cur;
+ attr_len = pbs_left(&trans_pbs);
+
+ /* preprocess authentication attributes only */
+ while (pbs_left(&trans_pbs) != 0)
+ {
+ struct isakmp_attribute a;
+ pb_stream attr_pbs;
+
+ if (!in_struct(&a, &isakmp_oakley_attribute_desc, &trans_pbs, &attr_pbs))
+ return BAD_PROPOSAL_SYNTAX;
+
+ passert((a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK) < 32);
+
+ switch (a.isaat_af_type)
+ {
+ case OAKLEY_AUTHENTICATION_METHOD | ISAKMP_ATTR_AF_TV:
+ switch (a.isaat_lv)
+ {
+ case OAKLEY_PRESHARED_KEY:
+ *policy |= POLICY_PSK;
+ break;
+ case OAKLEY_RSA_SIG:
+ *policy |= POLICY_RSASIG;
+ break;
+ case XAUTHInitPreShared:
+ *policy |= POLICY_XAUTH_SERVER;
+ /* fall through */
+ case XAUTHRespPreShared:
+ *policy |= POLICY_XAUTH_PSK;
+ break;
+ case XAUTHInitRSA:
+ *policy |= POLICY_XAUTH_SERVER;
+ /* fall through */
+ case XAUTHRespRSA:
+ *policy |= POLICY_XAUTH_RSASIG;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ DBG(DBG_CONTROL|DBG_PARSING,
+ DBG_log("preparse_isakmp_policy: peer requests %s authentication"
+ , prettypolicy(*policy))
+ )
+ return NOTHING_WRONG;
+}
+
+/*
+ * check that we can find a preshared secret
+ */
+static err_t
+find_preshared_key(struct state* st)
+{
+ err_t ugh = NULL;
+ struct connection *c = st->st_connection;
+
+ if (get_preshared_secret(c) == NULL)
+ {
+ char my_id[BUF_LEN], his_id[BUF_LEN];
+
+ idtoa(&c->spd.this.id, my_id, sizeof(my_id));
+ if (his_id_was_instantiated(c))
+ strcpy(his_id, "%any");
+ else
+ idtoa(&c->spd.that.id, his_id, sizeof(his_id));
+ ugh = builddiag("Can't authenticate: no preshared key found for `%s' and `%s'"
+ , my_id, his_id);
+ }
+ return ugh;
+}
+
+/* Parse the body of an ISAKMP SA Payload (i.e. Phase 1 / Main Mode).
+ * Various shortcuts are taken. In particular, the policy, such as
+ * it is, is hardwired.
+ *
+ * If r_sa is non-NULL, the body of an SA representing the selected
+ * proposal is emitted.
+ *
+ * This routine is used by main_inI1_outR1() and main_inR1_outI2().
+ */
+notification_t
+parse_isakmp_sa_body(u_int32_t ipsecdoisit
+ , pb_stream *proposal_pbs
+ , struct isakmp_proposal *proposal
+ , pb_stream *r_sa_pbs
+ , struct state *st
+ , bool initiator)
+{
+ struct connection *c = st->st_connection;
+ unsigned no_trans_left;
+
+ /* for each transform payload... */
+ no_trans_left = proposal->isap_notrans;
+
+ for (;;)
+ {
+ pb_stream trans_pbs;
+ u_char *attr_start;
+ size_t attr_len;
+ struct isakmp_transform trans;
+ lset_t seen_attrs = 0;
+ lset_t seen_durations = 0;
+ u_int16_t life_type = 0;
+ struct oakley_trans_attrs ta;
+ err_t ugh = NULL; /* set to diagnostic when problem detected */
+
+ /* initialize only optional field in ta */
+ ta.life_seconds = OAKLEY_ISAKMP_SA_LIFETIME_DEFAULT; /* When this SA expires (seconds) */
+
+ if (no_trans_left == 0)
+ {
+ loglog(RC_LOG_SERIOUS, "number of Transform Payloads disagrees with Oakley Proposal Payload");
+ return BAD_PROPOSAL_SYNTAX;
+ }
+
+ in_struct(&trans, &isakmp_isakmp_transform_desc, proposal_pbs, &trans_pbs);
+ attr_start = trans_pbs.cur;
+ attr_len = pbs_left(&trans_pbs);
+
+ /* process all the attributes that make up the transform */
+
+ while (pbs_left(&trans_pbs) != 0)
+ {
+ struct isakmp_attribute a;
+ pb_stream attr_pbs;
+ u_int32_t val; /* room for larger values */
+
+ if (!in_struct(&a, &isakmp_oakley_attribute_desc, &trans_pbs, &attr_pbs))
+ return BAD_PROPOSAL_SYNTAX;
+
+ passert((a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK) < 32);
+
+ if (LHAS(seen_attrs, a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK))
+ {
+ loglog(RC_LOG_SERIOUS, "repeated %s attribute in Oakley Transform %u"
+ , enum_show(&oakley_attr_names, a.isaat_af_type)
+ , trans.isat_transnum);
+ return BAD_PROPOSAL_SYNTAX;
+ }
+
+ seen_attrs |= LELEM(a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK);
+
+ val = a.isaat_lv;
+
+ DBG(DBG_PARSING,
+ {
+ enum_names *vdesc = oakley_attr_val_descs
+ [a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK];
+
+ if (vdesc != NULL)
+ {
+ const char *nm = enum_name(vdesc, val);
+
+ if (nm != NULL)
+ DBG_log(" [%u is %s]", (unsigned)val, nm);
+ }
+ });
+
+ switch (a.isaat_af_type)
+ {
+ case OAKLEY_ENCRYPTION_ALGORITHM | ISAKMP_ATTR_AF_TV:
+ if (ike_alg_enc_present(val))
+ {
+ ta.encrypt = val;
+ ta.encrypter = ike_alg_get_encrypter(val);
+ ta.enckeylen = ta.encrypter->keydeflen;
+ }
+ else
+ {
+ ugh = builddiag("%s is not supported"
+ , enum_show(&oakley_enc_names, val));
+ }
+ break;
+
+ case OAKLEY_HASH_ALGORITHM | ISAKMP_ATTR_AF_TV:
+ if (ike_alg_hash_present(val))
+ {
+ ta.hash = val;
+ ta.hasher = ike_alg_get_hasher(val);
+ }
+ else
+ {
+ ugh = builddiag("%s is not supported"
+ , enum_show(&oakley_hash_names, val));
+ }
+ break;
+
+ case OAKLEY_AUTHENTICATION_METHOD | ISAKMP_ATTR_AF_TV:
+ {
+ /* check that authentication method is acceptable */
+ lset_t iap = st->st_policy & POLICY_ID_AUTH_MASK;
+
+ /* is the initiator the XAUTH client? */
+ bool xauth_init = initiator && (st->st_policy & POLICY_XAUTH_SERVER) == LEMPTY
+ || !initiator && (st->st_policy & POLICY_XAUTH_SERVER) != LEMPTY;
+
+ switch (val)
+ {
+ case OAKLEY_PRESHARED_KEY:
+ if ((iap & POLICY_PSK) == LEMPTY)
+ {
+ ugh = "policy does not allow OAKLEY_PRESHARED_KEY authentication";
+ }
+ else
+ {
+ ugh = find_preshared_key(st);
+ ta.auth = OAKLEY_PRESHARED_KEY;
+ }
+ break;
+ case XAUTHInitPreShared:
+ if ((iap & POLICY_XAUTH_PSK) == LEMPTY || !xauth_init)
+ {
+ ugh = "policy does not allow XAUTHInitPreShared authentication";
+ }
+ else
+ {
+ ugh = find_preshared_key(st);
+ ta.auth = XAUTHInitPreShared;
+ }
+ break;
+ case XAUTHRespPreShared:
+ if ((iap & POLICY_XAUTH_PSK) == LEMPTY || xauth_init)
+ {
+ ugh = "policy does not allow XAUTHRespPreShared authentication";
+ }
+ else
+ {
+ ugh = find_preshared_key(st);
+ ta.auth = XAUTHRespPreShared;
+ }
+ break;
+ case OAKLEY_RSA_SIG:
+ /* Accept if policy specifies RSASIG or is default */
+ if ((iap & POLICY_RSASIG) == LEMPTY)
+ {
+ ugh = "policy does not allow OAKLEY_RSA_SIG authentication";
+ }
+ else
+ {
+ ta.auth = OAKLEY_RSA_SIG;
+ }
+ break;
+ case XAUTHInitRSA:
+ if ((iap & POLICY_XAUTH_RSASIG) == LEMPTY || !xauth_init)
+ {
+ ugh = "policy does not allow XAUTHInitRSA authentication";
+ }
+ else
+ {
+ ta.auth = XAUTHInitRSA;
+ }
+ break;
+ case XAUTHRespRSA:
+ if ((iap & POLICY_XAUTH_RSASIG) == LEMPTY || xauth_init)
+ {
+ ugh = "policy does not allow XAUTHRespRSA authentication";
+ }
+ else
+ {
+ ta.auth = XAUTHRespRSA;
+ }
+ break;
+ default:
+ ugh = builddiag("Pluto does not support %s authentication"
+ , enum_show(&oakley_auth_names, val));
+ break;
+ }
+ }
+ break;
+
+ case OAKLEY_GROUP_DESCRIPTION | ISAKMP_ATTR_AF_TV:
+ ta.group = lookup_group(val);
+ if (ta.group == NULL)
+ {
+ ugh = "only OAKLEY_GROUP_MODP1024 and OAKLEY_GROUP_MODP1536 supported";
+ }
+ break;
+
+ case OAKLEY_LIFE_TYPE | ISAKMP_ATTR_AF_TV:
+ switch (val)
+ {
+ case OAKLEY_LIFE_SECONDS:
+ case OAKLEY_LIFE_KILOBYTES:
+ if (LHAS(seen_durations, val))
+ {
+ loglog(RC_LOG_SERIOUS
+ , "attribute OAKLEY_LIFE_TYPE value %s repeated"
+ , enum_show(&oakley_lifetime_names, val));
+ return BAD_PROPOSAL_SYNTAX;
+ }
+ seen_durations |= LELEM(val);
+ life_type = val;
+ break;
+ default:
+ ugh = builddiag("unknown value %s"
+ , enum_show(&oakley_lifetime_names, val));
+ break;
+ }
+ break;
+
+ case OAKLEY_LIFE_DURATION | ISAKMP_ATTR_AF_TLV:
+ val = decode_long_duration(&attr_pbs);
+ /* fall through */
+ case OAKLEY_LIFE_DURATION | ISAKMP_ATTR_AF_TV:
+ if (!LHAS(seen_attrs, OAKLEY_LIFE_TYPE))
+ {
+ ugh = "OAKLEY_LIFE_DURATION attribute not preceded by OAKLEY_LIFE_TYPE attribute";
+ break;
+ }
+ seen_attrs &= ~(LELEM(OAKLEY_LIFE_DURATION) | LELEM(OAKLEY_LIFE_TYPE));
+
+ switch (life_type)
+ {
+ case OAKLEY_LIFE_SECONDS:
+ if (val > OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM)
+ {
+#ifdef CISCO_QUIRKS
+ plog("peer requested %lu seconds"
+ " which exceeds our limit %d seconds"
+ , (long) val
+ , OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM);
+ plog("lifetime reduced to %d seconds "
+ "(todo: IPSEC_RESPONDER_LIFETIME notification)"
+ , OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM);
+ val = OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM;
+#else
+ ugh = builddiag("peer requested %lu seconds"
+ " which exceeds our limit %d seconds"
+ , (long) val
+ , OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM);
+#endif
+ }
+ ta.life_seconds = val;
+ break;
+ case OAKLEY_LIFE_KILOBYTES:
+ ta.life_kilobytes = val;
+ break;
+ default:
+ bad_case(life_type);
+ }
+ break;
+
+ case OAKLEY_KEY_LENGTH | ISAKMP_ATTR_AF_TV:
+ if ((seen_attrs & LELEM(OAKLEY_ENCRYPTION_ALGORITHM)) == 0)
+ {
+ ugh = "OAKLEY_KEY_LENGTH attribute not preceded by "
+ "OAKLEY_ENCRYPTION_ALGORITHM attribute";
+ break;
+ }
+ if (ta.encrypter == NULL)
+ {
+ ugh = "NULL encrypter with seen OAKLEY_ENCRYPTION_ALGORITHM";
+ break;
+ }
+ /*
+ * check if this keylen is compatible with specified algorithm
+ */
+ if (val
+ && (val < ta.encrypter->keyminlen || val > ta.encrypter->keymaxlen))
+ {
+ ugh = "peer proposed key length not valid for "
+ "encryption algorithm specified";
+ }
+ ta.enckeylen = val;
+ break;
+#if 0 /* not yet supported */
+ case OAKLEY_GROUP_TYPE | ISAKMP_ATTR_AF_TV:
+ case OAKLEY_PRF | ISAKMP_ATTR_AF_TV:
+ case OAKLEY_FIELD_SIZE | ISAKMP_ATTR_AF_TV:
+
+ case OAKLEY_GROUP_PRIME | ISAKMP_ATTR_AF_TV:
+ case OAKLEY_GROUP_PRIME | ISAKMP_ATTR_AF_TLV:
+ case OAKLEY_GROUP_GENERATOR_ONE | ISAKMP_ATTR_AF_TV:
+ case OAKLEY_GROUP_GENERATOR_ONE | ISAKMP_ATTR_AF_TLV:
+ case OAKLEY_GROUP_GENERATOR_TWO | ISAKMP_ATTR_AF_TV:
+ case OAKLEY_GROUP_GENERATOR_TWO | ISAKMP_ATTR_AF_TLV:
+ case OAKLEY_GROUP_CURVE_A | ISAKMP_ATTR_AF_TV:
+ case OAKLEY_GROUP_CURVE_A | ISAKMP_ATTR_AF_TLV:
+ case OAKLEY_GROUP_CURVE_B | ISAKMP_ATTR_AF_TV:
+ case OAKLEY_GROUP_CURVE_B | ISAKMP_ATTR_AF_TLV:
+ case OAKLEY_GROUP_ORDER | ISAKMP_ATTR_AF_TV:
+ case OAKLEY_GROUP_ORDER | ISAKMP_ATTR_AF_TLV:
+#endif
+ default:
+ ugh = "unsupported OAKLEY attribute";
+ break;
+ }
+
+ if (ugh != NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "%s. Attribute %s"
+ , ugh, enum_show(&oakley_attr_names, a.isaat_af_type));
+ break;
+ }
+ }
+
+ /*
+ * ML: at last check for allowed transforms in alg_info_ike
+ * (ALG_INFO_F_STRICT flag)
+ */
+ if (ugh == NULL)
+ {
+ if (!ike_alg_ok_final(ta.encrypt, ta.enckeylen, ta.hash,
+ ta.group ? ta.group->group : -1, c->alg_info_ike))
+ {
+ ugh = "OAKLEY proposal refused";
+ }
+ }
+
+ if (ugh == NULL)
+ {
+ /* a little more checking is in order */
+ {
+ lset_t missing
+ = ~seen_attrs
+ & (LELEM(OAKLEY_ENCRYPTION_ALGORITHM)
+ | LELEM(OAKLEY_HASH_ALGORITHM)
+ | LELEM(OAKLEY_AUTHENTICATION_METHOD)
+ | LELEM(OAKLEY_GROUP_DESCRIPTION));
+
+ if (missing)
+ {
+ loglog(RC_LOG_SERIOUS, "missing mandatory attribute(s) %s in Oakley Transform %u"
+ , bitnamesof(oakley_attr_bit_names, missing)
+ , trans.isat_transnum);
+ return BAD_PROPOSAL_SYNTAX;
+ }
+ }
+ /* We must have liked this transform.
+ * Lets finish early and leave.
+ */
+
+ DBG(DBG_PARSING | DBG_CRYPT
+ , DBG_log("Oakley Transform %u accepted", trans.isat_transnum));
+
+ if (r_sa_pbs != NULL)
+ {
+ struct isakmp_proposal r_proposal = *proposal;
+ pb_stream r_proposal_pbs;
+ struct isakmp_transform r_trans = trans;
+ pb_stream r_trans_pbs;
+
+ /* Situation */
+ if (!out_struct(&ipsecdoisit, &ipsec_sit_desc, r_sa_pbs, NULL))
+ impossible();
+
+ /* Proposal */
+#ifdef EMIT_ISAKMP_SPI
+ r_proposal.isap_spisize = COOKIE_SIZE;
+#else
+ r_proposal.isap_spisize = 0;
+#endif
+ r_proposal.isap_notrans = 1;
+ if (!out_struct(&r_proposal, &isakmp_proposal_desc, r_sa_pbs, &r_proposal_pbs))
+ impossible();
+
+ /* SPI */
+#ifdef EMIT_ISAKMP_SPI
+ if (!out_raw(my_cookie, COOKIE_SIZE, &r_proposal_pbs, "SPI"))
+ impossible();
+ r_proposal.isap_spisize = COOKIE_SIZE;
+#else
+ /* none (0) */
+#endif
+
+ /* Transform */
+ r_trans.isat_np = ISAKMP_NEXT_NONE;
+ if (!out_struct(&r_trans, &isakmp_isakmp_transform_desc, &r_proposal_pbs, &r_trans_pbs))
+ impossible();
+
+ if (!out_raw(attr_start, attr_len, &r_trans_pbs, "attributes"))
+ impossible();
+ close_output_pbs(&r_trans_pbs);
+ close_output_pbs(&r_proposal_pbs);
+ close_output_pbs(r_sa_pbs);
+ }
+
+ /* copy over the results */
+ st->st_oakley = ta;
+ return NOTHING_WRONG;
+ }
+
+ /* on to next transform */
+ no_trans_left--;
+
+ if (trans.isat_np == ISAKMP_NEXT_NONE)
+ {
+ if (no_trans_left != 0)
+ {
+ loglog(RC_LOG_SERIOUS, "number of Transform Payloads disagrees with Oakley Proposal Payload");
+ return BAD_PROPOSAL_SYNTAX;
+ }
+ break;
+ }
+ if (trans.isat_np != ISAKMP_NEXT_T)
+ {
+ loglog(RC_LOG_SERIOUS, "unexpected %s payload in Oakley Proposal"
+ , enum_show(&payload_names, proposal->isap_np));
+ return BAD_PROPOSAL_SYNTAX;
+ }
+ }
+ loglog(RC_LOG_SERIOUS, "no acceptable Oakley Transform");
+ return NO_PROPOSAL_CHOSEN;
+}
+
+/* Parse the body of an IPsec SA Payload (i.e. Phase 2 / Quick Mode).
+ *
+ * The main routine is parse_ipsec_sa_body; other functions defined
+ * between here and there are just helpers.
+ *
+ * Various shortcuts are taken. In particular, the policy, such as
+ * it is, is hardwired.
+ *
+ * If r_sa is non-NULL, the body of an SA representing the selected
+ * proposal is emitted into it.
+ *
+ * If "selection" is true, the SA is supposed to represent the
+ * single tranform that the peer has accepted.
+ * ??? We only check that it is acceptable, not that it is one that we offered!
+ *
+ * Only IPsec DOI is accepted (what is the ISAKMP DOI?).
+ * Error response is rudimentary.
+ *
+ * Since all ISAKMP groups in all SA Payloads must match, st->st_pfs_group
+ * holds this across multiple payloads.
+ * &unset_group signifies not yet "set"; NULL signifies NONE.
+ *
+ * This routine is used by quick_inI1_outR1() and quick_inR1_outI2().
+ */
+
+static const struct ipsec_trans_attrs null_ipsec_trans_attrs = {
+ 0, /* transid (NULL, for now) */
+ 0, /* spi */
+ SA_LIFE_DURATION_DEFAULT, /* life_seconds */
+ SA_LIFE_DURATION_K_DEFAULT, /* life_kilobytes */
+ ENCAPSULATION_MODE_UNSPECIFIED, /* encapsulation */
+ AUTH_ALGORITHM_NONE, /* auth */
+ 0, /* key_len */
+ 0, /* key_rounds */
+};
+
+static bool
+parse_ipsec_transform(struct isakmp_transform *trans
+, struct ipsec_trans_attrs *attrs
+, pb_stream *prop_pbs
+, pb_stream *trans_pbs
+, struct_desc *trans_desc
+, int previous_transnum /* or -1 if none */
+, bool selection
+, bool is_last
+, bool is_ipcomp
+, struct state *st) /* current state object */
+{
+ lset_t seen_attrs = 0;
+ lset_t seen_durations = 0;
+ u_int16_t life_type = 0;
+ const struct oakley_group_desc *pfs_group = NULL;
+
+ if (!in_struct(trans, trans_desc, prop_pbs, trans_pbs))
+ return FALSE;
+
+ if (trans->isat_transnum <= previous_transnum)
+ {
+ loglog(RC_LOG_SERIOUS, "Transform Numbers in Proposal are not monotonically increasing");
+ return FALSE;
+ }
+
+ switch (trans->isat_np)
+ {
+ case ISAKMP_NEXT_T:
+ if (is_last)
+ {
+ loglog(RC_LOG_SERIOUS, "Proposal Payload has more Transforms than specified");
+ return FALSE;
+ }
+ break;
+ case ISAKMP_NEXT_NONE:
+ if (!is_last)
+ {
+ loglog(RC_LOG_SERIOUS, "Proposal Payload has fewer Transforms than specified");
+ return FALSE;
+ }
+ break;
+ default:
+ loglog(RC_LOG_SERIOUS, "expecting Transform Payload, but found %s in Proposal"
+ , enum_show(&payload_names, trans->isat_np));
+ return FALSE;
+ }
+
+ *attrs = null_ipsec_trans_attrs;
+ attrs->transid = trans->isat_transid;
+
+ while (pbs_left(trans_pbs) != 0)
+ {
+ struct isakmp_attribute a;
+ pb_stream attr_pbs;
+ enum_names *vdesc;
+ u_int32_t val; /* room for larger value */
+ bool ipcomp_inappropriate = is_ipcomp; /* will get reset if OK */
+
+ if (!in_struct(&a, &isakmp_ipsec_attribute_desc, trans_pbs, &attr_pbs))
+ return FALSE;
+
+ passert((a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK) < 32);
+
+ if (LHAS(seen_attrs, a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK))
+ {
+ loglog(RC_LOG_SERIOUS, "repeated %s attribute in IPsec Transform %u"
+ , enum_show(&ipsec_attr_names, a.isaat_af_type)
+ , trans->isat_transnum);
+ return FALSE;
+ }
+
+ seen_attrs |= LELEM(a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK);
+
+ val = a.isaat_lv;
+
+ vdesc = ipsec_attr_val_descs[a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK];
+ if (vdesc != NULL)
+ {
+ if (enum_name(vdesc, val) == NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "invalid value %u for attribute %s in IPsec Transform"
+ , (unsigned)val, enum_show(&ipsec_attr_names, a.isaat_af_type));
+ return FALSE;
+ }
+ DBG(DBG_PARSING
+ , if ((a.isaat_af_type & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV)
+ DBG_log(" [%u is %s]"
+ , (unsigned)val, enum_show(vdesc, val)));
+ }
+
+ switch (a.isaat_af_type)
+ {
+ case SA_LIFE_TYPE | ISAKMP_ATTR_AF_TV:
+ ipcomp_inappropriate = FALSE;
+ if (LHAS(seen_durations, val))
+ {
+ loglog(RC_LOG_SERIOUS, "attribute SA_LIFE_TYPE value %s repeated in message"
+ , enum_show(&sa_lifetime_names, val));
+ return FALSE;
+ }
+ seen_durations |= LELEM(val);
+ life_type = val;
+ break;
+ case SA_LIFE_DURATION | ISAKMP_ATTR_AF_TLV:
+ val = decode_long_duration(&attr_pbs);
+ /* fall through */
+ case SA_LIFE_DURATION | ISAKMP_ATTR_AF_TV:
+ ipcomp_inappropriate = FALSE;
+ if (!LHAS(seen_attrs, SA_LIFE_DURATION))
+ {
+ loglog(RC_LOG_SERIOUS, "SA_LIFE_DURATION IPsec attribute not preceded by SA_LIFE_TYPE attribute");
+ return FALSE;
+ }
+ seen_attrs &= ~(LELEM(SA_LIFE_DURATION) | LELEM(SA_LIFE_TYPE));
+
+ switch (life_type)
+ {
+ case SA_LIFE_TYPE_SECONDS:
+ /* silently limit duration to our maximum */
+ attrs->life_seconds = val <= SA_LIFE_DURATION_MAXIMUM
+ ? val : SA_LIFE_DURATION_MAXIMUM;
+ break;
+ case SA_LIFE_TYPE_KBYTES:
+ attrs->life_kilobytes = val;
+ break;
+ default:
+ bad_case(life_type);
+ }
+ break;
+ case GROUP_DESCRIPTION | ISAKMP_ATTR_AF_TV:
+ if (is_ipcomp)
+ {
+ /* Accept reluctantly. Should not happen, according to
+ * draft-shacham-ippcp-rfc2393bis-05.txt 4.1.
+ */
+ ipcomp_inappropriate = FALSE;
+ loglog(RC_COMMENT
+ , "IPCA (IPcomp SA) contains GROUP_DESCRIPTION."
+ " Ignoring inapproprate attribute.");
+ }
+ pfs_group = lookup_group(val);
+ if (pfs_group == NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "only OAKLEY_GROUP_MODP1024 and OAKLEY_GROUP_MODP1536 supported for PFS");
+ return FALSE;
+ }
+ break;
+ case ENCAPSULATION_MODE | ISAKMP_ATTR_AF_TV:
+ ipcomp_inappropriate = FALSE;
+ switch (val)
+ {
+ case ENCAPSULATION_MODE_TUNNEL:
+ case ENCAPSULATION_MODE_TRANSPORT:
+ if (st->nat_traversal & NAT_T_DETECTED)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "%s must only be used if NAT-Traversal is not detected"
+ , enum_name(&enc_mode_names, val));
+ /*
+ * Accept it anyway because SSH-Sentinel does not
+ * use UDP_TUNNEL or UDP_TRANSPORT for the diagnostic.
+ *
+ * remove when SSH-Sentinel is fixed
+ */
+#ifdef I_DONT_CARE_OF_SSH_SENTINEL
+ return FALSE;
+#endif
+ }
+ attrs->encapsulation = val;
+ break;
+ case ENCAPSULATION_MODE_UDP_TRANSPORT_DRAFTS:
+#ifndef I_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT
+ loglog(RC_LOG_SERIOUS
+ , "NAT-Traversal: Transport mode disabled due to security concerns");
+ return FALSE;
+#endif
+ case ENCAPSULATION_MODE_UDP_TUNNEL_DRAFTS:
+ if (st->nat_traversal & NAT_T_WITH_RFC_VALUES)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "%s must only be used with old IETF drafts"
+ , enum_name(&enc_mode_names, val));
+ return FALSE;
+ }
+ else if (st->nat_traversal & NAT_T_DETECTED)
+ {
+ attrs->encapsulation = val
+ - ENCAPSULATION_MODE_UDP_TUNNEL_DRAFTS
+ + ENCAPSULATION_MODE_TUNNEL;
+ }
+ else
+ {
+ loglog(RC_LOG_SERIOUS
+ , "%s must only be used if NAT-Traversal is detected"
+ , enum_name(&enc_mode_names, val));
+ return FALSE;
+ }
+ break;
+ case ENCAPSULATION_MODE_UDP_TRANSPORT_RFC:
+#ifndef I_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT
+ loglog(RC_LOG_SERIOUS
+ , "NAT-Traversal: Transport mode disabled due "
+ "to security concerns");
+ return FALSE;
+#endif
+ case ENCAPSULATION_MODE_UDP_TUNNEL_RFC:
+ if ((st->nat_traversal & NAT_T_DETECTED)
+ && (st->nat_traversal & NAT_T_WITH_RFC_VALUES))
+ {
+ attrs->encapsulation = val
+ - ENCAPSULATION_MODE_UDP_TUNNEL_RFC
+ + ENCAPSULATION_MODE_TUNNEL;
+ }
+ else if (st->nat_traversal & NAT_T_DETECTED)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "%s must only be used with NAT-T RFC"
+ , enum_name(&enc_mode_names, val));
+ return FALSE;
+ }
+ else
+ {
+ loglog(RC_LOG_SERIOUS
+ , "%s must only be used if NAT-Traversal is detected"
+ , enum_name(&enc_mode_names, val));
+ return FALSE;
+ }
+ break;
+ default:
+ loglog(RC_LOG_SERIOUS
+ , "unknown ENCAPSULATION_MODE %d in IPSec SA", val);
+ return FALSE;
+ }
+ break;
+ case AUTH_ALGORITHM | ISAKMP_ATTR_AF_TV:
+ attrs->auth = val;
+ break;
+ case KEY_LENGTH | ISAKMP_ATTR_AF_TV:
+ attrs->key_len = val;
+ break;
+ case KEY_ROUNDS | ISAKMP_ATTR_AF_TV:
+ attrs->key_rounds = val;
+ break;
+#if 0 /* not yet implemented */
+ case COMPRESS_DICT_SIZE | ISAKMP_ATTR_AF_TV:
+ break;
+ case COMPRESS_PRIVATE_ALG | ISAKMP_ATTR_AF_TV:
+ break;
+
+ case SA_LIFE_DURATION | ISAKMP_ATTR_AF_TLV:
+ break;
+ case COMPRESS_PRIVATE_ALG | ISAKMP_ATTR_AF_TLV:
+ break;
+#endif
+ default:
+ loglog(RC_LOG_SERIOUS, "unsupported IPsec attribute %s"
+ , enum_show(&ipsec_attr_names, a.isaat_af_type));
+ return FALSE;
+ }
+ if (ipcomp_inappropriate)
+ {
+ loglog(RC_LOG_SERIOUS, "IPsec attribute %s inappropriate for IPCOMP"
+ , enum_show(&ipsec_attr_names, a.isaat_af_type));
+ return FALSE;
+ }
+ }
+
+ /* Although an IPCOMP SA (IPCA) ought not to have a pfs_group,
+ * if it does, demand that it be consistent.
+ * See draft-shacham-ippcp-rfc2393bis-05.txt 4.1.
+ */
+ if (!is_ipcomp || pfs_group != NULL)
+ {
+ if (st->st_pfs_group == &unset_group)
+ st->st_pfs_group = pfs_group;
+
+ if (st->st_pfs_group != pfs_group)
+ {
+ loglog(RC_LOG_SERIOUS, "GROUP_DESCRIPTION inconsistent with that of %s in IPsec SA"
+ , selection? "the Proposal" : "a previous Transform");
+ return FALSE;
+ }
+ }
+
+ if (LHAS(seen_attrs, SA_LIFE_DURATION))
+ {
+ loglog(RC_LOG_SERIOUS, "SA_LIFE_TYPE IPsec attribute not followed by SA_LIFE_DURATION attribute in message");
+ return FALSE;
+ }
+
+ if (!LHAS(seen_attrs, ENCAPSULATION_MODE))
+ {
+ if (is_ipcomp)
+ {
+ /* draft-shacham-ippcp-rfc2393bis-05.txt 4.1:
+ * "If the Encapsulation Mode is unspecified,
+ * the default value of Transport Mode is assumed."
+ * This contradicts/overrides the DOI (quuoted below).
+ */
+ attrs->encapsulation = ENCAPSULATION_MODE_TRANSPORT;
+ }
+ else
+ {
+ /* ??? Technically, RFC 2407 (IPSEC DOI) 4.5 specifies that
+ * the default is "unspecified (host-dependent)".
+ * This makes little sense, so we demand that it be specified.
+ */
+ loglog(RC_LOG_SERIOUS, "IPsec Transform must specify ENCAPSULATION_MODE");
+ return FALSE;
+ }
+ }
+
+ /* ??? should check for key_len and/or key_rounds if required */
+
+ return TRUE;
+}
+
+static void
+echo_proposal(
+ struct isakmp_proposal r_proposal, /* proposal to emit */
+ struct isakmp_transform r_trans, /* winning transformation within it */
+ u_int8_t np, /* Next Payload for proposal */
+ pb_stream *r_sa_pbs, /* SA PBS into which to emit */
+ struct ipsec_proto_info *pi, /* info about this protocol instance */
+ struct_desc *trans_desc, /* descriptor for this transformation */
+ pb_stream *trans_pbs, /* PBS for incoming transform */
+ struct spd_route *sr, /* host details for the association */
+ bool tunnel_mode) /* true for inner most tunnel SA */
+{
+ pb_stream r_proposal_pbs;
+ pb_stream r_trans_pbs;
+
+ /* Proposal */
+ r_proposal.isap_np = np;
+ r_proposal.isap_notrans = 1;
+ if (!out_struct(&r_proposal, &isakmp_proposal_desc, r_sa_pbs, &r_proposal_pbs))
+ impossible();
+
+ /* allocate and emit our CPI/SPI */
+ if (r_proposal.isap_protoid == PROTO_IPCOMP)
+ {
+ /* CPI is stored in network low order end of an
+ * ipsec_spi_t. So we start a couple of bytes in.
+ * Note: we may fail to generate a satisfactory CPI,
+ * but we'll ignore that.
+ */
+ pi->our_spi = get_my_cpi(sr, tunnel_mode);
+ out_raw((u_char *) &pi->our_spi
+ + IPSEC_DOI_SPI_SIZE - IPCOMP_CPI_SIZE
+ , IPCOMP_CPI_SIZE
+ , &r_proposal_pbs, "CPI");
+ }
+ else
+ {
+ pi->our_spi = get_ipsec_spi(pi->attrs.spi
+ , r_proposal.isap_protoid == PROTO_IPSEC_AH ?
+ IPPROTO_AH : IPPROTO_ESP
+ , sr
+ , tunnel_mode);
+ /* XXX should check for errors */
+ out_raw((u_char *) &pi->our_spi, IPSEC_DOI_SPI_SIZE
+ , &r_proposal_pbs, "SPI");
+ }
+
+ /* Transform */
+ r_trans.isat_np = ISAKMP_NEXT_NONE;
+ if (!out_struct(&r_trans, trans_desc, &r_proposal_pbs, &r_trans_pbs))
+ impossible();
+
+ /* Transform Attributes: pure echo */
+ trans_pbs->cur = trans_pbs->start + sizeof(struct isakmp_transform);
+ if (!out_raw(trans_pbs->cur, pbs_left(trans_pbs)
+ , &r_trans_pbs, "attributes"))
+ impossible();
+
+ close_output_pbs(&r_trans_pbs);
+ close_output_pbs(&r_proposal_pbs);
+}
+
+notification_t
+parse_ipsec_sa_body(
+ pb_stream *sa_pbs, /* body of input SA Payload */
+ const struct isakmp_sa *sa, /* header of input SA Payload */
+ pb_stream *r_sa_pbs, /* if non-NULL, where to emit body of winning SA */
+ bool selection, /* if this SA is a selection, only one transform may appear */
+ struct state *st) /* current state object */
+{
+ const struct connection *c = st->st_connection;
+ u_int32_t ipsecdoisit;
+ pb_stream next_proposal_pbs;
+
+ struct isakmp_proposal next_proposal;
+ ipsec_spi_t next_spi;
+
+ bool next_full = TRUE;
+
+ /* DOI */
+ if (sa->isasa_doi != ISAKMP_DOI_IPSEC)
+ {
+ loglog(RC_LOG_SERIOUS, "Unknown or unsupported DOI %s", enum_show(&doi_names, sa->isasa_doi));
+ /* XXX Could send notification back */
+ return DOI_NOT_SUPPORTED;
+ }
+
+ /* Situation */
+ if (!in_struct(&ipsecdoisit, &ipsec_sit_desc, sa_pbs, NULL))
+ return SITUATION_NOT_SUPPORTED;
+
+ if (ipsecdoisit != SIT_IDENTITY_ONLY)
+ {
+ loglog(RC_LOG_SERIOUS, "unsupported IPsec DOI situation (%s)"
+ , bitnamesof(sit_bit_names, ipsecdoisit));
+ /* XXX Could send notification back */
+ return SITUATION_NOT_SUPPORTED;
+ }
+
+ /* The rules for IPsec SAs are scattered.
+ * RFC 2408 "ISAKMP" section 4.2 gives some info.
+ * There may be multiple proposals. Those with identical proposal
+ * numbers must be considered as conjuncts. Those with different
+ * numbers are disjuncts.
+ * Each proposal may have several transforms, each considered
+ * an alternative.
+ * Each transform may have several attributes, all applying.
+ *
+ * To handle the way proposals are combined, we need to do a
+ * look-ahead.
+ */
+
+ if (!in_struct(&next_proposal, &isakmp_proposal_desc, sa_pbs, &next_proposal_pbs))
+ return BAD_PROPOSAL_SYNTAX;
+
+ /* for each conjunction of proposals... */
+ while (next_full)
+ {
+ int propno = next_proposal.isap_proposal;
+ pb_stream ah_prop_pbs, esp_prop_pbs, ipcomp_prop_pbs;
+ struct isakmp_proposal ah_proposal, esp_proposal, ipcomp_proposal;
+ ipsec_spi_t ah_spi = 0;
+ ipsec_spi_t esp_spi = 0;
+ ipsec_spi_t ipcomp_cpi = 0;
+ bool ah_seen = FALSE;
+ bool esp_seen = FALSE;
+ bool ipcomp_seen = FALSE;
+ bool tunnel_mode = FALSE;
+ int inner_proto = 0;
+ u_int16_t well_known_cpi = 0;
+
+ pb_stream ah_trans_pbs, esp_trans_pbs, ipcomp_trans_pbs;
+ struct isakmp_transform ah_trans, esp_trans, ipcomp_trans;
+ struct ipsec_trans_attrs ah_attrs, esp_attrs, ipcomp_attrs;
+
+ /* for each proposal in the conjunction */
+ do {
+
+ if (next_proposal.isap_protoid == PROTO_IPCOMP)
+ {
+ /* IPCOMP CPI */
+ if (next_proposal.isap_spisize == IPSEC_DOI_SPI_SIZE)
+ {
+ /* This code is to accommodate those peculiar
+ * implementations that send a CPI in the bottom of an
+ * SPI-sized field.
+ * See draft-shacham-ippcp-rfc2393bis-05.txt 4.1
+ */
+ u_int8_t filler[IPSEC_DOI_SPI_SIZE - IPCOMP_CPI_SIZE];
+
+ if (!in_raw(filler, sizeof(filler)
+ , &next_proposal_pbs, "CPI filler")
+ || !all_zero(filler, sizeof(filler)))
+ return INVALID_SPI;
+ }
+ else if (next_proposal.isap_spisize != IPCOMP_CPI_SIZE)
+ {
+ loglog(RC_LOG_SERIOUS, "IPsec Proposal with improper CPI size (%u)"
+ , next_proposal.isap_spisize);
+ return INVALID_SPI;
+ }
+
+ /* We store CPI in the low order of a network order
+ * ipsec_spi_t. So we start a couple of bytes in.
+ */
+ zero(&next_spi);
+ if (!in_raw((u_char *)&next_spi
+ + IPSEC_DOI_SPI_SIZE - IPCOMP_CPI_SIZE
+ , IPCOMP_CPI_SIZE, &next_proposal_pbs, "CPI"))
+ return INVALID_SPI;
+
+ /* If sanity ruled, CPIs would have to be such that
+ * the SAID (the triple (CPI, IPCOM, destination IP))
+ * would be unique, just like for SPIs. But there is a
+ * perversion where CPIs can be well-known and consequently
+ * the triple is not unique. We hide this fact from
+ * ourselves by fudging the top 16 bits to make
+ * the property true internally!
+ */
+ switch (ntohl(next_spi))
+ {
+ case IPCOMP_DEFLATE:
+ well_known_cpi = ntohl(next_spi);
+ next_spi = uniquify_his_cpi(next_spi, st);
+ if (next_spi == 0)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "IPsec Proposal contains well-known CPI that I cannot uniquify");
+ return INVALID_SPI;
+ }
+ break;
+ default:
+ if (ntohl(next_spi) < IPCOMP_FIRST_NEGOTIATED
+ || ntohl(next_spi) > IPCOMP_LAST_NEGOTIATED)
+ {
+ loglog(RC_LOG_SERIOUS, "IPsec Proposal contains CPI from non-negotiated range (0x%lx)"
+ , (unsigned long) ntohl(next_spi));
+ return INVALID_SPI;
+ }
+ break;
+ }
+ }
+ else
+ {
+ /* AH or ESP SPI */
+ if (next_proposal.isap_spisize != IPSEC_DOI_SPI_SIZE)
+ {
+ loglog(RC_LOG_SERIOUS, "IPsec Proposal with improper SPI size (%u)"
+ , next_proposal.isap_spisize);
+ return INVALID_SPI;
+ }
+
+ if (!in_raw((u_char *)&next_spi, sizeof(next_spi), &next_proposal_pbs, "SPI"))
+ return INVALID_SPI;
+
+ /* SPI value 0 is invalid and values 1-255 are reserved to IANA.
+ * RFC 2402 (ESP) 2.4, RFC 2406 (AH) 2.1
+ * IPCOMP???
+ */
+ if (ntohl(next_spi) < IPSEC_DOI_SPI_MIN)
+ {
+ loglog(RC_LOG_SERIOUS, "IPsec Proposal contains invalid SPI (0x%lx)"
+ , (unsigned long) ntohl(next_spi));
+ return INVALID_SPI;
+ }
+ }
+
+ if (next_proposal.isap_notrans == 0)
+ {
+ loglog(RC_LOG_SERIOUS, "IPsec Proposal contains no Transforms");
+ return BAD_PROPOSAL_SYNTAX;
+ }
+
+ switch (next_proposal.isap_protoid)
+ {
+ case PROTO_IPSEC_AH:
+ if (ah_seen)
+ {
+ loglog(RC_LOG_SERIOUS, "IPsec SA contains two simultaneous AH Proposals");
+ return BAD_PROPOSAL_SYNTAX;
+ }
+ ah_seen = TRUE;
+ ah_prop_pbs = next_proposal_pbs;
+ ah_proposal = next_proposal;
+ ah_spi = next_spi;
+ break;
+
+ case PROTO_IPSEC_ESP:
+ if (esp_seen)
+ {
+ loglog(RC_LOG_SERIOUS, "IPsec SA contains two simultaneous ESP Proposals");
+ return BAD_PROPOSAL_SYNTAX;
+ }
+ esp_seen = TRUE;
+ esp_prop_pbs = next_proposal_pbs;
+ esp_proposal = next_proposal;
+ esp_spi = next_spi;
+ break;
+
+ case PROTO_IPCOMP:
+ if (ipcomp_seen)
+ {
+ loglog(RC_LOG_SERIOUS, "IPsec SA contains two simultaneous IPCOMP Proposals");
+ return BAD_PROPOSAL_SYNTAX;
+ }
+ ipcomp_seen = TRUE;
+ ipcomp_prop_pbs = next_proposal_pbs;
+ ipcomp_proposal = next_proposal;
+ ipcomp_cpi = next_spi;
+ break;
+
+ default:
+ loglog(RC_LOG_SERIOUS, "unexpected Protocol ID (%s) in IPsec Proposal"
+ , enum_show(&protocol_names, next_proposal.isap_protoid));
+ return INVALID_PROTOCOL_ID;
+ }
+
+ /* refill next_proposal */
+ if (next_proposal.isap_np == ISAKMP_NEXT_NONE)
+ {
+ next_full = FALSE;
+ break;
+ }
+ else if (next_proposal.isap_np != ISAKMP_NEXT_P)
+ {
+ loglog(RC_LOG_SERIOUS, "unexpected in Proposal: %s"
+ , enum_show(&payload_names, next_proposal.isap_np));
+ return BAD_PROPOSAL_SYNTAX;
+ }
+
+ if (!in_struct(&next_proposal, &isakmp_proposal_desc, sa_pbs, &next_proposal_pbs))
+ return BAD_PROPOSAL_SYNTAX;
+ } while (next_proposal.isap_proposal == propno);
+
+ /* Now that we have all conjuncts, we should try
+ * the Cartesian product of eachs tranforms!
+ * At the moment, we take short-cuts on account of
+ * our rudimentary hard-wired policy.
+ * For now, we find an acceptable AH (if any)
+ * and then an acceptable ESP. The only interaction
+ * is that the ESP acceptance can know whether there
+ * was an acceptable AH and hence not require an AUTH.
+ */
+
+ if (ah_seen)
+ {
+ int previous_transnum = -1;
+ int tn;
+
+ for (tn = 0; tn != ah_proposal.isap_notrans; tn++)
+ {
+ int ok_transid = 0;
+ bool ok_auth = FALSE;
+
+ if (!parse_ipsec_transform(&ah_trans
+ , &ah_attrs
+ , &ah_prop_pbs
+ , &ah_trans_pbs
+ , &isakmp_ah_transform_desc
+ , previous_transnum
+ , selection
+ , tn == ah_proposal.isap_notrans - 1
+ , FALSE
+ , st))
+ return BAD_PROPOSAL_SYNTAX;
+
+ previous_transnum = ah_trans.isat_transnum;
+
+ /* we must understand ah_attrs.transid
+ * COMBINED with ah_attrs.auth.
+ * See RFC 2407 "IPsec DOI" section 4.4.3
+ * The following combinations are legal,
+ * but we don't implement all of them:
+ * It seems as if each auth algorithm
+ * only applies to one ah transid.
+ * AH_MD5, AUTH_ALGORITHM_HMAC_MD5
+ * AH_MD5, AUTH_ALGORITHM_KPDK (unimplemented)
+ * AH_SHA, AUTH_ALGORITHM_HMAC_SHA1
+ * AH_DES, AUTH_ALGORITHM_DES_MAC (unimplemented)
+ */
+ switch (ah_attrs.auth)
+ {
+ case AUTH_ALGORITHM_NONE:
+ loglog(RC_LOG_SERIOUS, "AUTH_ALGORITHM attribute missing in AH Transform");
+ return BAD_PROPOSAL_SYNTAX;
+
+ case AUTH_ALGORITHM_HMAC_MD5:
+ ok_auth = TRUE;
+ /* fall through */
+ case AUTH_ALGORITHM_KPDK:
+ ok_transid = AH_MD5;
+ break;
+
+ case AUTH_ALGORITHM_HMAC_SHA1:
+ ok_auth = TRUE;
+ ok_transid = AH_SHA;
+ break;
+
+ case AUTH_ALGORITHM_DES_MAC:
+ ok_transid = AH_DES;
+ break;
+ }
+ if (ah_attrs.transid != ok_transid)
+ {
+ loglog(RC_LOG_SERIOUS, "%s attribute inappropriate in %s Transform"
+ , enum_name(&auth_alg_names, ah_attrs.auth)
+ , enum_show(&ah_transformid_names, ah_attrs.transid));
+ return BAD_PROPOSAL_SYNTAX;
+ }
+ if (!ok_auth)
+ {
+ DBG(DBG_CONTROL | DBG_CRYPT
+ , DBG_log("%s attribute unsupported"
+ " in %s Transform from %s"
+ , enum_name(&auth_alg_names, ah_attrs.auth)
+ , enum_show(&ah_transformid_names, ah_attrs.transid)
+ , ip_str(&c->spd.that.host_addr)));
+ continue; /* try another */
+ }
+ break; /* we seem to be happy */
+ }
+ if (tn == ah_proposal.isap_notrans)
+ continue; /* we didn't find a nice one */
+ ah_attrs.spi = ah_spi;
+ inner_proto = IPPROTO_AH;
+ if (ah_attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL)
+ tunnel_mode = TRUE;
+ }
+
+ if (esp_seen)
+ {
+ int previous_transnum = -1;
+ int tn;
+
+ for (tn = 0; tn != esp_proposal.isap_notrans; tn++)
+ {
+ if (!parse_ipsec_transform(&esp_trans
+ , &esp_attrs
+ , &esp_prop_pbs
+ , &esp_trans_pbs
+ , &isakmp_esp_transform_desc
+ , previous_transnum
+ , selection
+ , tn == esp_proposal.isap_notrans - 1
+ , FALSE
+ , st))
+ return BAD_PROPOSAL_SYNTAX;
+
+ previous_transnum = esp_trans.isat_transnum;
+
+ /* set default key length for AES encryption */
+ if (!esp_attrs.key_len && esp_attrs.transid == ESP_AES)
+ {
+ esp_attrs.key_len = 128 / BITS_PER_BYTE;
+ }
+
+ if (!kernel_alg_esp_enc_ok(esp_attrs.transid, esp_attrs.key_len
+ ,c->alg_info_esp))
+ {
+ switch (esp_attrs.transid)
+ {
+ case ESP_3DES:
+ break;
+#ifdef SUPPORT_ESP_NULL /* should be about as secure as AH-only */
+ case ESP_NULL:
+ if (esp_attrs.auth == AUTH_ALGORITHM_NONE)
+ {
+ loglog(RC_LOG_SERIOUS, "ESP_NULL requires auth algorithm");
+ return BAD_PROPOSAL_SYNTAX;
+ }
+ if (st->st_policy & POLICY_ENCRYPT)
+ {
+ DBG(DBG_CONTROL | DBG_CRYPT
+ , DBG_log("ESP_NULL Transform Proposal from %s"
+ " does not satisfy POLICY_ENCRYPT"
+ , ip_str(&c->spd.that.host_addr)));
+ continue; /* try another */
+ }
+ break;
+#endif
+ default:
+ DBG(DBG_CONTROL | DBG_CRYPT
+ , DBG_log("unsupported ESP Transform %s from %s"
+ , enum_show(&esp_transformid_names, esp_attrs.transid)
+ , ip_str(&c->spd.that.host_addr)));
+ continue; /* try another */
+ }
+ }
+
+ if (!kernel_alg_esp_auth_ok(esp_attrs.auth, c->alg_info_esp))
+ {
+ switch (esp_attrs.auth)
+ {
+ case AUTH_ALGORITHM_NONE:
+ if (!ah_seen)
+ {
+ DBG(DBG_CONTROL | DBG_CRYPT
+ , DBG_log("ESP from %s must either have AUTH or be combined with AH"
+ , ip_str(&c->spd.that.host_addr)));
+ continue; /* try another */
+ }
+ break;
+ case AUTH_ALGORITHM_HMAC_MD5:
+ case AUTH_ALGORITHM_HMAC_SHA1:
+ break;
+ default:
+ DBG(DBG_CONTROL | DBG_CRYPT
+ , DBG_log("unsupported ESP auth alg %s from %s"
+ , enum_show(&auth_alg_names, esp_attrs.auth)
+ , ip_str(&c->spd.that.host_addr)));
+ continue; /* try another */
+ }
+ }
+
+ /* A last check for allowed transforms in alg_info_esp
+ * (ALG_INFO_F_STRICT flag)
+ */
+ if (!kernel_alg_esp_ok_final(esp_attrs.transid, esp_attrs.key_len
+ ,esp_attrs.auth, c->alg_info_esp))
+ {
+ continue;
+ }
+
+ if (ah_seen && ah_attrs.encapsulation != esp_attrs.encapsulation)
+ {
+ /* ??? This should be an error, but is it? */
+ DBG(DBG_CONTROL | DBG_CRYPT
+ , DBG_log("AH and ESP transforms disagree about encapsulation; TUNNEL presumed"));
+ }
+
+ break; /* we seem to be happy */
+ }
+ if (tn == esp_proposal.isap_notrans)
+ continue; /* we didn't find a nice one */
+
+ esp_attrs.spi = esp_spi;
+ inner_proto = IPPROTO_ESP;
+ if (esp_attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL)
+ tunnel_mode = TRUE;
+ }
+ else if (st->st_policy & POLICY_ENCRYPT)
+ {
+ DBG(DBG_CONTROL | DBG_CRYPT
+ , DBG_log("policy for \"%s\" requires encryption but ESP not in Proposal from %s"
+ , c->name, ip_str(&c->spd.that.host_addr)));
+ continue; /* we needed encryption, but didn't find ESP */
+ }
+ else if ((st->st_policy & POLICY_AUTHENTICATE) && !ah_seen)
+ {
+ DBG(DBG_CONTROL | DBG_CRYPT
+ , DBG_log("policy for \"%s\" requires authentication"
+ " but none in Proposal from %s"
+ , c->name, ip_str(&c->spd.that.host_addr)));
+ continue; /* we need authentication, but we found neither ESP nor AH */
+ }
+
+ if (ipcomp_seen)
+ {
+ int previous_transnum = -1;
+ int tn;
+
+#ifdef NEVER /* we think IPcomp is working now */
+ /**** FUDGE TO PREVENT UNREQUESTED IPCOMP:
+ **** NEEDED BECAUSE OUR IPCOMP IS EXPERIMENTAL (UNSTABLE).
+ ****/
+ if (!(st->st_policy & POLICY_COMPRESS))
+ {
+ plog("compression proposed by %s, but policy for \"%s\" forbids it"
+ , ip_str(&c->spd.that.host_addr), c->name);
+ continue; /* unwanted compression proposal */
+ }
+#endif
+ if (!can_do_IPcomp)
+ {
+ plog("compression proposed by %s, but KLIPS is not configured with IPCOMP"
+ , ip_str(&c->spd.that.host_addr));
+ continue;
+ }
+
+ if (well_known_cpi != 0 && !ah_seen && !esp_seen)
+ {
+ plog("illegal proposal: bare IPCOMP used with well-known CPI");
+ return BAD_PROPOSAL_SYNTAX;
+ }
+
+ for (tn = 0; tn != ipcomp_proposal.isap_notrans; tn++)
+ {
+ if (!parse_ipsec_transform(&ipcomp_trans
+ , &ipcomp_attrs
+ , &ipcomp_prop_pbs
+ , &ipcomp_trans_pbs
+ , &isakmp_ipcomp_transform_desc
+ , previous_transnum
+ , selection
+ , tn == ipcomp_proposal.isap_notrans - 1
+ , TRUE
+ , st))
+ return BAD_PROPOSAL_SYNTAX;
+
+ previous_transnum = ipcomp_trans.isat_transnum;
+
+ if (well_known_cpi != 0 && ipcomp_attrs.transid != well_known_cpi)
+ {
+ plog("illegal proposal: IPCOMP well-known CPI disagrees with transform");
+ return BAD_PROPOSAL_SYNTAX;
+ }
+
+ switch (ipcomp_attrs.transid)
+ {
+ case IPCOMP_DEFLATE: /* all we can handle! */
+ break;
+
+ default:
+ DBG(DBG_CONTROL | DBG_CRYPT
+ , DBG_log("unsupported IPCOMP Transform %s from %s"
+ , enum_show(&ipcomp_transformid_names, ipcomp_attrs.transid)
+ , ip_str(&c->spd.that.host_addr)));
+ continue; /* try another */
+ }
+
+ if (ah_seen && ah_attrs.encapsulation != ipcomp_attrs.encapsulation)
+ {
+ /* ??? This should be an error, but is it? */
+ DBG(DBG_CONTROL | DBG_CRYPT
+ , DBG_log("AH and IPCOMP transforms disagree about encapsulation; TUNNEL presumed"));
+ } else if (esp_seen && esp_attrs.encapsulation != ipcomp_attrs.encapsulation)
+ {
+ /* ??? This should be an error, but is it? */
+ DBG(DBG_CONTROL | DBG_CRYPT
+ , DBG_log("ESP and IPCOMP transforms disagree about encapsulation; TUNNEL presumed"));
+ }
+
+ break; /* we seem to be happy */
+ }
+ if (tn == ipcomp_proposal.isap_notrans)
+ continue; /* we didn't find a nice one */
+ ipcomp_attrs.spi = ipcomp_cpi;
+ inner_proto = IPPROTO_COMP;
+ if (ipcomp_attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL)
+ tunnel_mode = TRUE;
+ }
+
+ /* Eureka: we liked what we saw -- accept it. */
+
+ if (r_sa_pbs != NULL)
+ {
+ /* emit what we've accepted */
+
+ /* Situation */
+ if (!out_struct(&ipsecdoisit, &ipsec_sit_desc, r_sa_pbs, NULL))
+ impossible();
+
+ /* AH proposal */
+ if (ah_seen)
+ echo_proposal(ah_proposal
+ , ah_trans
+ , esp_seen || ipcomp_seen? ISAKMP_NEXT_P : ISAKMP_NEXT_NONE
+ , r_sa_pbs
+ , &st->st_ah
+ , &isakmp_ah_transform_desc
+ , &ah_trans_pbs
+ , &st->st_connection->spd
+ , tunnel_mode && inner_proto == IPPROTO_AH);
+
+ /* ESP proposal */
+ if (esp_seen)
+ echo_proposal(esp_proposal
+ , esp_trans
+ , ipcomp_seen? ISAKMP_NEXT_P : ISAKMP_NEXT_NONE
+ , r_sa_pbs
+ , &st->st_esp
+ , &isakmp_esp_transform_desc
+ , &esp_trans_pbs
+ , &st->st_connection->spd
+ , tunnel_mode && inner_proto == IPPROTO_ESP);
+
+ /* IPCOMP proposal */
+ if (ipcomp_seen)
+ echo_proposal(ipcomp_proposal
+ , ipcomp_trans
+ , ISAKMP_NEXT_NONE
+ , r_sa_pbs
+ , &st->st_ipcomp
+ , &isakmp_ipcomp_transform_desc
+ , &ipcomp_trans_pbs
+ , &st->st_connection->spd
+ , tunnel_mode && inner_proto == IPPROTO_COMP);
+
+ close_output_pbs(r_sa_pbs);
+ }
+
+ /* save decoded version of winning SA in state */
+
+ st->st_ah.present = ah_seen;
+ if (ah_seen)
+ st->st_ah.attrs = ah_attrs;
+
+ st->st_esp.present = esp_seen;
+ if (esp_seen)
+ st->st_esp.attrs = esp_attrs;
+
+ st->st_ipcomp.present = ipcomp_seen;
+ if (ipcomp_seen)
+ st->st_ipcomp.attrs = ipcomp_attrs;
+
+ return NOTHING_WRONG;
+ }
+
+ loglog(RC_LOG_SERIOUS, "no acceptable Proposal in IPsec SA");
+ return NO_PROPOSAL_CHOSEN;
+}
diff --git a/src/pluto/spdb.h b/src/pluto/spdb.h
new file mode 100644
index 000000000..0df488841
--- /dev/null
+++ b/src/pluto/spdb.h
@@ -0,0 +1,112 @@
+/* Security Policy Data Base (such as it is)
+ * Copyright (C) 1998, 1999 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: spdb.h,v 1.4 2006/04/22 21:59:20 as Exp $
+ */
+
+#ifndef _SPDB_H
+#define _SPDB_H
+
+#include "packet.h"
+
+/* database of SA properties */
+
+/* Attribute type and value pair.
+ * Note: only "basic" values are represented so far.
+ */
+struct db_attr {
+ u_int16_t type; /* ISAKMP_ATTR_AF_TV is implied; 0 for end */
+ u_int16_t val;
+};
+
+/* transform */
+struct db_trans {
+ u_int8_t transid; /* Transform-Id */
+ struct db_attr *attrs; /* array */
+ int attr_cnt; /* number of elements */
+};
+
+/* proposal */
+struct db_prop {
+ u_int8_t protoid; /* Protocol-Id */
+ struct db_trans *trans; /* array (disjunction) */
+ int trans_cnt; /* number of elements */
+ /* SPI size and value isn't part of DB */
+};
+
+/* conjunction of proposals */
+struct db_prop_conj {
+ struct db_prop *props; /* array */
+ int prop_cnt; /* number of elements */
+};
+
+/* security association */
+struct db_sa {
+ struct db_prop_conj *prop_conjs; /* array */
+ int prop_conj_cnt; /* number of elements */
+ /* Hardwired for now;
+ * DOI: ISAKMP_DOI_IPSEC
+ * Situation: SIT_IDENTITY_ONLY
+ */
+};
+
+/* The oakley sadb */
+extern struct db_sa oakley_sadb;
+
+/* The ipsec sadb is subscripted by a bitset with members
+ * from POLICY_ENCRYPT, POLICY_AUTHENTICATE, POLICY_COMPRESS
+ */
+extern struct db_sa ipsec_sadb[1 << 3];
+
+/* forward declaration */
+struct state;
+
+extern bool out_sa(
+ pb_stream *outs,
+ struct db_sa *sadb,
+ struct state *st,
+ bool oakley_mode,
+ u_int8_t np);
+
+extern notification_t preparse_isakmp_sa_body(
+ const struct isakmp_sa *sa, /* header of input SA Payload */
+ pb_stream *sa_pbs, /* body of input SA Payload */
+ u_int32_t *ipsecdoisit, /* IPsec DOI SIT bitset */
+ pb_stream *proposal_pbs, /* body of proposal Payload */
+ struct isakmp_proposal *proposal);
+
+extern notification_t parse_isakmp_policy(
+ pb_stream *proposal_pbs, /* body of proposal Payload */
+ u_int notrans, /* number of transforms */
+ lset_t *policy); /* RSA, PSK or XAUTH policy */
+
+extern notification_t parse_isakmp_sa_body(
+ u_int32_t ipsecdoisit, /* IPsec DOI SIT bitset */
+ pb_stream *proposal_pbs, /* body of proposal Payload */
+ struct isakmp_proposal *proposal,
+ pb_stream *r_sa_pbs, /* if non-NULL, where to emit winning SA */
+ struct state *st, /* current state object */
+ bool initiator); /* is caller initiator? */
+
+extern notification_t parse_ipsec_sa_body(
+ pb_stream *sa_pbs, /* body of input SA Payload */
+ const struct isakmp_sa *sa, /* header of input SA Payload */
+ pb_stream *r_sa_pbs, /* if non-NULL, where to emit winning SA */
+ bool selection, /* if this SA is a selection, only one tranform can appear */
+ struct state *st); /* current state object */
+
+extern void backup_pbs(pb_stream *pbs);
+extern void restore_pbs(pb_stream *pbs);
+
+#endif /* _SPDB_H */
+
diff --git a/src/pluto/state.c b/src/pluto/state.c
new file mode 100644
index 000000000..80c3156b1
--- /dev/null
+++ b/src/pluto/state.c
@@ -0,0 +1,1012 @@
+/* routines for state objects
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: state.c,v 1.13 2006/04/29 18:16:02 as Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <sys/queue.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "connections.h"
+#include "state.h"
+#include "kernel.h"
+#include "log.h"
+#include "packet.h" /* so we can calculate sizeof(struct isakmp_hdr) */
+#include "keys.h" /* for free_public_key */
+#include "rnd.h"
+#include "timer.h"
+#include "whack.h"
+#include "demux.h" /* needs packet.h */
+#include "ipsec_doi.h" /* needs demux.h and state.h */
+
+#include "sha1.h"
+#include "md5.h"
+#include "crypto.h" /* requires sha1.h and md5.h */
+
+/*
+ * Global variables: had to go somewhere, might as well be this file.
+ */
+
+u_int16_t pluto_port = IKE_UDP_PORT; /* Pluto's port */
+
+/*
+ * This file has the functions that handle the
+ * state hash table and the Message ID list.
+ */
+
+/* Message-IDs
+ *
+ * A Message ID is contained in each IKE message header.
+ * For Phase 1 exchanges (Main and Aggressive), it will be zero.
+ * For other exchanges, which must be under the protection of an
+ * ISAKMP SA, the Message ID must be unique within that ISAKMP SA.
+ * Effectively, this labels the message as belonging to a particular
+ * exchange.
+ * BTW, we feel this uniqueness allows rekeying to be somewhat simpler
+ * than specified by draft-jenkins-ipsec-rekeying-06.txt.
+ *
+ * A MessageID is a 32 bit unsigned number. We represent the value
+ * internally in network order -- they are just blobs to us.
+ * They are unsigned numbers to make hashing and comparing easy.
+ *
+ * The following mechanism is used to allocate message IDs. This
+ * requires that we keep track of which numbers have already been used
+ * so that we don't allocate one in use.
+ */
+
+struct msgid_list
+{
+ msgid_t msgid; /* network order */
+ struct msgid_list *next;
+};
+
+bool
+reserve_msgid(struct state *isakmp_sa, msgid_t msgid)
+{
+ struct msgid_list *p;
+
+ passert(msgid != MAINMODE_MSGID);
+ passert(IS_ISAKMP_ENCRYPTED(isakmp_sa->st_state));
+
+ for (p = isakmp_sa->st_used_msgids; p != NULL; p = p->next)
+ if (p->msgid == msgid)
+ return FALSE;
+
+ p = alloc_thing(struct msgid_list, "msgid");
+ p->msgid = msgid;
+ p->next = isakmp_sa->st_used_msgids;
+ isakmp_sa->st_used_msgids = p;
+ return TRUE;
+}
+
+msgid_t
+generate_msgid(struct state *isakmp_sa)
+{
+ int timeout = 100; /* only try so hard for unique msgid */
+ msgid_t msgid;
+
+ passert(IS_ISAKMP_ENCRYPTED(isakmp_sa->st_state));
+
+ for (;;)
+ {
+ get_rnd_bytes((void *) &msgid, sizeof(msgid));
+ if (msgid != 0 && reserve_msgid(isakmp_sa, msgid))
+ break;
+
+ if (--timeout == 0)
+ {
+ plog("gave up looking for unique msgid; using 0x%08lx"
+ , (unsigned long) msgid);
+ break;
+ }
+ }
+ return msgid;
+}
+
+
+/* state table functions */
+
+#define STATE_TABLE_SIZE 32
+
+static struct state *statetable[STATE_TABLE_SIZE];
+
+static struct state **
+state_hash(const u_char *icookie, const u_char *rcookie, const ip_address *peer)
+{
+ u_int i = 0, j;
+ const unsigned char *byte_ptr;
+ size_t length = addrbytesptr(peer, &byte_ptr);
+
+ DBG(DBG_RAW | DBG_CONTROL,
+ DBG_dump("ICOOKIE:", icookie, COOKIE_SIZE);
+ DBG_dump("RCOOKIE:", rcookie, COOKIE_SIZE);
+ DBG_dump("peer:", byte_ptr, length));
+
+ /* XXX the following hash is pretty pathetic */
+
+ for (j = 0; j < COOKIE_SIZE; j++)
+ i = i * 407 + icookie[j] + rcookie[j];
+
+ for (j = 0; j < length; j++)
+ i = i * 613 + byte_ptr[j];
+
+ i = i % STATE_TABLE_SIZE;
+
+ DBG(DBG_CONTROL, DBG_log("state hash entry %d", i));
+
+ return &statetable[i];
+}
+
+/* Get a state object.
+ * Caller must schedule an event for this object so that it doesn't leak.
+ * Caller must insert_state().
+ */
+struct state *
+new_state(void)
+{
+ static const struct state blank_state; /* initialized all to zero & NULL */
+ static so_serial_t next_so = SOS_FIRST;
+ struct state *st;
+
+ st = clone_thing(blank_state, "struct state in new_state()");
+ st->st_serialno = next_so++;
+ passert(next_so > SOS_FIRST); /* overflow can't happen! */
+ st->st_whack_sock = NULL_FD;
+ DBG(DBG_CONTROL, DBG_log("creating state object #%lu at %p",
+ st->st_serialno, (void *) st));
+ return st;
+}
+
+/*
+ * Initialize the state table (and mask*).
+ */
+void
+init_states(void)
+{
+ int i;
+
+ for (i = 0; i < STATE_TABLE_SIZE; i++)
+ statetable[i] = (struct state *) NULL;
+}
+
+/* Find the state object with this serial number.
+ * This allows state object references that don't turn into dangerous
+ * dangling pointers: reference a state by its serial number.
+ * Returns NULL if there is no such state.
+ * If this turns out to be a significant CPU hog, it could be
+ * improved to use a hash table rather than sequential seartch.
+ */
+struct state *
+state_with_serialno(so_serial_t sn)
+{
+ if (sn >= SOS_FIRST)
+ {
+ struct state *st;
+ int i;
+
+ for (i = 0; i < STATE_TABLE_SIZE; i++)
+ for (st = statetable[i]; st != NULL; st = st->st_hashchain_next)
+ if (st->st_serialno == sn)
+ return st;
+ }
+ return NULL;
+}
+
+/* Insert a state object in the hash table. The object is inserted
+ * at the begining of list.
+ * Needs cookies, connection, and msgid.
+ */
+void
+insert_state(struct state *st)
+{
+ struct state **p = state_hash(st->st_icookie, st->st_rcookie
+ , &st->st_connection->spd.that.host_addr);
+
+ passert(st->st_hashchain_prev == NULL && st->st_hashchain_next == NULL);
+
+ if (*p != NULL)
+ {
+ passert((*p)->st_hashchain_prev == NULL);
+ (*p)->st_hashchain_prev = st;
+ }
+ st->st_hashchain_next = *p;
+ *p = st;
+
+ /* Ensure that somebody is in charge of killing this state:
+ * if no event is scheduled for it, schedule one to discard the state.
+ * If nothing goes wrong, this event will be replaced by
+ * a more appropriate one.
+ */
+ if (st->st_event == NULL)
+ event_schedule(EVENT_SO_DISCARD, 0, st);
+}
+
+/* unlink a state object from the hash table, but don't free it
+ */
+void
+unhash_state(struct state *st)
+{
+ /* unlink from forward chain */
+ struct state **p = st->st_hashchain_prev == NULL
+ ? state_hash(st->st_icookie, st->st_rcookie
+ , &st->st_connection->spd.that.host_addr)
+ : &st->st_hashchain_prev->st_hashchain_next;
+
+ /* unlink from forward chain */
+ passert(*p == st);
+ *p = st->st_hashchain_next;
+
+ /* unlink from backward chain */
+ if (st->st_hashchain_next != NULL)
+ {
+ passert(st->st_hashchain_next->st_hashchain_prev == st);
+ st->st_hashchain_next->st_hashchain_prev = st->st_hashchain_prev;
+ }
+
+ st->st_hashchain_next = st->st_hashchain_prev = NULL;
+}
+
+/* Free the Whack socket file descriptor.
+ * This has the side effect of telling Whack that we're done.
+ */
+void
+release_whack(struct state *st)
+{
+ close_any(st->st_whack_sock);
+}
+
+/* delete a state object */
+void
+delete_state(struct state *st)
+{
+ struct connection *const c = st->st_connection;
+ struct state *old_cur_state = cur_state == st? NULL : cur_state;
+
+ set_cur_state(st);
+
+ /* If DPD is enabled on this state object, clear any pending events */
+ if(st->st_dpd_event != NULL)
+ delete_dpd_event(st);
+
+ /* if there is a suspended state transition, disconnect us */
+ if (st->st_suspended_md != NULL)
+ {
+ passert(st->st_suspended_md->st == st);
+ st->st_suspended_md->st = NULL;
+ }
+
+ /* tell the other side of any IPSEC SAs that are going down */
+ if (IS_IPSEC_SA_ESTABLISHED(st->st_state)
+ || IS_ISAKMP_SA_ESTABLISHED(st->st_state))
+ send_delete(st);
+
+ delete_event(st); /* delete any pending timer event */
+
+ /* Ditch anything pending on ISAKMP SA being established.
+ * Note: this must be done before the unhash_state to prevent
+ * flush_pending_by_state inadvertently and prematurely
+ * deleting our connection.
+ */
+ flush_pending_by_state(st);
+
+ /* effectively, this deletes any ISAKMP SA that this state represents */
+ unhash_state(st);
+
+ /* tell kernel to delete any IPSEC SA
+ * ??? we ought to tell peer to delete IPSEC SAs
+ */
+ if (IS_IPSEC_SA_ESTABLISHED(st->st_state))
+ delete_ipsec_sa(st, FALSE);
+ else if (IS_ONLY_INBOUND_IPSEC_SA_ESTABLISHED(st->st_state))
+ delete_ipsec_sa(st, TRUE);
+
+ if (c->newest_ipsec_sa == st->st_serialno)
+ c->newest_ipsec_sa = SOS_NOBODY;
+
+ if (c->newest_isakmp_sa == st->st_serialno)
+ c->newest_isakmp_sa = SOS_NOBODY;
+
+ st->st_connection = NULL; /* we might be about to free it */
+ cur_state = old_cur_state; /* without st_connection, st isn't complete */
+ connection_discard(c);
+
+ release_whack(st);
+
+ /* from here on we are just freeing RAM */
+
+ {
+ struct msgid_list *p = st->st_used_msgids;
+
+ while (p != NULL)
+ {
+ struct msgid_list *q = p;
+ p = p->next;
+ pfree(q);
+ }
+ }
+
+ unreference_key(&st->st_peer_pubkey);
+
+ if (st->st_sec_in_use)
+ mpz_clear(&(st->st_sec));
+
+ pfreeany(st->st_tpacket.ptr);
+ pfreeany(st->st_rpacket.ptr);
+ pfreeany(st->st_p1isa.ptr);
+ pfreeany(st->st_gi.ptr);
+ pfreeany(st->st_gr.ptr);
+ pfreeany(st->st_shared.ptr);
+ pfreeany(st->st_ni.ptr);
+ pfreeany(st->st_nr.ptr);
+ pfreeany(st->st_skeyid.ptr);
+ pfreeany(st->st_skeyid_d.ptr);
+ pfreeany(st->st_skeyid_a.ptr);
+ pfreeany(st->st_skeyid_e.ptr);
+ pfreeany(st->st_enc_key.ptr);
+ pfreeany(st->st_ah.our_keymat);
+ pfreeany(st->st_ah.peer_keymat);
+ pfreeany(st->st_esp.our_keymat);
+ pfreeany(st->st_esp.peer_keymat);
+
+ pfree(st);
+}
+
+/*
+ * Is a connection in use by some state?
+ */
+bool
+states_use_connection(struct connection *c)
+{
+ /* are there any states still using it? */
+ struct state *st = NULL;
+ int i;
+
+ for (i = 0; st == NULL && i < STATE_TABLE_SIZE; i++)
+ for (st = statetable[i]; st != NULL; st = st->st_hashchain_next)
+ if (st->st_connection == c)
+ return TRUE;
+
+ return FALSE;
+}
+
+/*
+ * delete all states that were created for a given connection.
+ * if relations == TRUE, then also delete states that share
+ * the same phase 1 SA.
+ */
+void
+delete_states_by_connection(struct connection *c, bool relations)
+{
+ int pass;
+ /* this kludge avoids an n^2 algorithm */
+ enum connection_kind ck = c->kind;
+ struct spd_route *sr;
+
+ /* save this connection's isakmp SA, since it will get set to later SOS_NOBODY */
+ so_serial_t parent_sa = c->newest_isakmp_sa;
+
+ if (ck == CK_INSTANCE)
+ c->kind = CK_GOING_AWAY;
+
+ /* We take two passes so that we delete any ISAKMP SAs last.
+ * This allows Delete Notifications to be sent.
+ * ?? We could probably double the performance by caching any
+ * ISAKMP SA states found in the first pass, avoiding a second.
+ */
+ for (pass = 0; pass != 2; pass++)
+ {
+ int i;
+
+ /* For each hash chain... */
+ for (i = 0; i < STATE_TABLE_SIZE; i++)
+ {
+ struct state *st;
+
+ /* For each state in the hash chain... */
+ for (st = statetable[i]; st != NULL; )
+ {
+ struct state *this = st;
+
+ st = st->st_hashchain_next; /* before this is deleted */
+
+
+ if ((this->st_connection == c
+ || (relations && parent_sa != SOS_NOBODY
+ && this->st_clonedfrom == parent_sa))
+ && (pass == 1 || !IS_ISAKMP_SA_ESTABLISHED(this->st_state)))
+ {
+ struct state *old_cur_state
+ = cur_state == this? NULL : cur_state;
+#ifdef DEBUG
+ lset_t old_cur_debugging = cur_debugging;
+#endif
+
+ set_cur_state(this);
+ plog("deleting state (%s)"
+ , enum_show(&state_names, this->st_state));
+ delete_state(this);
+ cur_state = old_cur_state;
+#ifdef DEBUG
+ cur_debugging = old_cur_debugging;
+#endif
+ }
+ }
+ }
+ }
+
+ sr = &c->spd;
+ while (sr != NULL)
+ {
+ passert(sr->eroute_owner == SOS_NOBODY);
+ passert(sr->routing != RT_ROUTED_TUNNEL);
+ sr = sr->next;
+ }
+
+ if (ck == CK_INSTANCE)
+ {
+ c->kind = ck;
+ delete_connection(c, relations);
+ }
+}
+
+/* Walk through the state table, and delete each state whose phase 1 (IKE)
+ * peer is among those given.
+ */
+void
+delete_states_by_peer(ip_address *peer)
+{
+ char peerstr[ADDRTOT_BUF];
+ int i;
+
+ addrtot(peer, 0, peerstr, sizeof(peerstr));
+
+ /* For each hash chain... */
+ for (i = 0; i < STATE_TABLE_SIZE; i++)
+ {
+ struct state *st;
+
+ /* For each state in the hash chain... */
+ for (st = statetable[i]; st != NULL; )
+ {
+ struct state *this = st;
+ struct spd_route *sr;
+ struct connection *c = this->st_connection;
+
+ st = st->st_hashchain_next; /* before this is deleted */
+
+ /* ??? Is it not the case that the peer is the same for all spds? */
+ for (sr = &c->spd; sr != NULL; sr = sr->next)
+ {
+ if (sameaddr(&sr->that.host_addr, peer))
+ {
+ plog("peer %s for connection %s deleting - claimed to have crashed"
+ , peerstr
+ , c->name);
+ delete_states_by_connection(c, TRUE);
+ break; /* can only delete it once */
+ }
+ }
+ }
+ }
+}
+
+/* Duplicate a Phase 1 state object, to create a Phase 2 object.
+ * Caller must schedule an event for this object so that it doesn't leak.
+ * Caller must insert_state().
+ */
+struct state *
+duplicate_state(struct state *st)
+{
+ struct state *nst;
+
+ DBG(DBG_CONTROL, DBG_log("duplicating state object #%lu",
+ st->st_serialno));
+
+ /* record use of the Phase 1 state */
+ st->st_outbound_count++;
+ st->st_outbound_time = now();
+
+ nst = new_state();
+
+ memcpy(nst->st_icookie, st->st_icookie, COOKIE_SIZE);
+ memcpy(nst->st_rcookie, st->st_rcookie, COOKIE_SIZE);
+
+ nst->st_connection = st->st_connection;
+ nst->st_doi = st->st_doi;
+ nst->st_situation = st->st_situation;
+ nst->st_clonedfrom = st->st_serialno;
+ nst->st_oakley = st->st_oakley;
+ nst->st_modecfg = st->st_modecfg;
+
+# define clone_chunk(ch, name) \
+ clonetochunk(nst->ch, st->ch.ptr, st->ch.len, name)
+
+ clone_chunk(st_skeyid_d, "st_skeyid_d in duplicate_state");
+ clone_chunk(st_skeyid_a, "st_skeyid_a in duplicate_state");
+ clone_chunk(st_skeyid_e, "st_skeyid_e in duplicate_state");
+ clone_chunk(st_enc_key, "st_enc_key in duplicate_state");
+
+# undef clone_chunk
+
+ return nst;
+}
+
+#if 1
+void for_each_state(void *(f)(struct state *, void *data), void *data)
+{
+ struct state *st, *ocs = cur_state;
+ int i;
+ for (i=0; i<STATE_TABLE_SIZE; i++) {
+ for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) {
+ set_cur_state(st);
+ f(st, data);
+ }
+ }
+ cur_state = ocs;
+}
+#endif
+
+/*
+ * Find a state object.
+ */
+struct state *
+find_state(const u_char *icookie
+, const u_char *rcookie
+, const ip_address *peer
+, msgid_t /*network order*/ msgid)
+{
+ struct state *st = *state_hash(icookie, rcookie, peer);
+
+ while (st != (struct state *) NULL)
+ if (sameaddr(peer, &st->st_connection->spd.that.host_addr)
+ && memcmp(icookie, st->st_icookie, COOKIE_SIZE) == 0
+ && memcmp(rcookie, st->st_rcookie, COOKIE_SIZE) == 0
+ && msgid == st->st_msgid)
+ break;
+ else
+ st = st->st_hashchain_next;
+
+ DBG(DBG_CONTROL,
+ if (st == NULL)
+ DBG_log("state object not found");
+ else
+ DBG_log("state object #%lu found, in %s"
+ , st->st_serialno
+ , enum_show(&state_names, st->st_state)));
+
+ return st;
+}
+
+/* Find the state that sent a packet
+ * ??? this could be expensive -- it should be rate-limited to avoid DoS
+ */
+struct state *
+find_sender(size_t packet_len, u_char *packet)
+{
+ int i;
+ struct state *st;
+
+ if (packet_len >= sizeof(struct isakmp_hdr))
+ for (i = 0; i < STATE_TABLE_SIZE; i++)
+ for (st = statetable[i]; st != NULL; st = st->st_hashchain_next)
+ if (st->st_tpacket.ptr != NULL
+ && st->st_tpacket.len == packet_len
+ && memcmp(st->st_tpacket.ptr, packet, packet_len) == 0)
+ return st;
+
+ return NULL;
+}
+
+struct state *
+find_phase2_state_to_delete(const struct state *p1st
+, u_int8_t protoid
+, ipsec_spi_t spi
+, bool *bogus)
+{
+ struct state *st;
+ int i;
+
+ *bogus = FALSE;
+ for (i = 0; i < STATE_TABLE_SIZE; i++)
+ {
+ for (st = statetable[i]; st != NULL; st = st->st_hashchain_next)
+ {
+ if (IS_IPSEC_SA_ESTABLISHED(st->st_state)
+ && p1st->st_connection->host_pair == st->st_connection->host_pair
+ && same_peer_ids(p1st->st_connection, st->st_connection, NULL))
+ {
+ struct ipsec_proto_info *pr = protoid == PROTO_IPSEC_AH
+ ? &st->st_ah : &st->st_esp;
+
+ if (pr->present)
+ {
+ if (pr->attrs.spi == spi)
+ return st;
+ if (pr->our_spi == spi)
+ *bogus = TRUE;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+/* Find newest Phase 1 negotiation state object for suitable for connection c
+ */
+struct state *
+find_phase1_state(const struct connection *c, lset_t ok_states)
+{
+ struct state
+ *st,
+ *best = NULL;
+ int i;
+
+ for (i = 0; i < STATE_TABLE_SIZE; i++)
+ for (st = statetable[i]; st != NULL; st = st->st_hashchain_next)
+ if (LHAS(ok_states, st->st_state)
+ && c->host_pair == st->st_connection->host_pair
+ && same_peer_ids(c, st->st_connection, NULL)
+ && (best == NULL || best->st_serialno < st->st_serialno))
+ best = st;
+
+ return best;
+}
+
+void
+state_eroute_usage(ip_subnet *ours, ip_subnet *his
+, unsigned long count, time_t nw)
+{
+ struct state *st;
+ int i;
+
+ for (i = 0; i < STATE_TABLE_SIZE; i++)
+ {
+ for (st = statetable[i]; st != NULL; st = st->st_hashchain_next)
+ {
+ struct connection *c = st->st_connection;
+
+ /* XXX spd-enum */
+ if (IS_IPSEC_SA_ESTABLISHED(st->st_state)
+ && c->spd.eroute_owner == st->st_serialno
+ && c->spd.routing == RT_ROUTED_TUNNEL
+ && samesubnet(&c->spd.this.client, ours)
+ && samesubnet(&c->spd.that.client, his))
+ {
+ if (st->st_outbound_count != count)
+ {
+ st->st_outbound_count = count;
+ st->st_outbound_time = nw;
+ }
+ return;
+ }
+ }
+ }
+ DBG(DBG_CONTROL,
+ {
+ char ourst[SUBNETTOT_BUF];
+ char hist[SUBNETTOT_BUF];
+
+ subnettot(ours, 0, ourst, sizeof(ourst));
+ subnettot(his, 0, hist, sizeof(hist));
+ DBG_log("unknown tunnel eroute %s -> %s found in scan"
+ , ourst, hist);
+ });
+}
+
+void fmt_state(bool all, struct state *st, time_t n
+, char *state_buf, size_t state_buf_len
+, char *state_buf2, size_t state_buf2_len)
+{
+ /* what the heck is interesting about a state? */
+ const struct connection *c = st->st_connection;
+
+ long delta = st->st_event->ev_time >= n
+ ? (long)(st->st_event->ev_time - n)
+ : -(long)(n - st->st_event->ev_time);
+
+ char inst[CONN_INST_BUF];
+ const char *np1 = c->newest_isakmp_sa == st->st_serialno
+ ? "; newest ISAKMP" : "";
+ const char *np2 = c->newest_ipsec_sa == st->st_serialno
+ ? "; newest IPSEC" : "";
+ /* XXX spd-enum */
+ const char *eo = c->spd.eroute_owner == st->st_serialno
+ ? "; eroute owner" : "";
+ const char *dpd = (all && st->st_dpd && c->dpd_action != DPD_ACTION_NONE)
+ ? "; DPD active" : "";
+
+ passert(st->st_event != 0);
+
+ fmt_conn_instance(c, inst);
+
+ snprintf(state_buf, state_buf_len
+ , "#%lu: \"%s\"%s %s (%s); %s in %lds%s%s%s%s"
+ , st->st_serialno
+ , c->name, inst
+ , enum_name(&state_names, st->st_state)
+ , state_story[st->st_state - STATE_MAIN_R0]
+ , enum_name(&timer_event_names, st->st_event->ev_type)
+ , delta
+ , np1, np2, eo, dpd);
+
+ /* print out SPIs if SAs are established */
+ if (state_buf2_len != 0)
+ state_buf2[0] = '\0'; /* default to empty */
+ if (IS_IPSEC_SA_ESTABLISHED(st->st_state))
+ {
+
+ bool tunnel;
+ char buf[SATOT_BUF*6 + 2*20 + 1];
+ const char *p_end = buf + sizeof(buf);
+ char *p = buf;
+
+# define add_said(adst, aspi, aproto) { \
+ ip_said s; \
+ \
+ initsaid(adst, aspi, aproto, &s); \
+ if (p < p_end - 1) \
+ { \
+ *p++ = ' '; \
+ p += satot(&s, 0, p, p_end - p) - 1; \
+ } \
+ }
+
+# define add_sa_info(st, inbound) { \
+ u_int bytes; \
+ time_t use_time; \
+ \
+ if (get_sa_info(st, inbound, &bytes, &use_time)) \
+ { \
+ p += snprintf(p, p_end - p, " (%'u bytes", bytes); \
+ if (bytes > 0 && use_time != UNDEFINED_TIME) \
+ p += snprintf(p, p_end - p, ", %ds ago", (int)(now - use_time)); \
+ p += snprintf(p, p_end - p, ")"); \
+ } \
+ }
+
+ *p = '\0';
+ if (st->st_ah.present)
+ {
+ add_said(&c->spd.that.host_addr, st->st_ah.attrs.spi, SA_AH);
+ add_said(&c->spd.this.host_addr, st->st_ah.our_spi, SA_AH);
+ }
+ if (st->st_esp.present)
+ {
+ time_t now = time(NULL);
+
+ add_said(&c->spd.that.host_addr, st->st_esp.attrs.spi, SA_ESP);
+ add_sa_info(st, FALSE);
+ add_said(&c->spd.this.host_addr, st->st_esp.our_spi, SA_ESP);
+ add_sa_info(st, TRUE);
+ }
+ if (st->st_ipcomp.present)
+ {
+ add_said(&c->spd.that.host_addr, st->st_ipcomp.attrs.spi, SA_COMP);
+ add_said(&c->spd.this.host_addr, st->st_ipcomp.our_spi, SA_COMP);
+ }
+#ifdef KLIPS
+ tunnel = st->st_ah.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL
+ || st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL
+ || st->st_ipcomp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL;
+ p += snprintf(p, p_end - p, "; %s", tunnel? "tunnel":"transport");
+#endif
+
+ snprintf(state_buf2, state_buf2_len
+ , "#%lu: \"%s\"%s%s"
+ , st->st_serialno
+ , c->name, inst
+ , buf);
+
+# undef add_said
+# undef add_sa_info
+ }
+}
+
+/*
+ * sorting logic is:
+ *
+ * name
+ * type
+ * instance#
+ * isakmp_sa (XXX probably wrong)
+ *
+ */
+static int
+state_compare(const void *a, const void *b)
+{
+ const struct state *sap = *(const struct state *const *)a;
+ struct connection *ca = sap->st_connection;
+ const struct state *sbp = *(const struct state *const *)b;
+ struct connection *cb = sbp->st_connection;
+
+ /* DBG_log("comparing %s to %s", ca->name, cb->name); */
+
+ return connection_compare(ca, cb);
+}
+
+void
+show_states_status(bool all, const char *name)
+{
+ time_t n = now();
+ int i;
+ char state_buf[LOG_WIDTH];
+ char state_buf2[LOG_WIDTH];
+ int count;
+ struct state **array;
+
+ /* make count of states */
+ count = 0;
+ for (i = 0; i < STATE_TABLE_SIZE; i++)
+ {
+ struct state *st;
+
+ for (st = statetable[i]; st != NULL; st = st->st_hashchain_next)
+ {
+ if (name == NULL || streq(name, st->st_connection->name))
+ count++;
+ }
+ }
+
+ /* build the array */
+ array = alloc_bytes(sizeof(struct state *)*count, "state array");
+ count = 0;
+ for (i = 0; i < STATE_TABLE_SIZE; i++)
+ {
+ struct state *st;
+
+ for (st = statetable[i]; st != NULL; st = st->st_hashchain_next)
+ {
+ if (name == NULL || streq(name, st->st_connection->name))
+ array[count++]=st;
+ }
+ }
+
+ /* sort it! */
+ qsort(array, count, sizeof(struct state *), state_compare);
+
+ /* now print sorted results */
+ for (i = 0; i < count; i++)
+ {
+ struct state *st;
+
+ st = array[i];
+
+ fmt_state(all, st, n
+ , state_buf, sizeof(state_buf)
+ , state_buf2, sizeof(state_buf2));
+ whack_log(RC_COMMENT, state_buf);
+ if (state_buf2[0] != '\0')
+ whack_log(RC_COMMENT, state_buf2);
+
+ /* show any associated pending Phase 2s */
+ if (IS_PHASE1(st->st_state))
+ show_pending_phase2(st->st_connection->host_pair, st);
+ }
+ if (count > 0)
+ whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */
+
+ /* free the array */
+ pfree(array);
+}
+
+/* Given that we've used up a range of unused CPI's,
+ * search for a new range of currently unused ones.
+ * Note: this is very expensive when not trivial!
+ * If we can't find one easily, choose 0 (a bad SPI,
+ * no matter what order) indicating failure.
+ */
+void
+find_my_cpi_gap(cpi_t *latest_cpi, cpi_t *first_busy_cpi)
+{
+ int tries = 0;
+ cpi_t base = *latest_cpi;
+ cpi_t closest;
+ int i;
+
+startover:
+ closest = ~0; /* not close at all */
+ for (i = 0; i < STATE_TABLE_SIZE; i++)
+ {
+ struct state *st;
+
+ for (st = statetable[i]; st != NULL; st = st->st_hashchain_next)
+ {
+ if (st->st_ipcomp.present)
+ {
+ cpi_t c = ntohl(st->st_ipcomp.our_spi) - base;
+
+ if (c < closest)
+ {
+ if (c == 0)
+ {
+ /* oops: next spot is occupied; start over */
+ if (++tries == 20)
+ {
+ /* FAILURE */
+ *latest_cpi = *first_busy_cpi = 0;
+ return;
+ }
+ base++;
+ if (base > IPCOMP_LAST_NEGOTIATED)
+ base = IPCOMP_FIRST_NEGOTIATED;
+ goto startover; /* really a tail call */
+ }
+ closest = c;
+ }
+ }
+ }
+ }
+ *latest_cpi = base; /* base is first in next free range */
+ *first_busy_cpi = closest + base; /* and this is the roof */
+}
+
+/* Muck with high-order 16 bits of this SPI in order to make
+ * the corresponding SAID unique.
+ * Its low-order 16 bits hold a well-known IPCOMP CPI.
+ * Oh, and remember that SPIs are stored in network order.
+ * Kludge!!! So I name it with the non-English word "uniquify".
+ * If we can't find one easily, return 0 (a bad SPI,
+ * no matter what order) indicating failure.
+ */
+ipsec_spi_t
+uniquify_his_cpi(ipsec_spi_t cpi, struct state *st)
+{
+ int tries = 0;
+ int i;
+
+startover:
+
+ /* network order makes first two bytes our target */
+ get_rnd_bytes((u_char *)&cpi, 2);
+
+ /* Make sure that the result is unique.
+ * Hard work. If there is no unique value, we'll loop forever!
+ */
+ for (i = 0; i < STATE_TABLE_SIZE; i++)
+ {
+ struct state *s;
+
+ for (s = statetable[i]; s != NULL; s = s->st_hashchain_next)
+ {
+ if (s->st_ipcomp.present
+ && sameaddr(&s->st_connection->spd.that.host_addr
+ , &st->st_connection->spd.that.host_addr)
+ && cpi == s->st_ipcomp.attrs.spi)
+ {
+ if (++tries == 20)
+ return 0; /* FAILURE */
+ goto startover;
+ }
+ }
+ }
+ return cpi;
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset:4
+ * End:
+ */
diff --git a/src/pluto/state.h b/src/pluto/state.h
new file mode 100644
index 000000000..d3a980564
--- /dev/null
+++ b/src/pluto/state.h
@@ -0,0 +1,273 @@
+/* state and event objects
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: state.h,v 1.11 2006/03/08 22:12:37 as Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <time.h>
+#include <gmp.h> /* GNU MP library */
+
+#include "connections.h"
+
+/* Message ID mechanism.
+ *
+ * A Message ID is contained in each IKE message header.
+ * For Phase 1 exchanges (Main and Aggressive), it will be zero.
+ * For other exchanges, which must be under the protection of an
+ * ISAKMP SA, the Message ID must be unique within that ISAKMP SA.
+ * Effectively, this labels the message as belonging to a particular
+ * exchange.
+ *
+ * RFC2408 "ISAKMP" 3.1 "ISAKMP Header Format" (near end) states that
+ * the Message ID must be unique. We interpret this to be "unique within
+ * one ISAKMP SA".
+ *
+ * BTW, we feel this uniqueness allows rekeying to be somewhat simpler
+ * than specified by draft-jenkins-ipsec-rekeying-06.txt.
+ */
+
+typedef u_int32_t msgid_t; /* Network order! */
+#define MAINMODE_MSGID ((msgid_t) 0)
+
+struct state; /* forward declaration of tag */
+extern bool reserve_msgid(struct state *isakmp_sa, msgid_t msgid);
+extern msgid_t generate_msgid(struct state *isakmp_sa);
+
+
+/* Oakley (Phase 1 / Main Mode) transform and attributes
+ * This is a flattened/decoded version of what is represented
+ * in the Transaction Payload.
+ * Names are chosen to match corresponding names in state.
+ */
+struct oakley_trans_attrs {
+ u_int16_t encrypt; /* Encryption algorithm */
+ u_int16_t enckeylen; /* encryption key len (bits) */
+ const struct encrypt_desc *encrypter; /* package of encryption routines */
+ u_int16_t hash; /* Hash algorithm */
+ const struct hash_desc *hasher; /* package of hashing routines */
+ u_int16_t auth; /* Authentication method */
+ const struct oakley_group_desc *group; /* Oakley group */
+ time_t life_seconds; /* When this SA expires (seconds) */
+ u_int32_t life_kilobytes; /* When this SA is exhausted (kilobytes) */
+#if 0 /* not yet */
+ u_int16_t prf; /* Pseudo Random Function */
+#endif
+};
+
+/* IPsec (Phase 2 / Quick Mode) transform and attributes
+ * This is a flattened/decoded version of what is represented
+ * by a Transaction Payload. There may be one for AH, one
+ * for ESP, and a funny one for IPCOMP.
+ */
+struct ipsec_trans_attrs {
+ u_int8_t transid; /* transform id */
+ ipsec_spi_t spi; /* his SPI */
+ time_t life_seconds; /* When this SA expires */
+ u_int32_t life_kilobytes; /* When this SA expires */
+ u_int16_t encapsulation;
+ u_int16_t auth;
+ u_int16_t key_len;
+ u_int16_t key_rounds;
+#if 0 /* not implemented yet */
+ u_int16_t cmprs_dict_sz;
+ u_int32_t cmprs_alg;
+#endif
+};
+
+/* IPsec per protocol state information */
+struct ipsec_proto_info {
+ bool present; /* was this transform specified? */
+ struct ipsec_trans_attrs attrs;
+ ipsec_spi_t our_spi;
+ u_int16_t keymat_len; /* same for both */
+ u_char *our_keymat;
+ u_char *peer_keymat;
+};
+
+/* state object: record the state of a (possibly nascent) SA
+ *
+ * Invariants (violated only during short transitions):
+ * - each state object will be in statetable exactly once.
+ * - each state object will always have a pending event.
+ * This prevents leaks.
+ */
+struct state
+{
+ so_serial_t st_serialno; /* serial number (for seniority) */
+ so_serial_t st_clonedfrom; /* serial number of parent */
+
+ struct connection *st_connection; /* connection for this SA */
+
+ int st_whack_sock; /* fd for our Whack TCP socket.
+ * Single copy: close when freeing struct.
+ */
+
+ struct msg_digest *st_suspended_md; /* suspended state-transition */
+
+ struct oakley_trans_attrs st_oakley;
+
+ struct ipsec_proto_info st_ah;
+ struct ipsec_proto_info st_esp;
+ struct ipsec_proto_info st_ipcomp;
+#ifdef KLIPS
+ ipsec_spi_t st_tunnel_in_spi; /* KLUDGE */
+ ipsec_spi_t st_tunnel_out_spi; /* KLUDGE */
+#endif
+
+ const struct oakley_group_desc *st_pfs_group; /* group for Phase 2 PFS */
+
+ u_int32_t st_doi; /* Domain of Interpretation */
+ u_int32_t st_situation;
+
+ lset_t st_policy; /* policy for IPsec SA */
+
+ msgid_t st_msgid; /* MSG-ID from header. Network Order! */
+
+ /* only for a state representing an ISAKMP SA */
+ struct msgid_list *st_used_msgids; /* used-up msgids */
+
+/* symmetric stuff */
+
+ /* initiator stuff */
+ chunk_t st_gi; /* Initiator public value */
+ u_int8_t st_icookie[COOKIE_SIZE];/* Initiator Cookie */
+ chunk_t st_ni; /* Ni nonce */
+
+ /* responder stuff */
+ chunk_t st_gr; /* Responder public value */
+ u_int8_t st_rcookie[COOKIE_SIZE];/* Responder Cookie */
+ chunk_t st_nr; /* Nr nonce */
+
+
+ /* my stuff */
+
+ chunk_t st_tpacket; /* Transmitted packet */
+
+ /* Phase 2 ID payload info about my user */
+ u_int8_t st_myuserprotoid; /* IDcx.protoid */
+ u_int16_t st_myuserport;
+
+ /* his stuff */
+
+ chunk_t st_rpacket; /* Received packet */
+
+ /* Phase 2 ID payload info about peer's user */
+ u_int8_t st_peeruserprotoid; /* IDcx.protoid */
+ u_int16_t st_peeruserport;
+
+/* end of symmetric stuff */
+
+ u_int8_t st_sec_in_use; /* bool: does st_sec hold a value */
+ MP_INT st_sec; /* Our local secret value */
+
+ chunk_t st_shared; /* Derived shared secret
+ * Note: during Quick Mode,
+ * presence indicates PFS
+ * selected.
+ */
+
+ /* In a Phase 1 state, preserve peer's public key after authentication */
+ struct pubkey *st_peer_pubkey;
+
+ enum state_kind st_state; /* State of exchange */
+ u_int8_t st_retransmit; /* Number of retransmits */
+ unsigned long st_try; /* number of times rekeying attempted */
+ /* 0 means the only time */
+ time_t st_margin; /* life after EVENT_SA_REPLACE */
+ unsigned long st_outbound_count; /* traffic through eroute */
+ time_t st_outbound_time; /* time of last change to st_outbound_count */
+ chunk_t st_p1isa; /* Phase 1 initiator SA (Payload) for HASH */
+ chunk_t st_skeyid; /* Key material */
+ chunk_t st_skeyid_d; /* KM for non-ISAKMP key derivation */
+ chunk_t st_skeyid_a; /* KM for ISAKMP authentication */
+ chunk_t st_skeyid_e; /* KM for ISAKMP encryption */
+ u_char st_iv[MAX_DIGEST_LEN]; /* IV for encryption */
+ u_char st_new_iv[MAX_DIGEST_LEN];
+ u_char st_ph1_iv[MAX_DIGEST_LEN]; /* IV at end if phase 1 */
+ unsigned int st_iv_len;
+ unsigned int st_new_iv_len;
+ unsigned int st_ph1_iv_len;
+
+ chunk_t st_enc_key; /* Oakley Encryption key */
+
+ struct event *st_event; /* backpointer for certain events */
+ struct state *st_hashchain_next; /* Next in list */
+ struct state *st_hashchain_prev; /* Previous in list */
+
+ struct {
+ bool vars_set;
+ bool started;
+ } st_modecfg;
+
+ struct {
+ int attempt;
+ bool started;
+ bool status;
+ } st_xauth;
+
+ u_int32_t nat_traversal;
+ ip_address nat_oa;
+
+ /* RFC 3706 Dead Peer Detection */
+ bool st_dpd; /* Peer supports DPD */
+ time_t st_last_dpd; /* Time of last DPD transmit */
+ u_int32_t st_dpd_seqno; /* Next R_U_THERE to send */
+ u_int32_t st_dpd_expectseqno; /* Next R_U_THERE_ACK to receive */
+ u_int32_t st_dpd_peerseqno; /* global variables */
+ struct event *st_dpd_event; /* backpointer for DPD events */
+
+ u_int32_t st_seen_vendorid; /* Bit field about recognized Vendor ID */
+};
+
+/* global variables */
+
+extern u_int16_t pluto_port; /* Pluto's port */
+
+extern bool states_use_connection(struct connection *c);
+
+/* state functions */
+
+extern struct state *new_state(void);
+extern void init_states(void);
+extern void insert_state(struct state *st);
+extern void unhash_state(struct state *st);
+extern void release_whack(struct state *st);
+extern void state_eroute_usage(ip_subnet *ours, ip_subnet *his
+ , unsigned long count, time_t nw);
+extern void delete_state(struct state *st);
+extern void delete_states_by_connection(struct connection *c, bool relations);
+
+extern struct state
+ *duplicate_state(struct state *st),
+ *find_state(const u_char *icookie
+ , const u_char *rcookie
+ , const ip_address *peer
+ , msgid_t msgid),
+ *state_with_serialno(so_serial_t sn),
+ *find_phase2_state_to_delete(const struct state *p1st, u_int8_t protoid
+ , ipsec_spi_t spi, bool *bogus),
+ *find_phase1_state(const struct connection *c, lset_t ok_states),
+ *find_sender(size_t packet_len, u_char *packet);
+
+extern void show_states_status(bool all, const char *name);
+extern void for_each_state(void *(f)(struct state *, void *data), void *data);
+extern void find_my_cpi_gap(cpi_t *latest_cpi, cpi_t *first_busy_cpi);
+extern ipsec_spi_t uniquify_his_cpi(ipsec_spi_t cpi, struct state *st);
+extern void fmt_state(bool all, struct state *st, time_t n
+ , char *state_buf, size_t state_buf_len
+ , char *state_buf2, size_t state_buf_len2);
+extern void delete_states_by_peer(ip_address *peer);
diff --git a/src/pluto/timer.c b/src/pluto/timer.c
new file mode 100644
index 000000000..9d3f90ce3
--- /dev/null
+++ b/src/pluto/timer.c
@@ -0,0 +1,532 @@
+/* timer event handling
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: timer.c,v 1.5 2004/09/17 21:36:57 as Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/queue.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "connections.h"
+#include "state.h"
+#include "demux.h"
+#include "ipsec_doi.h" /* needs demux.h and state.h */
+#include "kernel.h"
+#include "server.h"
+#include "log.h"
+#include "rnd.h"
+#include "timer.h"
+#include "whack.h"
+#include "nat_traversal.h"
+
+/* monotonic version of time(3) */
+time_t
+now(void)
+{
+ static time_t delta = 0
+ , last_time = 0;
+ time_t n = time((time_t)NULL);
+
+ passert(n != (time_t)-1);
+ if (last_time > n)
+ {
+ plog("time moved backwards %ld seconds", (long)(last_time - n));
+ delta += last_time - n;
+ }
+ last_time = n;
+ return n + delta;
+}
+
+/* This file has the event handling routines. Events are
+ * kept as a linked list of event structures. These structures
+ * have information like event type, expiration time and a pointer
+ * to event specific data (for example, to a state structure).
+ */
+
+static struct event *evlist = (struct event *) NULL;
+
+/*
+ * This routine places an event in the event list.
+ */
+void
+event_schedule(enum event_type type, time_t tm, struct state *st)
+{
+ struct event *ev = alloc_thing(struct event, "struct event in event_schedule()");
+
+ ev->ev_type = type;
+ ev->ev_time = tm + now();
+ ev->ev_state = st;
+
+ /* If the event is associated with a state, put a backpointer to the
+ * event in the state object, so we can find and delete the event
+ * if we need to (for example, if we receive a reply).
+ */
+ if (st != NULL)
+ {
+ if (type == EVENT_DPD || type == EVENT_DPD_TIMEOUT)
+ {
+ passert(st->st_dpd_event == NULL);
+ st->st_dpd_event = ev;
+ }
+ else
+ {
+ passert(st->st_event == NULL);
+ st->st_event = ev;
+ }
+ }
+
+ DBG(DBG_CONTROL,
+ if (st == NULL)
+ DBG_log("inserting event %s, timeout in %lu seconds"
+ , enum_show(&timer_event_names, type), (unsigned long)tm);
+ else
+ DBG_log("inserting event %s, timeout in %lu seconds for #%lu"
+ , enum_show(&timer_event_names, type), (unsigned long)tm
+ , ev->ev_state->st_serialno));
+
+ if (evlist == (struct event *) NULL
+ || evlist->ev_time >= ev->ev_time)
+ {
+ ev->ev_next = evlist;
+ evlist = ev;
+ }
+ else
+ {
+ struct event *evt;
+
+ for (evt = evlist; evt->ev_next != NULL; evt = evt->ev_next)
+ if (evt->ev_next->ev_time >= ev->ev_time)
+ break;
+
+#ifdef NEVER /* this seems to be overkill */
+ DBG(DBG_CONTROL,
+ if (evt->ev_state == NULL)
+ DBG_log("event added after event %s"
+ , enum_show(&timer_event_names, evt->ev_type));
+ else
+ DBG_log("event added after event %s for #%lu"
+ , enum_show(&timer_event_names, evt->ev_type)
+ , evt->ev_state->st_serialno));
+#endif /* NEVER */
+
+ ev->ev_next = evt->ev_next;
+ evt->ev_next = ev;
+ }
+}
+
+/*
+ * Handle the first event on the list.
+ */
+void
+handle_timer_event(void)
+{
+ time_t tm;
+ struct event *ev = evlist;
+ int type;
+ struct state *st;
+ struct connection *c = NULL;
+ ip_address peer;
+
+ if (ev == (struct event *) NULL) /* Just paranoid */
+ {
+ DBG(DBG_CONTROL, DBG_log("empty event list, yet we're called"));
+ return;
+ }
+
+ type = ev->ev_type;
+ st = ev->ev_state;
+
+ tm = now();
+
+ if (tm < ev->ev_time)
+ {
+ DBG(DBG_CONTROL, DBG_log("called while no event expired (%lu/%lu, %s)"
+ , (unsigned long)tm, (unsigned long)ev->ev_time
+ , enum_show(&timer_event_names, type)));
+
+ /* This will happen if the most close-to-expire event was
+ * a retransmission or cleanup, and we received a packet
+ * at the same time as the event expired. Due to the processing
+ * order in call_server(), the packet processing will happen first,
+ * and the event will be removed.
+ */
+ return;
+ }
+
+ evlist = evlist->ev_next; /* Ok, we'll handle this event */
+
+ DBG(DBG_CONTROL,
+ if (evlist != (struct event *) NULL)
+ DBG_log("event after this is %s in %ld seconds"
+ , enum_show(&timer_event_names, evlist->ev_type)
+ , (long) (evlist->ev_time - tm)));
+
+ /* for state-associated events, pick up the state pointer
+ * and remove the backpointer from the state object.
+ * We'll eventually either schedule a new event, or delete the state.
+ */
+ passert(GLOBALS_ARE_RESET());
+ if (st != NULL)
+ {
+ c = st->st_connection;
+ if (type == EVENT_DPD || type == EVENT_DPD_TIMEOUT)
+ {
+ passert(st->st_dpd_event == ev);
+ st->st_dpd_event = NULL;
+ }
+ else
+ {
+ passert(st->st_event == ev);
+ st->st_event = NULL;
+ }
+ peer = c->spd.that.host_addr;
+ set_cur_state(st);
+ }
+
+ switch (type)
+ {
+ case EVENT_REINIT_SECRET:
+ passert(st == NULL);
+ DBG(DBG_CONTROL, DBG_log("event EVENT_REINIT_SECRET handled"));
+ init_secret();
+ break;
+
+#ifdef KLIPS
+ case EVENT_SHUNT_SCAN:
+ passert(st == NULL);
+ scan_proc_shunts();
+ break;
+#endif
+
+ case EVENT_LOG_DAILY:
+ daily_log_event();
+ break;
+
+ case EVENT_RETRANSMIT:
+ /* Time to retransmit, or give up.
+ *
+ * Generally, we'll only try to send the message
+ * MAXIMUM_RETRANSMISSIONS times. Each time we double
+ * our patience.
+ *
+ * As a special case, if this is the first initiating message
+ * of a Main Mode exchange, and we have been directed to try
+ * forever, we'll extend the number of retransmissions to
+ * MAXIMUM_RETRANSMISSIONS_INITIAL times, with all these
+ * extended attempts having the same patience. The intention
+ * is to reduce the bother when nobody is home.
+ */
+ {
+ time_t delay = 0;
+
+ DBG(DBG_CONTROL, DBG_log(
+ "handling event EVENT_RETRANSMIT for %s \"%s\" #%lu"
+ , ip_str(&peer), c->name, st->st_serialno));
+
+ if (st->st_retransmit < MAXIMUM_RETRANSMISSIONS)
+ delay = EVENT_RETRANSMIT_DELAY_0 << (st->st_retransmit + 1);
+ else if (st->st_state == STATE_MAIN_I1
+ && c->sa_keying_tries == 0
+ && st->st_retransmit < MAXIMUM_RETRANSMISSIONS_INITIAL)
+ delay = EVENT_RETRANSMIT_DELAY_0 << MAXIMUM_RETRANSMISSIONS;
+
+ if (delay != 0)
+ {
+ st->st_retransmit++;
+ whack_log(RC_RETRANSMISSION
+ , "%s: retransmission; will wait %lus for response"
+ , enum_name(&state_names, st->st_state)
+ , (unsigned long)delay);
+ send_packet(st, "EVENT_RETRANSMIT");
+ event_schedule(EVENT_RETRANSMIT, delay, st);
+ }
+ else
+ {
+ /* check if we've tried rekeying enough times.
+ * st->st_try == 0 means that this should be the only try.
+ * c->sa_keying_tries == 0 means that there is no limit.
+ */
+ unsigned long try = st->st_try;
+ unsigned long try_limit = c->sa_keying_tries;
+ const char *details = "";
+
+ switch (st->st_state)
+ {
+ case STATE_MAIN_I3:
+ details = ". Possible authentication failure:"
+ " no acceptable response to our"
+ " first encrypted message";
+ break;
+ case STATE_MAIN_I1:
+ details = ". No response (or no acceptable response) to our"
+ " first IKE message";
+ break;
+ case STATE_QUICK_I1:
+ if (c->newest_ipsec_sa == SOS_NOBODY)
+ details = ". No acceptable response to our"
+ " first Quick Mode message:"
+ " perhaps peer likes no proposal";
+ break;
+ default:
+ break;
+ }
+ loglog(RC_NORETRANSMISSION
+ , "max number of retransmissions (%d) reached %s%s"
+ , st->st_retransmit
+ , enum_show(&state_names, st->st_state), details);
+ if (try != 0 && try != try_limit)
+ {
+ /* A lot like EVENT_SA_REPLACE, but over again.
+ * Since we know that st cannot be in use,
+ * we can delete it right away.
+ */
+ char story[80]; /* arbitrary limit */
+
+ try++;
+ snprintf(story, sizeof(story), try_limit == 0
+ ? "starting keying attempt %ld of an unlimited number"
+ : "starting keying attempt %ld of at most %ld"
+ , try, try_limit);
+
+ if (st->st_whack_sock != NULL_FD)
+ {
+ /* Release whack because the observer will get bored. */
+ loglog(RC_COMMENT, "%s, but releasing whack"
+ , story);
+ release_pending_whacks(st, story);
+ }
+ else
+ {
+ /* no whack: just log to syslog */
+ plog("%s", story);
+ }
+ ipsecdoi_replace(st, try);
+ }
+ delete_state(st);
+ }
+ }
+ break;
+
+ case EVENT_SA_REPLACE:
+ case EVENT_SA_REPLACE_IF_USED:
+ {
+ so_serial_t newest = IS_PHASE1(st->st_state)
+ ? c->newest_isakmp_sa : c->newest_ipsec_sa;
+
+ if (newest != st->st_serialno
+ && newest != SOS_NOBODY)
+ {
+ /* not very interesting: no need to replace */
+ DBG(DBG_LIFECYCLE
+ , plog("not replacing stale %s SA: #%lu will do"
+ , IS_PHASE1(st->st_state)? "ISAKMP" : "IPsec"
+ , newest));
+ }
+ else if (type == EVENT_SA_REPLACE_IF_USED
+ && st->st_outbound_time <= tm - c->sa_rekey_margin)
+ {
+ /* we observed no recent use: no need to replace
+ *
+ * The sampling effects mean that st_outbound_time
+ * could be up to SHUNT_SCAN_INTERVAL more recent
+ * than actual traffic because the sampler looks at change
+ * over that interval.
+ * st_outbound_time could also not yet reflect traffic
+ * in the last SHUNT_SCAN_INTERVAL.
+ * We expect that SHUNT_SCAN_INTERVAL is smaller than
+ * c->sa_rekey_margin so that the effects of this will
+ * be unimportant.
+ * This is just an optimization: correctness is not
+ * at stake.
+ *
+ * Note: we are abusing the DBG mechanism to control
+ * normal log output.
+ */
+ DBG(DBG_LIFECYCLE
+ , plog("not replacing stale %s SA: inactive for %lus"
+ , IS_PHASE1(st->st_state)? "ISAKMP" : "IPsec"
+ , (unsigned long)(tm - st->st_outbound_time)));
+ }
+ else
+ {
+ DBG(DBG_LIFECYCLE
+ , plog("replacing stale %s SA"
+ , IS_PHASE1(st->st_state)? "ISAKMP" : "IPsec"));
+ ipsecdoi_replace(st, 1);
+ }
+ delete_dpd_event(st);
+ event_schedule(EVENT_SA_EXPIRE, st->st_margin, st);
+ }
+ break;
+
+ case EVENT_SA_EXPIRE:
+ {
+ const char *satype;
+ so_serial_t latest;
+
+ if (IS_PHASE1(st->st_state))
+ {
+ satype = "ISAKMP";
+ latest = c->newest_isakmp_sa;
+ }
+ else
+ {
+ satype = "IPsec";
+ latest = c->newest_ipsec_sa;
+ }
+
+ if (st->st_serialno != latest)
+ {
+ /* not very interesting: already superseded */
+ DBG(DBG_LIFECYCLE
+ , plog("%s SA expired (superseded by #%lu)"
+ , satype, latest));
+ }
+ else
+ {
+ plog("%s SA expired (%s)", satype
+ , (c->policy & POLICY_DONT_REKEY)
+ ? "--dontrekey"
+ : "LATEST!"
+ );
+ }
+ }
+ /* FALLTHROUGH */
+ case EVENT_SO_DISCARD:
+ /* Delete this state object. It must be in the hash table. */
+ delete_state(st);
+ break;
+
+ case EVENT_DPD:
+ dpd_outI(st);
+ break;
+ case EVENT_DPD_TIMEOUT:
+ dpd_timeout(st);
+ break;
+ case EVENT_NAT_T_KEEPALIVE:
+ nat_traversal_ka_event();
+ break;
+ default:
+ loglog(RC_LOG_SERIOUS, "INTERNAL ERROR: ignoring unknown expiring event %s"
+ , enum_show(&timer_event_names, type));
+ }
+
+ pfree(ev);
+ reset_cur_state();
+}
+
+/*
+ * Return the time until the next event in the queue
+ * expires (never negative), or -1 if no jobs in queue.
+ */
+long
+next_event(void)
+{
+ time_t tm;
+
+ if (evlist == (struct event *) NULL)
+ return -1;
+
+ tm = now();
+
+ DBG(DBG_CONTROL,
+ if (evlist->ev_state == NULL)
+ DBG_log("next event %s in %ld seconds"
+ , enum_show(&timer_event_names, evlist->ev_type)
+ , (long)evlist->ev_time - (long)tm);
+ else
+ DBG_log("next event %s in %ld seconds for #%lu"
+ , enum_show(&timer_event_names, evlist->ev_type)
+ , (long)evlist->ev_time - (long)tm
+ , evlist->ev_state->st_serialno));
+
+ if (evlist->ev_time - tm <= 0)
+ return 0;
+ else
+ return evlist->ev_time - tm;
+}
+
+/*
+ * Delete an event.
+ */
+void
+delete_event(struct state *st)
+{
+ if (st->st_event != (struct event *) NULL)
+ {
+ struct event **ev;
+
+ for (ev = &evlist; ; ev = &(*ev)->ev_next)
+ {
+ if (*ev == NULL)
+ {
+ DBG(DBG_CONTROL, DBG_log("event %s to be deleted not found",
+ enum_show(&timer_event_names, st->st_event->ev_type)));
+ break;
+ }
+ if ((*ev) == st->st_event)
+ {
+ *ev = (*ev)->ev_next;
+
+ if (st->st_event->ev_type == EVENT_RETRANSMIT)
+ st->st_retransmit = 0;
+ pfree(st->st_event);
+ st->st_event = (struct event *) NULL;
+
+ break;
+ }
+ }
+ }
+}
+
+/*
+ * Delete a DPD event.
+ */
+void
+delete_dpd_event(struct state *st)
+{
+ if (st->st_dpd_event != (struct event *) NULL)
+ {
+ struct event **ev;
+
+ for (ev = &evlist; ; ev = &(*ev)->ev_next)
+ {
+ if (*ev == NULL)
+ {
+ DBG(DBG_CONTROL, DBG_log("event %s to be deleted not found",
+ enum_show(&timer_event_names, st->st_dpd_event->ev_type)));
+ break;
+ }
+ if ((*ev) == st->st_dpd_event)
+ {
+ *ev = (*ev)->ev_next;
+ pfree(st->st_dpd_event);
+ st->st_dpd_event = (struct event *) NULL;
+ break;
+ }
+ }
+ }
+}
+
+
diff --git a/src/pluto/timer.h b/src/pluto/timer.h
new file mode 100644
index 000000000..92464192c
--- /dev/null
+++ b/src/pluto/timer.h
@@ -0,0 +1,34 @@
+/* timing machinery
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: timer.h,v 1.2 2004/07/29 18:33:45 as Exp $
+ */
+
+extern time_t now(void); /* careful version of time(2) */
+
+struct state; /* forward declaration */
+
+struct event
+{
+ time_t ev_time;
+ int ev_type; /* Event type */
+ struct state *ev_state; /* Pointer to relevant state (if any) */
+ struct event *ev_next; /* Pointer to next event */
+};
+
+extern void event_schedule(enum event_type type, time_t tm, struct state *st);
+extern void handle_timer_event(void);
+extern long next_event(void);
+extern void delete_event(struct state *st);
+extern void delete_dpd_event(struct state *st);
+extern void daily_log_event(void);
diff --git a/src/pluto/vendor.c b/src/pluto/vendor.c
new file mode 100644
index 000000000..e888d5e16
--- /dev/null
+++ b/src/pluto/vendor.c
@@ -0,0 +1,528 @@
+/* ISAKMP VendorID
+ * Copyright (C) 2002-2005 Mathieu Lafon - Arkoon Network Security
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: vendor.c,v 1.35 2006/04/12 16:44:28 as Exp $
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/queue.h>
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "md5.h"
+#include "connections.h"
+#include "packet.h"
+#include "demux.h"
+#include "whack.h"
+#include "vendor.h"
+#include "kernel.h"
+#include "nat_traversal.h"
+
+/**
+ * Unknown/Special VID:
+ *
+ * SafeNet SoftRemote 8.0.0:
+ * 47bbe7c993f1fc13b4e6d0db565c68e5010201010201010310382e302e3020284275696c6420313029000000
+ * >> 382e302e3020284275696c6420313029 = '8.0.0 (Build 10)'
+ * da8e937880010000
+ *
+ * SafeNet SoftRemote 9.0.1
+ * 47bbe7c993f1fc13b4e6d0db565c68e5010201010201010310392e302e3120284275696c6420313229000000
+ * >> 392e302e3120284275696c6420313229 = '9.0.1 (Build 12)'
+ * da8e937880010000
+ *
+ * Netscreen:
+ * d6b45f82f24bacb288af59a978830ab7
+ * cf49908791073fb46439790fdeb6aeed981101ab0000000500000300
+ *
+ * Cisco:
+ * 1f07f70eaa6514d3b0fa96542a500300 (VPN 3000 version 3.0.0)
+ * 1f07f70eaa6514d3b0fa96542a500301 (VPN 3000 version 3.0.1)
+ * 1f07f70eaa6514d3b0fa96542a500305 (VPN 3000 version 3.0.5)
+ * 1f07f70eaa6514d3b0fa96542a500407 (VPN 3000 version 4.0.7)
+ * (Can you see the pattern?)
+ * afcad71368a1f1c96b8696fc77570100 (Non-RFC Dead Peer Detection ?)
+ * c32364b3b4f447eb17c488ab2a480a57
+ * 6d761ddc26aceca1b0ed11fabbb860c4
+ * 5946c258f99a1a57b03eb9d1759e0f24 (From a Cisco VPN 3k)
+ * ebbc5b00141d0c895e11bd395902d690 (From a Cisco VPN 3k)
+ *
+ * Microsoft L2TP (???):
+ * 47bbe7c993f1fc13b4e6d0db565c68e5010201010201010310382e312e3020284275696c6420313029000000
+ * >> 382e312e3020284275696c6420313029 = '8.1.0 (Build 10)'
+ * 3025dbd21062b9e53dc441c6aab5293600000000
+ * da8e937880010000
+ *
+ * 3COM-superstack
+ * da8e937880010000
+ * 404bf439522ca3f6
+ *
+
+ * If someone know what they mean, mail me.
+ */
+
+#define MAX_LOG_VID_LEN 32
+
+#define VID_KEEP 0x0000
+#define VID_MD5HASH 0x0001
+#define VID_STRING 0x0002
+#define VID_FSWAN_HASH 0x0004
+
+#define VID_SUBSTRING_DUMPHEXA 0x0100
+#define VID_SUBSTRING_DUMPASCII 0x0200
+#define VID_SUBSTRING_MATCH 0x0400
+#define VID_SUBSTRING (VID_SUBSTRING_DUMPHEXA | VID_SUBSTRING_DUMPASCII | VID_SUBSTRING_MATCH)
+
+struct vid_struct {
+ enum known_vendorid id;
+ unsigned short flags;
+ const char *data;
+ const char *descr;
+ const char *vid;
+ u_int vid_len;
+};
+
+#define DEC_MD5_VID_D(id,str,descr) \
+ { VID_##id, VID_MD5HASH, str, descr, NULL, 0 },
+#define DEC_MD5_VID(id,str) \
+ { VID_##id, VID_MD5HASH, str, NULL, NULL, 0 },
+#define DEC_FSWAN_VID(id,str,descr) \
+ { VID_##id, VID_FSWAN_HASH, str, descr, NULL, 0 },
+
+static struct vid_struct _vid_tab[] = {
+
+ /* Implementation names */
+
+ { VID_OPENPGP, VID_STRING, "OpenPGP10171", "OpenPGP", NULL, 0 },
+
+ DEC_MD5_VID(KAME_RACOON, "KAME/racoon")
+
+ { VID_MS_NT5, VID_MD5HASH | VID_SUBSTRING_DUMPHEXA,
+ "MS NT5 ISAKMPOAKLEY", NULL, NULL, 0 },
+
+ DEC_MD5_VID(SSH_SENTINEL, "SSH Sentinel")
+ DEC_MD5_VID(SSH_SENTINEL_1_1, "SSH Sentinel 1.1")
+ DEC_MD5_VID(SSH_SENTINEL_1_2, "SSH Sentinel 1.2")
+ DEC_MD5_VID(SSH_SENTINEL_1_3, "SSH Sentinel 1.3")
+ DEC_MD5_VID(SSH_SENTINEL_1_4, "SSH Sentinel 1.4")
+ DEC_MD5_VID(SSH_SENTINEL_1_4_1, "SSH Sentinel 1.4.1")
+
+ /* These ones come from SSH vendors.txt */
+ DEC_MD5_VID(SSH_IPSEC_1_1_0,
+ "Ssh Communications Security IPSEC Express version 1.1.0")
+ DEC_MD5_VID(SSH_IPSEC_1_1_1,
+ "Ssh Communications Security IPSEC Express version 1.1.1")
+ DEC_MD5_VID(SSH_IPSEC_1_1_2,
+ "Ssh Communications Security IPSEC Express version 1.1.2")
+ DEC_MD5_VID(SSH_IPSEC_1_2_1,
+ "Ssh Communications Security IPSEC Express version 1.2.1")
+ DEC_MD5_VID(SSH_IPSEC_1_2_2,
+ "Ssh Communications Security IPSEC Express version 1.2.2")
+ DEC_MD5_VID(SSH_IPSEC_2_0_0,
+ "SSH Communications Security IPSEC Express version 2.0.0")
+ DEC_MD5_VID(SSH_IPSEC_2_1_0,
+ "SSH Communications Security IPSEC Express version 2.1.0")
+ DEC_MD5_VID(SSH_IPSEC_2_1_1,
+ "SSH Communications Security IPSEC Express version 2.1.1")
+ DEC_MD5_VID(SSH_IPSEC_2_1_2,
+ "SSH Communications Security IPSEC Express version 2.1.2")
+ DEC_MD5_VID(SSH_IPSEC_3_0_0,
+ "SSH Communications Security IPSEC Express version 3.0.0")
+ DEC_MD5_VID(SSH_IPSEC_3_0_1,
+ "SSH Communications Security IPSEC Express version 3.0.1")
+ DEC_MD5_VID(SSH_IPSEC_4_0_0,
+ "SSH Communications Security IPSEC Express version 4.0.0")
+ DEC_MD5_VID(SSH_IPSEC_4_0_1,
+ "SSH Communications Security IPSEC Express version 4.0.1")
+ DEC_MD5_VID(SSH_IPSEC_4_1_0,
+ "SSH Communications Security IPSEC Express version 4.1.0")
+ DEC_MD5_VID(SSH_IPSEC_4_2_0,
+ "SSH Communications Security IPSEC Express version 4.2.0")
+
+ /* note: md5('CISCO-UNITY') = 12f5f28c457168a9702d9fe274cc02d4 */
+ { VID_CISCO_UNITY, VID_KEEP, NULL, "Cisco-Unity",
+ "\x12\xf5\xf2\x8c\x45\x71\x68\xa9\x70\x2d\x9f\xe2\x74\xcc\x01\x00",
+ 16 },
+
+ { VID_CISCO3K, VID_KEEP | VID_SUBSTRING_MATCH,
+ NULL, "Cisco VPN 3000 Series" , "\x1f\x07\xf7\x0e\xaa\x65\x14\xd3\xb0\xfa\x96\x54\x2a\x50", 14},
+
+ { VID_CISCO_IOS, VID_KEEP | VID_SUBSTRING_MATCH,
+ NULL, "Cisco IOS Device", "\x3e\x98\x40\x48", 4},
+
+ /*
+ * Timestep VID seen:
+ * - 54494d455354455020312053475720313532302033313520322e303145303133
+ * = 'TIMESTEP 1 SGW 1520 315 2.01E013'
+ */
+ { VID_TIMESTEP, VID_STRING | VID_SUBSTRING_DUMPASCII, "TIMESTEP",
+ NULL, NULL, 0 },
+
+ /*
+ * Netscreen:
+ * 4865617274426561745f4e6f74696679386b0100 (HeartBeat_Notify + 386b0100)
+ */
+ { VID_MISC_HEARTBEAT_NOTIFY, VID_STRING | VID_SUBSTRING_DUMPHEXA,
+ "HeartBeat_Notify", "HeartBeat Notify", NULL, 0 },
+
+ /*
+ * MacOS X
+ */
+ { VID_MACOSX, VID_STRING|VID_SUBSTRING_DUMPHEXA, "Mac OSX 10.x",
+ "\x4d\xf3\x79\x28\xe9\xfc\x4f\xd1\xb3\x26\x21\x70\xd5\x15\xc6\x62", NULL, 0},
+
+ /*
+ * Openswan
+ */
+ DEC_FSWAN_VID(OPENSWAN2, "Openswan 2.2.0", "Openswan 2.2.0")
+
+ /* NCP */
+ { VID_NCP_SERVER, VID_KEEP | VID_SUBSTRING_MATCH, NULL, "NCP Server",
+ "\xc6\xf5\x7a\xc3\x98\xf4\x93\x20\x81\x45\xb7\x58", 12},
+ { VID_NCP_CLIENT, VID_KEEP | VID_SUBSTRING_MATCH, NULL, "NCP Client",
+ "\xeb\x4c\x1b\x78\x8a\xfd\x4a\x9c\xb7\x73\x0a\x68", 12},
+
+ /*
+ * Windows Vista (and Longhorn?)
+ */
+ DEC_MD5_VID(VISTA_AUTHIP, "MS-Negotiation Discovery Capable")
+ DEC_MD5_VID(VISTA_AUTHIP2, "IKE CGA version 1")
+
+ /*
+ * strongSwan
+ */
+ DEC_MD5_VID(STRONGSWAN, "strongSwan 4.1.1")
+ DEC_MD5_VID(STRONGSWAN_4_1_0, "strongSwan 4.1.0")
+ DEC_MD5_VID(STRONGSWAN_4_0_7, "strongSwan 4.0.7")
+ DEC_MD5_VID(STRONGSWAN_4_0_6, "strongSwan 4.0.6")
+ DEC_MD5_VID(STRONGSWAN_4_0_5, "strongSwan 4.0.5")
+ DEC_MD5_VID(STRONGSWAN_4_0_4, "strongSwan 4.0.4")
+ DEC_MD5_VID(STRONGSWAN_4_0_3, "strongSwan 4.0.3")
+ DEC_MD5_VID(STRONGSWAN_4_0_2, "strongSwan 4.0.2")
+ DEC_MD5_VID(STRONGSWAN_4_0_1, "strongSwan 4.0.1")
+ DEC_MD5_VID(STRONGSWAN_4_0_0, "strongSwan 4.0.0")
+
+ DEC_MD5_VID(STRONGSWAN_2_8_4, "strongSwan 2.8.4")
+ DEC_MD5_VID(STRONGSWAN_2_8_3, "strongSwan 2.8.3")
+ DEC_MD5_VID(STRONGSWAN_2_8_2, "strongSwan 2.8.2")
+ DEC_MD5_VID(STRONGSWAN_2_8_1, "strongSwan 2.8.1")
+ DEC_MD5_VID(STRONGSWAN_2_8_0, "strongSwan 2.8.0")
+ DEC_MD5_VID(STRONGSWAN_2_7_3, "strongSwan 2.7.3")
+ DEC_MD5_VID(STRONGSWAN_2_7_2, "strongSwan 2.7.2")
+ DEC_MD5_VID(STRONGSWAN_2_7_1, "strongSwan 2.7.1")
+ DEC_MD5_VID(STRONGSWAN_2_7_0, "strongSwan 2.7.0")
+ DEC_MD5_VID(STRONGSWAN_2_6_4, "strongSwan 2.6.4")
+ DEC_MD5_VID(STRONGSWAN_2_6_3, "strongSwan 2.6.3")
+ DEC_MD5_VID(STRONGSWAN_2_6_2, "strongSwan 2.6.2")
+ DEC_MD5_VID(STRONGSWAN_2_6_1, "strongSwan 2.6.1")
+ DEC_MD5_VID(STRONGSWAN_2_6_0, "strongSwan 2.6.0")
+ DEC_MD5_VID(STRONGSWAN_2_5_7, "strongSwan 2.5.7")
+ DEC_MD5_VID(STRONGSWAN_2_5_6, "strongSwan 2.5.6")
+ DEC_MD5_VID(STRONGSWAN_2_5_5, "strongSwan 2.5.5")
+ DEC_MD5_VID(STRONGSWAN_2_5_4, "strongSwan 2.5.4")
+ DEC_MD5_VID(STRONGSWAN_2_5_3, "strongSwan 2.5.3")
+ DEC_MD5_VID(STRONGSWAN_2_5_2, "strongSwan 2.5.2")
+ DEC_MD5_VID(STRONGSWAN_2_5_1, "strongSwan 2.5.1")
+ DEC_MD5_VID(STRONGSWAN_2_5_0, "strongSwan 2.5.0")
+ DEC_MD5_VID(STRONGSWAN_2_4_4, "strongSwan 2.4.4")
+ DEC_MD5_VID(STRONGSWAN_2_4_3, "strongSwan 2.4.3")
+ DEC_MD5_VID(STRONGSWAN_2_4_2, "strongSwan 2.4.2")
+ DEC_MD5_VID(STRONGSWAN_2_4_1, "strongSwan 2.4.1")
+ DEC_MD5_VID(STRONGSWAN_2_4_0, "strongSwan 2.4.0")
+ DEC_MD5_VID(STRONGSWAN_2_3_2, "strongSwan 2.3.2")
+ DEC_MD5_VID(STRONGSWAN_2_3_1, "strongSwan 2.3.1")
+ DEC_MD5_VID(STRONGSWAN_2_3_0, "strongSwan 2.3.0")
+ DEC_MD5_VID(STRONGSWAN_2_2_2, "strongSwan 2.2.2")
+ DEC_MD5_VID(STRONGSWAN_2_2_1, "strongSwan 2.2.1")
+ DEC_MD5_VID(STRONGSWAN_2_2_0, "strongSwan 2.2.0")
+
+ /* NAT-Traversal */
+
+ DEC_MD5_VID(NATT_STENBERG_01, "draft-stenberg-ipsec-nat-traversal-01")
+ DEC_MD5_VID(NATT_STENBERG_02, "draft-stenberg-ipsec-nat-traversal-02")
+ DEC_MD5_VID(NATT_HUTTUNEN, "ESPThruNAT")
+ DEC_MD5_VID(NATT_HUTTUNEN_ESPINUDP, "draft-huttunen-ipsec-esp-in-udp-00.txt")
+ DEC_MD5_VID(NATT_IETF_00, "draft-ietf-ipsec-nat-t-ike-00")
+ DEC_MD5_VID(NATT_IETF_02, "draft-ietf-ipsec-nat-t-ike-02")
+ /* hash in draft-ietf-ipsec-nat-t-ike-02 contains '\n'... Accept both */
+ DEC_MD5_VID_D(NATT_IETF_02_N, "draft-ietf-ipsec-nat-t-ike-02\n", "draft-ietf-ipsec-nat-t-ike-02_n")
+ DEC_MD5_VID(NATT_IETF_03, "draft-ietf-ipsec-nat-t-ike-03")
+ DEC_MD5_VID(NATT_RFC, "RFC 3947")
+
+ /* misc */
+
+ { VID_MISC_XAUTH, VID_KEEP, NULL, "XAUTH",
+ "\x09\x00\x26\x89\xdf\xd6\xb7\x12", 8 },
+
+ { VID_MISC_DPD, VID_KEEP, NULL, "Dead Peer Detection",
+ "\xaf\xca\xd7\x13\x68\xa1\xf1\xc9\x6b\x86\x96\xfc\x77\x57\x01\x00", 16 },
+
+ DEC_MD5_VID(MISC_FRAGMENTATION, "FRAGMENTATION")
+
+ DEC_MD5_VID(INITIAL_CONTACT, "Vid-Initial-Contact")
+
+ /**
+ * Cisco VPN 3000
+ */
+ { VID_MISC_FRAGMENTATION, VID_MD5HASH | VID_SUBSTRING_DUMPHEXA,
+ "FRAGMENTATION", NULL, NULL, 0 },
+
+ /* -- */
+ { 0, 0, NULL, NULL, NULL, 0 }
+
+};
+
+static const char _hexdig[] = "0123456789abcdef";
+
+static int _vid_struct_init = 0;
+
+void
+init_vendorid(void)
+{
+ struct vid_struct *vid;
+ MD5_CTX ctx;
+ int i;
+
+ for (vid = _vid_tab; vid->id; vid++)
+ {
+ if (vid->flags & VID_STRING)
+ {
+ /** VendorID is a string **/
+ vid->vid = strdup(vid->data);
+ vid->vid_len = strlen(vid->data);
+ }
+ else if (vid->flags & VID_MD5HASH)
+ {
+ /** VendorID is a string to hash with MD5 **/
+ char *vidm = malloc(MD5_DIGEST_SIZE);
+
+ vid->vid = vidm;
+ if (vidm)
+ {
+ MD5Init(&ctx);
+ MD5Update(&ctx, (const u_char *)vid->data, strlen(vid->data));
+ MD5Final(vidm, &ctx);
+ vid->vid_len = MD5_DIGEST_SIZE;
+ }
+ }
+ else if (vid->flags & VID_FSWAN_HASH)
+ {
+ /** FreeS/WAN 2.00+ specific hash **/
+#define FSWAN_VID_SIZE 12
+ unsigned char hash[MD5_DIGEST_SIZE];
+ char *vidm = malloc(FSWAN_VID_SIZE);
+
+ vid->vid = vidm;
+ if (vidm)
+ {
+ MD5Init(&ctx);
+ MD5Update(&ctx, (const u_char *)vid->data, strlen(vid->data));
+ MD5Final(hash, &ctx);
+ vidm[0] = 'O';
+ vidm[1] = 'E';
+#if FSWAN_VID_SIZE - 2 <= MD5_DIGEST_SIZE
+ memcpy(vidm + 2, hash, FSWAN_VID_SIZE - 2);
+#else
+ memcpy(vidm + 2, hash, MD5_DIGEST_SIZE);
+ memset(vidm + 2 + MD5_DIGEST_SIZE, '\0',
+ FSWAN_VID_SIZE - 2 - MD5_DIGEST_SIZE);
+#endif
+ for (i = 2; i < FSWAN_VID_SIZE; i++)
+ {
+ vidm[i] &= 0x7f;
+ vidm[i] |= 0x40;
+ }
+ vid->vid_len = FSWAN_VID_SIZE;
+ }
+ }
+
+ if (vid->descr == NULL)
+ {
+ /** Find something to display **/
+ vid->descr = vid->data;
+ }
+ }
+ _vid_struct_init = 1;
+}
+
+static void
+handle_known_vendorid (struct msg_digest *md
+, const char *vidstr, size_t len, struct vid_struct *vid)
+{
+ char vid_dump[128];
+ bool vid_useful = FALSE;
+ size_t i, j;
+
+ switch (vid->id) {
+ /* Remote side supports OpenPGP certificates */
+ case VID_OPENPGP:
+ md->openpgp = TRUE;
+ vid_useful = TRUE;
+ break;
+
+ /*
+ * Use most recent supported NAT-Traversal method and ignore the
+ * other ones (implementations will send all supported methods but
+ * only one will be used)
+ *
+ * Note: most recent == higher id in vendor.h
+ */
+ case VID_NATT_IETF_00:
+ if (!nat_traversal_support_non_ike)
+ break;
+ if ((nat_traversal_enabled) && (!md->nat_traversal_vid))
+ {
+ md->nat_traversal_vid = vid->id;
+ vid_useful = TRUE;
+ }
+ break;
+ case VID_NATT_IETF_02:
+ case VID_NATT_IETF_02_N:
+ case VID_NATT_IETF_03:
+ case VID_NATT_RFC:
+ if (nat_traversal_support_port_floating
+ && md->nat_traversal_vid < vid->id)
+ {
+ md->nat_traversal_vid = vid->id;
+ vid_useful = TRUE;
+ }
+ break;
+
+ /* Remote side would like to do DPD with us on this connection */
+ case VID_MISC_DPD:
+ md->dpd = TRUE;
+ vid_useful = TRUE;
+ break;
+ case VID_MISC_XAUTH:
+ vid_useful = TRUE;
+ break;
+ default:
+ break;
+ }
+
+ if (vid->flags & VID_SUBSTRING_DUMPHEXA)
+ {
+ /* Dump description + Hexa */
+ memset(vid_dump, 0, sizeof(vid_dump));
+ snprintf(vid_dump, sizeof(vid_dump), "%s ",
+ vid->descr ? vid->descr : "");
+ for (i = strlen(vid_dump), j = vid->vid_len;
+ j < len && i < sizeof(vid_dump) - 2;
+ i += 2, j++)
+ {
+ vid_dump[i] = _hexdig[(vidstr[j] >> 4) & 0xF];
+ vid_dump[i+1] = _hexdig[vidstr[j] & 0xF];
+ }
+ }
+ else if (vid->flags & VID_SUBSTRING_DUMPASCII)
+ {
+ /* Dump ASCII content */
+ memset(vid_dump, 0, sizeof(vid_dump));
+ for (i = 0; i < len && i < sizeof(vid_dump) - 1; i++)
+ {
+ vid_dump[i] = (isprint(vidstr[i])) ? vidstr[i] : '.';
+ }
+ }
+ else
+ {
+ /* Dump description (descr) */
+ snprintf(vid_dump, sizeof(vid_dump), "%s",
+ vid->descr ? vid->descr : "");
+ }
+
+ loglog(RC_LOG_SERIOUS, "%s Vendor ID payload [%s]",
+ vid_useful ? "received" : "ignoring", vid_dump);
+}
+
+void
+handle_vendorid (struct msg_digest *md, const char *vid, size_t len)
+{
+ struct vid_struct *pvid;
+
+ if (!_vid_struct_init)
+ init_vendorid();
+
+ /*
+ * Find known VendorID in _vid_tab
+ */
+ for (pvid = _vid_tab; pvid->id; pvid++)
+ {
+ if (pvid->vid && vid && pvid->vid_len && len)
+ {
+ if (pvid->vid_len == len)
+ {
+ if (memcmp(pvid->vid, vid, len) == 0)
+ {
+ handle_known_vendorid(md, vid, len, pvid);
+ return;
+ }
+ }
+ else if ((pvid->vid_len < len) && (pvid->flags & VID_SUBSTRING))
+ {
+ if (memcmp(pvid->vid, vid, pvid->vid_len) == 0)
+ {
+ handle_known_vendorid(md, vid, len, pvid);
+ return;
+ }
+ }
+ }
+ }
+
+ /*
+ * Unknown VendorID. Log the beginning.
+ */
+ {
+ char log_vid[2*MAX_LOG_VID_LEN+1];
+ size_t i;
+
+ memset(log_vid, 0, sizeof(log_vid));
+
+ for (i = 0; i < len && i < MAX_LOG_VID_LEN; i++)
+ {
+ log_vid[2*i] = _hexdig[(vid[i] >> 4) & 0xF];
+ log_vid[2*i+1] = _hexdig[vid[i] & 0xF];
+ }
+ loglog(RC_LOG_SERIOUS, "ignoring Vendor ID payload [%s%s]",
+ log_vid, (len>MAX_LOG_VID_LEN) ? "..." : "");
+ }
+}
+
+/**
+ * Add a vendor id payload to the msg
+ */
+bool
+out_vendorid (u_int8_t np, pb_stream *outs, enum known_vendorid vid)
+{
+ struct vid_struct *pvid;
+
+ if (!_vid_struct_init)
+ init_vendorid();
+
+ for (pvid = _vid_tab; pvid->id && pvid->id != vid; pvid++);
+
+ if (pvid->id != vid)
+ return STF_INTERNAL_ERROR; /* not found */
+ if (!pvid->vid)
+ return STF_INTERNAL_ERROR; /* not initialized */
+
+ DBG(DBG_EMITTING,
+ DBG_log("out_vendorid(): sending [%s]", pvid->descr)
+ )
+ return out_generic_raw(np, &isakmp_vendor_id_desc, outs,
+ pvid->vid, pvid->vid_len, "V_ID");
+}
+
diff --git a/src/pluto/vendor.h b/src/pluto/vendor.h
new file mode 100644
index 000000000..8e0444f4d
--- /dev/null
+++ b/src/pluto/vendor.h
@@ -0,0 +1,131 @@
+/* FreeS/WAN ISAKMP VendorID
+ * Copyright (C) 2002-2003 Mathieu Lafon - Arkoon Network Security
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: vendor.h,v 1.30 2006/04/12 16:44:28 as Exp $
+ */
+
+#ifndef _VENDOR_H_
+#define _VENDOR_H_
+
+enum known_vendorid {
+/* 1 - 100 : Implementation names */
+ VID_OPENPGP = 1,
+ VID_KAME_RACOON = 2,
+ VID_MS_NT5 = 3,
+ VID_SSH_SENTINEL = 4,
+ VID_SSH_SENTINEL_1_1 = 5,
+ VID_SSH_SENTINEL_1_2 = 6,
+ VID_SSH_SENTINEL_1_3 = 7,
+ VID_SSH_SENTINEL_1_4 = 8,
+ VID_SSH_SENTINEL_1_4_1 = 9,
+ VID_SSH_IPSEC_1_1_0 = 10,
+ VID_SSH_IPSEC_1_1_1 = 11,
+ VID_SSH_IPSEC_1_1_2 = 12,
+ VID_SSH_IPSEC_1_2_1 = 13,
+ VID_SSH_IPSEC_1_2_2 = 14,
+ VID_SSH_IPSEC_2_0_0 = 15,
+ VID_SSH_IPSEC_2_1_0 = 16,
+ VID_SSH_IPSEC_2_1_1 = 17,
+ VID_SSH_IPSEC_2_1_2 = 18,
+ VID_SSH_IPSEC_3_0_0 = 19,
+ VID_SSH_IPSEC_3_0_1 = 20,
+ VID_SSH_IPSEC_4_0_0 = 21,
+ VID_SSH_IPSEC_4_0_1 = 22,
+ VID_SSH_IPSEC_4_1_0 = 23,
+ VID_SSH_IPSEC_4_2_0 = 24,
+ VID_CISCO_UNITY = 25,
+ VID_CISCO3K = 26,
+ VID_CISCO_IOS = 27,
+ VID_TIMESTEP = 28,
+ VID_SAFENET = 29,
+ VID_MACOSX = 30,
+ VID_OPENSWAN2 = 31,
+ VID_NCP_SERVER = 32,
+ VID_NCP_CLIENT = 33,
+ VID_VISTA_AUTHIP = 34,
+ VID_VISTA_AUTHIP2 = 35,
+
+ VID_STRONGSWAN = 36,
+ VID_STRONGSWAN_2_2_0 = 37,
+ VID_STRONGSWAN_2_2_1 = 38,
+ VID_STRONGSWAN_2_2_2 = 39,
+ VID_STRONGSWAN_2_3_0 = 40,
+ VID_STRONGSWAN_2_3_1 = 41,
+ VID_STRONGSWAN_2_3_2 = 42,
+ VID_STRONGSWAN_2_4_0 = 43,
+ VID_STRONGSWAN_2_4_1 = 44,
+ VID_STRONGSWAN_2_4_2 = 45,
+ VID_STRONGSWAN_2_4_3 = 46,
+ VID_STRONGSWAN_2_4_4 = 47,
+ VID_STRONGSWAN_2_5_0 = 48,
+ VID_STRONGSWAN_2_5_1 = 49,
+ VID_STRONGSWAN_2_5_2 = 50,
+ VID_STRONGSWAN_2_5_3 = 51,
+ VID_STRONGSWAN_2_5_4 = 52,
+ VID_STRONGSWAN_2_5_5 = 53,
+ VID_STRONGSWAN_2_5_6 = 54,
+ VID_STRONGSWAN_2_5_7 = 55,
+ VID_STRONGSWAN_2_6_0 = 56,
+ VID_STRONGSWAN_2_6_1 = 57,
+ VID_STRONGSWAN_2_6_2 = 58,
+ VID_STRONGSWAN_2_6_3 = 59,
+ VID_STRONGSWAN_2_6_4 = 60,
+ VID_STRONGSWAN_2_7_0 = 61,
+ VID_STRONGSWAN_2_7_1 = 62,
+ VID_STRONGSWAN_2_7_2 = 63,
+ VID_STRONGSWAN_2_7_3 = 64,
+ VID_STRONGSWAN_2_8_0 = 65,
+ VID_STRONGSWAN_2_8_1 = 66,
+ VID_STRONGSWAN_2_8_2 = 67,
+ VID_STRONGSWAN_2_8_3 = 68,
+ VID_STRONGSWAN_2_8_4 = 69,
+
+ VID_STRONGSWAN_4_0_0 = 70,
+ VID_STRONGSWAN_4_0_1 = 71,
+ VID_STRONGSWAN_4_0_2 = 72,
+ VID_STRONGSWAN_4_0_3 = 73,
+ VID_STRONGSWAN_4_0_4 = 74,
+ VID_STRONGSWAN_4_0_5 = 75,
+ VID_STRONGSWAN_4_0_6 = 76,
+ VID_STRONGSWAN_4_0_7 = 77,
+ VID_STRONGSWAN_4_1_0 = 78,
+
+ /* 101 - 200 : NAT-Traversal */
+ VID_NATT_STENBERG_01 =101,
+ VID_NATT_STENBERG_02 =102,
+ VID_NATT_HUTTUNEN =103,
+ VID_NATT_HUTTUNEN_ESPINUDP =104,
+ VID_NATT_IETF_00 =105,
+ VID_NATT_IETF_02_N =106,
+ VID_NATT_IETF_02 =107,
+ VID_NATT_IETF_03 =108,
+ VID_NATT_RFC =109,
+
+ /* 201 - 300 : Misc */
+ VID_MISC_XAUTH =201,
+ VID_MISC_DPD =202,
+ VID_MISC_HEARTBEAT_NOTIFY =203,
+ VID_MISC_FRAGMENTATION =204,
+ VID_INITIAL_CONTACT =205,
+ VID_CISCO3K_FRAGMENTATION =206
+};
+
+void init_vendorid(void);
+
+struct msg_digest;
+void handle_vendorid (struct msg_digest *md, const char *vid, size_t len);
+
+bool out_vendorid (u_int8_t np, pb_stream *outs, enum known_vendorid vid);
+
+#endif /* _VENDOR_H_ */
+
diff --git a/src/pluto/virtual.c b/src/pluto/virtual.c
new file mode 100644
index 000000000..d1553364e
--- /dev/null
+++ b/src/pluto/virtual.c
@@ -0,0 +1,334 @@
+/* FreeS/WAN Virtual IP Management
+ * Copyright (C) 2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: virtual.c,v 1.4 2004/04/02 10:38:52 as Exp $
+ */
+
+#include <freeswan.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/queue.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "connections.h"
+#include "whack.h"
+#include "virtual.h"
+
+#define F_VIRTUAL_NO 1
+#define F_VIRTUAL_DHCP 2
+#define F_VIRTUAL_IKE_CONFIG 4
+#define F_VIRTUAL_PRIVATE 8
+#define F_VIRTUAL_ALL 16
+#define F_VIRTUAL_HOST 32
+
+struct virtual_t {
+ unsigned short flags;
+ unsigned short n_net;
+ ip_subnet net[0];
+};
+
+static ip_subnet *private_net_ok=NULL, *private_net_ko=NULL;
+static unsigned short private_net_ok_len=0, private_net_ko_len=0;
+
+/**
+ * read %v4:x.x.x.x/y or %v6:xxxxxxxxx/yy
+ * or %v4:!x.x.x.x/y if dstko not NULL
+ */
+static bool
+_read_subnet(const char *src, size_t len, ip_subnet *dst, ip_subnet *dstko,
+ bool *isok)
+{
+ bool ok;
+ int af;
+
+ if ((len > 4) && (strncmp(src, "%v4:", 4)==0))
+ {
+ af = AF_INET;
+ }
+ else if ((len > 4) && (strncmp(src, "%v6:", 4)==0))
+ {
+ af = AF_INET6;
+ }
+ else
+ {
+ return FALSE;
+ }
+
+ ok = (src[4] != '!');
+ src += ok ? 4 : 5;
+ len -= ok ? 4 : 5;
+
+ if (!len)
+ return FALSE;
+ if (!ok && !dstko)
+ return FALSE;
+
+ passert ( ((ok)?(dst):(dstko))!=NULL );
+
+ if (ttosubnet(src, len, af, ((ok)?(dst):(dstko))))
+ {
+ return FALSE;
+ }
+ if (isok)
+ *isok = ok;
+ return TRUE;
+}
+
+void
+init_virtual_ip(const char *private_list)
+{
+ const char *next, *str=private_list;
+ unsigned short ign = 0, i_ok, i_ko;
+ ip_subnet sub;
+ bool ok;
+
+ /** Count **/
+ private_net_ok_len=0;
+ private_net_ko_len=0;
+
+ while (str)
+ {
+ next = strchr(str,',');
+ if (!next)
+ next = str + strlen(str);
+ if (_read_subnet(str, next-str, &sub, &sub, &ok))
+ if (ok)
+ private_net_ok_len++;
+ else
+ private_net_ko_len++;
+ else
+ ign++;
+ str = *next ? next+1 : NULL;
+ }
+
+ if (!ign)
+ {
+ /** Allocate **/
+ if (private_net_ok_len)
+ {
+ private_net_ok = (ip_subnet *)alloc_bytes(
+ (private_net_ok_len*sizeof(ip_subnet)),
+ "private_net_ok subnets");
+ }
+ if (private_net_ko_len)
+ {
+ private_net_ko = (ip_subnet *)alloc_bytes(
+ (private_net_ko_len*sizeof(ip_subnet)),
+ "private_net_ko subnets");
+ }
+ if ((private_net_ok_len && !private_net_ok)
+ || (private_net_ko_len && !private_net_ko))
+ {
+ loglog(RC_LOG_SERIOUS,
+ "can't alloc in init_virtual_ip");
+ pfreeany(private_net_ok);
+ private_net_ok = NULL;
+ pfreeany(private_net_ko);
+ private_net_ko = NULL;
+ }
+ else
+ {
+ /** Fill **/
+ str = private_list;
+ i_ok = 0;
+ i_ko = 0;
+
+ while (str)
+ {
+ next = strchr(str,',');
+ if (!next)
+ next = str + strlen(str);
+ if (_read_subnet(str, next-str,
+ &(private_net_ok[i_ok]), &(private_net_ko[i_ko]), &ok))
+ {
+ if (ok)
+ i_ok++;
+ else
+ i_ko++;
+ }
+ str = *next ? next+1 : NULL;
+ }
+ }
+ }
+ else
+ loglog(RC_LOG_SERIOUS,
+ "%d bad entries in virtual_private - none loaded", ign);
+}
+
+/**
+ * virtual string must be :
+ * {vhost,vnet}:[%method]*
+ *
+ * vhost = accept only a host (/32)
+ * vnet = accept any network
+ *
+ * %no = no virtual IP (accept public IP)
+ * %dhcp = accept DHCP SA (0.0.0.0/0) of affected IP [not implemented]
+ * %ike = accept affected IKE Config Mode IP [not implemented]
+ * %priv = accept system-wide private net list
+ * %v4:x = accept ipv4 in list 'x'
+ * %v6:x = accept ipv6 in list 'x'
+ * %all = accept all ips [only for testing]
+ *
+ * ex: vhost:%no,%dhcp,%priv,%v4:192.168.1.0/24
+ */
+struct virtual_t
+*create_virtual(const struct connection *c, const char *string)
+{
+ unsigned short flags=0, n_net=0, i;
+ const char *str = string, *next, *first_net=NULL;
+ ip_subnet sub;
+ struct virtual_t *v;
+
+ if (!string || string[0] == '\0')
+ return NULL;
+
+ if (strlen(string) >= 6 && strncmp(string,"vhost:",6) == 0)
+ {
+ flags |= F_VIRTUAL_HOST;
+ str += 6;
+ }
+ else if (strlen(string) >= 5 && strncmp(string,"vnet:",5) == 0)
+ str += 5;
+ else
+ goto fail;
+
+ /**
+ * Parse string : fill flags & count subnets
+ */
+ while ((str) && (*str))
+ {
+ next = strchr(str,',');
+ if (!next) next = str + strlen(str);
+ if (next-str == 3 && strncmp(str, "%no", 3) == 0)
+ flags |= F_VIRTUAL_NO;
+#if 0
+ else if (next-str == 4 && strncmp(str, "%ike", 4) == 0)
+ flags |= F_VIRTUAL_IKE_CONFIG;
+ else if (next-str == 5 && strncmp(str, "%dhcp", 5) == 0)
+ flags |= F_VIRTUAL_DHCP;
+#endif
+ else if (next-str == 5 && strncmp(str, "%priv", 5) == 0)
+ flags |= F_VIRTUAL_PRIVATE;
+ else if (next-str == 4 && strncmp(str, "%all", 4) == 0)
+ flags |= F_VIRTUAL_ALL;
+ else if (_read_subnet(str, next-str, &sub, NULL, NULL))
+ {
+ n_net++;
+ if (!first_net)
+ first_net = str;
+ }
+ else
+ goto fail;
+
+ str = *next ? next+1 : NULL;
+ }
+
+ v = (struct virtual_t *)alloc_bytes(
+ sizeof(struct virtual_t) + (n_net*sizeof(ip_subnet)),
+ "virtual description");
+ if (!v) goto fail;
+
+ v->flags = flags;
+ v->n_net = n_net;
+ if (n_net && first_net)
+ {
+ /**
+ * Save subnets in newly allocated struct
+ */
+ for (str = first_net, i = 0; str && *str; )
+ {
+ next = strchr(str,',');
+ if (!next) next = str + strlen(str);
+ if (_read_subnet(str, next-str, &(v->net[i]), NULL, NULL))
+ i++;
+ str = *next ? next+1 : NULL;
+ }
+ }
+
+ return v;
+
+fail:
+ plog("invalid virtual string [%s] - "
+ "virtual selection disabled for connection '%s'", string, c->name);
+ return NULL;
+}
+
+bool
+is_virtual_end(const struct end *that)
+{
+ return ((that->virt)?TRUE:FALSE);
+}
+
+bool
+is_virtual_connection(const struct connection *c)
+{
+ return ((c->spd.that.virt)?TRUE:FALSE);
+}
+
+static bool
+net_in_list(const ip_subnet *peer_net, const ip_subnet *list,
+ unsigned short len)
+{
+ unsigned short i;
+
+ if (!list || !len)
+ return FALSE;
+
+ for (i = 0; i < len; i++)
+ {
+ if (subnetinsubnet(peer_net, &(list[i])))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+bool
+is_virtual_net_allowed(const struct connection *c, const ip_subnet *peer_net,
+ const ip_address *his_addr)
+{
+ if (c->spd.that.virt == NULL)
+ return FALSE;
+
+ if ((c->spd.that.virt->flags & F_VIRTUAL_HOST)
+ && !subnetishost(peer_net))
+ return FALSE;
+
+ if ((c->spd.that.virt->flags & F_VIRTUAL_NO)
+ && subnetishost(peer_net) && addrinsubnet(his_addr, peer_net))
+ return TRUE;
+
+ if ((c->spd.that.virt->flags & F_VIRTUAL_PRIVATE)
+ && net_in_list(peer_net, private_net_ok, private_net_ok_len)
+ && !net_in_list(peer_net, private_net_ko, private_net_ko_len))
+ return TRUE;
+
+ if (c->spd.that.virt->n_net
+ && net_in_list(peer_net, c->spd.that.virt->net, c->spd.that.virt->n_net))
+ return TRUE;
+
+ if (c->spd.that.virt->flags & F_VIRTUAL_ALL)
+ {
+ /** %all must only be used for testing - log it **/
+ loglog(RC_LOG_SERIOUS, "Warning - "
+ "v%s:%%all must only be used for testing",
+ (c->spd.that.virt->flags & F_VIRTUAL_HOST) ? "host" : "net");
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
diff --git a/src/pluto/virtual.h b/src/pluto/virtual.h
new file mode 100644
index 000000000..2d5bf27ae
--- /dev/null
+++ b/src/pluto/virtual.h
@@ -0,0 +1,31 @@
+/* FreeS/WAN Virtual IP Management
+ * Copyright (C) 2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: virtual.h,v 1.2 2004/03/22 21:53:20 as Exp $
+ */
+
+#ifndef _VIRTUAL_IP_H
+#define _VIRTUAL_IP_H
+
+extern void init_virtual_ip(const char *private_list);
+
+extern struct virtual_t *create_virtual(const struct connection *c,
+ const char *string);
+
+extern bool is_virtual_end(const struct end *that);
+extern bool is_virtual_connection(const struct connection *c);
+extern bool is_virtual_net_allowed(const struct connection *c,
+ const ip_subnet *peer_net, const ip_address *his_addr);
+
+#endif /* _VIRTUAL_IP_H */
+
diff --git a/src/pluto/x509.c b/src/pluto/x509.c
new file mode 100644
index 000000000..2521244f7
--- /dev/null
+++ b/src/pluto/x509.c
@@ -0,0 +1,2241 @@
+/* Support of X.509 certificates
+ * Copyright (C) 2000 Andreas Hess, Patric Lichtsteiner, Roger Wegmann
+ * Copyright (C) 2001 Marco Bertossa, Andreas Schleiss
+ * Copyright (C) 2002 Mario Strasser
+ * Copyright (C) 2000-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.
+ *
+ * RCSID $Id: x509.c,v 1.36 2006/04/10 16:08:33 as Exp $
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <time.h>
+#include <sys/types.h>
+
+#include <freeswan.h>
+#include <ipsec_policy.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "mp_defs.h"
+#include "log.h"
+#include "id.h"
+#include "asn1.h"
+#include "oid.h"
+#include "pkcs1.h"
+#include "x509.h"
+#include "crl.h"
+#include "ca.h"
+#include "certs.h"
+#include "keys.h"
+#include "whack.h"
+#include "fetch.h"
+#include "ocsp.h"
+#include "sha1.h"
+
+/* chained lists of X.509 end certificates */
+
+static x509cert_t *x509certs = NULL;
+
+/* 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 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, "uniformResourceIdentifier", ASN1_CONTEXT_S_6, ASN1_OPT |
+ ASN1_BODY }, /* 12 */
+ { 0, "end choice", ASN1_EOC, ASN1_END }, /* 13 */
+ { 0, "ipAddress", ASN1_CONTEXT_S_7, ASN1_OPT |
+ ASN1_BODY }, /* 14 */
+ { 0, "end choice", ASN1_EOC, ASN1_END }, /* 15 */
+ { 0, "registeredID", ASN1_CONTEXT_S_8, ASN1_OPT |
+ ASN1_BODY }, /* 16 */
+ { 0, "end choice", ASN1_EOC, ASN1_END } /* 17 */
+};
+
+#define GN_OBJ_OTHER_NAME 0
+#define GN_OBJ_RFC822_NAME 2
+#define GN_OBJ_DNS_NAME 4
+#define GN_OBJ_X400_ADDRESS 6
+#define GN_OBJ_DIRECTORY_NAME 8
+#define GN_OBJ_EDI_PARTY_NAME 10
+#define GN_OBJ_URI 12
+#define GN_OBJ_IP_ADDRESS 14
+#define GN_OBJ_REGISTERED_ID 16
+#define GN_OBJ_ROOF 18
+
+/* ASN.1 definition of otherName */
+
+static const asn1Object_t otherNameObjects[] = {
+ {0, "type-id", ASN1_OID, ASN1_BODY }, /* 0 */
+ {0, "value", ASN1_CONTEXT_C_0, ASN1_BODY } /* 1 */
+};
+
+#define ON_OBJ_ID_TYPE 0
+#define ON_OBJ_VALUE 1
+#define ON_OBJ_ROOF 2
+
+/* ASN.1 definition of 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, "nameRelativeToCRLIssuer", 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 certificate */
+
+static const asn1Object_t certObjects[] = {
+ { 0, "certificate", 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_OBJ }, /* 14 */
+ { 5, "modulus", ASN1_INTEGER, ASN1_BODY }, /* 15 */
+ { 5, "publicExponent", ASN1_INTEGER, ASN1_BODY }, /* 16 */
+ { 2, "issuerUniqueID", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 17 */
+ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 18 */
+ { 2, "subjectUniqueID", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 19 */
+ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 20 */
+ { 2, "optional extensions", ASN1_CONTEXT_C_3, ASN1_OPT }, /* 21 */
+ { 3, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 22 */
+ { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 23 */
+ { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 24 */
+ { 5, "critical", ASN1_BOOLEAN, ASN1_DEF |
+ ASN1_BODY }, /* 25 */
+ { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 26 */
+ { 3, "end loop", ASN1_EOC, ASN1_END }, /* 27 */
+ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 28 */
+ { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 29 */
+ { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY } /* 30 */
+};
+
+#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_MODULUS 15
+#define X509_OBJ_PUBLIC_EXPONENT 16
+#define X509_OBJ_EXTN_ID 24
+#define X509_OBJ_CRITICAL 25
+#define X509_OBJ_EXTN_VALUE 26
+#define X509_OBJ_ALGORITHM 29
+#define X509_OBJ_SIGNATURE 30
+#define X509_OBJ_ROOF 31
+
+
+const x509cert_t empty_x509cert = {
+ NULL , /* *next */
+ UNDEFINED_TIME, /* installed */
+ 0 , /* count */
+ FALSE , /* smartcard */
+ AUTH_NONE , /* authority_flags */
+ { NULL, 0 } , /* certificate */
+ { NULL, 0 } , /* tbsCertificate */
+ 1 , /* version */
+ { NULL, 0 } , /* serialNumber */
+ OID_UNKNOWN , /* sigAlg */
+ { NULL, 0 } , /* issuer */
+ /* validity */
+ 0 , /* notBefore */
+ 0 , /* notAfter */
+ { NULL, 0 } , /* subject */
+ /* subjectPublicKeyInfo */
+ OID_UNKNOWN , /* subjectPublicKeyAlgorithm */
+ { NULL, 0 } , /* subjectPublicKey */
+ { NULL, 0 } , /* modulus */
+ { NULL, 0 } , /* publicExponent */
+ /* issuerUniqueID */
+ /* subjectUniqueID */
+ /* extensions */
+ /* extension */
+ /* extnID */
+ /* critical */
+ /* extnValue */
+ FALSE , /* isCA */
+ FALSE , /* isOcspSigner */
+ { NULL, 0 } , /* subjectKeyID */
+ { NULL, 0 } , /* authKeyID */
+ { NULL, 0 } , /* authKeySerialNumber */
+ { NULL, 0 } , /* accessLocation */
+ NULL , /* subjectAltName */
+ NULL , /* crlDistributionPoints */
+ OID_UNKNOWN , /* algorithm */
+ { NULL, 0 } /* signature */
+};
+
+/* coding of X.501 distinguished name */
+
+typedef struct {
+ const u_char *name;
+ chunk_t oid;
+ u_char type;
+} x501rdn_t;
+
+/* 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};
+
+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
+
+static u_char ASN1_subjectAltName_oid_str[] = {
+ 0x06, 0x03, 0x55, 0x1D, 0x11
+};
+
+static const chunk_t ASN1_subjectAltName_oid = strchunk(ASN1_subjectAltName_oid_str);
+
+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;
+}
+
+
+/*
+ * Pointer is set to the first RDN in a DN
+ */
+static err_t
+init_rdn(chunk_t dn, chunk_t *rdn, chunk_t *attribute, bool *next)
+{
+ *rdn = empty_chunk;
+ *attribute = empty_chunk;
+
+ /* a DN is a SEQUENCE OF RDNs */
+
+ if (*dn.ptr != ASN1_SEQUENCE)
+ {
+ return "DN is not a SEQUENCE";
+ }
+
+ rdn->len = asn1_length(&dn);
+
+ if (rdn->len == ASN1_INVALID_LENGTH)
+ return "Invalid RDN length";
+
+ rdn->ptr = dn.ptr;
+
+ /* are there any RDNs ? */
+ *next = rdn->len > 0;
+
+ return NULL;
+}
+
+/*
+ * Fetches the next RDN in a DN
+ */
+static err_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 = empty_chunk;
+ *value = empty_chunk;
+
+ /* 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)
+ return "RDN is not a SET";
+
+ attribute->len = asn1_length(rdn);
+
+ if (attribute->len == ASN1_INVALID_LENGTH)
+ return "Invalid attribute length";
+
+ 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)
+ return "attributeTypeAndValue is not a SEQUENCE";
+
+ /* extract the attribute body */
+ body.len = asn1_length(attribute);
+
+ if (body.len == ASN1_INVALID_LENGTH)
+ return "Invalid attribute body length";
+
+ 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)
+ return "attributeType is not an OID";
+
+ /* extract OID */
+ oid->len = asn1_length(&body);
+
+ if (oid->len == ASN1_INVALID_LENGTH)
+ return "Invalid attribute OID length";
+
+ 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)
+ return "Invalid attribute string length";
+
+ value->ptr = body.ptr;
+
+ /* are there any RDNs left? */
+ *next = rdn->len > 0 || attribute->len > 0;
+
+ return NULL;
+}
+
+/*
+ * Parses an ASN.1 distinguished name int its OID/value pairs
+ */
+static err_t
+dn_parse(chunk_t dn, chunk_t *str)
+{
+ chunk_t rdn, oid, attribute, value;
+ asn1_t type;
+ int oid_code;
+ bool next;
+ bool first = TRUE;
+
+ err_t ugh = init_rdn(dn, &rdn, &attribute, &next);
+
+ if (ugh != NULL) /* a parsing error has occured */
+ return ugh;
+
+ while (next)
+ {
+ ugh = get_next_rdn(&rdn, &attribute, &oid, &value, &type, &next);
+
+ if (ugh != NULL) /* a parsing error has occured */
+ return ugh;
+
+ 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 NULL;
+}
+
+/*
+ * Count the number of wildcard RDNs in a distinguished name
+ */
+int
+dn_count_wildcards(chunk_t dn)
+{
+ chunk_t rdn, attribute, oid, value;
+ asn1_t type;
+ bool next;
+ int wildcards = 0;
+
+ err_t ugh = init_rdn(dn, &rdn, &attribute, &next);
+
+ if (ugh != NULL) /* a parsing error has occured */
+ return -1;
+
+ while (next)
+ {
+ ugh = get_next_rdn(&rdn, &attribute, &oid, &value, &type, &next);
+
+ if (ugh != NULL) /* a parsing error has occured */
+ return -1;
+ if (value.len == 1 && *value.ptr == '*')
+ wildcards++; /* we have found a wildcard RDN */
+ }
+ return wildcards;
+}
+
+/*
+ * 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++));
+}
+
+
+/* Converts a binary DER-encoded ASN.1 distinguished name
+ * into LDAP-style human-readable ASCII format
+ */
+int
+dntoa(char *dst, size_t dstlen, chunk_t dn)
+{
+ err_t ugh = NULL;
+ chunk_t str;
+
+ str.ptr = dst;
+ str.len = dstlen;
+ ugh = dn_parse(dn, &str);
+
+ if (ugh != NULL) /* error, print DN as hex string */
+ {
+ DBG(DBG_PARSING,
+ DBG_log("error in DN parsing: %s", ugh)
+ )
+ str.ptr = dst;
+ str.len = dstlen;
+ hex_str(dn, &str);
+ }
+ return (int)(dstlen - str.len);
+}
+
+/*
+ * Same as dntoa but prints a special string for a null dn
+ */
+int
+dntoa_or_null(char *dst, size_t dstlen, chunk_t dn, const char* null_dn)
+{
+ if (dn.ptr == NULL)
+ return snprintf(dst, dstlen, "%s", null_dn);
+ else
+ return dntoa(dst, dstlen, dn);
+}
+
+/* Converts an LDAP-style human-readable ASCII-encoded
+ * ASN.1 distinguished name into binary DER-encoded format
+ */
+err_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;
+
+ u_char oid_len_buf[3];
+ u_char name_len_buf[3];
+ u_char rdn_seq_len_buf[3];
+ u_char rdn_set_len_buf[3];
+ u_char dn_seq_len_buf[3];
+
+ chunk_t asn1_oid_len = { oid_len_buf, 0 };
+ chunk_t asn1_name_len = { name_len_buf, 0 };
+ chunk_t asn1_rdn_seq_len = { rdn_seq_len_buf, 0 };
+ chunk_t asn1_rdn_set_len = { rdn_set_len_buf, 0 };
+ chunk_t asn1_dn_seq_len = { dn_seq_len_buf, 0 };
+ chunk_t oid = empty_chunk;
+ chunk_t name = empty_chunk;
+
+ int whitespace = 0;
+ int rdn_seq_len = 0;
+ int rdn_set_len = 0;
+ int dn_seq_len = 0;
+ int pos = 0;
+
+ err_t ugh = NULL;
+
+ u_char *dn_ptr = dn->ptr + 4;
+
+ state_t state = SEARCH_OID;
+
+ 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)
+ {
+ ugh = "unknown OID in distinguished name";
+ state = UNKNOWN_OID;
+ break;
+ }
+ code_asn1_length(x501rdns[pos].oid.len, &asn1_oid_len);
+
+ /* reset oid and change state */
+ oid = empty_chunk;
+ 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;
+ code_asn1_length(name.len, &asn1_name_len);
+
+ /* compute the length of the relative distinguished name sequence */
+ rdn_seq_len = 1 + asn1_oid_len.len + x501rdns[pos].oid.len +
+ 1 + asn1_name_len.len + name.len;
+ code_asn1_length(rdn_seq_len, &asn1_rdn_seq_len);
+
+ /* compute the length of the relative distinguished name set */
+ rdn_set_len = 1 + asn1_rdn_seq_len.len + rdn_seq_len;
+ code_asn1_length(rdn_set_len, &asn1_rdn_set_len);
+
+ /* encode the relative distinguished name */
+ *dn_ptr++ = ASN1_SET;
+ chunkcpy(dn_ptr, asn1_rdn_set_len);
+ *dn_ptr++ = ASN1_SEQUENCE;
+ chunkcpy(dn_ptr, asn1_rdn_seq_len);
+ *dn_ptr++ = ASN1_OID;
+ chunkcpy(dn_ptr, asn1_oid_len);
+ chunkcpy(dn_ptr, x501rdns[pos].oid);
+ /* encode the ASN.1 character string type of the name */
+ *dn_ptr++ = (x501rdns[pos].type == ASN1_PRINTABLESTRING
+ && !is_printablestring(name))? ASN1_T61STRING : x501rdns[pos].type;
+ chunkcpy(dn_ptr, asn1_name_len);
+ chunkcpy(dn_ptr, name);
+
+ /* accumulate the length of the distinguished name sequence */
+ dn_seq_len += 1 + asn1_rdn_set_len.len + rdn_set_len;
+
+ /* reset name and change state */
+ name = empty_chunk;
+ state = SEARCH_OID;
+ }
+ break;
+ case UNKNOWN_OID:
+ break;
+ }
+ } while (*src++ != '\0');
+
+ /* complete the distinguished name sequence*/
+ code_asn1_length(dn_seq_len, &asn1_dn_seq_len);
+ dn->ptr += 3 - asn1_dn_seq_len.len;
+ dn->len = 1 + asn1_dn_seq_len.len + dn_seq_len;
+ dn_ptr = dn->ptr;
+ *dn_ptr++ = ASN1_SEQUENCE;
+ chunkcpy(dn_ptr, asn1_dn_seq_len);
+ return ugh;
+}
+
+/* compare two distinguished names by
+ * comparing the individual RDNs
+ */
+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) != NULL
+ || init_rdn(b, &rdn_b, &attribute_b, &next_b) != NULL)
+ 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) != NULL
+ || get_next_rdn(&rdn_b, &attribute_b, &oid_b, &value_b, &type_b, &next_b) != NULL)
+ {
+ 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.
+ */
+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) != NULL
+ || init_rdn(b, &rdn_b, &attribute_b, &next_b) != NULL)
+ 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) != NULL
+ || get_next_rdn(&rdn_b, &attribute_b, &oid_b, &value_b, &type_b, &next_b) != NULL)
+ {
+ 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;
+}
+
+/*
+ * compare two X.509 certificates by comparing their signatures
+ */
+bool
+same_x509cert(const x509cert_t *a, const x509cert_t *b)
+{
+ return same_chunk(a->signature, b->signature);
+}
+
+/* for each link pointing to the certificate
+ " increase the count by one
+ */
+void
+share_x509cert(x509cert_t *cert)
+{
+ if (cert != NULL)
+ cert->count++;
+}
+
+/*
+ * add a X.509 user/host certificate to the chained list
+ */
+x509cert_t*
+add_x509cert(x509cert_t *cert)
+{
+ x509cert_t *c = x509certs;
+
+ while (c != NULL)
+ {
+ if (same_x509cert(c, cert)) /* already in chain, free cert */
+ {
+ free_x509cert(cert);
+ return c;
+ }
+ c = c->next;
+ }
+
+ /* insert new cert at the root of the chain */
+ lock_certs_and_keys("add_x509cert");
+ cert->next = x509certs;
+ x509certs = cert;
+ DBG(DBG_CONTROL | DBG_PARSING,
+ DBG_log(" x509 cert inserted")
+ )
+ unlock_certs_and_keys("add_x509cert");
+ return cert;
+}
+
+/*
+ * choose either subject DN or a subjectAltName as connection end ID
+ */
+void
+select_x509cert_id(x509cert_t *cert, struct id *end_id)
+{
+ bool copy_subject_dn = TRUE; /* ID is subject DN */
+
+ if (end_id->kind != ID_NONE) /* check for matching subjectAltName */
+ {
+ generalName_t *gn = cert->subjectAltName;
+
+ while (gn != NULL)
+ {
+ struct id id = empty_id;
+
+ gntoid(&id, gn);
+ if (same_id(&id, end_id))
+ {
+ copy_subject_dn = FALSE; /* take subjectAltName instead */
+ break;
+ }
+ gn = gn->next;
+ }
+ }
+
+ if (copy_subject_dn)
+ {
+ if (end_id->kind != ID_NONE && end_id->kind != ID_DER_ASN1_DN)
+ {
+ char buf[BUF_LEN];
+
+ idtoa(end_id, buf, BUF_LEN);
+ plog(" no subjectAltName matches ID '%s', replaced by subject DN", buf);
+ }
+ end_id->kind = ID_DER_ASN1_DN;
+ end_id->name.len = cert->subject.len;
+ end_id->name.ptr = temporary_cyclic_buffer();
+ memcpy(end_id->name.ptr, cert->subject.ptr, cert->subject.len);
+ }
+}
+
+/*
+ * check for equality between two key identifiers
+ */
+bool
+same_keyid(chunk_t a, chunk_t b)
+{
+ if (a.ptr == NULL || b.ptr == NULL)
+ return FALSE;
+
+ return same_chunk(a, b);
+}
+
+/*
+ * check for equality between two serial numbers
+ */
+bool
+same_serial(chunk_t a, chunk_t b)
+{
+ /* do not compare serial numbers if one of them is not defined */
+ if (a.ptr == NULL || b.ptr == NULL)
+ return TRUE;
+
+ return same_chunk(a, b);
+}
+
+/*
+ * get a X.509 certificate with a given issuer found at a certain position
+ */
+x509cert_t*
+get_x509cert(chunk_t issuer, chunk_t serial, chunk_t keyid, x509cert_t *chain)
+{
+ x509cert_t *cert = (chain != NULL)? chain->next : x509certs;
+
+ while (cert != NULL)
+ {
+ if ((keyid.ptr != NULL) ? same_keyid(keyid, cert->authKeyID)
+ : (same_dn(issuer, cert->issuer)
+ && same_serial(serial, cert->authKeySerialNumber)))
+ {
+ return cert;
+ }
+ cert = cert->next;
+ }
+ return NULL;
+}
+
+/*
+ * 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)
+ {
+ chunkcpy(pos, gn->name);
+ gn = gn->next;
+ }
+
+ return asn1_wrap(ASN1_SEQUENCE, "cm"
+ , ASN1_subjectAltName_oid
+ , asn1_wrap(ASN1_OCTET_STRING, "m", names));
+}
+
+/*
+ * build a to-be-signed X.509 certificate body
+ */
+static chunk_t
+build_tbs_x509cert(x509cert_t *cert, const RSA_public_key_t *rsa)
+{
+ /* version is always X.509v3 */
+ chunk_t version = asn1_simple_object(ASN1_CONTEXT_C_0, ASN1_INTEGER_2);
+
+ chunk_t extensions = empty_chunk;
+
+ if (cert->subjectAltName != NULL)
+ {
+ extensions = asn1_wrap(ASN1_CONTEXT_C_3, "m"
+ , asn1_wrap(ASN1_SEQUENCE, "m"
+ , build_subjectAltNames(cert->subjectAltName)));
+ }
+
+ return asn1_wrap(ASN1_SEQUENCE, "mmccmcmm"
+ , version
+ , asn1_simple_object(ASN1_INTEGER, cert->serialNumber)
+ , asn1_algorithmIdentifier(cert->sigAlg)
+ , cert->issuer
+ , asn1_wrap(ASN1_SEQUENCE, "mm"
+ , timetoasn1(&cert->notBefore, ASN1_UTCTIME)
+ , timetoasn1(&cert->notAfter, ASN1_UTCTIME)
+ )
+ , cert->subject
+ , pkcs1_build_publicKeyInfo(rsa)
+ , extensions
+ );
+}
+
+/*
+ * build a DER-encoded X.509 certificate
+ */
+void
+build_x509cert(x509cert_t *cert, const RSA_public_key_t *cert_key
+, const RSA_private_key_t *signer_key)
+{
+ chunk_t tbs_cert = build_tbs_x509cert(cert, cert_key);
+
+ chunk_t signature = pkcs1_build_signature(tbs_cert, cert->sigAlg
+ , signer_key, TRUE);
+
+ cert->certificate = asn1_wrap(ASN1_SEQUENCE, "mcm"
+ , tbs_cert
+ , asn1_algorithmIdentifier(cert->sigAlg)
+ , signature);
+}
+
+/*
+ * 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)
+ {
+ pfree(gn->name.ptr);
+ }
+ gn = gn->next;
+ pfree(gn_top);
+ }
+}
+
+/*
+ * free a X.509 certificate
+ */
+void
+free_x509cert(x509cert_t *cert)
+{
+ if (cert != NULL)
+ {
+ free_generalNames(cert->subjectAltName, FALSE);
+ free_generalNames(cert->crlDistributionPoints, FALSE);
+ pfreeany(cert->certificate.ptr);
+ pfree(cert);
+ cert = NULL;
+ }
+}
+
+/* release of a certificate decreases the count by one
+ " the certificate is freed when the counter reaches zero
+ */
+void
+release_x509cert(x509cert_t *cert)
+{
+ if (cert != NULL && --cert->count == 0)
+ {
+ x509cert_t **pp = &x509certs;
+ while (*pp != cert)
+ pp = &(*pp)->next;
+ *pp = cert->next;
+ free_x509cert(cert);
+ }
+}
+
+
+/*
+ * stores a chained list of end certs and CA certs
+ */
+void
+store_x509certs(x509cert_t **firstcert, bool strict)
+{
+ x509cert_t *cacerts = NULL;
+ x509cert_t **pp = firstcert;
+
+ /* first extract CA certs, discarding root CA certs */
+
+ while (*pp != NULL)
+ {
+ x509cert_t *cert = *pp;
+
+ if (cert->isCA)
+ {
+ *pp = cert->next;
+
+ /* we don't accept self-signed CA certs */
+ if (same_dn(cert->issuer, cert->subject))
+ {
+ plog("self-signed cacert rejected");
+ free_x509cert(cert);
+ }
+ else
+ {
+ /* insertion into temporary chain of candidate CA certs */
+ cert->next = cacerts;
+ cacerts = cert;
+ }
+ }
+ else
+ pp = &cert->next;
+ }
+
+ /* now verify the candidate CA certs */
+
+ while (cacerts != NULL)
+ {
+ x509cert_t *cert = cacerts;
+
+ cacerts = cacerts->next;
+
+ if (trust_authcert_candidate(cert, cacerts))
+ {
+ add_authcert(cert, AUTH_CA);
+ }
+ else
+ {
+ plog("intermediate cacert rejected");
+ free_x509cert(cert);
+ }
+ }
+
+ /* now verify the end certificates */
+
+ pp = firstcert;
+
+ while (*pp != NULL)
+ {
+ time_t valid_until;
+ x509cert_t *cert = *pp;
+
+ if (verify_x509cert(cert, strict, &valid_until))
+ {
+ DBG(DBG_CONTROL | DBG_PARSING,
+ DBG_log("public key validated")
+ )
+ add_x509_public_key(cert, valid_until, DAL_SIGNED);
+ }
+ else
+ {
+ plog("X.509 certificate rejected");
+ }
+ *pp = cert->next;
+ free_x509cert(cert);
+ }
+}
+
+/*
+ * decrypts an RSA signature using the issuer's certificate
+ */
+static bool
+decrypt_sig(chunk_t sig, int alg, const x509cert_t *issuer_cert,
+ chunk_t *digest)
+{
+ switch (alg)
+ {
+ chunk_t decrypted;
+
+ case OID_RSA_ENCRYPTION:
+ case OID_MD2_WITH_RSA:
+ case OID_MD5_WITH_RSA:
+ case OID_SHA1_WITH_RSA:
+ case OID_SHA1_WITH_RSA_OIW:
+ case OID_SHA256_WITH_RSA:
+ case OID_SHA384_WITH_RSA:
+ case OID_SHA512_WITH_RSA:
+ {
+ mpz_t s;
+ RSA_public_key_t rsa;
+
+ init_RSA_public_key(&rsa, issuer_cert->publicExponent
+ , issuer_cert->modulus);
+
+ /* decrypt the signature s = s^e mod n */
+ n_to_mpz(s, sig.ptr, sig.len);
+ mpz_powm(s, s, &rsa.e, &rsa.n);
+
+ /* convert back to bytes */
+ decrypted = mpz_to_n(s, rsa.k);
+ DBG(DBG_PARSING,
+ DBG_dump_chunk(" decrypted signature: ", decrypted)
+ )
+
+ /* copy the least significant bits of decrypted signature
+ * into the digest string
+ */
+ memcpy(digest->ptr, decrypted.ptr + decrypted.len - digest->len,
+ digest->len);
+
+ /* free memory */
+ free_RSA_public_content(&rsa);
+ pfree(decrypted.ptr);
+ mpz_clear(s);
+ return TRUE;
+ }
+ default:
+ digest->len = 0;
+ return FALSE;
+ }
+}
+
+/*
+ * Check if a signature over binary blob is genuine
+ */
+bool
+check_signature(chunk_t tbs, chunk_t sig, int digest_alg, int enc_alg
+, const x509cert_t *issuer_cert)
+{
+ u_char digest_buf[MAX_DIGEST_LEN];
+ u_char decrypted_buf[MAX_DIGEST_LEN];
+ chunk_t digest = {digest_buf, MAX_DIGEST_LEN};
+ chunk_t decrypted = {decrypted_buf, MAX_DIGEST_LEN};
+
+ DBG(DBG_PARSING,
+ if (digest_alg != OID_UNKNOWN)
+ DBG_log("signature digest algorithm: '%s'",oid_names[digest_alg].name);
+ else
+ DBG_log("unknown signature digest algorithm");
+ )
+
+ if (!compute_digest(tbs, digest_alg, &digest))
+ {
+ plog(" digest algorithm not supported");
+ return FALSE;
+ }
+
+ DBG(DBG_PARSING,
+ DBG_dump_chunk(" digest:", digest)
+ )
+
+ decrypted.len = digest.len; /* we want the same digest length */
+
+ DBG(DBG_PARSING,
+ if (enc_alg != OID_UNKNOWN)
+ DBG_log("signature encryption algorithm: '%s'",oid_names[enc_alg].name);
+ else
+ DBG_log("unknown signature encryption algorithm");
+ )
+
+ if (!decrypt_sig(sig, enc_alg, issuer_cert, &decrypted))
+ {
+ plog(" decryption algorithm not supported");
+ return FALSE;
+ }
+
+ /* check if digests are equal */
+ return !memcmp(decrypted.ptr, digest.ptr, digest.len);
+}
+
+/*
+ * 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, DBG_RAW);
+
+ while (objectID < BASIC_CONSTRAINTS_ROOF) {
+
+ if (!extract_object(basicConstraintsObjects, &objectID,
+ &object,&level, &ctx))
+ break;
+
+ if (objectID == BASIC_CONSTRAINTS_CA)
+ {
+ isCA = object.len && *object.ptr;
+ DBG(DBG_PARSING,
+ DBG_log(" %s",(isCA)?"TRUE":"FALSE");
+ )
+ }
+ objectID++;
+ }
+ return isCA;
+}
+
+/*
+ * Converts a X.500 generalName into an ID
+ */
+void
+gntoid(struct id *id, const generalName_t *gn)
+{
+ switch(gn->kind)
+ {
+ case GN_DNS_NAME: /* ID type: ID_FQDN */
+ id->kind = ID_FQDN;
+ id->name = gn->name;
+ break;
+ case GN_IP_ADDRESS: /* ID type: ID_IPV4_ADDR */
+ {
+ const struct af_info *afi = &af_inet4_info;
+ err_t ugh = NULL;
+
+ id->kind = afi->id_addr;
+ ugh = initaddr(gn->name.ptr, gn->name.len, afi->af, &id->ip_addr);
+ }
+ break;
+ case GN_RFC822_NAME: /* ID type: ID_USER_FQDN */
+ id->kind = ID_USER_FQDN;
+ id->name = gn->name;
+ break;
+ default:
+ id->kind = ID_NONE;
+ id->name = empty_chunk;
+ }
+}
+
+/* compute the subjectKeyIdentifier according to section 4.2.1.2 of RFC 3280
+ * as the 160 bit SHA-1 hash of the public key
+ */
+void
+compute_subjectKeyID(x509cert_t *cert, chunk_t subjectKeyID)
+{
+ SHA1_CTX context;
+
+ SHA1Init(&context);
+ SHA1Update(&context
+ , cert->subjectPublicKey.ptr
+ , cert->subjectPublicKey.len);
+ SHA1Final(subjectKeyID.ptr, &context);
+ subjectKeyID.len = SHA1_DIGEST_SIZE;
+}
+
+/*
+ * extracts an otherName
+ */
+static bool
+parse_otherName(chunk_t blob, int level0)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ int objectID = 0;
+ u_int level;
+ int oid = OID_UNKNOWN;
+
+ asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
+
+ while (objectID < ON_OBJ_ROOF)
+ {
+ if (!extract_object(otherNameObjects, &objectID, &object, &level, &ctx))
+ return FALSE;
+
+ switch (objectID)
+ {
+ case ON_OBJ_ID_TYPE:
+ oid = known_oid(object);
+ break;
+ case ON_OBJ_VALUE:
+ if (oid == OID_XMPP_ADDR)
+ {
+ if (!parse_asn1_simple_object(&object, ASN1_UTF8STRING
+ , level + 1, "xmppAddr"))
+ {
+ return FALSE;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ objectID++;
+ }
+ return TRUE;
+}
+
+
+/*
+ * extracts a generalName
+ */
+static generalName_t*
+parse_generalName(chunk_t blob, int level0)
+{
+ u_char buf[BUF_LEN];
+ asn1_ctx_t ctx;
+ chunk_t object;
+ int objectID = 0;
+ u_int level;
+
+ asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
+
+ while (objectID < GN_OBJ_ROOF)
+ {
+ bool valid_gn = FALSE;
+
+ 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:
+ DBG(DBG_PARSING,
+ DBG_log(" '%.*s'", (int)object.len, object.ptr);
+ )
+ valid_gn = TRUE;
+ break;
+ case GN_OBJ_DIRECTORY_NAME:
+ DBG(DBG_PARSING,
+ dntoa(buf, BUF_LEN, object);
+ DBG_log(" '%s'", buf)
+ )
+ valid_gn = TRUE;
+ break;
+ case GN_OBJ_IP_ADDRESS:
+ DBG(DBG_PARSING,
+ DBG_log(" '%d.%d.%d.%d'", *object.ptr, *(object.ptr+1),
+ *(object.ptr+2), *(object.ptr+3));
+ )
+ valid_gn = TRUE;
+ break;
+ case GN_OBJ_OTHER_NAME:
+ if (!parse_otherName(object, level + 1))
+ return NULL;
+ break;
+ case GN_OBJ_X400_ADDRESS:
+ case GN_OBJ_EDI_PARTY_NAME:
+ case GN_OBJ_REGISTERED_ID:
+ break;
+ default:
+ break;
+ }
+
+ if (valid_gn)
+ {
+ generalName_t *gn = alloc_thing(generalName_t, "generalName");
+ gn->kind = (objectID - GN_OBJ_OTHER_NAME) / 2;
+ gn->name = object;
+ gn->next = NULL;
+ return gn;
+ }
+ objectID++;
+ }
+ return NULL;
+}
+
+
+/*
+ * extracts one or several GNs and puts them into a chained list
+ */
+static generalName_t*
+parse_generalNames(chunk_t blob, int level0, bool implicit)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+
+ generalName_t *top_gn = NULL;
+
+ asn1_init(&ctx, blob, level0, implicit, DBG_RAW);
+
+ while (objectID < GENERAL_NAMES_ROOF)
+ {
+ if (!extract_object(generalNamesObjects, &objectID, &object, &level, &ctx))
+ return NULL;
+
+ if (objectID == GENERAL_NAMES_GN)
+ {
+ generalName_t *gn = parse_generalName(object, level+1);
+ if (gn != NULL)
+ {
+ gn->next = top_gn;
+ top_gn = gn;
+ }
+ }
+ objectID++;
+ }
+ return top_gn;
+}
+
+/*
+ * returns a directoryName
+ */
+chunk_t get_directoryName(chunk_t blob, int level, bool implicit)
+{
+ chunk_t name = empty_chunk;
+ generalName_t * gn = parse_generalNames(blob, level, implicit);
+
+ if (gn != NULL && gn->kind == GN_DIRECTORY_NAME)
+ name= gn->name;
+
+ free_generalNames(gn, FALSE);
+
+ return name;
+}
+
+/*
+ * 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, DBG_RAW);
+
+ while (objectID < TIME_ROOF)
+ {
+ if (!extract_object(timeObjects, &objectID, &object, &level, &ctx))
+ return UNDEFINED_TIME;
+
+ if (objectID == TIME_UTC || objectID == TIME_GENERALIZED)
+ {
+ return asn1totime(&object, (objectID == TIME_UTC)
+ ? ASN1_UTCTIME : ASN1_GENERALIZEDTIME);
+ }
+ objectID++;
+ }
+ return UNDEFINED_TIME;
+ }
+
+/*
+ * 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, DBG_RAW);
+
+ 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, DBG_RAW);
+
+ 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:
+ {
+ generalName_t * gn = parse_generalNames(object, level+1, TRUE);
+
+ free_generalNames(gn, FALSE);
+ }
+ 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, DBG_RAW);
+
+ 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;
+
+ DBG(DBG_PARSING,
+ DBG_log(" '%.*s'",(int)object.len, object.ptr)
+ )
+
+ /* only HTTP(S) URIs accepted */
+ if (strncasecmp(object.ptr, "http", 4) == 0)
+ {
+ *accessLocation = object;
+ return;
+ }
+ }
+ plog("warning: 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, DBG_RAW);
+
+ 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 generalName_t*
+parse_crlDistributionPoints(chunk_t blob, int level0)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+
+ generalName_t *top_gn = NULL; /* top of the chained list */
+ generalName_t **tail_gn = &top_gn; /* tail of the chained list */
+
+ asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
+
+ while (objectID < CRL_DIST_POINTS_ROOF)
+ {
+ if (!extract_object(crlDistributionPointsObjects, &objectID,
+ &object, &level, &ctx))
+ return NULL;
+
+ if (objectID == CRL_DIST_POINTS_FULLNAME)
+ {
+ generalName_t *gn = parse_generalNames(object, level+1, TRUE);
+ /* append extracted generalNames to existing chained list */
+ *tail_gn = gn;
+ /* find new tail of the chained list */
+ while (gn != NULL)
+ {
+ tail_gn = &gn->next; gn = gn->next;
+ }
+ }
+ objectID++;
+ }
+ return top_gn;
+}
+
+
+/*
+ * Parses an X.509v3 certificate
+ */
+bool
+parse_x509cert(chunk_t blob, u_int level0, x509cert_t *cert)
+{
+ u_char buf[BUF_LEN];
+ 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, DBG_RAW);
+
+ 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->certificate = 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;
+ DBG(DBG_PARSING,
+ DBG_log(" 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 = object;
+ DBG(DBG_PARSING,
+ dntoa(buf, BUF_LEN, object);
+ DBG_log(" '%s'",buf)
+ )
+ 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 = object;
+ DBG(DBG_PARSING,
+ dntoa(buf, BUF_LEN, object);
+ DBG_log(" '%s'",buf)
+ )
+ break;
+ case X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM:
+ if (parse_algorithmIdentifier(object, level, NULL) == OID_RSA_ENCRYPTION)
+ cert->subjectPublicKeyAlgorithm = PUBKEY_ALG_RSA;
+ else
+ {
+ plog(" 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
+ {
+ plog(" invalid RSA public key format");
+ return FALSE;
+ }
+ break;
+ case X509_OBJ_RSA_PUBLIC_KEY:
+ cert->subjectPublicKey = object;
+ break;
+ case X509_OBJ_MODULUS:
+ if (object.len < RSA_MIN_OCTETS + 1)
+ {
+ plog(" " RSA_MIN_OCTETS_UGH);
+ return FALSE;
+ }
+ if (object.len > RSA_MAX_OCTETS + (size_t)(*object.ptr == 0x00))
+ {
+ plog(" " RSA_MAX_OCTETS_UGH);
+ return FALSE;
+ }
+ cert->modulus = object;
+ break;
+ case X509_OBJ_PUBLIC_EXPONENT:
+ cert->publicExponent = object;
+ break;
+ case X509_OBJ_EXTN_ID:
+ extn_oid = known_oid(object);
+ break;
+ case X509_OBJ_CRITICAL:
+ critical = object.len && *object.ptr;
+ DBG(DBG_PARSING,
+ DBG_log(" %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:
+ cert->subjectAltName =
+ parse_generalNames(object, level, FALSE);
+ break;
+ case OID_BASIC_CONSTRAINTS:
+ cert->isCA =
+ parse_basicConstraints(object, level);
+ break;
+ case OID_CRL_DISTRIBUTION_POINTS:
+ cert->crlDistributionPoints =
+ parse_crlDistributionPoints(object, level);
+ 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 certificate by
+ * checking the notBefore and notAfter dates
+ */
+err_t
+check_validity(const x509cert_t *cert, time_t *until)
+{
+ time_t current_time;
+
+ time(&current_time);
+ DBG(DBG_CONTROL | DBG_PARSING ,
+ DBG_log(" not before : %s", timetoa(&cert->notBefore, TRUE));
+ DBG_log(" current time: %s", timetoa(&current_time, TRUE));
+ DBG_log(" not after : %s", timetoa(&cert->notAfter, TRUE));
+ )
+
+ if (cert->notAfter < *until) *until = cert->notAfter;
+
+ if (current_time < cert->notBefore)
+ return "certificate is not valid yet";
+ if (current_time > cert->notAfter)
+ return "certificate has expired";
+ else
+ return NULL;
+}
+
+/*
+ * verifies a X.509 certificate
+ */
+bool
+verify_x509cert(const x509cert_t *cert, bool strict, time_t *until)
+{
+ int pathlen;
+
+ *until = cert->notAfter;
+
+ for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++)
+ {
+ x509cert_t *issuer_cert;
+ u_char buf[BUF_LEN];
+ err_t ugh = NULL;
+
+ DBG(DBG_CONTROL,
+ dntoa(buf, BUF_LEN, cert->subject);
+ DBG_log("subject: '%s'",buf);
+ dntoa(buf, BUF_LEN, cert->issuer);
+ DBG_log("issuer: '%s'",buf);
+ if (cert->authKeyID.ptr != NULL)
+ {
+ datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':'
+ , buf, BUF_LEN);
+ DBG_log("authkey: %s", buf);
+ }
+ )
+
+ ugh = check_validity(cert, until);
+
+ if (ugh != NULL)
+ {
+ plog("%s", ugh);
+ return FALSE;
+ }
+
+ DBG(DBG_CONTROL,
+ DBG_log("certificate is valid")
+ )
+
+ lock_authcert_list("verify_x509cert");
+ issuer_cert = get_authcert(cert->issuer, cert->authKeySerialNumber
+ , cert->authKeyID, AUTH_CA);
+
+ if (issuer_cert == NULL)
+ {
+ plog("issuer cacert not found");
+ unlock_authcert_list("verify_x509cert");
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("issuer cacert found")
+ )
+
+ if (!check_signature(cert->tbsCertificate, cert->signature
+ , cert->algorithm, cert->algorithm, issuer_cert))
+ {
+ plog("certificate signature is invalid");
+ unlock_authcert_list("verify_x509cert");
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("certificate signature is valid")
+ )
+ unlock_authcert_list("verify_x509cert");
+
+ /* check if cert is a self-signed root ca */
+ if (pathlen > 0 && same_dn(cert->issuer, cert->subject))
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("reached self-signed root ca")
+ )
+ return TRUE;
+ }
+ else
+ {
+ time_t nextUpdate = *until;
+ time_t revocationDate = UNDEFINED_TIME;
+ crl_reason_t revocationReason = REASON_UNSPECIFIED;
+
+ /* first check certificate revocation using ocsp */
+ cert_status_t status = verify_by_ocsp(cert, &nextUpdate
+ , &revocationDate, &revocationReason);
+
+ /* if ocsp service is not available then fall back to crl */
+ if ((status == CERT_UNDEFINED)
+ || (status == CERT_UNKNOWN && strict))
+ {
+ status = verify_by_crl(cert, &nextUpdate, &revocationDate
+ , &revocationReason);
+ }
+
+ switch (status)
+ {
+ case CERT_GOOD:
+ /* if status information is stale */
+ if (strict && nextUpdate < time(NULL))
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("certificate is good but status is stale")
+ )
+ remove_x509_public_key(cert);
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("certificate is good")
+ )
+
+ /* with strict crl policy the public key must have the same
+ * lifetime as the validity of the ocsp status or crl lifetime
+ */
+ if (strict && nextUpdate < *until)
+ *until = nextUpdate;
+ break;
+ case CERT_REVOKED:
+ plog("certificate was revoked on %s, reason: %s"
+ , timetoa(&revocationDate, TRUE)
+ , enum_name(&crl_reason_names, revocationReason));
+ remove_x509_public_key(cert);
+ return FALSE;
+ case CERT_UNKNOWN:
+ case CERT_UNDEFINED:
+ default:
+ plog("certificate status unknown");
+ if (strict)
+ {
+ remove_x509_public_key(cert);
+ return FALSE;
+ }
+ break;
+ }
+ }
+
+ /* go up one step in the trust chain */
+ cert = issuer_cert;
+ }
+ plog("maximum ca path length of %d levels exceeded", MAX_CA_PATH_LEN);
+ return FALSE;
+}
+
+/*
+ * list all X.509 certs in a chained list
+ */
+void
+list_x509cert_chain(const char *caption, x509cert_t* cert, u_char auth_flags
+ , bool utc)
+{
+ bool first = TRUE;
+ time_t now;
+
+ /* determine the current time */
+ time(&now);
+
+ while (cert != NULL)
+ {
+ if (auth_flags == AUTH_NONE || (auth_flags & cert->authority_flags))
+ {
+ unsigned keysize;
+ char keyid[KEYID_BUF];
+ u_char buf[BUF_LEN];
+ cert_t c;
+
+ c.type = CERT_X509_SIGNATURE;
+ c.u.x509 = cert;
+
+ if (first)
+ {
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of X.509 %s Certificates:", caption);
+ whack_log(RC_COMMENT, " ");
+ first = FALSE;
+ }
+
+ whack_log(RC_COMMENT, "%s, count: %d", timetoa(&cert->installed, utc),
+ cert->count);
+ dntoa(buf, BUF_LEN, cert->subject);
+ whack_log(RC_COMMENT, " subject: '%s'", buf);
+ dntoa(buf, BUF_LEN, cert->issuer);
+ whack_log(RC_COMMENT, " issuer: '%s'", buf);
+ datatot(cert->serialNumber.ptr, cert->serialNumber.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " serial: %s", buf);
+ form_keyid(cert->publicExponent, cert->modulus, keyid, &keysize);
+ whack_log(RC_COMMENT, " pubkey: %4d RSA Key %s%s"
+ , 8*keysize, keyid
+ , cert->smartcard ? ", on smartcard" :
+ (has_private_key(c)? ", has private key" : ""));
+ whack_log(RC_COMMENT, " validity: not before %s %s",
+ timetoa(&cert->notBefore, utc),
+ (cert->notBefore < now)?"ok":"fatal (not valid yet)");
+ whack_log(RC_COMMENT, " not after %s %s",
+ timetoa(&cert->notAfter, utc),
+ check_expiry(cert->notAfter, CA_CERT_WARNING_INTERVAL, TRUE));
+ if (cert->subjectKeyID.ptr != NULL)
+ {
+ datatot(cert->subjectKeyID.ptr, cert->subjectKeyID.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " subjkey: %s", buf);
+ }
+ if (cert->authKeyID.ptr != NULL)
+ {
+ datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " authkey: %s", buf);
+ }
+ if (cert->authKeySerialNumber.ptr != NULL)
+ {
+ datatot(cert->authKeySerialNumber.ptr, cert->authKeySerialNumber.len
+ , ':', buf, BUF_LEN);
+ whack_log(RC_COMMENT, " aserial: %s", buf);
+ }
+ }
+ cert = cert->next;
+ }
+}
+
+/*
+ * list all X.509 end certificates in a chained list
+ */
+void
+list_x509_end_certs(bool utc)
+{
+ list_x509cert_chain("End", x509certs, AUTH_NONE, utc);
+}
diff --git a/src/pluto/x509.h b/src/pluto/x509.h
new file mode 100644
index 000000000..d15b3da53
--- /dev/null
+++ b/src/pluto/x509.h
@@ -0,0 +1,138 @@
+/* Support of X.509 certificates
+ * Copyright (C) 2000 Andreas Hess, Patric Lichtsteiner, Roger Wegmann
+ * Copyright (C) 2001 Marco Bertossa, Andreas Schleiss
+ * Copyright (C) 2002 Mario Strasser
+ * Copyright (C) 2000-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.
+ *
+ * RCSID $Id: x509.h,v 1.10 2005/12/06 22:52:44 as Exp $
+ */
+
+#ifndef _X509_H
+#define _X509_H
+
+#include "pkcs1.h"
+#include "id.h"
+
+/* Definition of generalNames kinds */
+
+typedef enum {
+ GN_OTHER_NAME = 0,
+ GN_RFC822_NAME = 1,
+ GN_DNS_NAME = 2,
+ GN_X400_ADDRESS = 3,
+ GN_DIRECTORY_NAME = 4,
+ GN_EDI_PARTY_NAME = 5,
+ GN_URI = 6,
+ GN_IP_ADDRESS = 7,
+ GN_REGISTERED_ID = 8
+} generalNames_t;
+
+/* access structure for a GeneralName */
+
+typedef struct generalName generalName_t;
+
+struct generalName {
+ generalName_t *next;
+ generalNames_t kind;
+ chunk_t name;
+};
+
+/* access structure for an X.509v3 certificate */
+
+typedef struct x509cert x509cert_t;
+
+struct x509cert {
+ x509cert_t *next;
+ time_t installed;
+ int count;
+ bool smartcard;
+ u_char authority_flags;
+ chunk_t certificate;
+ chunk_t tbsCertificate;
+ u_int version;
+ chunk_t serialNumber;
+ /* signature */
+ int sigAlg;
+ chunk_t issuer;
+ /* validity */
+ time_t notBefore;
+ time_t notAfter;
+ chunk_t subject;
+ /* subjectPublicKeyInfo */
+ enum pubkey_alg subjectPublicKeyAlgorithm;
+ chunk_t subjectPublicKey;
+ chunk_t modulus;
+ chunk_t publicExponent;
+ /* 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 */
+ generalName_t *subjectAltName;
+ generalName_t *crlDistributionPoints;
+ /* signatureAlgorithm */
+ int algorithm;
+ chunk_t signature;
+};
+
+/* used for initialization */
+extern const x509cert_t empty_x509cert;
+
+extern bool same_serial(chunk_t a, chunk_t b);
+extern bool same_keyid(chunk_t a, chunk_t b);
+extern bool same_dn(chunk_t a, chunk_t b);
+extern bool match_dn(chunk_t a, chunk_t b, int *wildcards);
+extern bool same_x509cert(const x509cert_t *a, const x509cert_t *b);
+extern void hex_str(chunk_t bin, chunk_t *str);
+extern int dn_count_wildcards(chunk_t dn);
+extern int dntoa(char *dst, size_t dstlen, chunk_t dn);
+extern int dntoa_or_null(char *dst, size_t dstlen, chunk_t dn
+ , const char* null_dn);
+extern err_t atodn(char *src, chunk_t *dn);
+extern void gntoid(struct id *id, const generalName_t *gn);
+extern void compute_subjectKeyID(x509cert_t *cert, chunk_t subjectKeyID);
+extern void select_x509cert_id(x509cert_t *cert, struct id *end_id);
+extern bool parse_x509cert(chunk_t blob, u_int level0, x509cert_t *cert);
+extern time_t parse_time(chunk_t blob, int level0);
+extern void parse_authorityKeyIdentifier(chunk_t blob, int level0
+ , chunk_t *authKeyID, chunk_t *authKeySerialNumber);
+extern chunk_t get_directoryName(chunk_t blob, int level, bool implicit);
+extern err_t check_validity(const x509cert_t *cert, time_t *until);
+extern bool check_signature(chunk_t tbs, chunk_t sig, int digest_alg
+ , int enc_alg, const x509cert_t *issuer_cert);
+extern bool verify_x509cert(const x509cert_t *cert, bool strict, time_t *until);
+extern x509cert_t* add_x509cert(x509cert_t *cert);
+extern x509cert_t* get_x509cert(chunk_t issuer, chunk_t serial, chunk_t keyid
+ , x509cert_t* chain);
+extern void build_x509cert(x509cert_t *cert, const RSA_public_key_t *cert_key
+ , const RSA_private_key_t *signer_key);
+extern chunk_t build_subjectAltNames(generalName_t *subjectAltNames);
+extern void share_x509cert(x509cert_t *cert);
+extern void release_x509cert(x509cert_t *cert);
+extern void free_x509cert(x509cert_t *cert);
+extern void store_x509certs(x509cert_t **firstcert, bool strict);
+extern void list_x509cert_chain(const char *caption, x509cert_t* cert
+ , u_char auth_flags, bool utc);
+extern void list_x509_end_certs(bool utc);
+extern void free_generalNames(generalName_t* gn, bool free_name);
+
+#endif /* _X509_H */
diff --git a/src/pluto/xauth.c b/src/pluto/xauth.c
new file mode 100644
index 000000000..3d30ad227
--- /dev/null
+++ b/src/pluto/xauth.c
@@ -0,0 +1,79 @@
+/* Initialization and finalization of the dynamic XAUTH module
+ * Copyright (C) 2006 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil, Switzerland
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: xauth.c,v 1.1 2005/01/06 22:10:15 as Exp $
+ */
+
+#include <dlfcn.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "xauth.h"
+#include "keys.h"
+#include "log.h"
+
+void
+xauth_init(void)
+{
+#ifdef XAUTH_DEFAULT_LIB
+ xauth_module.handle = dlopen(XAUTH_DEFAULT_LIB, RTLD_NOW);
+
+ if (xauth_module.handle != NULL)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("xauth module '%s' loading'", XAUTH_DEFAULT_LIB)
+ )
+ xauth_module.get_secret = (bool (*) (const xauth_t*))
+ dlsym(xauth_module.handle, "get_secret");
+ DBG(DBG_CONTROL,
+ if (xauth_module.get_secret != NULL)
+ {
+ DBG_log("xauth module: found get_secret() function");
+ }
+ )
+ xauth_module.verify_secret = (bool (*) (const xauth_t*))
+ dlsym(xauth_module.handle, "verify_secret");
+ DBG(DBG_CONTROL,
+ if (xauth_module.verify_secret != NULL)
+ {
+ DBG_log("xauth module: found verify_secret() function");
+ }
+ )
+ }
+#endif
+ /* any null function pointers will be filled in by default functions */
+ xauth_defaults();
+}
+
+void
+xauth_finalize(void)
+{
+#ifdef XAUTH_DEFAULT_LIB
+ if (xauth_module.handle != NULL)
+ {
+ if (dlclose(xauth_module.handle))
+ {
+ plog("failed to unload xauth module");
+ }
+ else
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("xauth module unloaded")
+ )
+ }
+ }
+#endif
+}
diff --git a/src/pluto/xauth.h b/src/pluto/xauth.h
new file mode 100644
index 000000000..1f06aefd9
--- /dev/null
+++ b/src/pluto/xauth.h
@@ -0,0 +1,41 @@
+/* Interface definition of the XAUTH server and|or client module
+ * Copyright (C) 2006 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil, Switzerland
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: xauth.h,v 1.1 2005/01/06 22:10:15 as Exp $
+ */
+
+#ifndef _XAUTH_H
+#define _XAUTH_H
+
+/* XAUTH credentials */
+
+struct chunk_t;
+
+typedef struct {
+ chunk_t user_name;
+ chunk_t user_password;
+} xauth_t;
+
+typedef struct {
+ void *handle;
+ bool (*get_secret) (xauth_t *xauth_secret);
+ bool (*verify_secret) (const xauth_t *xauth_secret);
+} xauth_module_t;
+
+extern xauth_module_t xauth_module;
+
+extern void xauth_init(void);
+extern void xauth_finalize(void);
+
+#endif /* _XAUTH_H */
diff --git a/src/scepclient/Makefile.am b/src/scepclient/Makefile.am
new file mode 100644
index 000000000..a4de3bc58
--- /dev/null
+++ b/src/scepclient/Makefile.am
@@ -0,0 +1,103 @@
+ipsec_PROGRAMS = scepclient
+scepclient_SOURCES = rsakey.c rsakey.h pkcs10.c pkcs10.h scep.c scep.h scepclient.c
+
+INCLUDES = \
+-I$(top_srcdir)/src/libfreeswan \
+-I$(top_srcdir)/src/pluto \
+-I$(top_srcdir)/src/whack \
+-I$(top_srcdir)/src/libcrypto
+
+AM_CFLAGS = -DDEBUG -DNO_PLUTO -DIPSEC_CONFDIR=\"${confdir}\"
+scepclient_LDADD = asn1.o ca.o crl.o certs.o constants.o defs.o fetch.o id.o \
+ keys.o lex.o md2.o md5.o mp_defs.o ocsp.o oid.o pem.o pgp.o \
+ pkcs1.o pkcs7.o rnd.o sha1.o smartcard.o x509.o loglite.o \
+ $(top_srcdir)/src/libfreeswan/libfreeswan.a $(top_srcdir)/src/libcrypto/libcrypto.a \
+ -lgmp
+
+# This compile option activates dynamic URL fetching using libcurl
+if USE_LIBCURL
+ scepclient_LDADD += -lcurl
+endif
+
+# This compile option activates smartcard support
+if USE_SMARTCARD
+ scepclient_LDADD += -ldl
+endif
+
+dist_man_MANS = scepclient.8
+
+PLUTODIR=$(top_srcdir)/src/pluto
+OPENACDIR=$(top_srcdir)/src/openac
+
+
+loglite.o: $(OPENACDIR)/loglite.c $(PLUTODIR)/log.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+asn1.o : $(PLUTODIR)/asn1.c $(PLUTODIR)/asn1.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+ca.o : $(PLUTODIR)/ca.c $(PLUTODIR)/ca.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+certs.o : $(PLUTODIR)/certs.c $(PLUTODIR)/certs.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+constants.o : $(PLUTODIR)/constants.c $(PLUTODIR)/constants.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+crl.o : $(PLUTODIR)/crl.c $(PLUTODIR)/crl.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+defs.o : $(PLUTODIR)/defs.c $(PLUTODIR)/defs.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+mp_defs.o : $(PLUTODIR)/mp_defs.c $(PLUTODIR)/mp_defs.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+fetch.o : $(PLUTODIR)/fetch.c $(PLUTODIR)/fetch.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+id.o : $(PLUTODIR)/id.c $(PLUTODIR)/id.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+keys.o : $(PLUTODIR)/keys.c $(PLUTODIR)/keys.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+lex.o : $(PLUTODIR)/lex.c $(PLUTODIR)/lex.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+md2.o : $(PLUTODIR)/md2.c $(PLUTODIR)/md2.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+md5.o : $(PLUTODIR)/md5.c $(PLUTODIR)/md5.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+ocsp.o : $(PLUTODIR)/ocsp.c $(PLUTODIR)/ocsp.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+oid.o : $(PLUTODIR)/oid.c $(PLUTODIR)/oid.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+pem.o : $(PLUTODIR)/pem.c $(PLUTODIR)/pem.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+pgp.o : $(PLUTODIR)/pgp.c $(PLUTODIR)/pgp.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+pkcs1.o : $(PLUTODIR)/pkcs1.c $(PLUTODIR)/pkcs1.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+pkcs7.o : $(PLUTODIR)/pkcs7.c $(PLUTODIR)/pkcs7.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+rnd.o : $(PLUTODIR)/rnd.c $(PLUTODIR)/rnd.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+sha1.o : $(PLUTODIR)/sha1.c $(PLUTODIR)/sha1.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+smartcard.o : $(PLUTODIR)/smartcard.c $(PLUTODIR)/smartcard.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+x509.o : $(PLUTODIR)/x509.c $(PLUTODIR)/x509.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
diff --git a/src/scepclient/Makefile.in b/src/scepclient/Makefile.in
new file mode 100644
index 000000000..b21b9bf05
--- /dev/null
+++ b/src/scepclient/Makefile.in
@@ -0,0 +1,630 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+ipsec_PROGRAMS = scepclient$(EXEEXT)
+
+# This compile option activates dynamic URL fetching using libcurl
+@USE_LIBCURL_TRUE@am__append_1 = -lcurl
+
+# This compile option activates smartcard support
+@USE_SMARTCARD_TRUE@am__append_2 = -ldl
+subdir = src/scepclient
+DIST_COMMON = $(dist_man_MANS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_CLEAN_FILES =
+am__installdirs = "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(man8dir)"
+ipsecPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(ipsec_PROGRAMS)
+am_scepclient_OBJECTS = rsakey.$(OBJEXT) pkcs10.$(OBJEXT) \
+ scep.$(OBJEXT) scepclient.$(OBJEXT)
+scepclient_OBJECTS = $(am_scepclient_OBJECTS)
+am__DEPENDENCIES_1 =
+scepclient_DEPENDENCIES = asn1.o ca.o crl.o certs.o constants.o defs.o \
+ fetch.o id.o keys.o lex.o md2.o md5.o mp_defs.o ocsp.o oid.o \
+ pem.o pgp.o pkcs1.o pkcs7.o rnd.o sha1.o smartcard.o x509.o \
+ loglite.o $(top_srcdir)/src/libfreeswan/libfreeswan.a \
+ $(top_srcdir)/src/libcrypto/libcrypto.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+DEFAULT_INCLUDES = -I. -I$(srcdir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(scepclient_SOURCES)
+DIST_SOURCES = $(scepclient_SOURCES)
+man8dir = $(mandir)/man8
+NROFF = nroff
+MANS = $(dist_man_MANS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_EAP_SIM_FALSE = @BUILD_EAP_SIM_FALSE@
+BUILD_EAP_SIM_TRUE = @BUILD_EAP_SIM_TRUE@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GPERF = @GPERF@
+GREP = @GREP@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+USE_CISCO_QUIRKS_FALSE = @USE_CISCO_QUIRKS_FALSE@
+USE_CISCO_QUIRKS_TRUE = @USE_CISCO_QUIRKS_TRUE@
+USE_LEAK_DETECTIVE_FALSE = @USE_LEAK_DETECTIVE_FALSE@
+USE_LEAK_DETECTIVE_TRUE = @USE_LEAK_DETECTIVE_TRUE@
+USE_LIBCURL_FALSE = @USE_LIBCURL_FALSE@
+USE_LIBCURL_TRUE = @USE_LIBCURL_TRUE@
+USE_LIBLDAP_FALSE = @USE_LIBLDAP_FALSE@
+USE_LIBLDAP_TRUE = @USE_LIBLDAP_TRUE@
+USE_NAT_TRANSPORT_FALSE = @USE_NAT_TRANSPORT_FALSE@
+USE_NAT_TRANSPORT_TRUE = @USE_NAT_TRANSPORT_TRUE@
+USE_SMARTCARD_FALSE = @USE_SMARTCARD_FALSE@
+USE_SMARTCARD_TRUE = @USE_SMARTCARD_TRUE@
+USE_VENDORID_FALSE = @USE_VENDORID_FALSE@
+USE_VENDORID_TRUE = @USE_VENDORID_TRUE@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+confdir = @confdir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+eapdir = @eapdir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+ipsecdir = @ipsecdir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+piddir = @piddir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+scepclient_SOURCES = rsakey.c rsakey.h pkcs10.c pkcs10.h scep.c scep.h scepclient.c
+INCLUDES = \
+-I$(top_srcdir)/src/libfreeswan \
+-I$(top_srcdir)/src/pluto \
+-I$(top_srcdir)/src/whack \
+-I$(top_srcdir)/src/libcrypto
+
+AM_CFLAGS = -DDEBUG -DNO_PLUTO -DIPSEC_CONFDIR=\"${confdir}\"
+scepclient_LDADD = asn1.o ca.o crl.o certs.o constants.o defs.o \
+ fetch.o id.o keys.o lex.o md2.o md5.o mp_defs.o ocsp.o oid.o \
+ pem.o pgp.o pkcs1.o pkcs7.o rnd.o sha1.o smartcard.o x509.o \
+ loglite.o $(top_srcdir)/src/libfreeswan/libfreeswan.a \
+ $(top_srcdir)/src/libcrypto/libcrypto.a -lgmp $(am__append_1) \
+ $(am__append_2)
+dist_man_MANS = scepclient.8
+PLUTODIR = $(top_srcdir)/src/pluto
+OPENACDIR = $(top_srcdir)/src/openac
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/scepclient/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/scepclient/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-ipsecPROGRAMS: $(ipsec_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(ipsecdir)" || $(mkdir_p) "$(DESTDIR)$(ipsecdir)"
+ @list='$(ipsec_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ || test -f $$p1 \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(ipsecPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(ipsecdir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(ipsecPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(ipsecdir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-ipsecPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(ipsec_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(ipsecdir)/$$f'"; \
+ rm -f "$(DESTDIR)$(ipsecdir)/$$f"; \
+ done
+
+clean-ipsecPROGRAMS:
+ @list='$(ipsec_PROGRAMS)'; for p in $$list; do \
+ f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f $$p $$f"; \
+ rm -f $$p $$f ; \
+ done
+scepclient$(EXEEXT): $(scepclient_OBJECTS) $(scepclient_DEPENDENCIES)
+ @rm -f scepclient$(EXEEXT)
+ $(LINK) $(scepclient_LDFLAGS) $(scepclient_OBJECTS) $(scepclient_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pkcs10.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rsakey.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scep.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scepclient.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+install-man8: $(man8_MANS) $(man_MANS)
+ @$(NORMAL_INSTALL)
+ test -z "$(man8dir)" || $(mkdir_p) "$(DESTDIR)$(man8dir)"
+ @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 8*) ;; \
+ *) ext='8' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst"; \
+ done
+uninstall-man8:
+ @$(NORMAL_UNINSTALL)
+ @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 8*) ;; \
+ *) ext='8' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f '$(DESTDIR)$(man8dir)/$$inst'"; \
+ rm -f "$(DESTDIR)$(man8dir)/$$inst"; \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS) $(MANS)
+installdirs:
+ for dir in "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(man8dir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-ipsecPROGRAMS clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-ipsecPROGRAMS install-man
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man: install-man8
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-ipsecPROGRAMS uninstall-man
+
+uninstall-man: uninstall-man8
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-ipsecPROGRAMS clean-libtool ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am \
+ install-ipsecPROGRAMS install-man install-man8 install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-info-am \
+ uninstall-ipsecPROGRAMS uninstall-man uninstall-man8
+
+
+loglite.o: $(OPENACDIR)/loglite.c $(PLUTODIR)/log.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+asn1.o : $(PLUTODIR)/asn1.c $(PLUTODIR)/asn1.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+ca.o : $(PLUTODIR)/ca.c $(PLUTODIR)/ca.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+certs.o : $(PLUTODIR)/certs.c $(PLUTODIR)/certs.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+constants.o : $(PLUTODIR)/constants.c $(PLUTODIR)/constants.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+crl.o : $(PLUTODIR)/crl.c $(PLUTODIR)/crl.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+defs.o : $(PLUTODIR)/defs.c $(PLUTODIR)/defs.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+mp_defs.o : $(PLUTODIR)/mp_defs.c $(PLUTODIR)/mp_defs.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+fetch.o : $(PLUTODIR)/fetch.c $(PLUTODIR)/fetch.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+id.o : $(PLUTODIR)/id.c $(PLUTODIR)/id.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+keys.o : $(PLUTODIR)/keys.c $(PLUTODIR)/keys.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+lex.o : $(PLUTODIR)/lex.c $(PLUTODIR)/lex.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+md2.o : $(PLUTODIR)/md2.c $(PLUTODIR)/md2.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+md5.o : $(PLUTODIR)/md5.c $(PLUTODIR)/md5.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+ocsp.o : $(PLUTODIR)/ocsp.c $(PLUTODIR)/ocsp.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+oid.o : $(PLUTODIR)/oid.c $(PLUTODIR)/oid.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+pem.o : $(PLUTODIR)/pem.c $(PLUTODIR)/pem.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+pgp.o : $(PLUTODIR)/pgp.c $(PLUTODIR)/pgp.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+pkcs1.o : $(PLUTODIR)/pkcs1.c $(PLUTODIR)/pkcs1.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+pkcs7.o : $(PLUTODIR)/pkcs7.c $(PLUTODIR)/pkcs7.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+rnd.o : $(PLUTODIR)/rnd.c $(PLUTODIR)/rnd.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+sha1.o : $(PLUTODIR)/sha1.c $(PLUTODIR)/sha1.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+smartcard.o : $(PLUTODIR)/smartcard.c $(PLUTODIR)/smartcard.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+
+x509.o : $(PLUTODIR)/x509.c $(PLUTODIR)/x509.h
+ $(COMPILE) $(INCLUDES) -c -o $@ $<
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/scepclient/pkcs10.c b/src/scepclient/pkcs10.c
new file mode 100644
index 000000000..de3f06e18
--- /dev/null
+++ b/src/scepclient/pkcs10.c
@@ -0,0 +1,220 @@
+/**
+ * @file pkcs10.c
+ * @brief Functions to build PKCS#10 requests
+ *
+ * Contains functions to build DER encoded pkcs#10 certificate requests
+ */
+
+/* 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 <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <freeswan.h>
+
+#include "../pluto/constants.h"
+#include "../pluto/defs.h"
+#include "../pluto/oid.h"
+#include "../pluto/asn1.h"
+#include "../pluto/pkcs1.h"
+#include "../pluto/log.h"
+#include "../pluto/x509.h"
+
+#include "pkcs10.h"
+
+/* some pre-coded OIDs */
+
+static u_char ASN1_challengePassword_oid_str[] = {
+ 0x06,0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x07
+};
+
+static const chunk_t ASN1_challengePassword_oid = strchunk(ASN1_challengePassword_oid_str);
+
+static u_char ASN1_extensionRequest_oid_str[] = {
+ 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x0E
+};
+
+static const chunk_t ASN1_extensionRequest_oid = strchunk(ASN1_extensionRequest_oid_str);
+
+/**
+ * @brief Adds a subjectAltName in DER-coded form to a linked list
+ *
+ * @param[in,out] subjectAltNames head of the linked list of subjectAltNames
+ * @param[in] kind type of the subjectAltName (which is a generalName)
+ * @param[in] value value of the subjectAltName as an ASCII string
+ */
+void
+pkcs10_add_subjectAltName(generalName_t **subjectAltNames, generalNames_t kind
+, char *value)
+{
+ generalName_t *gn;
+ asn1_t asn1_type = ASN1_EOC;
+ chunk_t name = { value, strlen(value) };
+
+ switch (kind)
+ {
+ case GN_RFC822_NAME:
+ asn1_type = ASN1_CONTEXT_S_1;
+ break;
+ case GN_DNS_NAME:
+ asn1_type = ASN1_CONTEXT_S_2;
+ break;
+ case GN_IP_ADDRESS:
+ {
+ struct in_addr addr;
+
+ /* convert an ASCII dotted IPv4 address (e.g. 123.456.78.90)
+ * to a byte representation in network order
+ */
+ if (!inet_aton(value, &addr))
+ {
+ fprintf(stderr, "error in IPv4 subjectAltName\n");
+ return;
+ }
+ asn1_type = ASN1_CONTEXT_S_7;
+ name.ptr = (u_char *) &addr.s_addr;
+ name.len = sizeof(addr.s_addr);
+ break;
+ }
+ default:
+ break;
+ }
+
+ gn = alloc_thing(generalName_t, "subjectAltName");
+ gn->kind = kind;
+ gn->name = asn1_simple_object(asn1_type, name);
+ gn->next = *subjectAltNames;
+ *subjectAltNames = gn;
+}
+
+/**
+ * @brief Builds the requestInfoAttributes of the certificationRequestInfo-field
+ *
+ * challenge password ans subjectAltNames are only included,
+ * when avaiable in given #pkcs10_t structure
+ *
+ * @param[in] pkcs10 Pointer to a #pkcs10_t structure
+ * @return 1 if succeeded, 0 otherwise
+ */
+static chunk_t
+build_req_info_attributes(pkcs10_t* pkcs10)
+{
+
+ chunk_t subjectAltNames = empty_chunk;
+ chunk_t challengePassword = empty_chunk;
+
+ if (pkcs10->subjectAltNames != NULL)
+ {
+
+ subjectAltNames = asn1_wrap(ASN1_SEQUENCE, "cm"
+ , ASN1_extensionRequest_oid
+ , asn1_wrap(ASN1_SET, "m"
+ , asn1_wrap(ASN1_SEQUENCE, "m"
+ , build_subjectAltNames(pkcs10->subjectAltNames)
+ )
+ )
+ );
+ }
+
+ if (pkcs10->challengePassword.len > 0)
+ {
+ asn1_t type = is_printablestring(pkcs10->challengePassword)
+ ? ASN1_PRINTABLESTRING : ASN1_T61STRING;
+
+ challengePassword = asn1_wrap(ASN1_SEQUENCE, "cm"
+ , ASN1_challengePassword_oid
+ , asn1_wrap(ASN1_SET, "m"
+ , asn1_simple_object(type, pkcs10->challengePassword)
+ )
+ );
+ }
+
+ return asn1_wrap(ASN1_CONTEXT_C_0, "mm"
+ , subjectAltNames
+ , challengePassword);
+}
+
+/**
+ * @brief Builds a DER-code pkcs#10 certificate request
+ *
+ * @param[in] pkcs10 pointer to a pkcs10_t struct
+ * @return DER-code pkcs10 request
+ */
+static chunk_t
+pkcs10_build_request(pkcs10_t *pkcs10, int signature_alg)
+{
+ RSA_public_key_t *rsak = (RSA_public_key_t *) pkcs10->private_key;
+
+ chunk_t cert_req_info = asn1_wrap(ASN1_SEQUENCE, "ccmm"
+ , ASN1_INTEGER_0
+ , pkcs10->subject
+ , pkcs1_build_publicKeyInfo(rsak)
+ , build_req_info_attributes(pkcs10));
+
+ chunk_t signature = pkcs1_build_signature(cert_req_info
+ , signature_alg, pkcs10->private_key, TRUE);
+
+ return asn1_wrap(ASN1_SEQUENCE, "mcm"
+ , cert_req_info
+ , asn1_algorithmIdentifier(signature_alg)
+ , signature);
+}
+
+/**
+ * @brief Creates a pkcs#10 certificate request object
+ *
+ * To create a certificate request, the RSA key and the
+ * names to be included as subject in the certificate request
+ * (e.g. commonName, organization) are needed. An optional challenge
+ * password or some subjectAltNames may be included.
+ *
+ * @param[in] key rsakey of type #rsakey_t
+ * @param[in] subject DER-coded subject distinguished name
+ * @param[in] challengePassword challenge password or empty_chunk
+ * @param[in] subjectAltNames linked list of subjectAltNames or NULL
+ * @return pointer to a #pkcs10_t object
+ */
+pkcs10_t*
+pkcs10_build(RSA_private_key_t *key, chunk_t subject, chunk_t challengePassword
+, generalName_t *subjectAltNames, int signature_alg)
+{
+ pkcs10_t *pkcs10 = alloc_thing(pkcs10_t, "pkcs10_t");
+
+ pkcs10->subject = subject;
+ pkcs10->private_key = key;
+ pkcs10->challengePassword = challengePassword;
+ pkcs10->subjectAltNames = subjectAltNames;
+
+ pkcs10->request = pkcs10_build_request(pkcs10, signature_alg);
+ return pkcs10;
+}
+
+/**
+ * @brief Frees the resources used by an #pkcs10_t object
+ *
+ * @param[in] pkcs10 #pkcs10_t to free
+ */
+void
+pkcs10_free(pkcs10_t *pkcs10)
+{
+ if (pkcs10 != NULL)
+ {
+ freeanychunk(pkcs10->request);
+ pfree(pkcs10);
+ }
+}
diff --git a/src/scepclient/pkcs10.h b/src/scepclient/pkcs10.h
new file mode 100644
index 000000000..c2a4c1b92
--- /dev/null
+++ b/src/scepclient/pkcs10.h
@@ -0,0 +1,57 @@
+/**
+ * @file pkcs10.h
+ * @brief Functions to build PKCS#10 Request's
+ *
+ * Contains functions to build DER encoded pkcs#10 certificate requests
+ */
+
+/*
+ * 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 _PKCS10_H
+#define _PKCS10_H
+
+#include "../pluto/defs.h"
+#include "../pluto/pkcs1.h"
+#include "../pluto/x509.h"
+
+typedef struct pkcs10_struct pkcs10_t;
+
+/**
+ * @brief type representating a pkcs#10 request.
+ *
+ * A pkcs#10 request contains a distinguished name, an optional
+ * challenge password, a public key and optional subjectAltNames.
+ *
+ * The RSA private key is needed to compute the signature of the given request
+ */
+struct pkcs10_struct {
+ RSA_private_key_t *private_key;
+ chunk_t request;
+ chunk_t subject;
+ chunk_t challengePassword;
+ generalName_t *subjectAltNames;
+};
+
+extern const pkcs10_t empty_pkcs10;
+
+extern void pkcs10_add_subjectAltName(generalName_t **subjectAltNames
+ , generalNames_t kind, char *value);
+extern pkcs10_t* pkcs10_build(RSA_private_key_t *key, chunk_t subject
+ , chunk_t challengePassword, generalName_t *subjectAltNames
+ , int signature_alg);
+extern void pkcs10_free(pkcs10_t *pkcs10);
+
+#endif /* _PKCS10_H */
diff --git a/src/scepclient/rsakey.c b/src/scepclient/rsakey.c
new file mode 100644
index 000000000..a7c6321f5
--- /dev/null
+++ b/src/scepclient/rsakey.c
@@ -0,0 +1,349 @@
+/**
+ * @file rsakey.c
+ * @brief Functions for RSA key generation
+ */
+
+/*
+ * 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.
+ *
+ * $Id: rsakey.c,v 1.5 2006/01/04 21:16:30 as Exp $
+ */
+
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <assert.h>
+#include <gmp.h>
+
+#include <freeswan.h>
+
+#include "../pluto/constants.h"
+#include "../pluto/defs.h"
+#include "../pluto/mp_defs.h"
+#include "../pluto/log.h"
+#include "../pluto/asn1.h"
+#include "../pluto/pkcs1.h"
+
+#include "rsakey.h"
+
+/* Number of times the probabilistic primality test is applied */
+#define PRIMECHECK_ROUNDS 30
+
+/* Public exponent used for signature key generation */
+#define PUBLIC_EXPONENT 0x10001
+
+#ifndef DEV_RANDOM
+#define DEV_RANDOM "/dev/random"
+#endif
+
+
+/**
+ * @brief Reads a specific number of bytes from a given device/file
+ *
+ * @param[in] nbytes number of bytes to read from random device
+ * @param[out] buf pointer to buffer where to write the data in.
+ * size of buffer has to be at least nbytes.
+ * @return TRUE, if succeeded, FALSE otherwise
+ */
+
+static bool
+get_true_random_bytes(size_t nbytes, char *buf)
+{
+ size_t ndone;
+ size_t got;
+ char *device = DEV_RANDOM;
+
+ int dev = open(DEV_RANDOM, 0);
+
+ if (dev < 0)
+ {
+ fprintf(stderr, "could not open random device %s", device);
+ return FALSE;
+ }
+
+ DBG(DBG_CONTROL,
+ DBG_log("getting %d bytes from %s...", (int) nbytes, device)
+ )
+
+ ndone = 0;
+ while (ndone < nbytes)
+ {
+ got = read(dev, buf + ndone, nbytes - ndone);
+ if (got < 0)
+ {
+ fprintf(stderr, "read error on %s", device);
+ return FALSE;
+ }
+ if (got == 0)
+ {
+ fprintf(stderr, "eof on %s", device);
+ return FALSE;
+ }
+ ndone += got;
+ }
+ close(dev);
+ return TRUE;
+}
+
+/**
+ * @brief initialize an mpz_t to a random number, specified bit count
+ *
+ * Converting the random value in a value of type mpz_t is done
+ * by creating a hexbuffer.
+ * Converting via hex is a bit weird, but it's the best route GMP gives us.
+ * Note that highmost and lowmost bits are forced on -- highmost to give a
+ * number of exactly the specified length, lowmost so it is an odd number.
+ *
+ * @param[out] var uninitialized mpz_t to store th random number in
+ * @param[in] nbits length of var in bits (known to be a multiple of BITS_PER_BYTE)
+ * @return TRUE on success, FALSE otherwise
+ */
+static bool
+init_random(mpz_t var, int nbits)
+{
+ size_t nbytes = (size_t)(nbits/BITS_PER_BYTE);
+ char random_buf[RSA_MAX_OCTETS/2];
+
+ assert(nbytes <= sizeof(random_buf));
+
+ if (!get_true_random_bytes(nbytes, random_buf))
+ return FALSE;
+
+ random_buf[0] |= 01 << (BITS_PER_BYTE-1); /* force high bit on */
+ random_buf[nbytes-1] |= 01; /* force low bit on */
+ n_to_mpz(var, random_buf, nbytes);
+ return TRUE;
+}
+
+/**
+ * @brief initialize an mpz_t to a random prime of specified size
+ *
+ * Efficiency tweak: we reject candidates that are 1 higher than a multiple
+ * of e, since they will make the internal modulus not relatively prime to e.
+ *
+ * @param[out] var mpz_t variable to initialize
+ * @param[in] nbits length of given prime in bits (known to be a multiple of BITS_PER_BYTE)
+ * @param[in] eval E-Value, 0 means don't bother w. tweak
+ * @return 1 on success, 0 otherwise
+ */
+static bool
+init_prime(mpz_t var, int nbits, int eval)
+{
+ unsigned long tries;
+ size_t len;
+
+ /* get a random value of nbits length */
+ if (!init_random(var, nbits))
+ return FALSE;
+
+ /* check if odd number */
+ assert(mpz_fdiv_ui(var, 2) == 1);
+ DBG(DBG_CONTROLMORE,
+ DBG_log("looking for a prime starting there (can take a while)...")
+ )
+
+ tries = 1;
+ while (mpz_fdiv_ui(var, eval) == 1
+ || !mpz_probab_prime_p(var, PRIMECHECK_ROUNDS))
+ {
+ /* not a prime, increase by 2 */
+ mpz_add_ui(var, var, 2);
+ tries++;
+ }
+
+ len = mpz_sizeinbase(var, 2);
+
+ /* check bit length of primee */
+ assert(len == (size_t)nbits || len == (size_t)(nbits+1));
+
+ if (len == (size_t)(nbits+1))
+ {
+ DBG(DBG_CONTROLMORE,
+ DBG_log("carry out occurred (!), retrying...")
+ )
+ mpz_clear(var);
+ /* recursive call */
+ return init_prime(var, nbits, eval);
+ }
+ DBG(DBG_CONTROLMORE,
+ DBG_log("found it after %lu tries.",tries)
+ )
+ return TRUE;
+}
+
+/**
+ * @brief Generate a RSA key usable for encryption
+ *
+ * Generate an RSA key usable for encryption. All the
+ * values of the RSA key are filled into mpz_t parameters.
+ * These mpz_t parameters must not be initialized and have
+ * to be cleared with mpz_clear after using.
+ *
+ * @param[in] nbits size of rsa key in bits
+ * @return RSA_public_key_t containing the generated RSA key
+ */
+err_t
+generate_rsa_private_key(int nbits, RSA_private_key_t *key)
+{
+ mpz_t p, q, n, e, d, exp1, exp2, coeff;
+ mpz_t m, q1, t; /* temporary variables*/
+
+ DBG(DBG_CONTROL,
+ DBG_log("generating %d bit RSA key:", nbits)
+ )
+
+ if (nbits <= 0)
+ return "negative rsa key length!";
+
+ /* Get values of primes p and q */
+ DBG(DBG_CONTROLMORE,
+ DBG_log("initialize prime p")
+ )
+ if (!init_prime(p, nbits/2, PUBLIC_EXPONENT))
+ return "could not generate prime p";
+
+ DBG(DBG_CONTROLMORE,
+ DBG_log("initialize prime q")
+ )
+ if (!init_prime(q, nbits/2, PUBLIC_EXPONENT))
+ return "could not generate prime q";
+
+ mpz_init(t);
+
+ /* Swapping primes so p is larger then q */
+ if (mpz_cmp(p, q) < 0)
+ {
+ DBG(DBG_CONTROLMORE,
+ DBG_log("swapping primes so p is the larger...")
+ );
+ mpz_set(t, p);
+ mpz_set(p, q);
+ mpz_set(q, t);
+ }
+
+ DBG(DBG_CONTROLMORE,
+ DBG_log("computing modulus...")
+ )
+ mpz_init(n);
+ /* n = p*q */
+ mpz_mul(n, p, q);
+
+ /* Assign e the value of defined PUBLIC_EXPONENT */
+ mpz_init_set_ui(e, PUBLIC_EXPONENT);
+
+ DBG(DBG_CONTROLMORE,
+ DBG_log("computing lcm(p-1, q-1)...")
+ )
+ /* m = p */
+ mpz_init_set(m, p);
+ /* m = m-1 */
+ mpz_sub_ui(m, m, 1);
+ /* q1 = q */
+ mpz_init_set(q1, q);
+ /* q1 = q1-1 */
+ mpz_sub_ui(q1, q1, 1);
+ /* t = gcd(p-1, q-1) */
+ mpz_gcd(t, m, q1);
+ /* m = (p-1)*(q-1) */
+ mpz_mul(m, m, q1);
+ /* m = m / t */
+ mpz_divexact(m, m, t);
+ /* t = gcd(m, e) (greatest common divisor) */
+ mpz_gcd(t, m, e);
+ /* m and e relatively prime */
+ assert(mpz_cmp_ui(t, 1) == 0);
+
+ /* decryption key */
+ DBG(DBG_CONTROLMORE,
+ DBG_log("computing d...")
+ )
+ mpz_init(d);
+ /* e has an inverse mod m */
+ assert(mpz_invert(d, e, m));
+
+ /* make sure d is positive */
+ if (mpz_cmp_ui(d, 0) < 0)
+ mpz_add(d, d, m);
+
+ /* d has to be positive */
+ assert(mpz_cmp(d, m) < 0);
+
+ /* the speedup hacks */
+ DBG(DBG_CONTROLMORE,
+ DBG_log("computing exp1, exp1, coeff...")
+ )
+ mpz_init(exp1);
+ /* t = p-1 */
+ mpz_sub_ui(t, p, 1);
+ /* exp1 = d mod p-1 */
+ mpz_mod(exp1, d, t);
+
+ mpz_init(exp2);
+ /* t = q-1 */
+ mpz_sub_ui(t, q, 1);
+ /* exp2 = d mod q-1 */
+ mpz_mod(exp2, d, t);
+
+ mpz_init(coeff);
+ /* coeff = q^-1 mod p */
+ mpz_invert(coeff, q, p);
+
+ /* make sure coeff is positive */
+ if (mpz_cmp_ui(coeff, 0) < 0)
+ mpz_add(coeff, coeff, p);
+
+ /* coeff has to be positive */
+ assert(mpz_cmp(coeff, p) < 0);
+
+ /* Clear temporary variables */
+ mpz_clear(q1);
+ mpz_clear(m);
+ mpz_clear(t);
+
+ /* form FreeS/WAN keyid */
+ {
+ size_t e_len = (mpz_sizeinbase(e,2)+BITS_PER_BYTE-1)/BITS_PER_BYTE;
+ size_t n_len = (mpz_sizeinbase(n,2)+BITS_PER_BYTE-1)/BITS_PER_BYTE;
+ chunk_t e_ch = mpz_to_n(e, e_len);
+ chunk_t n_ch = mpz_to_n(n, n_len);
+ form_keyid(e_ch, n_ch, key->pub.keyid, &key->pub.k);
+ freeanychunk(e_ch);
+ freeanychunk(n_ch);
+ }
+ /* fill in the elements of the RSA private key */
+ key->p = *p;
+ key->q = *q;
+ key->pub.n = *n;
+ key->pub.e = *e;
+ key->d = *d;
+ key->dP = *exp1;
+ key->dQ = *exp2;
+ key->qInv = *coeff;
+
+ DBG(DBG_CONTROL,
+ DBG_log("RSA key *%s generated with %d bits", key->pub.keyid
+ , (int)mpz_sizeinbase(n,2))
+ )
+
+#ifdef DEBUG
+ DBG(DBG_PRIVATE,
+ RSA_show_private_key(key)
+ )
+#endif
+ return NULL;
+}
diff --git a/src/scepclient/rsakey.h b/src/scepclient/rsakey.h
new file mode 100644
index 000000000..3e3156d81
--- /dev/null
+++ b/src/scepclient/rsakey.h
@@ -0,0 +1,31 @@
+/**
+ * @file rsakey.h
+ * @brief Functions for RSA key generation
+ */
+
+/*
+ * 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.
+ *
+ * $Id: rsakey.h,v 1.2 2005/08/11 21:52:56 as Exp $
+ */
+
+#ifndef RSAKEY_H_
+#define RSAKEY_H_
+
+#include "../pluto/pkcs1.h"
+
+extern err_t generate_rsa_private_key(int nbits, RSA_private_key_t *key);
+
+#endif // RSAKEY_H_
diff --git a/src/scepclient/scep.c b/src/scepclient/scep.c
new file mode 100644
index 000000000..577191787
--- /dev/null
+++ b/src/scepclient/scep.c
@@ -0,0 +1,598 @@
+/**
+ * @file scep.c
+ * @brief SCEP specific functions
+ *
+ * Contains functions to build SCEP request's and to parse SCEP reply's.
+ */
+
+/*
+ * 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 <stdlib.h>
+
+#include <freeswan.h>
+
+#ifdef LIBCURL
+#include <curl/curl.h>
+#endif
+
+#include "../pluto/constants.h"
+#include "../pluto/defs.h"
+#include "../pluto/rnd.h"
+#include "../pluto/oid.h"
+#include "../pluto/asn1.h"
+#include "../pluto/pkcs1.h"
+#include "../pluto/fetch.h"
+#include "../pluto/log.h"
+
+#include "scep.h"
+
+static char ASN1_messageType_oid_str[] = {
+ 0x06, 0x0A, 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, 0x09, 0x02
+};
+
+static char ASN1_senderNonce_oid_str[] = {
+ 0x06, 0x0A, 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, 0x09, 0x05
+};
+
+static char ASN1_transId_oid_str[] = {
+ 0x06, 0x0A, 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, 0x09, 0x07
+};
+
+static const chunk_t ASN1_messageType_oid =
+ strchunk(ASN1_messageType_oid_str);
+static const chunk_t ASN1_senderNonce_oid =
+ strchunk(ASN1_senderNonce_oid_str);
+static const chunk_t ASN1_transId_oid =
+ strchunk(ASN1_transId_oid_str);
+
+static const char *pkiStatus_values[] = { "0", "2", "3" };
+
+static const char *pkiStatus_names[] = {
+ "SUCCESS",
+ "FAILURE",
+ "PENDING",
+ "UNKNOWN"
+};
+
+static const char *msgType_values[] = { "3", "19", "20", "21", "22" };
+
+static const char *msgType_names[] = {
+ "CertRep",
+ "PKCSReq",
+ "GetCertInitial",
+ "GetCert",
+ "GetCRL",
+ "Unknown"
+};
+
+static const char *failInfo_reasons[] = {
+ "badAlg - unrecognized or unsupported algorithm identifier",
+ "badMessageCheck - integrity check failed",
+ "badRequest - transaction not permitted or supported",
+ "badTime - Message time field was not sufficiently close to the system time",
+ "badCertId - No certificate could be identified matching the provided criteria"
+};
+
+const scep_attributes_t empty_scep_attributes = {
+ SCEP_Unknown_MSG , /* msgType */
+ SCEP_UNKNOWN , /* pkiStatus */
+ SCEP_unknown_REASON, /* failInfo */
+ { NULL, 0 } , /* transID */
+ { NULL, 0 } , /* senderNonce */
+ { NULL, 0 } , /* recipientNonce */
+};
+
+/* ASN.1 definition of the X.501 atttribute type */
+
+static const asn1Object_t attributesObjects[] = {
+ { 0, "attributes", ASN1_SET, ASN1_LOOP }, /* 0 */
+ { 1, "attribute", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */
+ { 2, "type", ASN1_OID, ASN1_BODY }, /* 2 */
+ { 2, "values", ASN1_SET, ASN1_LOOP }, /* 3 */
+ { 3, "value", ASN1_EOC, ASN1_RAW }, /* 4 */
+ { 2, "end loop", ASN1_EOC, ASN1_END }, /* 5 */
+ { 0, "end loop", ASN1_EOC, ASN1_END }, /* 6 */
+};
+
+#define ATTRIBUTE_OBJ_TYPE 2
+#define ATTRIBUTE_OBJ_VALUE 4
+#define ATTRIBUTE_OBJ_ROOF 7
+
+/*
+ * extract and store an attribute
+ */
+static bool
+extract_attribute(int oid, chunk_t object, u_int level
+, scep_attributes_t *attrs)
+{
+ asn1_t type = ASN1_EOC;
+ const char *name = "none";
+
+ switch (oid)
+ {
+ case OID_PKCS9_CONTENT_TYPE:
+ type = ASN1_OID;
+ name = "contentType";
+ break;
+ case OID_PKCS9_SIGNING_TIME:
+ type = ASN1_UTCTIME;
+ name = "signingTime";
+ break;
+ case OID_PKCS9_MESSAGE_DIGEST:
+ type = ASN1_OCTET_STRING;
+ name = "messageDigest";
+ break;
+ case OID_PKI_MESSAGE_TYPE:
+ type = ASN1_PRINTABLESTRING;
+ name = "messageType";
+ break;
+ case OID_PKI_STATUS:
+ type = ASN1_PRINTABLESTRING;
+ name = "pkiStatus";
+ break;
+ case OID_PKI_FAIL_INFO:
+ type = ASN1_PRINTABLESTRING;
+ name = "failInfo";
+ break;
+ case OID_PKI_SENDER_NONCE:
+ type = ASN1_OCTET_STRING;
+ name = "senderNonce";
+ break;
+ case OID_PKI_RECIPIENT_NONCE:
+ type = ASN1_OCTET_STRING;
+ name = "recipientNonce";
+ break;
+ case OID_PKI_TRANS_ID:
+ type = ASN1_PRINTABLESTRING;
+ name = "transID";
+ break;
+ default:
+ break;
+ }
+
+ if (type == ASN1_EOC)
+ return TRUE;
+
+ if (!parse_asn1_simple_object(&object, type, level+1, name))
+ return FALSE;
+
+ switch (oid)
+ {
+ case OID_PKCS9_CONTENT_TYPE:
+ break;
+ case OID_PKCS9_SIGNING_TIME:
+ break;
+ case OID_PKCS9_MESSAGE_DIGEST:
+ break;
+ case OID_PKI_MESSAGE_TYPE:
+ {
+ scep_msg_t m;
+
+ for (m = SCEP_CertRep_MSG; m < SCEP_Unknown_MSG; m++)
+ {
+ if (strncmp(msgType_values[m], object.ptr, object.len) == 0)
+ attrs->msgType = m;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("messageType: %s", msgType_names[attrs->msgType])
+ )
+ }
+ break;
+ case OID_PKI_STATUS:
+ {
+ pkiStatus_t s;
+
+ for (s = SCEP_SUCCESS; s < SCEP_UNKNOWN; s++)
+ {
+ if (strncmp(pkiStatus_values[s], object.ptr, object.len) == 0)
+ attrs->pkiStatus = s;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("pkiStatus: %s", pkiStatus_names[attrs->pkiStatus])
+ )
+ }
+ break;
+ case OID_PKI_FAIL_INFO:
+ if (object.len == 1
+ && *object.ptr >= '0' && *object.ptr <= '4')
+ {
+ attrs->failInfo = (failInfo_t)(*object.ptr - '0');
+ }
+ if (attrs->failInfo != SCEP_unknown_REASON)
+ plog("failInfo: %s", failInfo_reasons[attrs->failInfo]);
+ break;
+ case OID_PKI_SENDER_NONCE:
+ attrs->senderNonce = object;
+ break;
+ case OID_PKI_RECIPIENT_NONCE:
+ attrs->recipientNonce = object;
+ break;
+ case OID_PKI_TRANS_ID:
+ attrs->transID = object;
+ }
+ return TRUE;
+}
+
+/*
+ * parse X.501 attributes
+ */
+bool
+parse_attributes(chunk_t blob, scep_attributes_t *attrs)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int oid = OID_UNKNOWN;
+ int objectID = 0;
+
+ asn1_init(&ctx, blob, 0, FALSE, DBG_RAW);
+
+ DBG(DBG_CONTROL | DBG_PARSING,
+ DBG_log("parsing attributes")
+ )
+ while (objectID < ATTRIBUTE_OBJ_ROOF)
+ {
+ if (!extract_object(attributesObjects, &objectID
+ , &object, &level, &ctx))
+ return FALSE;
+
+ switch (objectID)
+ {
+ case ATTRIBUTE_OBJ_TYPE:
+ oid = known_oid(object);
+ break;
+ case ATTRIBUTE_OBJ_VALUE:
+ if (!extract_attribute(oid, object, level, attrs))
+ return FALSE;
+ }
+ objectID++;
+ }
+ return TRUE;
+}
+
+/* generates a unique fingerprint of the pkcs10 request
+ * by computing an MD5 hash over it
+ */
+void
+scep_generate_pkcs10_fingerprint(chunk_t pkcs10, chunk_t *fingerprint)
+{
+ char buf[MD5_DIGEST_SIZE];
+ chunk_t digest = { buf, sizeof(buf) };
+
+ /* the fingerprint is the MD5 hash in hexadecimal format */
+ compute_digest(pkcs10, OID_MD5, &digest);
+ fingerprint->len = 2*digest.len;
+ fingerprint->ptr = alloc_bytes(fingerprint->len + 1, "fingerprint");
+ datatot(digest.ptr, digest.len, 16, fingerprint->ptr, fingerprint->len + 1);
+}
+
+/* generate a transaction id as the MD5 hash of an public key
+ * the transaction id is also used as a unique serial number
+ */
+void
+scep_generate_transaction_id(const RSA_public_key_t *rsak
+, chunk_t *transID, chunk_t *serialNumber)
+{
+ char buf[MD5_DIGEST_SIZE];
+
+ chunk_t digest = { buf, sizeof(buf) };
+ chunk_t public_key = pkcs1_build_publicKeyInfo(rsak);
+
+ bool msb_set;
+ u_char *pos;
+
+ compute_digest(public_key, OID_MD5, &digest);
+ pfree(public_key.ptr);
+
+ /* is the most significant bit of the digest set? */
+ msb_set = (*digest.ptr & 0x80) == 0x80;
+
+ /* allocate space for the serialNumber */
+ serialNumber->len = msb_set + digest.len;
+ serialNumber->ptr = alloc_bytes(serialNumber->len, "serialNumber");
+
+ /* the serial number as the two's complement of the digest */
+ pos = serialNumber->ptr;
+ if (msb_set)
+ {
+ *pos++ = 0x00;
+ }
+ memcpy(pos, digest.ptr, digest.len);
+
+ /* the transaction id is the serial number in hex format */
+ transID->len = 2*digest.len;
+ transID->ptr = alloc_bytes(transID->len + 1, "transID");
+ datatot(digest.ptr, digest.len, 16, transID->ptr, transID->len + 1);
+}
+
+/*
+ * builds a transId attribute
+ */
+chunk_t
+scep_transId_attribute(chunk_t transID)
+{
+ return asn1_wrap(ASN1_SEQUENCE, "cm"
+ , ASN1_transId_oid
+ , asn1_wrap(ASN1_SET, "m"
+ , asn1_simple_object(ASN1_PRINTABLESTRING, transID)
+ )
+ );
+}
+
+/*
+ * builds a messageType attribute
+ */
+chunk_t
+scep_messageType_attribute(scep_msg_t m)
+{
+ chunk_t msgType = {
+ msgType_values[m],
+ strlen(msgType_values[m])
+ };
+
+ return asn1_wrap(ASN1_SEQUENCE, "cm"
+ , ASN1_messageType_oid
+ , asn1_wrap(ASN1_SET, "m"
+ , asn1_simple_object(ASN1_PRINTABLESTRING, msgType)
+ )
+ );
+}
+
+/*
+ * builds a senderNonce attribute
+ */
+chunk_t
+scep_senderNonce_attribute(void)
+{
+ const size_t nonce_len = 16;
+ u_char nonce_buf[nonce_len];
+ chunk_t senderNonce = { nonce_buf, nonce_len };
+
+ get_rnd_bytes(nonce_buf, nonce_len);
+
+ return asn1_wrap(ASN1_SEQUENCE, "cm"
+ , ASN1_senderNonce_oid
+ , asn1_wrap(ASN1_SET, "m"
+ , asn1_simple_object(ASN1_OCTET_STRING, senderNonce)
+ )
+ );
+}
+
+/*
+ * builds a pkcs7 enveloped and signed scep request
+ */
+chunk_t
+scep_build_request(chunk_t data, chunk_t transID, scep_msg_t msg
+, const x509cert_t *enc_cert, int enc_alg
+, const x509cert_t *signer_cert, int digest_alg
+, const RSA_private_key_t *private_key)
+{
+ chunk_t envelopedData, attributes, request;
+
+ envelopedData = pkcs7_build_envelopedData(data, enc_cert, enc_alg);
+
+ attributes = asn1_wrap(ASN1_SET, "mmmmm"
+ , pkcs7_contentType_attribute()
+ , pkcs7_messageDigest_attribute(envelopedData
+ , digest_alg)
+ , scep_transId_attribute(transID)
+ , scep_messageType_attribute(msg)
+ , scep_senderNonce_attribute());
+
+ request = pkcs7_build_signedData(envelopedData, attributes
+ , signer_cert, digest_alg, private_key);
+ freeanychunk(envelopedData);
+ freeanychunk(attributes);
+ return request;
+}
+
+#ifdef LIBCURL
+/* converts a binary request to base64 with 64 characters per line
+ * newline and '+' characters are escaped by %0A and %2B, respectively
+ */
+static char*
+escape_http_request(chunk_t req)
+{
+ char *escaped_req = NULL;
+ char *p1, *p2;
+ int lines = 0;
+ int plus = 0;
+ int n = 0;
+
+ /* compute and allocate the size of the base64-encoded request */
+ int len = 1 + 4*((req.len + 2)/3);
+ char *encoded_req = alloc_bytes(len, "encoded request");
+
+ /* do the base64 conversion */
+ len = datatot(req.ptr, req.len, 64, encoded_req, len);
+
+ /* compute newline characters to be inserted every 64 characters */
+ lines = (len - 2) / 64;
+
+ /* count number of + characters to be escaped */
+ p1 = encoded_req;
+ while (*p1 != '\0')
+ {
+ if (*p1++ == '+')
+ plus++;
+ }
+
+ escaped_req = alloc_bytes(len + 3*(lines + plus), "escaped request");
+
+ /* escape special characters in the request */
+ p1 = encoded_req;
+ p2 = escaped_req;
+ while (*p1 != '\0')
+ {
+ if (n == 64)
+ {
+ memcpy(p2, "%0A", 3);
+ p2 += 3;
+ n = 0;
+ }
+ if (*p1 == '+')
+ {
+ memcpy(p2, "%2B", 3);
+ p2 += 3;
+ }
+ else
+ {
+ *p2++ = *p1;
+ }
+ p1++;
+ n++;
+ }
+ *p2 = '\0';
+ pfreeany(encoded_req);
+ return escaped_req;
+}
+#endif
+
+/*
+ * send a SCEP request via HTTP and wait for a response
+ */
+bool
+scep_http_request(const char *url, chunk_t pkcs7, scep_op_t op
+, fetch_request_t req_type, chunk_t *response)
+{
+#ifdef LIBCURL
+ char errorbuffer[CURL_ERROR_SIZE] = "";
+ char *complete_url = NULL;
+ struct curl_slist *headers = NULL;
+ CURL *curl;
+ CURLcode res;
+
+ /* initialize response */
+ *response = empty_chunk;
+
+ /* initialize curl context */
+ curl = curl_easy_init();
+ if (curl == NULL)
+ {
+ plog("could not initialize curl context");
+ return FALSE;
+ }
+
+ if (op == SCEP_PKI_OPERATION)
+ {
+ const char operation[] = "PKIOperation";
+
+ if (req_type == FETCH_GET)
+ {
+ char *escaped_req = escape_http_request(pkcs7);
+
+ /* form complete url */
+ int len = strlen(url) + 20 + strlen(operation) + strlen(escaped_req) + 1;
+
+ complete_url = alloc_bytes(len, "complete url");
+ snprintf(complete_url, len, "%s?operation=%s&message=%s"
+ , url, operation, escaped_req);
+ pfreeany(escaped_req);
+
+ curl_easy_setopt(curl, CURLOPT_HTTPGET, TRUE);
+ headers = curl_slist_append(headers, "Pragma:");
+ headers = curl_slist_append(headers, "Host:");
+ headers = curl_slist_append(headers, "Accept:");
+ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
+ curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ }
+ else /* HTTP_POST */
+ {
+ /* form complete url */
+ int len = strlen(url) + 11 + strlen(operation) + 1;
+
+ complete_url = alloc_bytes(len, "complete url");
+ snprintf(complete_url, len, "%s?operation=%s", url, operation);
+
+ curl_easy_setopt(curl, CURLOPT_HTTPGET, FALSE);
+ headers = curl_slist_append(headers, "Content-Type:");
+ headers = curl_slist_append(headers, "Expect:");
+ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDS, pkcs7.ptr);
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, pkcs7.len);
+ }
+ }
+ else /* SCEP_GET_CA_CERT */
+ {
+ const char operation[] = "GetCACert";
+
+ /* form complete url */
+ int len = strlen(url) + 32 + strlen(operation) + 1;
+
+ complete_url = alloc_bytes(len, "complete url");
+ snprintf(complete_url, len, "%s?operation=%s&message=CAIdentifier"
+ , url, operation);
+
+ curl_easy_setopt(curl, CURLOPT_HTTPGET, TRUE);
+ }
+
+ curl_easy_setopt(curl, CURLOPT_URL, complete_url);
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_buffer);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)response);
+ curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorbuffer);
+ curl_easy_setopt(curl, CURLOPT_FAILONERROR, TRUE);
+ curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, FETCH_CMD_TIMEOUT);
+
+ DBG(DBG_CONTROL,
+ DBG_log("sending scep request to '%s'", url)
+ )
+ res = curl_easy_perform(curl);
+
+ if (res == CURLE_OK)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("received scep response")
+ )
+ DBG(DBG_RAW,
+ DBG_dump_chunk("SCEP response:\n", *response)
+ )
+ }
+ else
+ {
+ plog("failed to fetch scep response from '%s': %s", url, errorbuffer);
+ }
+ curl_slist_free_all(headers);
+ curl_easy_cleanup(curl);
+ pfreeany(complete_url);
+
+ return (res == CURLE_OK);
+#else /* !LIBCURL */
+ plog("scep error: pluto wasn't compiled with libcurl support");
+ return FALSE;
+#endif /* !LIBCURL */
+}
+
+err_t
+scep_parse_response(chunk_t response, chunk_t transID, contentInfo_t *data
+, scep_attributes_t *attrs, x509cert_t *signer_cert)
+{
+ chunk_t attributes;
+
+ if (!pkcs7_parse_signedData(response, data, NULL, &attributes, signer_cert))
+ {
+ return "error parsing the scep response";
+ }
+ if (!parse_attributes(attributes, attrs))
+ {
+ return "error parsing the scep response attributes";
+ }
+ if (!same_chunk(transID, attrs->transID))
+ {
+ return "transaction ID of scep response does not match";
+ }
+ return NULL;
+}
diff --git a/src/scepclient/scep.h b/src/scepclient/scep.h
new file mode 100644
index 000000000..81e5d1a4b
--- /dev/null
+++ b/src/scepclient/scep.h
@@ -0,0 +1,93 @@
+/**
+ * @file scep.h
+ * @brief SCEP specific functions
+ *
+ * Contains functions to build and parse SCEP requests and replies
+ */
+
+/*
+ * 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 _SCEP_H
+#define _SCEP_H
+
+#include "../pluto/defs.h"
+#include "../pluto/pkcs1.h"
+#include "../pluto/pkcs7.h"
+
+/* supported SCEP operation types */
+typedef enum {
+ SCEP_PKI_OPERATION,
+ SCEP_GET_CA_CERT
+} scep_op_t;
+
+/* SCEP pkiStatus values */
+typedef enum {
+ SCEP_SUCCESS,
+ SCEP_FAILURE,
+ SCEP_PENDING,
+ SCEP_UNKNOWN
+} pkiStatus_t;
+
+/* SCEP messageType values */
+typedef enum {
+ SCEP_CertRep_MSG,
+ SCEP_PKCSReq_MSG,
+ SCEP_GetCertInitial_MSG,
+ SCEP_GetCert_MSG,
+ SCEP_GetCRL_MSG,
+ SCEP_Unknown_MSG
+} scep_msg_t;
+
+/* SCEP failure reasons */
+typedef enum {
+ SCEP_badAlg_REASON = 0,
+ SCEP_badMessageCheck_REASON = 1,
+ SCEP_badRequest_REASON = 2,
+ SCEP_badTime_REASON = 3,
+ SCEP_badCertId_REASON = 4,
+ SCEP_unknown_REASON = 5
+} failInfo_t;
+
+/* SCEP attributes */
+typedef struct {
+ scep_msg_t msgType;
+ pkiStatus_t pkiStatus;
+ failInfo_t failInfo;
+ chunk_t transID;
+ chunk_t senderNonce;
+ chunk_t recipientNonce;
+} scep_attributes_t;
+
+extern const scep_attributes_t empty_scep_attributes;
+
+extern bool parse_attributes(chunk_t blob, scep_attributes_t *attrs);
+extern void scep_generate_pkcs10_fingerprint(chunk_t pkcs10
+ , chunk_t *fingerprint);
+extern void scep_generate_transaction_id(const RSA_public_key_t *rsak
+ , chunk_t *transID, chunk_t *serialNumber);
+extern chunk_t scep_transId_attribute(chunk_t transaction_id);
+extern chunk_t scep_messageType_attribute(scep_msg_t m);
+extern chunk_t scep_senderNonce_attribute(void);
+extern chunk_t scep_build_request(chunk_t data, chunk_t transID, scep_msg_t msg
+ , const x509cert_t *enc_cert, int enc_alg
+ , const x509cert_t *signer_cert, int digest_alg
+ , const RSA_private_key_t *private_key);
+extern bool scep_http_request(const char *url, chunk_t pkcs7, scep_op_t op
+ , fetch_request_t request_type, chunk_t *response);
+extern err_t scep_parse_response(chunk_t response, chunk_t transID
+ , contentInfo_t *data, scep_attributes_t *attrs, x509cert_t *signer_cert);
+
+#endif /* _SCEP_H */
diff --git a/src/scepclient/scepclient.8 b/src/scepclient/scepclient.8
new file mode 100644
index 000000000..0d6364ef2
--- /dev/null
+++ b/src/scepclient/scepclient.8
@@ -0,0 +1,288 @@
+.\"
+.TH "IPSEC_SCEPCLIENT" "8" "29 September 2005" "Jan Hutter, Martin Willi" ""
+.SH "NAME"
+ipsec scepclient \- Client for the SCEP protocol
+.SH "SYNOPSIS"
+.B ipsec scepclient [argument ...]
+.sp
+.B ipsec scepclient
+.B \-\-help
+.br
+.B ipsec scepclient
+.B \-\-version
+.SH "DESCRIPTION"
+.BR scepclient
+is a client implementation of Cisco System's Simple Certificate Enrollment Protocol (SCEP) written for Linux strongSwan <http://www.strongswan.org>.
+.BR scepclient
+is designed to be used for certificate enrollment on machines using the OpenSource IPsec solution
+.I strongSwan.
+.SH "FEATURES"
+.BR scepclient
+implements the following features of SCEP:
+.br
+.IP "\-" 4
+Automatic enrollment of client certificate using a preshared secret
+.IP "\-" 4
+Manual enrollment of client certificate. Offline fingerprint check required!
+.IP "\-" 4
+Acquisition of CA certificate(s)
+.SH "OPTIONS"
+.SS Basic Startup Options
+.B \-v, \-\-version
+.RS 4
+Display the version of ipsec scepclient.
+.PP
+.RE
+.B \-h, \-\-help
+.RS 4
+Display usage of ipsec scepclient.
+.RE
+
+.SS General Options
+.B \-u, \-\-url \fIurl\fP
+.RS 4
+Full HTTP URL of the SCEP server to be used for certificate enrollment and CA certificate acquisition.
+.RE
+.PP
+.B \-+, \-\-optionsfrom \fIfilename\fP
+.RS 4
+Reads additional options from \fIfilename\fP.
+.RE
+.PP
+.B \-f, \-\-force
+.RS 4
+Overwrite existing output file[s].
+.RE
+.PP
+.B \-q, \-\-quiet
+.RS 4
+Do not write log output to stderr.
+.RE
+
+.SS Options for CA Certificate Acquisition
+.B \-o, \-\-out cacert[=\fIfilename\fP]
+.RS 4
+Output file of acquired CA certificate. If more then one CA certificate is available, \fIfilename\fP is used as prefix for the resulting files.
+.br
+The default \fIfilename\fP is $CONFDIR/ipsec.d/cacerts/caCert.der.
+.RE
+
+.SS Options For Certificate Enrollment
+.B \-i, \-\-in \fItype\fP[=\fIfilename\fP]
+.RS 4
+Input file for certificate enrollment. This option can be specified multiple times to specify input files for every \fItype\fP.
+Input files can bei either DER or PEM encoded.
+.PP
+Supported values for \fItype\fP:
+.IP "\fBpkcs1\fP" 12
+RSA private key in PKCS#1 file format. If no input of this type is specified, a RSA key gets generated.
+.br
+The default \fIfilename\fP is $CONFDIR/ipsec.d/private/myKey.der.
+.IP "\fBcacert\-enc\fP" 12
+CA certificate to encrypt the SCEP request. Has to be specified for certificate enrollment.
+.br
+The default \fIfilename\fP is $CONFDIR/ipsec.d/cacerts/caCert.der.
+.IP "\fBcacert\-sig\fP" 12
+CA certificate to check signature of SCEP reply. Has to be specified for certificate enrollment.
+.br
+The default \fIfilename\fP is $CONFDIR/ipsec.d/cacerts/caCert.der.
+.RE
+.PP
+.B \-k, \-\-keylength \fIbits\fP
+.RS 4
+sets the key length for RSA key generation. The default length for a generated rsa key is set to 2048 bit.
+.RE
+.PP
+.B \-D, \-\-days \fIdays\fP
+.RS 4
+Validity of the self-signed X.509 certificate in days. The default is 1825 days (5 years).
+.RE
+.PP
+.B \-S, \-\-startdate \fIYYMMDDHHMMSS\fPZ
+.RS 4
+defines the \fBnotBefore\fP date when the X.509 certificate becomes valid.
+The date has the format \fIYYMMDDHHMMSS\fP and must be specified in UTC (Zulu time).
+If the \fB--startdate\fP option is not specified then the current date is taken as a default.
+.RE
+.PP
+.B \-E, \-\-enddate \fIYYMMDDHHMMSS\fPZ
+.RS 4
+defines the \fBnotAfter\fP date when the X.509 certificate will expire.
+The date has the format \fIYYMMDDHHMMSS\fP and must be specified in UTC (Zulu time).
+If the \fB--enddate\fP option is not specified then the default \fBnotAfter\fP value is computed by
+adding the validity interval specified by the \fB--days\fP option to the \fBnotBefore\fP date.
+.RE
+.PP
+.B \-d, \-\-dn \fIdn\fP
+.RS 4
+Distinguished name as comma separated list of relative distinguished names. Use quotation marks for a distinguished name containing spaces. If the \fB\-\-dn\fP parameter is missing then the default "C=CH, O=Linux strongSwan, CN=\fIhostname\fP"
+is used with \fIhostname\fP being the return value of the \fIgethostname\fP() function.
+.RE
+.PP
+.B \-s, \-\-subjectAltName \fItype\fP=\fIvalue\fP
+.RS 4
+Include subjectAltName in certificate request. This option can be specified multiple times to specify a subjectAltName
+for every \fItype\fP.
+.PP
+Supported values for \fItype\fP:
+.IP "\fBemail\fP" 12
+subjectAltName is a email address.
+.IP "\fBdns\fP" 12
+subjectAltName is a hostname.
+.IP "\fBip\fP" 12
+subjectAltName is a IP address.
+.RE
+.PP
+.B \-p, \-\-password \fIpw\fP
+.RS 4
+Password to be included as a \fIchallenge password\fP in SCEP request.
+If \fIpw\fP is \fB%prompt\fP', the password gets prompted for on the command line.
+.IP
+\- In automatic mode, this password corresponds to the preshared secret for the given enrollment.
+.IP
+\- In manual mode, this password can be used to later revoke the corresponding certificate.
+.RE
+.PP
+.B \-a, \-\-algorithm \fIalgo\fP
+.RS 4
+Change symmetric algorithm to use for encryption of certificate Request.
+The default is \fB3des\-cbc\fP.
+.PP
+Supported values for \fIalgo\fP:
+.IP "\fBdes\-cbc\fP" 12
+DES CBC encryption (key size = 56 bit).
+.IP "\fB3des\-cbc\fP" 12
+Triple DES CBC encryption (key size = 168 bit).
+.RE
+.PP
+.B \-o, \-\-out \fItype\fP[=\fIfilename\fP]
+.RS 4
+Output file for certificate enrollment. This option can be specified multiple times to specify output files for every \fItype\fP.
+.PP
+Supported values for \fItype\fP:
+.IP "\fBpkcs1\fP" 12
+RSA private key in PKCS#1 file format. If specified, the RSA key used for enrollment is stored in file \fIfilename\fP.
+If none of the \fItypes\fP listed below are specified, \fBscepclient\fP will stop after outputting this file.
+.br
+The default \fIfilename\fP is $CONFDIR/ipsec.d/private/myKey.der.
+.IP "\fBpkcs10\fP" 12
+PKCS#10 certificate request. If specified, the PKCS#10 request used or certificate enrollment is stored in file \fIfilename\fP.
+If none of the \fItypes\fP listed below are specified, \fBscepclient\fP will stop after outputting this file.
+.br
+The default \fIfilename\fP is $CONFDIR/ipsec.d/req/myReq.der.
+.IP "\fBpkcs7\fP" 12
+PKCS#7 SCEP request as it is sent using HTTP to the SCEP server. If specified, this SCEP request is stored in file \fIfilename\fP.
+If none of \fItypes\fP listed below is not specified, \fBscepclient\fP will stop after outputting this file.
+.br
+The default \fIfilename\fP is $CONFDIR/ipsec.d/req/pkcs7.der.
+.IP "\fBcert-self\fP" 12
+Self-signed certificate. If specified the self-signed certificate is stored in file \fIfilename\fP.
+.br
+The default \fIfilename\fP is $CONFDIR/ipsec.d/certs/selfCert.der.
+.IP "\fBcert\fP" 12
+Enrolled certificate. This \fItype\fP must be specified for certificate enrollment.
+The enrolled certificate is stored in file \fIfilename\fP.
+.br
+The default \fIfilename\fP is set to $CONFDIR/ipsec.d/certs/myCert.der.
+.RE
+.PP
+.B \-m, \-\-method \fImethod\fP
+.RS 4
+Change HTTP request method for certificate enrollment. Default is \fBget\fP.
+.PP
+Supported values for \fImethod\fP:
+.IP "\fBpost\fP" 12
+Certificate enrollment using HTTP POST. Must be supported by the given SCEP server.
+.IP "\fBget\fP" 12
+Certificate enrollment using HTTP GET.
+.RE
+.PP
+.B \-t, \-\-interval \fIseconds\fP
+.RS 4
+Set interval time in seconds when polling in manual mode.
+The default interval is set to 5 seconds.
+.RE
+.PP
+.B \-x, \-\-maxpolltime \fIseconds\fP
+.RS 4
+Set max time in seconds to poll in manual mode.
+The default max time is set to unlimited.
+.RE
+
+.SS Debugging Output Options:
+.B \-A, \-\-debug\-all
+.RS 4
+Log everything except private data.
+.RE
+.PP
+.B \-P, \-\-debug\-parsing
+.RS 4
+Log parsing relevant stuff.
+.RE
+.PP
+.B \-R, \-\-debug\-raw
+.RS 4
+Log raw hex dumps.
+.RE
+.PP
+.B \-C, \-\-debug\-control
+.RS 4
+Log informations about control flow.
+.RE
+.PP
+.B \-M, \-\-debug\-controlmore
+.RS 4
+Log more detailed informations about control flow.
+.RE
+.PP
+.B \-X, \-\-debug\-private
+.RS 4
+Log sensitive data (e.g. private keys).
+.RE
+.SH "EXAMPLES"
+.B ipsec scepclient \-\-out caCert \-\-url http://scepserver/cgi\-bin/pkiclient.exe \-f
+.RS 4
+Acquire CA certificate from SCEP server and store it in the default file $CONFDIR/ipsec.d/cacerts/caCert.der.
+If more then one CA certificate is returned, store them in files named caCert.der\-1', caCert.der\-2', etc.
+.br
+Existing files are overwritten.
+.RE
+.PP
+.B ipsec scepclient \-\-out pkcs1=joeKey.der \-k 1024
+.RS 4
+Generate RSA private key with key length of 1024 bit and store it in file joeKey.der.
+.RE
+.PP
+.B ipsec scepclient \-\-in pkcs1=joeKey.der \-\-out pkcs10=joeReq.der \e
+.br
+.B \-\-dn \*(rqC=AT, CN=John Doe\*(rq \-s email=john@doe.com \-p mypassword
+.RS 4
+Generate a PKCS#10 request and store it in file joeReq.der. Use the RSA private key joeKey.der
+created earlier to sign the PKCS#10\-Request. In addition to the distinguished name include a
+email\-subjectAltName and a challenge password in the request.
+.RE
+.PP
+.B ipsec scepclient \-\-out pkcs1=joeKey.der \-\-out cert==joeCert.der \e
+.br
+.B \-\-dn \*(rqC=CH, CN=John Doe\*(rq \-k 512 \-p 5xH2pnT7wq \e
+.br
+.B \-\-url http://scep.hsr.ch/cgi\-bin/pkiclient.exe \e
+.br
+.B \-\-in cacert\-enc=caCert.der \-\-in cacert\-sig=caCert.der
+.RS 4
+Generate a new RSA key for the request and store it in joeKey.der. Then enroll a certificate and store as joeCert.der.
+The challenge password is '5xH2pnT7wq'. The encryption and signature check has to be made with the same CA certificate
+caCert.der.
+.RE
+
+
+.SH "BUGS"
+\fB\-\-optionsfrom\fP seems to have parsing problems reading option files containing strings in quotation marks.
+.SH "COPYRIGHT"
+Copyright (C) 2005 Jan Hutter, Martin Willi
+.br
+Hochschule fuer Technik Rapperswil
+.PP
+This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+.PP
+This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
diff --git a/src/scepclient/scepclient.c b/src/scepclient/scepclient.c
new file mode 100644
index 000000000..bde460844
--- /dev/null
+++ b/src/scepclient/scepclient.c
@@ -0,0 +1,1036 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file main.c
+ * @brief scepclient main program
+ */
+
+/**
+ * @mainpage SCEP for Linux strongSwan
+ *
+ * Documentation of SCEP for Linux StrongSwan
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <time.h>
+#include <gmp.h>
+
+#include <freeswan.h>
+
+#include "../pluto/constants.h"
+#include "../pluto/defs.h"
+#include "../pluto/log.h"
+#include "../pluto/oid.h"
+#include "../pluto/asn1.h"
+#include "../pluto/pkcs1.h"
+#include "../pluto/pkcs7.h"
+#include "../pluto/certs.h"
+#include "../pluto/fetch.h"
+#include "../pluto/rnd.h"
+
+#include "rsakey.h"
+#include "pkcs10.h"
+#include "scep.h"
+
+/*
+ * definition of some defaults
+ */
+
+/* default name of DER-encoded PKCS#1 private key file */
+#define DEFAULT_FILENAME_PKCS1 "myKey.der"
+
+/* default name of DER-encoded PKCS#10 certificate request file */
+#define DEFAULT_FILENAME_PKCS10 "myReq.der"
+
+/* default name of DER-encoded PKCS#7 file */
+#define DEFAULT_FILENAME_PKCS7 "pkcs7.der"
+
+/* default name of DER-encoded self-signed X.509 certificate file */
+#define DEFAULT_FILENAME_CERT_SELF "selfCert.der"
+
+/* default name of DER-encoded X.509 certificate file */
+#define DEFAULT_FILENAME_CERT "myCert.der"
+
+/* default name of DER-encoded CA cert file used for key encipherment */
+#define DEFAULT_FILENAME_CACERT_ENC "caCert.der"
+
+/* default name of the der encoded CA cert file used for signature verification */
+#define DEFAULT_FILENAME_CACERT_SIG "caCert.der"
+
+/* default prefix of the der encoded CA certificates received from the SCEP server */
+#define DEFAULT_FILENAME_PREFIX_CACERT "caCert.der"
+
+/* default certificate validity */
+#define DEFAULT_CERT_VALIDITY 5 * 3600 * 24 * 365 /* seconds */
+
+/* default polling time interval in SCEP manual mode */
+#define DEFAULT_POLL_INTERVAL 20 /* seconds */
+
+/* default key length for self-generated RSA keys */
+#define DEFAULT_RSA_KEY_LENGTH 2048 /* bits */
+
+/* default distinguished name */
+#define DEFAULT_DN "C=CH, O=Linux strongSwan, CN="
+
+/* challenge password buffer size */
+#define MAX_PASSWORD_LENGTH 256
+
+/* Max length of filename for tempfile */
+#define MAX_TEMP_FILENAME_LENGTH 256
+
+
+/* current scepclient version */
+static const char *scepclient_version = "1.0";
+
+/* by default the CRL policy is lenient */
+bool strict_crl_policy = FALSE;
+
+/* by default pluto does not check crls dynamically */
+long crl_check_interval = 0;
+
+/* by default pluto logs out after every smartcard use */
+bool pkcs11_keep_state = FALSE;
+
+
+/*
+ * Global variables
+ */
+
+RSA_private_key_t *private_key = NULL;
+
+chunk_t pkcs1;
+chunk_t pkcs7;
+chunk_t subject;
+chunk_t challengePassword;
+chunk_t serialNumber;
+chunk_t transID;
+chunk_t fingerprint;
+chunk_t issuerAndSubject;
+chunk_t getCertInitial;
+chunk_t scep_response;
+cert_t cert;
+
+x509cert_t *x509_signer = NULL;
+x509cert_t *x509_ca_enc = NULL;
+x509cert_t *x509_ca_sig = NULL;
+generalName_t *subjectAltNames = NULL;
+pkcs10_t *pkcs10 = NULL;
+
+/**
+ * @brief exit scepclient
+ *
+ * The log is closed and leaks are reported
+ * if LEAK_DETECTIVE is activated
+ *
+ * @param status 0 = OK, 1 = general discomfort
+ */
+static void
+exit_scepclient(err_t message, ...)
+{
+ if (private_key != NULL)
+ {
+ free_RSA_private_content(private_key);
+ pfree(private_key);
+ }
+ freeanychunk(pkcs1);
+ freeanychunk(pkcs7);
+ freeanychunk(subject);
+ freeanychunk(serialNumber);
+ freeanychunk(transID);
+ freeanychunk(fingerprint);
+ freeanychunk(issuerAndSubject);
+ freeanychunk(getCertInitial);
+ if (scep_response.ptr != NULL)
+ free(scep_response.ptr);
+
+ free_generalNames(subjectAltNames, TRUE);
+ if (x509_signer != NULL)
+ x509_signer->subjectAltName = NULL;
+
+ free_x509cert(x509_signer);
+ free_x509cert(x509_ca_enc);
+ free_x509cert(x509_ca_sig);
+ pkcs10_free(pkcs10);
+
+#ifdef LEAK_DETECTIVE
+ report_leaks();
+#endif /* LEAK_DETECTIVE */
+ close_log();
+
+ /* print any error message to stderr */
+ if (message != NULL && *message != '\0')
+ {
+ va_list args;
+ char m[LOG_WIDTH]; /* longer messages will be truncated */
+
+ va_start(args, message);
+ vsnprintf(m, sizeof(m), message, args);
+ va_end(args);
+
+ fprintf(stderr, "error: %s\n", m);
+ exit(-1);
+ }
+ exit(0);
+}
+
+/**
+ * @brief prints the program version and exits
+ *
+ */
+static void
+version(void)
+{
+ printf("scepclient %s\n", scepclient_version);
+ exit_scepclient(NULL);
+}
+
+/**
+ * @brief prints the usage of the program to the stderr output
+ *
+ * If message is set, program is exitet with 1 (error)
+ * @param message message in case of an error
+ */
+static void
+usage(const char *message)
+{
+ fprintf(stderr,
+ "Usage: scepclient\n"
+ " --help (-h) show usage and exit\n"
+ " --version (-v) show version and exit\n"
+ " --quiet (-q) do not write log output to stderr\n"
+ " --in (-i) <type>[=<filename>] use <filename> of <type> for input \n"
+ " <type> = pkcs1 | cacert-enc | cacert-sig\n"
+ " - if no pkcs1 input is defined, a \n"
+ " RSA key will be generated\n"
+ " - if no filename is given, default is used\n"
+ " --out (-o) <type>[=<filename>] write output of <type> to <filename>\n"
+ " multiple outputs are allowed\n"
+ " <type> = pkcs1 | pkcs10 | pkcs7 | cert-self | cert | cacert\n"
+ " - type cacert defines filename prefix of\n"
+ " received CA certificate(s)\n"
+ " - if no filename is given, default is used\n"
+ " --optionsfrom (-+) <filename> reads additional options from given file\n"
+ " --force (-f) force existing file(s)\n"
+ "\n"
+ "Options for key generation (pkcs1):\n"
+ " --keylength (-k) <bits> key length for RSA key generation\n"
+ "(default: 2048 bits)\n"
+ "\n"
+ "Options for validity:\n"
+ " --days (-D) <days> validity in days\n"
+ " --startdate (-S) <YYMMDDHHMMSS>Z not valid before date\n"
+ " --enddate (-E) <YYMMDDHHMMSS>Z not valid after date\n"
+ "\n"
+ "Options for request generation (pkcs10):\n"
+ " --dn (-d) <dn> comma separated list of distinguished names\n"
+ " --subjectAltName (-s) <t>=<v> include subjectAltName in certificate request\n"
+ " <t> = email | dns | ip \n"
+ " --password (-p) <pw> challenge password\n"
+ " - if pw is '%%prompt', password gets prompted for\n"
+ " --algorithm (-a) <algo> use specified algorithm for PKCS#7 encryption\n"
+ " <algo> = des-cbc | 3des-cbc (default: 3des-cbc)\n"
+ "\n"
+ "Options for enrollment (cert):\n"
+ " --url (-u) <url> url of the SCEP server\n"
+ " --method (-m) post | get http request type\n"
+ " --interval (-t) <seconds> manual mode poll interval in seconds (default 20s)\n"
+ " --maxpolltime (-x) <seconds> max poll time in seconds when in manual mode\n"
+ " (default: unlimited)\n"
+#ifdef DEBUG
+ "\n"
+ "Debugging output:\n"
+ " --debug-all (-A) show everything except private\n"
+ " --debug-parsing (-P) show parsing relevant stuff\n"
+ " --debug-raw (-R) show raw hex dumps\n"
+ " --debug-control (-C) show control flow output\n"
+ " --debug-controlmore (-M) show more control flow\n"
+ " --debug-private (-X) show sensitive data (private keys, etc.)\n"
+#endif
+ );
+ exit_scepclient(message);
+}
+
+/**
+ * @brief main of scepclient
+ *
+ * @param argc number of arguments
+ * @param argv pointer to the argument values
+ */
+int main(int argc, char **argv)
+{
+ /* external values */
+ extern char * optarg;
+ extern int optind;
+
+ /* type of input and output files */
+ typedef enum {
+ PKCS1 = 0x01,
+ PKCS10 = 0x02,
+ PKCS7 = 0x04,
+ CERT_SELF = 0x08,
+ CERT = 0x10,
+ CACERT_ENC = 0x20,
+ CACERT_SIG = 0x40
+ } scep_filetype_t;
+
+ /* filetype to read from, defaults to "generate a key" */
+ scep_filetype_t filetype_in = 0;
+
+ /* filetype to write to, no default here */
+ scep_filetype_t filetype_out = 0;
+
+ /* input files */
+ char *file_in_pkcs1 = DEFAULT_FILENAME_PKCS1;
+ char *file_in_cacert_enc = DEFAULT_FILENAME_CACERT_ENC;
+ char *file_in_cacert_sig = DEFAULT_FILENAME_CACERT_SIG;
+
+ /* output files */
+ char *file_out_pkcs1 = DEFAULT_FILENAME_PKCS1;
+ char *file_out_pkcs10 = DEFAULT_FILENAME_PKCS10;
+ char *file_out_pkcs7 = DEFAULT_FILENAME_PKCS7;
+ char *file_out_cert_self = DEFAULT_FILENAME_CERT_SELF;
+ char *file_out_cert = DEFAULT_FILENAME_CERT;
+ char *file_out_prefix_cacert = DEFAULT_FILENAME_PREFIX_CACERT;
+
+ /* by default user certificate is requested */
+ bool request_ca_certificate = FALSE;
+
+ /* by default existing files are not overwritten */
+ bool force = FALSE;
+
+ /* length of RSA key in bits */
+ u_int rsa_keylength = DEFAULT_RSA_KEY_LENGTH;
+
+ /* validity of self-signed certificate */
+ time_t validity = DEFAULT_CERT_VALIDITY;
+ time_t notBefore = 0;
+ time_t notAfter = 0;
+
+ /* distinguished name for requested certificate, ASCII format */
+ char *distinguishedName = NULL;
+
+ /* challenge password */
+ char challenge_password_buffer[MAX_PASSWORD_LENGTH];
+
+ /* symmetric encryption algorithm used by pkcs7, default is 3DES */
+ int pkcs7_symmetric_cipher = OID_3DES_EDE_CBC;
+
+ /* digest algorithm used by pkcs7, default is MD5 */
+ int pkcs7_digest_alg = OID_MD5;
+
+ /* signature algorithm used by pkcs10, default is MD5 with RSA encryption */
+ int pkcs10_signature_alg = OID_MD5;
+
+ /* URL of the SCEP-Server */
+ char *scep_url = NULL;
+
+ /* http request method, default is GET */
+ fetch_request_t request_type = FETCH_GET;
+
+ /* poll interval time in manual mode in seconds */
+ u_int poll_interval = DEFAULT_POLL_INTERVAL;
+
+ /* maximum poll time */
+ u_int max_poll_time = 0;
+
+ err_t ugh = NULL;
+
+ /* initialize global variables */
+ pkcs1 = empty_chunk;
+ pkcs7 = empty_chunk;
+ serialNumber = empty_chunk;
+ transID = empty_chunk;
+ fingerprint = empty_chunk;
+ issuerAndSubject = empty_chunk;
+ challengePassword = empty_chunk;
+ getCertInitial = empty_chunk;
+ scep_response = empty_chunk;
+ log_to_stderr = TRUE;
+
+ for (;;)
+ {
+ static const struct option long_opts[] = {
+ /* name, has_arg, flag, val */
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'v' },
+ { "optionsfrom", required_argument, NULL, '+' },
+ { "quiet", no_argument, NULL, 'q' },
+ { "in", required_argument, NULL, 'i' },
+ { "out", required_argument, NULL, 'o' },
+ { "force", no_argument, NULL, 'f' },
+ { "keylength", required_argument, NULL, 'k' },
+ { "dn", required_argument, NULL, 'd' },
+ { "days", required_argument, NULL, 'D' },
+ { "startdate", required_argument, NULL, 'S' },
+ { "enddate", required_argument, NULL, 'E' },
+ { "subjectAltName", required_argument, NULL, 's' },
+ { "password", required_argument, NULL, 'p' },
+ { "algorithm", required_argument, NULL, 'a' },
+ { "url", required_argument, NULL, 'u' },
+ { "method", required_argument, NULL, 'm' },
+ { "interval", required_argument, NULL, 't' },
+ { "maxpolltime", required_argument, NULL, 'x' },
+#ifdef DEBUG
+ { "debug-all", no_argument, NULL, 'A' },
+ { "debug-parsing", no_argument, NULL, 'P'},
+ { "debug-raw", no_argument, NULL, 'R'},
+ { "debug-control", no_argument, NULL, 'C'},
+ { "debug-controlmore", no_argument, NULL, 'M'},
+ { "debug-private", no_argument, NULL, 'X'},
+#endif
+ { 0,0,0,0 }
+ };
+
+ /* parse next option */
+ int c = getopt_long(argc, argv, "hv+:qi:o:fk:d:s:p:a:u:m:t:x:APRCMS", long_opts, NULL);
+
+ switch (c)
+ {
+ case EOF: /* end of flags */
+ break;
+
+ case 'h': /* --help */
+ usage(NULL);
+
+ case 'v': /* --version */
+ version();
+
+ case 'q': /* --quiet */
+ log_to_stderr = FALSE;
+ continue;
+
+ case 'i': /* --in <type> [= <filename>] */
+ {
+ char *filename = strstr(optarg, "=");
+
+ if (filename)
+ {
+ /* replace '=' by '\0' */
+ *filename = '\0';
+ /* set pointer to start of filename */
+ filename++;
+ }
+ if (strcasecmp("pkcs1", optarg) == 0)
+ {
+ filetype_in |= PKCS1;
+ if (filename)
+ file_in_pkcs1 = filename;
+ }
+ else if (strcasecmp("cacert-enc", optarg) == 0)
+ {
+ filetype_in |= CACERT_ENC;
+ if (filename)
+ file_in_cacert_enc = filename;
+ }
+ else if (strcasecmp("cacert-sig", optarg) == 0)
+ {
+ filetype_in |= CACERT_SIG;
+ if (filename)
+ file_in_cacert_sig = filename;
+ }
+ else
+ {
+ usage("invalid --in file type");
+ }
+ continue;
+ }
+
+ case 'o': /* --out <type> [= <filename>] */
+ {
+ char *filename = strstr(optarg, "=");
+
+ if (filename)
+ {
+ /* replace '=' by '\0' */
+ *filename = '\0';
+ /* set pointer to start of filename */
+ filename++;
+ }
+ if (strcasecmp("pkcs1", optarg) == 0)
+ {
+ filetype_out |= PKCS1;
+ if (filename)
+ file_out_pkcs1 = filename;
+ }
+ else if (strcasecmp("pkcs10", optarg) == 0)
+ {
+ filetype_out |= PKCS10;
+ if (filename)
+ file_out_pkcs10 = filename;
+ }
+ else if (strcasecmp("pkcs7", optarg) == 0)
+ {
+ filetype_out |= PKCS7;
+ if (filename)
+ file_out_pkcs7 = filename;
+ }
+ else if (strcasecmp("cert-self", optarg) == 0)
+ {
+ filetype_out |= CERT_SELF;
+ if (filename)
+ file_out_cert_self = filename;
+ }
+ else if (strcasecmp("cert", optarg) == 0)
+ {
+ filetype_out |= CERT;
+ if (filename)
+ file_out_cert = filename;
+ }
+ else if (strcasecmp("cacert", optarg) == 0)
+ {
+ request_ca_certificate = TRUE;
+ if (filename)
+ file_out_prefix_cacert = filename;
+ }
+ else
+ {
+ usage("invalid --out file type");
+ }
+ continue;
+ }
+
+ case 'f': /* --force */
+ force = TRUE;
+ continue;
+
+ case '+': /* --optionsfrom <filename> */
+ optionsfrom(optarg, &argc, &argv, optind, stderr);
+ /* does not return on error */
+ continue;
+
+ case 'k': /* --keylength <length> */
+ {
+ div_t q;
+
+ rsa_keylength = atoi(optarg);
+ if (rsa_keylength == 0)
+ usage("invalid keylength");
+
+ /* check if key length is a multiple of 8 bits */
+ q = div(rsa_keylength, 2*BITS_PER_BYTE);
+ if (q.rem != 0)
+ {
+ exit_scepclient("keylength is not a multiple of %d bits!"
+ , 2*BITS_PER_BYTE);
+ }
+ continue;
+ }
+
+ case 'D': /* --days */
+ if (optarg == NULL || !isdigit(optarg[0]))
+ usage("missing number of days");
+ {
+ char *endptr;
+ long days = strtol(optarg, &endptr, 0);
+
+ if (*endptr != '\0' || endptr == optarg
+ || days <= 0)
+ usage("<days> must be a positive number");
+ validity = 24*3600*days;
+ }
+ continue;
+
+ case 'S': /* --startdate */
+ if (optarg == NULL || strlen(optarg) != 13 || optarg[12] != 'Z')
+ usage("date format must be YYMMDDHHMMSSZ");
+ {
+ chunk_t date = { optarg, 13 };
+ notBefore = asn1totime(&date, ASN1_UTCTIME);
+ }
+ continue;
+
+ case 'E': /* --enddate */
+ if (optarg == NULL || strlen(optarg) != 13 || optarg[12] != 'Z')
+ usage("date format must be YYMMDDHHMMSSZ");
+ {
+ chunk_t date = { optarg, 13 };
+ notAfter = asn1totime(&date, ASN1_UTCTIME);
+ }
+ continue;
+
+ case 'd': /* --dn */
+ if (distinguishedName)
+ usage("only one distinguished name allowed");
+ distinguishedName = optarg;
+ continue;
+
+ case 's': /* --subjectAltName */
+ {
+ generalNames_t kind;
+ char *value = strstr(optarg, "=");
+
+ if (value)
+ {
+ /* replace '=' by '\0' */
+ *value = '\0';
+ /* set pointer to start of value */
+ value++;
+ }
+
+ if (!strcasecmp("email", optarg))
+ kind = GN_RFC822_NAME;
+ else if (!strcasecmp("dns", optarg))
+ kind = GN_DNS_NAME;
+ else if (!strcasecmp("ip", optarg))
+ kind = GN_IP_ADDRESS;
+ else
+ {
+ usage("invalid --subjectAltName type");
+ continue;
+ }
+ pkcs10_add_subjectAltName(&subjectAltNames, kind, value);
+ continue;
+ }
+
+ case 'p': /* --password */
+ if (challengePassword.len > 0)
+ usage("only one challenge password allowed");
+
+ if (strcasecmp("%prompt", optarg) == 0)
+ {
+ printf("Challenge password: ");
+ if (fgets(challenge_password_buffer, sizeof(challenge_password_buffer)-1, stdin))
+ {
+ challengePassword.ptr = challenge_password_buffer;
+ /* discard the terminating '\n' from the input */
+ challengePassword.len = strlen(challenge_password_buffer) - 1;
+ }
+ else
+ {
+ usage("challenge password could not be read");
+ }
+ }
+ else
+ {
+ challengePassword.ptr = optarg;
+ challengePassword.len = strlen(optarg);
+ }
+ continue;
+
+ case 'u': /* -- url */
+ if (scep_url)
+ usage("only one URL argument allowed");
+ scep_url = optarg;
+ continue;
+
+ case 'm': /* --method */
+ if (strcasecmp("post", optarg) == 0)
+ request_type = FETCH_POST;
+ else if (strcasecmp("get", optarg) == 0)
+ request_type = FETCH_GET;
+ else
+ usage("invalid http request method specified");
+ continue;
+
+ case 't': /* --interval */
+ poll_interval = atoi(optarg);
+ if (poll_interval <= 0)
+ usage("invalid interval specified");
+ continue;
+
+ case 'x': /* --maxpolltime */
+ max_poll_time = atoi(optarg);
+ if (max_poll_time < 0)
+ usage("invalid maxpolltime specified");
+ continue;
+
+ case 'a': /*--algorithm */
+ if (strcasecmp("des-cbc", optarg) == 0)
+ pkcs7_symmetric_cipher = OID_DES_CBC;
+ else if (strcasecmp("3des-cbc", optarg) == 0)
+ pkcs7_symmetric_cipher = OID_3DES_EDE_CBC;
+ else
+ usage("invalid encryption algorithm specified");
+ continue;
+#ifdef DEBUG
+ case 'A': /* --debug-all */
+ base_debugging |= DBG_ALL;
+ continue;
+ case 'P': /* debug parsing */
+ base_debugging |= DBG_PARSING;
+ continue;
+ case 'R': /* debug raw */
+ base_debugging |= DBG_RAW;
+ continue;
+ case 'C': /* debug control */
+ base_debugging |= DBG_CONTROL;
+ continue;
+ case 'M': /* debug control more */
+ base_debugging |= DBG_CONTROLMORE;
+ continue;
+ case 'X': /* debug private */
+ base_debugging |= DBG_PRIVATE;
+ continue;
+#endif
+ default:
+ usage("unknown option");
+ }
+ /* break from loop */
+ break;
+ }
+
+ init_log("scepclient");
+ cur_debugging = base_debugging;
+ init_rnd_pool();
+ init_fetch();
+
+ if ((filetype_out == 0) && (!request_ca_certificate))
+ usage ("--out filetype required");
+
+ if (request_ca_certificate && (filetype_out > 0 || filetype_in > 0))
+ usage("in CA certificate request, no other --in or --out option allowed");
+
+ /* check if url is given, if cert output defined */
+ if (((filetype_out & CERT) || request_ca_certificate) && !scep_url)
+ usage("URL of SCEP server required");
+
+ /* check for sanity of --in/--out */
+ if (!filetype_in && (filetype_in > filetype_out))
+ usage("cannot generate --out of given --in!");
+
+ /*
+ * input of PKCS#1 file
+ */
+ private_key = alloc_thing(RSA_private_key_t, "RSA_private_key_t");
+
+ if (filetype_in & PKCS1) /* load an RSA key pair from file */
+ {
+ prompt_pass_t pass = { "", FALSE, STDIN_FILENO };
+ const char *path = concatenate_paths(PRIVATE_KEY_PATH, file_in_pkcs1);
+
+ ugh = load_rsa_private_key(path, &pass, private_key);
+ }
+ else /* generate an RSA key pair */
+ {
+ ugh = generate_rsa_private_key(rsa_keylength, private_key);
+ }
+ if (ugh != NULL)
+ exit_scepclient(ugh);
+
+ /* check for minimum key length */
+ if ((private_key->pub.k) < RSA_MIN_OCTETS)
+ {
+ exit_scepclient("length of RSA key has to be at least %d bits"
+ ,RSA_MIN_OCTETS * BITS_PER_BYTE);
+ }
+
+ /*
+ * input of PKCS#10 file
+ */
+ if (filetype_in & PKCS10)
+ {
+ /* user wants to load a pkcs10 request
+ * operation is not yet supported
+ * would require a PKCS#10 parsing function
+
+ pkcs10 = pkcs10_read_from_file(file_in_pkcs10);
+
+ */
+ }
+ else
+ {
+ char buf[IDTOA_BUF];
+ chunk_t dn = empty_chunk;
+
+ dn.ptr = buf;
+
+ if (distinguishedName == NULL)
+ {
+ char buf[BUF_LEN];
+ int n = sprintf(buf, DEFAULT_DN);
+
+ /* set the common name to the hostname */
+ if (gethostname(buf + n, BUF_LEN - n) || strlen(buf) == n)
+ {
+ exit_scepclient("no hostname defined, use "
+ "--dn <distinguished name> option");
+ }
+ distinguishedName = buf;
+ }
+
+ DBG(DBG_CONTROL,
+ DBG_log("dn: '%s'", distinguishedName);
+ )
+ ugh = atodn(distinguishedName, &dn);
+ if (ugh != NULL)
+ exit_scepclient(ugh);
+
+ clonetochunk(subject, dn.ptr, dn.len, "subject dn");
+
+ DBG(DBG_CONTROL,
+ DBG_log("building pkcs10 object:")
+ )
+ pkcs10 = pkcs10_build(private_key, subject, challengePassword
+ , subjectAltNames, pkcs10_signature_alg);
+ scep_generate_pkcs10_fingerprint(pkcs10->request, &fingerprint);
+ plog(" fingerprint: %.*s", (int)fingerprint.len, fingerprint.ptr);
+ }
+
+ /*
+ * output of PKCS#10 file
+ */
+ if (filetype_out & PKCS10)
+ {
+ const char *path = concatenate_paths(REQ_PATH, file_out_pkcs10);
+
+ if (!write_chunk(path, "pkcs10", pkcs10->request, 0022, force))
+ exit_scepclient("could not write pkcs10 file '%s'", path);
+
+ filetype_out &= ~PKCS10; /* delete PKCS10 flag */
+ }
+
+ if (!filetype_out)
+ exit_scepclient(NULL); /* no further output required */
+
+ /*
+ * output of PKCS#1 file
+ */
+ if (filetype_out & PKCS1)
+ {
+ const char *path = concatenate_paths(PRIVATE_KEY_PATH, file_out_pkcs1);
+
+ DBG(DBG_CONTROL,
+ DBG_log("building pkcs1 object:")
+ )
+ pkcs1 = pkcs1_build_private_key(private_key);
+
+ if (!write_chunk(path, "pkcs1", pkcs1, 0066, force))
+ exit_scepclient("could not write pkcs1 file '%s'", path);
+
+ filetype_out &= ~PKCS1; /* delete PKCS1 flag */
+ }
+
+ if (!filetype_out)
+ exit_scepclient(NULL); /* no further output required */
+
+ scep_generate_transaction_id((const RSA_public_key_t *)private_key
+ , &transID, &serialNumber);
+ plog(" transaction ID: %.*s", (int)transID.len, transID.ptr);
+
+ /* generate a self-signed X.509 certificate */
+ x509_signer = alloc_thing(x509cert_t, "signer cert");
+ *x509_signer = empty_x509cert;
+ x509_signer->serialNumber = serialNumber;
+ x509_signer->sigAlg = OID_SHA1_WITH_RSA;
+ x509_signer->issuer = subject;
+ x509_signer->notBefore = (notBefore)? notBefore
+ : time(NULL);
+ x509_signer->notAfter = (notAfter)? notAfter
+ : x509_signer->notBefore + validity;
+ x509_signer->subject = subject;
+ x509_signer->subjectAltName = subjectAltNames;
+
+ build_x509cert(x509_signer, (const RSA_public_key_t *)private_key
+ , private_key);
+
+ /*
+ * output of self-signed X.509 certificate file
+ */
+ if (filetype_out & CERT_SELF)
+ {
+ const char *path = concatenate_paths(HOST_CERT_PATH, file_out_cert_self);
+
+ if (!write_chunk(path, "self-signed cert", x509_signer->certificate, 0022, force))
+ exit_scepclient("could not write self-signed cert file '%s'", path);
+;
+ filetype_out &= ~CERT_SELF; /* delete CERT_SELF flag */
+ }
+
+ if (!filetype_out)
+ exit_scepclient(NULL); /* no further output required */
+
+ /*
+ * load ca encryption certificate
+ */
+ {
+ const char *path = concatenate_paths(CA_CERT_PATH, file_in_cacert_enc);
+ cert_t cert;
+
+ if (!load_cert(path, "encryption cacert", &cert))
+ exit_scepclient("could not load encryption cacert file '%s'", path);
+ x509_ca_enc = cert.u.x509;
+ }
+
+ /*
+ * input of PKCS#7 file
+ */
+ if (filetype_in & PKCS7)
+ {
+ /* user wants to load a pkcs7 encrypted request
+ * operation is not yet supported!
+ * would require additional parsing of transaction-id
+
+ pkcs7 = pkcs7_read_from_file(file_in_pkcs7);
+
+ */
+ }
+ else
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("building pkcs7 request")
+ )
+ pkcs7 = scep_build_request(pkcs10->request
+ , transID, SCEP_PKCSReq_MSG
+ , x509_ca_enc, pkcs7_symmetric_cipher
+ , x509_signer, pkcs7_digest_alg, private_key);
+ }
+
+ /*
+ * output pkcs7 encrypted and signed certificate request
+ */
+ if (filetype_out & PKCS7)
+ {
+ const char *path = concatenate_paths(REQ_PATH, file_out_pkcs7);
+
+ if (!write_chunk(path, "pkcs7 encrypted request", pkcs7, 0022, force))
+ exit_scepclient("could not write pkcs7 file '%s'", path);
+;
+ filetype_out &= ~PKCS7; /* delete PKCS7 flag */
+ }
+
+ if (!filetype_out)
+ exit_scepclient(NULL); /* no further output required */
+
+ /*
+ * output certificate fetch from SCEP server
+ */
+ if (filetype_out & CERT)
+ {
+ const char *path = concatenate_paths(CA_CERT_PATH, file_in_cacert_sig);
+ cert_t cert;
+ time_t poll_start;
+
+ x509cert_t *certs = NULL;
+ chunk_t envelopedData = empty_chunk;
+ chunk_t certData = empty_chunk;
+ contentInfo_t data = empty_contentInfo;
+ scep_attributes_t attrs = empty_scep_attributes;
+
+ if (!load_cert(path, "signature cacert", &cert))
+ exit_scepclient("could not load signature cacert file '%s'", path);
+ x509_ca_sig = cert.u.x509;
+
+ if (!scep_http_request(scep_url, pkcs7, SCEP_PKI_OPERATION
+ , request_type, &scep_response))
+ {
+ exit_scepclient("did not receive a valid scep response");
+ }
+ ugh = scep_parse_response(scep_response, transID, &data, &attrs
+ , x509_ca_sig);
+ if (ugh != NULL)
+ exit_scepclient(ugh);
+
+ /* in case of manual mode, we are going into a polling loop */
+ if (attrs.pkiStatus == SCEP_PENDING)
+ {
+ plog(" scep request pending, polling every %d seconds"
+ , poll_interval);
+ time(&poll_start);
+ issuerAndSubject = asn1_wrap(ASN1_SEQUENCE, "cc"
+ , x509_ca_sig->subject
+ , subject);
+ }
+ while (attrs.pkiStatus == SCEP_PENDING)
+ {
+ if (max_poll_time > 0
+ && (time(NULL) - poll_start >= max_poll_time))
+ {
+ exit_scepclient("maximum poll time reached: %d seconds"
+ , max_poll_time);
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("going to sleep for %d seconds", poll_interval)
+ )
+ sleep(poll_interval);
+ free(scep_response.ptr);
+
+ DBG(DBG_CONTROL,
+ DBG_log("fingerprint: %.*s", (int)fingerprint.len, fingerprint.ptr);
+ DBG_log("transaction ID: %.*s", (int)transID.len, transID.ptr)
+ )
+
+ freeanychunk(getCertInitial);
+ getCertInitial = scep_build_request(issuerAndSubject
+ , transID, SCEP_GetCertInitial_MSG
+ , x509_ca_enc, pkcs7_symmetric_cipher
+ , x509_signer, pkcs7_digest_alg, private_key);
+
+ if (!scep_http_request(scep_url, getCertInitial, SCEP_PKI_OPERATION
+ , request_type, &scep_response))
+ {
+ exit_scepclient("did not receive a valid scep response");
+ }
+ ugh = scep_parse_response(scep_response, transID, &data, &attrs
+ , x509_ca_sig);
+ if (ugh != NULL)
+ exit_scepclient(ugh);
+ }
+
+ if (attrs.pkiStatus != SCEP_SUCCESS)
+ {
+ exit_scepclient("reply status is not 'SUCCESS'");
+ }
+
+ envelopedData = data.content;
+
+ if (data.type != OID_PKCS7_DATA
+ || !parse_asn1_simple_object(&envelopedData, ASN1_OCTET_STRING, 0, "data"))
+ {
+ exit_scepclient("contentInfo is not of type 'data'");
+ }
+ if (!pkcs7_parse_envelopedData(envelopedData, &certData
+ , serialNumber, private_key))
+ {
+ exit_scepclient("could not decrypt envelopedData");
+ }
+ if (!pkcs7_parse_signedData(certData, NULL, &certs, NULL, NULL))
+ {
+ exit_scepclient("error parsing the scep response");
+ }
+ freeanychunk(certData);
+
+ /* store the end entity certificate */
+ path = concatenate_paths(HOST_CERT_PATH, file_out_cert);
+ while (certs != NULL)
+ {
+ bool stored = FALSE;
+ x509cert_t *cert = certs;
+
+ if (!cert->isCA)
+ {
+ if (stored)
+ exit_scepclient("multiple certs received, only first stored");
+ if (!write_chunk(path, "requested cert", cert->certificate, 0022, force))
+ exit_scepclient("could not write cert file '%s'", path);
+ stored = TRUE;
+ }
+ certs = certs->next;
+ free_x509cert(cert);
+ }
+ filetype_out &= ~CERT; /* delete CERT flag */
+ }
+
+ exit_scepclient(NULL);
+ return -1; /* should never be reached */
+}
+
+
diff --git a/src/starter/Makefile.am b/src/starter/Makefile.am
new file mode 100644
index 000000000..7d5a4b69a
--- /dev/null
+++ b/src/starter/Makefile.am
@@ -0,0 +1,37 @@
+ipsec_PROGRAMS = starter
+starter_SOURCES = y.tab.c netkey.c y.tab.h parser.h args.h netkey.h \
+starterwhack.c starterwhack.h starterstroke.c invokepluto.c confread.c \
+starterstroke.h interfaces.c invokepluto.h confread.h interfaces.h args.c \
+keywords.c files.h keywords.h cmp.c starter.c cmp.h exec.c invokecharon.c \
+exec.h invokecharon.h lex.yy.c
+
+INCLUDES = -I$(top_srcdir)/src/libfreeswan -I$(top_srcdir)/src/pluto -I$(top_srcdir)/src/whack -I$(top_srcdir)/src/stroke
+AM_CFLAGS = -DIPSEC_DIR=\"${ipsecdir}\" -DIPSEC_CONFDIR=\"${confdir}\" -DIPSEC_PIDDIR=\"${piddir}\" -DIPSEC_EAPDIR=\"${eapdir}\" -DDEBUG
+starter_LDADD = loglite.o defs.o $(top_srcdir)/src/libfreeswan/libfreeswan.a
+EXTRA_DIST = parser.l parser.y keywords.txt ipsec.conf
+dist_man_MANS = ipsec.conf.5
+MAINTAINERCLEANFILES = lex.yy.c y.tab.c y.tab.h keywords.c
+
+PLUTODIR=$(top_srcdir)/src/pluto
+OPENACDIR=$(top_srcdir)/src/openac
+
+lex.yy.c: y.tab.c parser.l parser.y parser.h
+ $(LEX) parser.l
+
+y.tab.c: parser.l parser.y parser.h
+ $(YACC) -v -d parser.y
+
+y.tab.h: parser.l parser.y parser.h
+ $(YACC) -v -d parser.y
+
+keywords.c: keywords.txt keywords.h
+ $(GPERF) -C -G -t < keywords.txt > keywords.c
+
+loglite.o: $(OPENACDIR)/loglite.c $(PLUTODIR)/log.h
+ $(COMPILE) -c -o $@ $<
+
+defs.o: $(PLUTODIR)/defs.c $(PLUTODIR)/defs.h
+ $(COMPILE) -c -o $@ $<
+
+install-exec-local :
+ test -e "$(sysconfdir)/ipsec.conf" || $(INSTALL) ipsec.conf $(sysconfdir)/ipsec.conf
diff --git a/src/starter/Makefile.in b/src/starter/Makefile.in
new file mode 100644
index 000000000..80410a205
--- /dev/null
+++ b/src/starter/Makefile.in
@@ -0,0 +1,581 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+ipsec_PROGRAMS = starter$(EXEEXT)
+subdir = src/starter
+DIST_COMMON = README $(dist_man_MANS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_CLEAN_FILES =
+am__installdirs = "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(man5dir)"
+ipsecPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(ipsec_PROGRAMS)
+am_starter_OBJECTS = y.tab.$(OBJEXT) netkey.$(OBJEXT) \
+ starterwhack.$(OBJEXT) starterstroke.$(OBJEXT) \
+ invokepluto.$(OBJEXT) confread.$(OBJEXT) interfaces.$(OBJEXT) \
+ args.$(OBJEXT) keywords.$(OBJEXT) cmp.$(OBJEXT) \
+ starter.$(OBJEXT) exec.$(OBJEXT) invokecharon.$(OBJEXT) \
+ lex.yy.$(OBJEXT)
+starter_OBJECTS = $(am_starter_OBJECTS)
+starter_DEPENDENCIES = loglite.o defs.o \
+ $(top_srcdir)/src/libfreeswan/libfreeswan.a
+DEFAULT_INCLUDES = -I. -I$(srcdir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(starter_SOURCES)
+DIST_SOURCES = $(starter_SOURCES)
+man5dir = $(mandir)/man5
+NROFF = nroff
+MANS = $(dist_man_MANS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_EAP_SIM_FALSE = @BUILD_EAP_SIM_FALSE@
+BUILD_EAP_SIM_TRUE = @BUILD_EAP_SIM_TRUE@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GPERF = @GPERF@
+GREP = @GREP@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+USE_CISCO_QUIRKS_FALSE = @USE_CISCO_QUIRKS_FALSE@
+USE_CISCO_QUIRKS_TRUE = @USE_CISCO_QUIRKS_TRUE@
+USE_LEAK_DETECTIVE_FALSE = @USE_LEAK_DETECTIVE_FALSE@
+USE_LEAK_DETECTIVE_TRUE = @USE_LEAK_DETECTIVE_TRUE@
+USE_LIBCURL_FALSE = @USE_LIBCURL_FALSE@
+USE_LIBCURL_TRUE = @USE_LIBCURL_TRUE@
+USE_LIBLDAP_FALSE = @USE_LIBLDAP_FALSE@
+USE_LIBLDAP_TRUE = @USE_LIBLDAP_TRUE@
+USE_NAT_TRANSPORT_FALSE = @USE_NAT_TRANSPORT_FALSE@
+USE_NAT_TRANSPORT_TRUE = @USE_NAT_TRANSPORT_TRUE@
+USE_SMARTCARD_FALSE = @USE_SMARTCARD_FALSE@
+USE_SMARTCARD_TRUE = @USE_SMARTCARD_TRUE@
+USE_VENDORID_FALSE = @USE_VENDORID_FALSE@
+USE_VENDORID_TRUE = @USE_VENDORID_TRUE@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+confdir = @confdir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+eapdir = @eapdir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+ipsecdir = @ipsecdir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+piddir = @piddir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+starter_SOURCES = y.tab.c netkey.c y.tab.h parser.h args.h netkey.h \
+starterwhack.c starterwhack.h starterstroke.c invokepluto.c confread.c \
+starterstroke.h interfaces.c invokepluto.h confread.h interfaces.h args.c \
+keywords.c files.h keywords.h cmp.c starter.c cmp.h exec.c invokecharon.c \
+exec.h invokecharon.h lex.yy.c
+
+INCLUDES = -I$(top_srcdir)/src/libfreeswan -I$(top_srcdir)/src/pluto -I$(top_srcdir)/src/whack -I$(top_srcdir)/src/stroke
+AM_CFLAGS = -DIPSEC_DIR=\"${ipsecdir}\" -DIPSEC_CONFDIR=\"${confdir}\" -DIPSEC_PIDDIR=\"${piddir}\" -DIPSEC_EAPDIR=\"${eapdir}\" -DDEBUG
+starter_LDADD = loglite.o defs.o $(top_srcdir)/src/libfreeswan/libfreeswan.a
+EXTRA_DIST = parser.l parser.y keywords.txt ipsec.conf
+dist_man_MANS = ipsec.conf.5
+MAINTAINERCLEANFILES = lex.yy.c y.tab.c y.tab.h keywords.c
+PLUTODIR = $(top_srcdir)/src/pluto
+OPENACDIR = $(top_srcdir)/src/openac
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/starter/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/starter/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-ipsecPROGRAMS: $(ipsec_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(ipsecdir)" || $(mkdir_p) "$(DESTDIR)$(ipsecdir)"
+ @list='$(ipsec_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ || test -f $$p1 \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(ipsecPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(ipsecdir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(ipsecPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(ipsecdir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-ipsecPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(ipsec_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(ipsecdir)/$$f'"; \
+ rm -f "$(DESTDIR)$(ipsecdir)/$$f"; \
+ done
+
+clean-ipsecPROGRAMS:
+ @list='$(ipsec_PROGRAMS)'; for p in $$list; do \
+ f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f $$p $$f"; \
+ rm -f $$p $$f ; \
+ done
+starter$(EXEEXT): $(starter_OBJECTS) $(starter_DEPENDENCIES)
+ @rm -f starter$(EXEEXT)
+ $(LINK) $(starter_LDFLAGS) $(starter_OBJECTS) $(starter_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/args.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/confread.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exec.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interfaces.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/invokecharon.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/invokepluto.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keywords.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lex.yy.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netkey.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/starter.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/starterstroke.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/starterwhack.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/y.tab.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+install-man5: $(man5_MANS) $(man_MANS)
+ @$(NORMAL_INSTALL)
+ test -z "$(man5dir)" || $(mkdir_p) "$(DESTDIR)$(man5dir)"
+ @list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.5*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 5*) ;; \
+ *) ext='5' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst"; \
+ done
+uninstall-man5:
+ @$(NORMAL_UNINSTALL)
+ @list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.5*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 5*) ;; \
+ *) ext='5' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f '$(DESTDIR)$(man5dir)/$$inst'"; \
+ rm -f "$(DESTDIR)$(man5dir)/$$inst"; \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS) $(MANS)
+installdirs:
+ for dir in "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(man5dir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic clean-ipsecPROGRAMS clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-ipsecPROGRAMS install-man
+
+install-exec-am: install-exec-local
+
+install-info: install-info-am
+
+install-man: install-man5
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-ipsecPROGRAMS uninstall-man
+
+uninstall-man: uninstall-man5
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-ipsecPROGRAMS clean-libtool ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-exec \
+ install-exec-am install-exec-local install-info \
+ install-info-am install-ipsecPROGRAMS install-man install-man5 \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am \
+ uninstall-info-am uninstall-ipsecPROGRAMS uninstall-man \
+ uninstall-man5
+
+
+lex.yy.c: y.tab.c parser.l parser.y parser.h
+ $(LEX) parser.l
+
+y.tab.c: parser.l parser.y parser.h
+ $(YACC) -v -d parser.y
+
+y.tab.h: parser.l parser.y parser.h
+ $(YACC) -v -d parser.y
+
+keywords.c: keywords.txt keywords.h
+ $(GPERF) -C -G -t < keywords.txt > keywords.c
+
+loglite.o: $(OPENACDIR)/loglite.c $(PLUTODIR)/log.h
+ $(COMPILE) -c -o $@ $<
+
+defs.o: $(PLUTODIR)/defs.c $(PLUTODIR)/defs.h
+ $(COMPILE) -c -o $@ $<
+
+install-exec-local :
+ test -e "$(sysconfdir)/ipsec.conf" || $(INSTALL) ipsec.conf $(sysconfdir)/ipsec.conf
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/starter/README b/src/starter/README
new file mode 100644
index 000000000..12a60a11d
--- /dev/null
+++ b/src/starter/README
@@ -0,0 +1,104 @@
+
+IPsec Starter -- Version 0.2 [Contributed by Arkoon Network Security]
+============================ [ http://www.arkoon.net/]
+
+IPsec Starter is aimed to replace all the scripts which are used to
+start and stop strongSwan and to do that in a quicker and a smarter way.
+
+IPsec Starter can also reload the configuration file (kill --HUP or periodicaly)
+and apply the changes.
+
+Usage:
+ starter [--debug] [--auto_update <x seconds>]
+ --debug: enable debugging output
+ --no_fork: all msg (including pluto) are sent to the console
+ --auto_update: reload the config file (like kill -HUP) every x seconds
+ and determine any configuration changes
+
+FEATURES
+--------
+
+o Load and unload KLIPS (ipsec.o kernel module)
+
+o Load modules of the native Linux 2.6 IPsec stack
+
+o Launch and monitor pluto
+
+o Add, initiate, route and del connections
+
+o Attach and detach interfaces according to config file
+
+o kill -HUP can be used to reload the config file. New connections will be
+ added, old ones will be removed and modified ones will be reloaded.
+ Interfaces/Klips/Pluto will be reloaded if necessary.
+
+o Full support of the %defaultroute wildcard parameter.
+
+o save own pid in /var/run/starter
+
+o Upon reloading, dynamic DNS addr will be resolved and reloaded. Use
+ --auto_update to periodicaly check dynamic DNS changes.
+
+o kill -USR1 can be used to reload all connections (delete then add and
+ route/initiate)
+
+o /var/run/dynip/xxxx can be used to use a virtual interface name in
+ ipsec.conf. By example, when adsl can be ppp0, ppp1, ... :
+ ipsec.conf: interfaces="ipsec0=adsl"
+ And use /etc/ppp/ip-up to create /var/run/dynip/adsl
+ /var/run/dynip/adsl: IP_PHYS=ppp0
+
+o %auto can be used to automaticaly name the connections
+
+o kill -TERM can be used to stop FS. pluto will be stopped and KLIPS unloaded
+ (if it has been loaded).
+
+o Can be used to start strongSwan and load lots of connections in a few
+ seconds.
+
+TODO
+----
+
+o handle wildcards in include lines -- use glob() fct
+ ex: include /etc/ipsec.*.conf
+
+o handle duplicates keywords and sections
+
+o 'also' keyword not supported
+
+o manually keyed connections
+
+o IPv6
+
+o Documentation
+
+
+CHANGES
+-------
+
+o Version 0.1 -- 2002.01.14 -- First public release
+
+o Version 0.2 -- 2002.09.04 -- Various enhancements
+ FreeS/WAN 1.98b, x509 0.9.14, algo 0.8.0
+
+o Version 0.2d -- 2004.01.13 -- Adaptions for Openswan 1.0.0
+ by Stephan Scholz <sscholz@astaro.com>
+
+o Version 0.2e -- 2004.10.14 -- Added support for change of interface address
+ by Stephan Scholz <sscholz@astaro.com>
+
+o Version 0.2s -- 2005-12-02 -- Ported to strongSwan
+ by Stephan Scholz <sscholz@astaro.com>
+
+o Version 0.2x -- 2006-01-02 -- Added missing strongSwan keywords
+ Full support of the native Linux 2.6 IPsec stack
+ Full support of %defaultroute
+ Improved parsing of keywords using perfect hash
+ function generated by gperf.
+ by Andreas Steffen <andreas.steffen@hsr.ch>
+
+THANKS
+------
+
+o Nathan Angelacos - include fix
+
diff --git a/src/starter/args.c b/src/starter/args.c
new file mode 100644
index 000000000..82e957f59
--- /dev/null
+++ b/src/starter/args.c
@@ -0,0 +1,632 @@
+/* automatic handling of confread struct arguments
+ * Copyright (C) 2006 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil, Switzerland
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: args.c,v 1.9 2006/04/17 10:32:36 as Exp $
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <freeswan.h>
+
+#include "../pluto/constants.h"
+#include "../pluto/defs.h"
+#include "../pluto/log.h"
+
+#include "keywords.h"
+#include "parser.h"
+#include "confread.h"
+#include "args.h"
+
+/* argument types */
+
+typedef enum {
+ ARG_NONE,
+ ARG_ENUM,
+ ARG_UINT,
+ ARG_TIME,
+ ARG_ULNG,
+ ARG_PCNT,
+ ARG_STR,
+ ARG_LST,
+ ARG_MISC
+} arg_t;
+
+/* various keyword lists */
+
+static const char *LST_bool[] = {
+ "no",
+ "yes",
+ NULL
+};
+
+static const char *LST_sendcert[] = {
+ "always",
+ "ifasked",
+ "never",
+ "yes",
+ "no",
+ NULL
+};
+
+static const char *LST_dpd_action[] = {
+ "none",
+ "clear",
+ "hold",
+ "restart",
+ NULL
+};
+
+static const char *LST_startup[] = {
+ "ignore",
+ "add",
+ "route",
+ "start",
+ NULL
+};
+
+static const char *LST_packetdefault[] = {
+ "drop",
+ "reject",
+ "pass",
+ NULL
+};
+
+static const char *LST_keyexchange[] = {
+ "ike",
+ "ikev1",
+ "ikev2",
+ NULL
+};
+
+static const char *LST_pfsgroup[] = {
+ "modp1024",
+ "modp1536",
+ "modp2048",
+ "modp3072",
+ "modp4096",
+ "modp6144",
+ "modp8192",
+ NULL
+};
+
+static const char *LST_plutodebug[] = {
+ "none",
+ "all",
+ "raw",
+ "crypt",
+ "parsing",
+ "emitting",
+ "control",
+ "lifecycle",
+ "klips",
+ "dns",
+ "natt",
+ "oppo",
+ "controlmore",
+ "private",
+ NULL
+};
+
+static const char *LST_klipsdebug[] = {
+ "tunnel",
+ "tunnel-xmit",
+ "pfkey",
+ "xform",
+ "eroute",
+ "spi",
+ "radij",
+ "esp",
+ "ah",
+ "ipcomp",
+ "verbose",
+ "all",
+ "none",
+ NULL
+};
+
+typedef struct {
+ arg_t type;
+ size_t offset;
+ const char **list;
+} token_info_t;
+
+static const token_info_t token_info[] =
+{
+ /* config setup keywords */
+ { ARG_LST, offsetof(starter_config_t, setup.interfaces), NULL },
+ { ARG_STR, offsetof(starter_config_t, setup.dumpdir), NULL },
+ { ARG_ENUM, offsetof(starter_config_t, setup.charonstart), LST_bool },
+ { ARG_ENUM, offsetof(starter_config_t, setup.plutostart), LST_bool },
+
+ /* pluto/charon keywords */
+ { ARG_LST, offsetof(starter_config_t, setup.plutodebug), LST_plutodebug },
+ { ARG_STR, offsetof(starter_config_t, setup.charondebug), NULL },
+ { ARG_STR, offsetof(starter_config_t, setup.prepluto), NULL },
+ { ARG_STR, offsetof(starter_config_t, setup.postpluto), NULL },
+ { ARG_ENUM, offsetof(starter_config_t, setup.uniqueids), LST_bool },
+ { ARG_UINT, offsetof(starter_config_t, setup.overridemtu), NULL },
+ { ARG_TIME, offsetof(starter_config_t, setup.crlcheckinterval), NULL },
+ { ARG_ENUM, offsetof(starter_config_t, setup.cachecrls), LST_bool },
+ { ARG_ENUM, offsetof(starter_config_t, setup.strictcrlpolicy), LST_bool },
+ { ARG_ENUM, offsetof(starter_config_t, setup.nocrsend), LST_bool },
+ { ARG_ENUM, offsetof(starter_config_t, setup.nat_traversal), LST_bool },
+ { ARG_TIME, offsetof(starter_config_t, setup.keep_alive), NULL },
+ { ARG_STR, offsetof(starter_config_t, setup.virtual_private), NULL },
+ { ARG_STR, offsetof(starter_config_t, setup.eapdir), NULL },
+ { ARG_STR, offsetof(starter_config_t, setup.pkcs11module), NULL },
+ { ARG_ENUM, offsetof(starter_config_t, setup.pkcs11keepstate), LST_bool },
+ { ARG_ENUM, offsetof(starter_config_t, setup.pkcs11proxy), LST_bool },
+
+ /* KLIPS keywords */
+ { ARG_LST, offsetof(starter_config_t, setup.klipsdebug), LST_klipsdebug },
+ { ARG_ENUM, offsetof(starter_config_t, setup.fragicmp), LST_bool },
+ { ARG_STR, offsetof(starter_config_t, setup.packetdefault), LST_packetdefault },
+ { ARG_ENUM, offsetof(starter_config_t, setup.hidetos), LST_bool },
+
+ /* conn section keywords */
+ { ARG_STR, offsetof(starter_conn_t, name), NULL },
+ { ARG_ENUM, offsetof(starter_conn_t, startup), LST_startup },
+ { ARG_ENUM, offsetof(starter_conn_t, keyexchange), LST_keyexchange },
+ { ARG_MISC, 0, NULL /* KW_TYPE */ },
+ { ARG_MISC, 0, NULL /* KW_PFS */ },
+ { ARG_MISC, 0, NULL /* KW_COMPRESS */ },
+ { ARG_MISC, 0, NULL /* KW_AUTH */ },
+ { ARG_MISC, 0, NULL /* KW_AUTHBY */ },
+ { ARG_MISC, 0, NULL /* KW_EAP */ },
+ { ARG_TIME, offsetof(starter_conn_t, sa_ike_life_seconds), NULL },
+ { ARG_TIME, offsetof(starter_conn_t, sa_ipsec_life_seconds), NULL },
+ { ARG_TIME, offsetof(starter_conn_t, sa_rekey_margin), NULL },
+ { ARG_ULNG, offsetof(starter_conn_t, sa_keying_tries), NULL },
+ { ARG_PCNT, offsetof(starter_conn_t, sa_rekey_fuzz), NULL },
+ { ARG_MISC, 0, NULL /* KW_REKEY */ },
+ { ARG_MISC, 0, NULL /* KW_REAUTH */ },
+ { ARG_STR, offsetof(starter_conn_t, ike), NULL },
+ { ARG_STR, offsetof(starter_conn_t, esp), NULL },
+ { ARG_STR, offsetof(starter_conn_t, pfsgroup), LST_pfsgroup },
+ { ARG_TIME, offsetof(starter_conn_t, dpd_delay), NULL },
+ { ARG_TIME, offsetof(starter_conn_t, dpd_timeout), NULL },
+ { ARG_ENUM, offsetof(starter_conn_t, dpd_action), LST_dpd_action },
+ { ARG_MISC, 0, NULL /* KW_MODECONFIG */ },
+ { ARG_MISC, 0, NULL /* KW_XAUTH */ },
+
+ /* ca section keywords */
+ { ARG_STR, offsetof(starter_ca_t, name), NULL },
+ { ARG_ENUM, offsetof(starter_ca_t, startup), LST_startup },
+ { ARG_STR, offsetof(starter_ca_t, cacert), NULL },
+ { ARG_STR, offsetof(starter_ca_t, ldaphost), NULL },
+ { ARG_STR, offsetof(starter_ca_t, ldapbase), NULL },
+ { ARG_STR, offsetof(starter_ca_t, crluri), NULL },
+ { ARG_STR, offsetof(starter_ca_t, crluri2), NULL },
+ { ARG_STR, offsetof(starter_ca_t, ocspuri), NULL },
+ { ARG_STR, offsetof(starter_ca_t, ocspuri2), NULL },
+
+ /* end keywords */
+ { ARG_MISC, 0, NULL /* KW_HOST */ },
+ { ARG_MISC, 0, NULL /* KW_NEXTHOP */ },
+ { ARG_MISC, 0, NULL /* KW_SUBNET */ },
+ { ARG_MISC, 0, NULL /* KW_SUBNETWITHIN */ },
+ { ARG_MISC, 0, NULL /* KW_PROTOPORT */ },
+ { ARG_MISC, 0, NULL /* KW_SOURCEIP */ },
+ { ARG_MISC, 0, NULL /* KW_NATIP */ },
+ { ARG_ENUM, offsetof(starter_end_t, firewall), LST_bool },
+ { ARG_ENUM, offsetof(starter_end_t, hostaccess), LST_bool },
+ { ARG_STR, offsetof(starter_end_t, updown), NULL },
+ { ARG_STR, offsetof(starter_end_t, id), NULL },
+ { ARG_STR, offsetof(starter_end_t, rsakey), NULL },
+ { ARG_STR, offsetof(starter_end_t, cert), NULL },
+ { ARG_ENUM, offsetof(starter_end_t, sendcert), LST_sendcert },
+ { ARG_STR, offsetof(starter_end_t, ca), NULL },
+ { ARG_STR, offsetof(starter_end_t, groups), NULL },
+ { ARG_STR, offsetof(starter_end_t, iface), NULL }
+};
+
+static void
+free_list(char **list)
+{
+ char **s;
+
+ for (s = list; *s; s++)
+ pfree(*s);
+ pfree(list);
+}
+
+char **
+new_list(char *value)
+{
+ char *val, *b, *e, *end, **ret;
+ int count;
+
+ val = value ? clone_str(value, "list value") : NULL;
+ if (!val)
+ return NULL;
+ end = val + strlen(val);
+ for (b = val, count = 0; b < end;)
+ {
+ for (e = b; ((*e != ' ') && (*e != '\0')); e++);
+ *e = '\0';
+ if (e != b)
+ count++;
+ b = e + 1;
+ }
+ if (count == 0)
+ {
+ pfree(val);
+ return NULL;
+ }
+ ret = (char **)alloc_bytes((count+1) * sizeof(char *), "list");
+
+ for (b = val, count = 0; b < end; )
+ {
+ for (e = b; (*e != '\0'); e++);
+ if (e != b)
+ ret[count++] = clone_str(b, "list value");
+ b = e + 1;
+ }
+ ret[count] = NULL;
+ pfree(val);
+ return ret;
+}
+
+
+/*
+ * assigns an argument value to a struct field
+ */
+bool
+assign_arg(kw_token_t token, kw_token_t first, kw_list_t *kw, char *base
+ , bool *assigned)
+{
+ char *p = base + token_info[token].offset;
+ const char **list = token_info[token].list;
+
+ int index = -1; /* used for enumeration arguments */
+
+ lset_t *seen = (lset_t *)base; /* seen flags are at the top of the struct */
+ lset_t f = LELEM(token - first); /* compute flag position of argument */
+
+ *assigned = FALSE;
+
+ DBG(DBG_CONTROLMORE,
+ DBG_log(" %s=%s", kw->entry->name, kw->value)
+ )
+
+ if (*seen & f)
+ {
+ plog("# duplicate '%s' option", kw->entry->name);
+ return FALSE;
+ }
+
+ /* set flag that this argument has been seen */
+ *seen |= f;
+
+ /* is there a keyword list? */
+ if (list != NULL && token_info[token].type != ARG_LST)
+ {
+ bool match = FALSE;
+
+ while (*list != NULL && !match)
+ {
+ index++;
+ match = streq(kw->value, *list++);
+ }
+ if (!match)
+ {
+ plog("# bad value: %s=%s", kw->entry->name, kw->value);
+ return FALSE;
+ }
+ }
+
+ switch (token_info[token].type)
+ {
+ case ARG_NONE:
+ plog("# option '%s' not supported yet", kw->entry->name);
+ return FALSE;
+ case ARG_ENUM:
+ {
+ int *i = (int *)p;
+
+ if (index < 0)
+ {
+ plog("# bad enumeration value: %s=%s (%d)"
+ , kw->entry->name, kw->value, index);
+ return FALSE;
+ }
+ *i = index;
+ }
+ break;
+
+ case ARG_UINT:
+ {
+ char *endptr;
+ u_int *u = (u_int *)p;
+
+ *u = strtoul(kw->value, &endptr, 10);
+
+ if (*endptr != '\0')
+ {
+ plog("# bad integer value: %s=%s", kw->entry->name, kw->value);
+ return FALSE;
+ }
+ }
+ break;
+ case ARG_ULNG:
+ case ARG_PCNT:
+ {
+ char *endptr;
+ unsigned long *l = (unsigned long *)p;
+
+ *l = strtoul(kw->value, &endptr, 10);
+
+ if (token_info[token].type == ARG_ULNG)
+ {
+ if (*endptr != '\0')
+ {
+ plog("# bad integer value: %s=%s", kw->entry->name, kw->value);
+ return FALSE;
+ }
+ }
+ else
+ {
+ if ((*endptr != '%') || (endptr[1] != '\0') || endptr == kw->value)
+ {
+ plog("# bad percent value: %s=%s", kw->entry->name, kw->value);
+ return FALSE;
+ }
+ }
+
+ }
+ break;
+ case ARG_TIME:
+ {
+ char *endptr;
+ time_t *t = (time_t *)p;
+
+ *t = strtoul(kw->value, &endptr, 10);
+
+ /* time in seconds? */
+ if (*endptr == '\0' || (*endptr == 's' && endptr[1] == '\0'))
+ break;
+
+ if (endptr[1] == '\0')
+ {
+ if (*endptr == 'm') /* time in minutes? */
+ {
+ *t *= 60;
+ break;
+ }
+ if (*endptr == 'h') /* time in hours? */
+ {
+ *t *= 3600;
+ break;
+ }
+ if (*endptr == 'd') /* time in days? */
+ {
+ *t *= 3600*24;
+ break;
+ }
+ }
+ plog("# bad duration value: %s=%s", kw->entry->name, kw->value);
+ return FALSE;
+ }
+ case ARG_STR:
+ {
+ char **cp = (char **)p;
+
+ /* free any existing string */
+ pfreeany(*cp);
+
+ /* assign the new string */
+ *cp = clone_str(kw->value, "str_value");
+ }
+ break;
+ case ARG_LST:
+ {
+ char ***listp = (char ***)p;
+
+ /* free any existing list */
+ if (*listp != NULL)
+ free_list(*listp);
+
+ /* create a new list and assign values */
+ *listp = new_list(kw->value);
+
+ /* is there a keyword list? */
+ if (list != NULL)
+ {
+ char ** lst;
+
+ for (lst = *listp; lst && *lst; lst++)
+ {
+ bool match = FALSE;
+
+ list = token_info[token].list;
+
+ while (*list != NULL && !match)
+ {
+ match = streq(*lst, *list++);
+ }
+ if (!match)
+ {
+ plog("# bad value: %s=%s", kw->entry->name, *lst);
+ return FALSE;
+ }
+ }
+ }
+ }
+ default:
+ return TRUE;
+ }
+
+ *assigned = TRUE;
+ return TRUE;
+}
+
+/*
+ * frees all dynamically allocated arguments in a struct
+ */
+void
+free_args(kw_token_t first, kw_token_t last, char *base)
+{
+ kw_token_t token;
+
+ for (token = first; token <= last; token++)
+ {
+ char *p = base + token_info[token].offset;
+
+ switch (token_info[token].type)
+ {
+ case ARG_STR:
+ {
+ char **cp = (char **)p;
+
+ pfreeany(*cp);
+ *cp = NULL;
+ }
+ break;
+ case ARG_LST:
+ {
+ char ***listp = (char ***)p;
+
+ if (*listp != NULL)
+ {
+ free_list(*listp);
+ *listp = NULL;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/*
+ * clone all dynamically allocated arguments in a struct
+ */
+void
+clone_args(kw_token_t first, kw_token_t last, char *base1, char *base2)
+{
+ kw_token_t token;
+
+ for (token = first; token <= last; token++)
+ {
+ if (token_info[token].type == ARG_STR)
+ {
+ char **cp1 = (char **)(base1 + token_info[token].offset);
+ char **cp2 = (char **)(base2 + token_info[token].offset);
+
+ *cp1 = clone_str(*cp2, "cloned str");
+ }
+ }
+}
+
+static bool
+cmp_list(char **list1, char **list2)
+{
+ if ((list1 == NULL) && (list2 == NULL))
+ return TRUE;
+ if ((list1 == NULL) || (list2 == NULL))
+ return FALSE;
+
+ for ( ; *list1 && *list2; list1++, list2++)
+ {
+ if (strcmp(*list1,*list2) != 0)
+ return FALSE;
+ }
+
+ if ((*list1 != NULL) || (*list2 != NULL))
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * compare all arguments in a struct
+ */
+bool
+cmp_args(kw_token_t first, kw_token_t last, char *base1, char *base2)
+{
+ kw_token_t token;
+
+ for (token = first; token <= last; token++)
+ {
+ char *p1 = base1 + token_info[token].offset;
+ char *p2 = base2 + token_info[token].offset;
+
+ switch (token_info[token].type)
+ {
+ case ARG_ENUM:
+ {
+ int *i1 = (int *)p1;
+ int *i2 = (int *)p2;
+
+ if (*i1 != *i2)
+ return FALSE;
+ }
+ break;
+ case ARG_UINT:
+ {
+ u_int *u1 = (u_int *)p1;
+ u_int *u2 = (u_int *)p2;
+
+ if (*u1 != *u2)
+ return FALSE;
+ }
+ break;
+ case ARG_ULNG:
+ case ARG_PCNT:
+ {
+ unsigned long *l1 = (unsigned long *)p1;
+ unsigned long *l2 = (unsigned long *)p2;
+
+ if (*l1 != *l2)
+ return FALSE;
+ }
+ break;
+ case ARG_TIME:
+ {
+ time_t *t1 = (time_t *)p1;
+ time_t *t2 = (time_t *)p2;
+
+ if (*t1 != *t2)
+ return FALSE;
+ }
+ break;
+ case ARG_STR:
+ {
+ char **cp1 = (char **)p1;
+ char **cp2 = (char **)p2;
+
+ if (*cp1 == NULL && *cp2 == NULL)
+ break;
+ if (*cp1 == NULL || *cp2 == NULL || strcmp(*cp1, *cp2) != 0)
+ return FALSE;
+ }
+ break;
+ case ARG_LST:
+ {
+ char ***listp1 = (char ***)p1;
+ char ***listp2 = (char ***)p2;
+
+ if (!cmp_list(*listp1, *listp2))
+ return FALSE;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return TRUE;
+}
diff --git a/src/starter/args.h b/src/starter/args.h
new file mode 100644
index 000000000..302e9bb7b
--- /dev/null
+++ b/src/starter/args.h
@@ -0,0 +1,34 @@
+/* automatic handling of confread struct arguments
+ * Copyright (C) 2006 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil, Switzerland
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: args.h,v 1.3 2006/01/13 18:02:02 as Exp $
+ */
+
+#ifndef _ARGS_H_
+#define _ARGS_H_
+
+#include "keywords.h"
+#include "parser.h"
+
+extern char **new_list(char *value);
+extern bool assign_arg(kw_token_t token, kw_token_t first, kw_list_t *kw
+ , char *base, bool *assigned);
+extern void free_args(kw_token_t first, kw_token_t last, char *base);
+extern void clone_args(kw_token_t first, kw_token_t last, char *base1
+ , char *base2);
+extern bool cmp_args(kw_token_t first, kw_token_t last, char *base1
+ , char *base2);
+
+#endif /* _ARGS_H_ */
+
diff --git a/src/starter/cmp.c b/src/starter/cmp.c
new file mode 100644
index 000000000..9222bf58f
--- /dev/null
+++ b/src/starter/cmp.c
@@ -0,0 +1,105 @@
+/* strongSwan IPsec starter comparison functions
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: cmp.c,v 1.12 2006/01/13 18:03:25 as Exp $
+ */
+
+#include <string.h>
+
+#include <freeswan.h>
+
+#include "../pluto/constants.h"
+#include "../pluto/defs.h"
+
+#include "confread.h"
+#include "args.h"
+#include "interfaces.h"
+#include "cmp.h"
+
+#define VARCMP(obj) if (c1->obj != c2->obj) return FALSE
+#define ADDCMP(obj) if (!sameaddr(&c1->obj,&c2->obj)) return FALSE
+#define SUBCMP(obj) if (!samesubnet(&c1->obj,&c2->obj)) return FALSE
+
+static bool
+starter_cmp_end(starter_end_t *c1, starter_end_t *c2)
+{
+ if ((c1 == NULL) || (c2 == NULL))
+ return FALSE;
+
+ ADDCMP(addr);
+ ADDCMP(nexthop);
+ ADDCMP(srcip);
+ SUBCMP(subnet);
+ VARCMP(has_client);
+ VARCMP(has_client_wildcard);
+ VARCMP(has_port_wildcard);
+ VARCMP(has_srcip);
+ VARCMP(modecfg);
+ VARCMP(port);
+ VARCMP(protocol);
+
+ return cmp_args(KW_END_FIRST, KW_END_LAST, (char *)c1, (char *)c2);
+ }
+
+bool
+starter_cmp_conn(starter_conn_t *c1, starter_conn_t *c2)
+{
+ if ((c1 == NULL) || (c2 == NULL))
+ return FALSE;
+
+ VARCMP(policy);
+ VARCMP(addr_family);
+ VARCMP(tunnel_addr_family);
+
+ if (!starter_cmp_end(&c1->left, &c2->left))
+ return FALSE;
+ if (!starter_cmp_end(&c1->right, &c2->right))
+ return FALSE;
+
+ return cmp_args(KW_CONN_NAME, KW_CONN_LAST, (char *)c1, (char *)c2);
+}
+
+bool
+starter_cmp_ca(starter_ca_t *c1, starter_ca_t *c2)
+{
+ if (c1 == NULL || c2 == NULL)
+ return FALSE;
+
+ return cmp_args(KW_CA_NAME, KW_CA_LAST, (char *)c1, (char *)c2);
+}
+
+bool
+starter_cmp_klips(starter_config_t *c1, starter_config_t *c2)
+{
+ if ((c1 == NULL) || (c2 == NULL))
+ return FALSE;
+
+ return cmp_args(KW_KLIPS_FIRST, KW_KLIPS_LAST, (char *)c1, (char *)c2);
+}
+
+bool
+starter_cmp_pluto(starter_config_t *c1, starter_config_t *c2)
+{
+ if ((c1 == NULL) || (c2 == NULL))
+ return FALSE;
+
+ return cmp_args(KW_PLUTO_FIRST, KW_PLUTO_LAST, (char *)c1, (char *)c2);
+}
+
+bool
+starter_cmp_defaultroute(defaultroute_t *d1, defaultroute_t *d2)
+{
+ if ((d1 == NULL) || (d2 == NULL))
+ return FALSE;
+ return memcmp(d1, d2, sizeof(defaultroute_t)) == 0;
+}
diff --git a/src/starter/cmp.h b/src/starter/cmp.h
new file mode 100644
index 000000000..ca355e9eb
--- /dev/null
+++ b/src/starter/cmp.h
@@ -0,0 +1,29 @@
+/* strongSwan IPsec starter comparison functions
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: cmp.h,v 1.4 2006/01/06 20:24:41 as Exp $
+ */
+
+#ifndef _STARTER_CMP_H_
+#define _STARTER_CMP_H_
+
+#include "interfaces.h"
+
+extern bool starter_cmp_conn(starter_conn_t *c1, starter_conn_t *c2);
+extern bool starter_cmp_ca(starter_ca_t *c1, starter_ca_t *c2);
+extern bool starter_cmp_klips(starter_config_t *c1, starter_config_t *c2);
+extern bool starter_cmp_pluto(starter_config_t *c1, starter_config_t *c2);
+extern bool starter_cmp_defaultroute(defaultroute_t *d1, defaultroute_t *d2);
+
+#endif
+
diff --git a/src/starter/confread.c b/src/starter/confread.c
new file mode 100644
index 000000000..e7a4789a9
--- /dev/null
+++ b/src/starter/confread.c
@@ -0,0 +1,936 @@
+/* strongSwan IPsec config file parser
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: confread.c,v 1.37 2006/04/17 19:35:07 as Exp $
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include <freeswan.h>
+
+#include "../pluto/constants.h"
+#include "../pluto/defs.h"
+#include "../pluto/log.h"
+
+#include "keywords.h"
+#include "parser.h"
+#include "confread.h"
+#include "args.h"
+#include "interfaces.h"
+
+/* strings containing a colon are interpreted as an IPv6 address */
+#define ip_version(string) (strchr(string, ':') != NULL)? AF_INET6 : AF_INET;
+
+static const char ike_defaults[] = "aes128-sha-modp2048";
+static const char esp_defaults[] = "aes128-sha1, 3des-md5";
+
+static const char firewall_defaults[] = "ipsec _updown iptables";
+
+static void default_values(starter_config_t *cfg)
+{
+ if (cfg == NULL)
+ return;
+
+ memset(cfg, 0, sizeof(struct starter_config));
+
+ /* is there enough space for all seen flags? */
+ assert(KW_SETUP_LAST - KW_SETUP_FIRST <
+ sizeof(cfg->setup.seen) * BITS_PER_BYTE);
+ assert(KW_CONN_LAST - KW_CONN_FIRST <
+ sizeof(cfg->conn_default.seen) * BITS_PER_BYTE);
+ assert(KW_END_LAST - KW_END_FIRST <
+ sizeof(cfg->conn_default.right.seen) * BITS_PER_BYTE);
+ assert(KW_CA_LAST - KW_CA_FIRST <
+ sizeof(cfg->ca_default.seen) * BITS_PER_BYTE);
+
+ cfg->setup.seen = LEMPTY;
+ cfg->setup.fragicmp = TRUE;
+ cfg->setup.hidetos = TRUE;
+ cfg->setup.uniqueids = TRUE;
+ cfg->setup.interfaces = new_list("%defaultroute");
+ cfg->setup.charonstart = TRUE;
+ cfg->setup.plutostart = TRUE;
+
+ cfg->conn_default.seen = LEMPTY;
+ cfg->conn_default.startup = STARTUP_NO;
+ cfg->conn_default.state = STATE_IGNORE;
+ cfg->conn_default.policy = POLICY_ENCRYPT | POLICY_TUNNEL | POLICY_RSASIG | POLICY_PFS ;
+
+ cfg->conn_default.ike = clone_str(ike_defaults, "ike_defaults");
+ cfg->conn_default.esp = clone_str(esp_defaults, "esp_defaults");
+ cfg->conn_default.sa_ike_life_seconds = OAKLEY_ISAKMP_SA_LIFETIME_DEFAULT;
+ cfg->conn_default.sa_ipsec_life_seconds = PLUTO_SA_LIFE_DURATION_DEFAULT;
+ cfg->conn_default.sa_rekey_margin = SA_REPLACEMENT_MARGIN_DEFAULT;
+ cfg->conn_default.sa_rekey_fuzz = SA_REPLACEMENT_FUZZ_DEFAULT;
+ cfg->conn_default.sa_keying_tries = SA_REPLACEMENT_RETRIES_DEFAULT;
+ cfg->conn_default.addr_family = AF_INET;
+ cfg->conn_default.tunnel_addr_family = AF_INET;
+
+ cfg->conn_default.left.seen = LEMPTY;
+ cfg->conn_default.right.seen = LEMPTY;
+
+ cfg->conn_default.left.sendcert = CERT_SEND_IF_ASKED;
+ cfg->conn_default.right.sendcert = CERT_SEND_IF_ASKED;
+
+ anyaddr(AF_INET, &cfg->conn_default.left.addr);
+ anyaddr(AF_INET, &cfg->conn_default.left.nexthop);
+ anyaddr(AF_INET, &cfg->conn_default.left.srcip);
+ anyaddr(AF_INET, &cfg->conn_default.right.addr);
+ anyaddr(AF_INET, &cfg->conn_default.right.nexthop);
+ anyaddr(AF_INET, &cfg->conn_default.right.srcip);
+
+ cfg->ca_default.seen = LEMPTY;
+}
+
+#define KW_POLICY_FLAG(sy, sn, fl) \
+ if (streq(kw->value, sy)) { conn->policy |= fl; } \
+ else if (streq(kw->value, sn)) { conn->policy &= ~fl; } \
+ else { plog("# bad policy value: %s=%s", kw->entry->name, kw->value); cfg->err++; }
+
+static void
+load_setup(starter_config_t *cfg, config_parsed_t *cfgp)
+{
+ kw_list_t *kw;
+
+ DBG(DBG_CONTROL,
+ DBG_log("Loading config setup")
+ )
+
+ for (kw = cfgp->config_setup; kw; kw = kw->next)
+ {
+ bool assigned = FALSE;
+
+ kw_token_t token = kw->entry->token;
+
+ if (token < KW_SETUP_FIRST || token > KW_SETUP_LAST)
+ {
+ plog("# unsupported keyword '%s' in config setup", kw->entry->name);
+ cfg->err++;
+ continue;
+ }
+
+ if (!assign_arg(token, KW_SETUP_FIRST, kw, (char *)cfg, &assigned))
+ {
+ plog(" bad argument value in config setup");
+ cfg->err++;
+ continue;
+ }
+ }
+}
+
+static void
+kw_end(starter_conn_t *conn, starter_end_t *end, kw_token_t token
+ , kw_list_t *kw, char *conn_name, starter_config_t *cfg)
+{
+ err_t ugh = NULL;
+ bool assigned = FALSE;
+ int has_port_wildcard; /* set if port is %any */
+
+ char *name = kw->entry->name;
+ char *value = kw->value;
+
+ if (!assign_arg(token, KW_END_FIRST, kw, (char *)end, &assigned))
+ goto err;
+
+ if (token == KW_SENDCERT)
+ {
+ if (end->sendcert == CERT_YES_SEND)
+ end->sendcert = CERT_ALWAYS_SEND;
+ else if (end->sendcert == CERT_NO_SEND)
+ end->sendcert = CERT_NEVER_SEND;
+ }
+
+ if (assigned)
+ return;
+
+ switch (token)
+ {
+ case KW_HOST:
+ if (streq(value, "%defaultroute"))
+ {
+ if (cfg->defaultroute.defined)
+ {
+ end->addr = cfg->defaultroute.addr;
+ end->nexthop = cfg->defaultroute.nexthop;
+ }
+ else
+ {
+ plog("# default route not known: %s=%s", name, value);
+ goto err;
+ }
+ }
+ else if (streq(value, "%any"))
+ {
+ anyaddr(conn->addr_family, &end->addr);
+ }
+ else if (streq(value, "%any6"))
+ {
+ conn->addr_family = AF_INET6;
+ anyaddr(conn->addr_family, &end->addr);
+ }
+ else
+ {
+ conn->addr_family = ip_version(value);
+ ugh = ttoaddr(value, 0, conn->addr_family, &end->addr);
+ if (ugh != NULL)
+ {
+ plog("# bad addr: %s=%s [%s]", name, value, ugh);
+ goto err;
+ }
+ }
+ break;
+ case KW_NEXTHOP:
+ if (streq(value, "%defaultroute"))
+ {
+ if (cfg->defaultroute.defined)
+ end->nexthop = cfg->defaultroute.nexthop;
+ else
+ {
+ plog("# default route not known: %s=%s", name, value);
+ goto err;
+ }
+ }
+ else if (streq(value, "%direct"))
+ {
+ ugh = anyaddr(conn->addr_family, &end->nexthop);
+ }
+ else
+ {
+ conn->addr_family = ip_version(value);
+ ugh = ttoaddr(value, 0, conn->addr_family, &end->nexthop);
+ }
+ if (ugh != NULL)
+ {
+ plog("# bad addr: %s=%s [%s]", name, value, ugh);
+ goto err;
+ }
+ break;
+ case KW_SUBNET:
+ if ((strlen(value) >= 6 && strncmp(value,"vhost:",6) == 0)
+ || (strlen(value) >= 5 && strncmp(value,"vnet:",5) == 0))
+ {
+ end->virt = clone_str(value, "virt");
+ }
+ else
+ {
+ end->has_client = TRUE;
+ conn->tunnel_addr_family = ip_version(value);
+ ugh = ttosubnet(value, 0, conn->tunnel_addr_family, &end->subnet);
+ if (ugh != NULL)
+ {
+ plog("# bad subnet: %s=%s [%s]", name, value, ugh);
+ goto err;
+ }
+ }
+ break;
+ case KW_SUBNETWITHIN:
+ end->has_client = TRUE;
+ end->has_client_wildcard = TRUE;
+ conn->tunnel_addr_family = ip_version(value);
+ ugh = ttosubnet(value, 0, conn->tunnel_addr_family, &end->subnet);
+ break;
+ case KW_PROTOPORT:
+ ugh = ttoprotoport(value, 0, &end->protocol, &end->port, &has_port_wildcard);
+ end->has_port_wildcard = has_port_wildcard;
+ break;
+ case KW_SOURCEIP:
+ if (end->has_natip)
+ {
+ plog("# natip and sourceip cannot be defined at the same time");
+ goto err;
+ }
+ if (streq(value, "%modeconfig") || streq(value, "%modecfg") ||
+ streq(value, "%config") || streq(value, "%cfg"))
+ {
+ end->modecfg = TRUE;
+ }
+ else
+ {
+ conn->tunnel_addr_family = ip_version(value);
+ ugh = ttoaddr(value, 0, conn->tunnel_addr_family, &end->srcip);
+ if (ugh != NULL)
+ {
+ plog("# bad addr: %s=%s [%s]", name, value, ugh);
+ goto err;
+ }
+ end->has_srcip = TRUE;
+ }
+ conn->policy |= POLICY_TUNNEL;
+ break;
+ case KW_NATIP:
+ if (end->has_srcip)
+ {
+ plog("# natip and sourceip cannot be defined at the same time");
+ goto err;
+ }
+ if (streq(value, "%defaultroute"))
+ {
+ if (cfg->defaultroute.defined)
+ {
+ end->srcip = cfg->defaultroute.addr;
+ }
+ else
+ {
+ plog("# default route not known: %s=%s", name, value);
+ goto err;
+ }
+ }
+ else
+ {
+ conn->tunnel_addr_family = ip_version(value);
+ ugh = ttoaddr(value, 0, conn->tunnel_addr_family, &end->srcip);
+ if (ugh != NULL)
+ {
+ plog("# bad addr: %s=%s [%s]", name, value, ugh);
+ goto err;
+ }
+ }
+ end->has_natip = TRUE;
+ conn->policy |= POLICY_TUNNEL;
+ break;
+ default:
+ break;
+ }
+ return;
+
+err:
+ plog(" bad argument value in conn '%s'", conn_name);
+ cfg->err++;
+}
+
+/*
+ * handles left|rightfirewall and left|rightupdown parameters
+ */
+static void
+handle_firewall( const char *label, starter_end_t *end, starter_config_t *cfg)
+{
+ if (end->firewall && (end->seen & LELEM(KW_FIREWALL - KW_END_FIRST)))
+ {
+ if (end->updown != NULL)
+ {
+ plog("# cannot have both %sfirewall and %supdown", label, label);
+ cfg->err++;
+ }
+ else
+ {
+ end->updown = clone_str(firewall_defaults, "firewall_defaults");
+ end->firewall = FALSE;
+ }
+ }
+}
+
+/*
+ * parse a conn section
+ */
+static void
+load_conn(starter_conn_t *conn, kw_list_t *kw, starter_config_t *cfg)
+{
+ char *conn_name = (conn->name == NULL)? "%default":conn->name;
+
+ for ( ; kw; kw = kw->next)
+ {
+ bool assigned = FALSE;
+
+ kw_token_t token = kw->entry->token;
+
+ if (token >= KW_LEFT_FIRST && token <= KW_LEFT_LAST)
+ {
+ kw_end(conn, &conn->left, token - KW_LEFT_FIRST + KW_END_FIRST
+ , kw, conn_name, cfg);
+ continue;
+ }
+ else if (token >= KW_RIGHT_FIRST && token <= KW_RIGHT_LAST)
+ {
+ kw_end(conn, &conn->right, token - KW_RIGHT_FIRST + KW_END_FIRST
+ , kw, conn_name, cfg);
+ continue;
+ }
+
+ if (token == KW_AUTO)
+ {
+ token = KW_CONN_SETUP;
+ }
+ else if (token == KW_ALSO)
+ {
+ if (cfg->parse_also)
+ {
+ also_t *also = alloc_thing(also_t, "also_t");
+
+ also->name = clone_str(kw->value, "also");
+ also->next = conn->also;
+ conn->also = also;
+
+ DBG(DBG_CONTROL,
+ DBG_log(" also=%s", kw->value)
+ )
+ }
+ continue;
+ }
+
+ if (token < KW_CONN_FIRST || token > KW_CONN_LAST)
+ {
+ plog("# unsupported keyword '%s' in conn '%s'"
+ , kw->entry->name, conn_name);
+ cfg->err++;
+ continue;
+ }
+
+ if (!assign_arg(token, KW_CONN_FIRST, kw, (char *)conn, &assigned))
+ {
+ plog(" bad argument value in conn '%s'", conn_name);
+ cfg->err++;
+ continue;
+ }
+
+ if (assigned)
+ continue;
+
+ switch (token)
+ {
+ case KW_TYPE:
+ conn->policy &= ~(POLICY_TUNNEL | POLICY_SHUNT_MASK);
+ if (streq(kw->value, "tunnel"))
+ conn->policy |= POLICY_TUNNEL;
+ else if (streq(kw->value, "beet"))
+ conn->policy |= POLICY_BEET;
+ else if (streq(kw->value, "passthrough") || streq(kw->value, "pass"))
+ conn->policy |= POLICY_SHUNT_PASS;
+ else if (streq(kw->value, "drop"))
+ conn->policy |= POLICY_SHUNT_DROP;
+ else if (streq(kw->value, "reject"))
+ conn->policy |= POLICY_SHUNT_REJECT;
+ else if (strcmp(kw->value, "transport") != 0)
+ {
+ plog("# bad policy value: %s=%s", kw->entry->name, kw->value);
+ cfg->err++;
+ }
+ break;
+ case KW_PFS:
+ KW_POLICY_FLAG("yes", "no", POLICY_PFS)
+ break;
+ case KW_COMPRESS:
+ KW_POLICY_FLAG("yes", "no", POLICY_COMPRESS)
+ break;
+ case KW_AUTH:
+ KW_POLICY_FLAG("ah", "esp", POLICY_AUTHENTICATE)
+ break;
+ case KW_AUTHBY:
+ conn->policy &= ~(POLICY_ID_AUTH_MASK | POLICY_ENCRYPT);
+
+ if (!(streq(kw->value, "never") || streq(kw->value, "eap")))
+ {
+ char *value = kw->value;
+ char *second = strchr(kw->value, '|');
+
+ if (second != NULL)
+ *second = '\0';
+
+ /* also handles the cases secret|rsasig and rsasig|secret */
+ for (;;)
+ {
+ if (streq(value, "rsasig"))
+ conn->policy |= POLICY_RSASIG | POLICY_ENCRYPT;
+ else if (streq(value, "secret") || streq(value, "psk"))
+ conn->policy |= POLICY_PSK | POLICY_ENCRYPT;
+ else if (streq(value, "xauthrsasig"))
+ conn->policy |= POLICY_XAUTH_RSASIG | POLICY_ENCRYPT;
+ else if (streq(value, "xauthpsk"))
+ conn->policy |= POLICY_XAUTH_PSK | POLICY_ENCRYPT;
+ else
+ {
+ plog("# bad policy value: %s=%s", kw->entry->name, kw->value);
+ cfg->err++;
+ break;
+ }
+ if (second == NULL)
+ break;
+ value = second;
+ second = NULL; /* traverse the loop no more than twice */
+ }
+ }
+ break;
+ case KW_EAP:
+ /* TODO: a gperf function for all EAP types */
+ if (streq(kw->value, "aka"))
+ conn->eap = 23;
+ else if (streq(kw->value, "sim"))
+ {
+ conn->eap = 18;
+
+ }
+ else
+ {
+ conn->eap = atoi(kw->value);
+ if (conn->eap == 0)
+ {
+ plog("# unknown EAP type: %s=%s", kw->entry->name, kw->value);
+ cfg->err++;
+ }
+ }
+ break;
+ case KW_REKEY:
+ KW_POLICY_FLAG("no", "yes", POLICY_DONT_REKEY)
+ break;
+ case KW_REAUTH:
+ KW_POLICY_FLAG("no", "yes", POLICY_DONT_REAUTH)
+ break;
+ case KW_MODECONFIG:
+ KW_POLICY_FLAG("push", "pull", POLICY_MODECFG_PUSH)
+ break;
+ case KW_XAUTH:
+ KW_POLICY_FLAG("server", "client", POLICY_XAUTH_SERVER)
+ break;
+ default:
+ break;
+ }
+ }
+ handle_firewall("left", &conn->left, cfg);
+ handle_firewall("right", &conn->right, cfg);
+}
+
+/*
+ * initialize a conn object with the default conn
+ */
+static void
+conn_default(char *name, starter_conn_t *conn, starter_conn_t *def)
+{
+ memcpy(conn, def, sizeof(starter_conn_t));
+ conn->name = clone_str(name, "conn name");
+
+ clone_args(KW_CONN_FIRST, KW_CONN_LAST, (char *)conn, (char *)def);
+ clone_args(KW_END_FIRST, KW_END_LAST, (char *)&conn->left, (char *)&def->left);
+ clone_args(KW_END_FIRST, KW_END_LAST, (char *)&conn->right, (char *)&def->right);
+}
+
+/*
+ * parse a ca section
+ */
+static void
+load_ca(starter_ca_t *ca, kw_list_t *kw, starter_config_t *cfg)
+{
+ char *ca_name = (ca->name == NULL)? "%default":ca->name;
+
+ for ( ; kw; kw = kw->next)
+ {
+ bool assigned = FALSE;
+
+ kw_token_t token = kw->entry->token;
+
+ if (token == KW_AUTO)
+ {
+ token = KW_CA_SETUP;
+ }
+ else if (token == KW_ALSO)
+ {
+ if (cfg->parse_also)
+ {
+ also_t *also = alloc_thing(also_t, "also_t");
+
+ also->name = clone_str(kw->value, "also");
+ also->next = ca->also;
+ ca->also = also;
+
+ DBG(DBG_CONTROL,
+ DBG_log(" also=%s", kw->value)
+ )
+ }
+ continue;
+ }
+
+ if (token < KW_CA_FIRST || token > KW_CA_LAST)
+ {
+ plog("# unsupported keyword '%s' in ca '%s'", kw->entry->name, ca_name);
+ cfg->err++;
+ continue;
+ }
+
+ if (!assign_arg(token, KW_CA_FIRST, kw, (char *)ca, &assigned))
+ {
+ plog(" bad argument value in ca '%s'", ca_name);
+ cfg->err++;
+ }
+ }
+
+ /* treat 'route' and 'start' as 'add' */
+ if (ca->startup != STARTUP_NO)
+ ca->startup = STARTUP_ADD;
+}
+
+/*
+ * initialize a ca object with the default ca
+ */
+static void
+ca_default(char *name, starter_ca_t *ca, starter_ca_t *def)
+{
+ memcpy(ca, def, sizeof(starter_ca_t));
+ ca->name = clone_str(name, "ca name");
+
+ clone_args(KW_CA_FIRST, KW_CA_LAST, (char *)ca, (char *)def);
+}
+
+static kw_list_t*
+find_also_conn(const char* name, starter_conn_t *conn, starter_config_t *cfg);
+
+static void
+load_also_conns(starter_conn_t *conn, also_t *also, starter_config_t *cfg)
+{
+ while (also != NULL)
+ {
+ kw_list_t *kw = find_also_conn(also->name, conn, cfg);
+
+ if (kw == NULL)
+ {
+ plog(" conn '%s' cannot include '%s'", conn->name, also->name);
+ }
+ else
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("conn '%s' includes '%s'", conn->name, also->name)
+ )
+ /* only load if no error occurred in the first round */
+ if (cfg->err == 0)
+ load_conn(conn, kw, cfg);
+ }
+ also = also->next;
+ }
+}
+
+/*
+ * find a conn included by also
+ */
+static kw_list_t*
+find_also_conn(const char* name, starter_conn_t *conn, starter_config_t *cfg)
+{
+ starter_conn_t *c = cfg->conn_first;
+
+ while (c != NULL)
+ {
+ if (streq(name, c->name))
+ {
+ if (conn->visit == c->visit)
+ {
+ plog("# detected also loop");
+ cfg->err++;
+ return NULL;
+ }
+ c->visit = conn->visit;
+ load_also_conns(conn, c->also, cfg);
+ return c->kw;
+ }
+ c = c->next;
+ }
+
+ plog("# also '%s' not found", name);
+ cfg->err++;
+ return NULL;
+}
+
+static kw_list_t*
+find_also_ca(const char* name, starter_ca_t *ca, starter_config_t *cfg);
+
+static void
+load_also_cas(starter_ca_t *ca, also_t *also, starter_config_t *cfg)
+{
+ while (also != NULL)
+ {
+ kw_list_t *kw = find_also_ca(also->name, ca, cfg);
+
+ if (kw == NULL)
+ {
+ plog(" ca '%s' cannot include '%s'", ca->name, also->name);
+ }
+ else
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("ca '%s' includes '%s'", ca->name, also->name)
+ )
+ /* only load if no error occurred in the first round */
+ if (cfg->err == 0)
+ load_ca(ca, kw, cfg);
+ }
+ also = also->next;
+ }
+}
+
+/*
+ * find a ca included by also
+ */
+static kw_list_t*
+find_also_ca(const char* name, starter_ca_t *ca, starter_config_t *cfg)
+{
+ starter_ca_t *c = cfg->ca_first;
+
+ while (c != NULL)
+ {
+ if (streq(name, c->name))
+ {
+ if (ca->visit == c->visit)
+ {
+ plog("# detected also loop");
+ cfg->err++;
+ return NULL;
+ }
+ c->visit = ca->visit;
+ load_also_cas(ca, c->also, cfg);
+ return c->kw;
+ }
+ c = c->next;
+ }
+
+ plog("# also '%s' not found", name);
+ cfg->err++;
+ return NULL;
+}
+
+
+
+/*
+ * load and parse an IPsec configuration file
+ */
+starter_config_t *
+confread_load(const char *file)
+{
+ starter_config_t *cfg = NULL;
+ config_parsed_t *cfgp;
+ section_list_t *sconn, *sca;
+ starter_conn_t *conn;
+ starter_ca_t *ca;
+
+ u_int visit = 0;
+
+ /* load IPSec configuration file */
+ cfgp = parser_load_conf(file);
+ if (!cfgp)
+ return NULL;
+
+ cfg = (starter_config_t *)alloc_thing(starter_config_t, "starter_config_t");
+
+ /* set default values */
+ default_values(cfg);
+
+ /* determine default route */
+ get_defaultroute(&cfg->defaultroute);
+
+ /* load config setup section */
+ load_setup(cfg, cfgp);
+
+ /* in the first round parse also statements */
+ cfg->parse_also = TRUE;
+
+ /* find %default ca section */
+ for (sca = cfgp->ca_first; sca; sca = sca->next)
+ {
+ if (streq(sca->name, "%default"))
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("Loading ca %%default")
+ )
+ load_ca(&cfg->ca_default, sca->kw, cfg);
+ }
+ }
+
+ /* parameters defined in ca %default sections can be overloads */
+ cfg->ca_default.seen = LEMPTY;
+
+ /* load other ca sections */
+ for (sca = cfgp->ca_first; sca; sca = sca->next)
+ {
+ /* skip %default ca section */
+ if (streq(sca->name, "%default"))
+ continue;
+
+ DBG(DBG_CONTROL,
+ DBG_log("Loading ca '%s'", sca->name)
+ )
+ ca = (starter_ca_t *)alloc_thing(starter_ca_t, "starter_ca_t");
+
+ ca_default(sca->name, ca, &cfg->ca_default);
+ ca->kw = sca->kw;
+ ca->next = NULL;
+
+ if (cfg->ca_last)
+ cfg->ca_last->next = ca;
+ cfg->ca_last = ca;
+ if (!cfg->ca_first)
+ cfg->ca_first = ca;
+
+ load_ca(ca, ca->kw, cfg);
+ }
+
+ for (ca = cfg->ca_first; ca; ca = ca->next)
+ {
+ also_t *also = ca->also;
+
+ while (also != NULL)
+ {
+ kw_list_t *kw = find_also_ca(also->name, cfg->ca_first, cfg);
+
+ load_ca(ca, kw, cfg);
+ also = also->next;
+ }
+
+ if (ca->startup != STARTUP_NO)
+ ca->state = STATE_TO_ADD;
+ }
+
+ /* find %default conn sections */
+ for (sconn = cfgp->conn_first; sconn; sconn = sconn->next)
+ {
+ if (streq(sconn->name, "%default"))
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("Loading conn %%default")
+ )
+ load_conn(&cfg->conn_default, sconn->kw, cfg);
+ }
+ }
+
+ /* parameter defined in conn %default sections can be overloaded */
+ cfg->conn_default.seen = LEMPTY;
+ cfg->conn_default.right.seen = LEMPTY;
+ cfg->conn_default.left.seen = LEMPTY;
+
+ /* load other conn sections */
+ for (sconn = cfgp->conn_first; sconn; sconn = sconn->next)
+ {
+ /* skip %default conn section */
+ if (streq(sconn->name, "%default"))
+ continue;
+
+ DBG(DBG_CONTROL,
+ DBG_log("Loading conn '%s'", sconn->name)
+ )
+ conn = (starter_conn_t *)alloc_thing(starter_conn_t, "starter_conn_t");
+
+ conn_default(sconn->name, conn, &cfg->conn_default);
+ conn->kw = sconn->kw;
+ conn->next = NULL;
+
+ if (cfg->conn_last)
+ cfg->conn_last->next = conn;
+ cfg->conn_last = conn;
+ if (!cfg->conn_first)
+ cfg->conn_first = conn;
+
+ load_conn(conn, conn->kw, cfg);
+ }
+
+ /* in the second round do not parse also statements */
+ cfg->parse_also = FALSE;
+
+ for (ca = cfg->ca_first; ca; ca = ca->next)
+ {
+ ca->visit = ++visit;
+ load_also_cas(ca, ca->also, cfg);
+
+ if (ca->startup != STARTUP_NO)
+ ca->state = STATE_TO_ADD;
+ }
+
+ for (conn = cfg->conn_first; conn; conn = conn->next)
+ {
+ conn->visit = ++visit;
+ load_also_conns(conn, conn->also, cfg);
+
+ if (conn->startup != STARTUP_NO)
+ conn->state = STATE_TO_ADD;
+ }
+
+ parser_free_conf(cfgp);
+
+ if (cfg->err)
+ {
+ plog("### %d parsing error%s ###", cfg->err, (cfg->err > 1)?"s":"");
+ confread_free(cfg);
+ cfg = NULL;
+ }
+
+ return cfg;
+}
+
+/*
+ * free the memory used by also_t objects
+ */
+static void
+free_also(also_t *head)
+{
+ while (head != NULL)
+ {
+ also_t *also = head;
+
+ head = also->next;
+ pfree(also->name);
+ pfree(also);
+ }
+}
+
+/*
+ * free the memory used by a starter_conn_t object
+ */
+static void
+confread_free_conn(starter_conn_t *conn)
+{
+ free_args(KW_END_FIRST, KW_END_LAST, (char *)&conn->left);
+ free_args(KW_END_FIRST, KW_END_LAST, (char *)&conn->right);
+ free_args(KW_CONN_NAME, KW_CONN_LAST, (char *)conn);
+ free_also(conn->also);
+}
+
+/*
+ * free the memory used by a starter_ca_t object
+ */
+static void
+confread_free_ca(starter_ca_t *ca)
+{
+ free_args(KW_CA_NAME, KW_CA_LAST, (char *)ca);
+ free_also(ca->also);
+}
+
+/*
+ * free the memory used by a starter_config_t object
+ */
+void
+confread_free(starter_config_t *cfg)
+{
+ starter_conn_t *conn = cfg->conn_first;
+ starter_ca_t *ca = cfg->ca_first;
+
+ free_args(KW_SETUP_FIRST, KW_SETUP_LAST, (char *)cfg);
+
+ confread_free_conn(&cfg->conn_default);
+
+ while (conn != NULL)
+ {
+ starter_conn_t *conn_aux = conn;
+
+ conn = conn->next;
+ confread_free_conn(conn_aux);
+ pfree(conn_aux);
+ }
+
+ confread_free_ca(&cfg->ca_default);
+
+ while (ca != NULL)
+ {
+ starter_ca_t *ca_aux = ca;
+
+ ca = ca->next;
+ confread_free_ca(ca_aux);
+ pfree(ca_aux);
+ }
+
+ pfree(cfg);
+}
diff --git a/src/starter/confread.h b/src/starter/confread.h
new file mode 100644
index 000000000..e0de68376
--- /dev/null
+++ b/src/starter/confread.h
@@ -0,0 +1,210 @@
+/* strongSwan IPsec config file parser
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: confread.h,v 1.23 2006/04/17 10:32:36 as Exp $
+ */
+
+#ifndef _IPSEC_CONFREAD_H_
+#define _IPSEC_CONFREAD_H_
+
+#ifndef _FREESWAN_H
+#include <freeswan.h>
+#include "../pluto/constants.h"
+#endif
+
+#include "parser.h"
+#include "interfaces.h"
+
+typedef enum {
+ STARTUP_NO,
+ STARTUP_ADD,
+ STARTUP_ROUTE,
+ STARTUP_START
+} startup_t;
+
+typedef enum {
+ STATE_IGNORE,
+ STATE_TO_ADD,
+ STATE_ADDED,
+ STATE_REPLACED,
+ STATE_INVALID
+} starter_state_t;
+
+typedef enum {
+ KEY_EXCHANGE_IKE,
+ KEY_EXCHANGE_IKEV1,
+ KEY_EXCHANGE_IKEV2
+} keyexchange_t;
+
+typedef struct starter_end starter_end_t;
+
+struct starter_end {
+ lset_t seen;
+ char *id;
+ char *rsakey;
+ char *cert;
+ char *ca;
+ char *groups;
+ char *iface;
+ ip_address addr;
+ ip_address nexthop;
+ ip_address srcip;
+ ip_subnet subnet;
+ bool has_client;
+ bool has_client_wildcard;
+ bool has_port_wildcard;
+ bool has_srcip;
+ bool has_natip;
+ bool modecfg;
+ certpolicy_t sendcert;
+ bool firewall;
+ bool hostaccess;
+ char *updown;
+ u_int16_t port;
+ u_int8_t protocol;
+ char *virt;
+};
+
+typedef struct also also_t;
+
+struct also {
+ char *name;
+ bool included;
+ also_t *next;
+};
+
+typedef struct starter_conn starter_conn_t;
+
+struct starter_conn {
+ lset_t seen;
+ char *name;
+ also_t *also;
+ kw_list_t *kw;
+ u_int visit;
+ startup_t startup;
+ starter_state_t state;
+
+ keyexchange_t keyexchange;
+ int eap;
+ lset_t policy;
+ time_t sa_ike_life_seconds;
+ time_t sa_ipsec_life_seconds;
+ time_t sa_rekey_margin;
+ unsigned long sa_keying_tries;
+ unsigned long sa_rekey_fuzz;
+ sa_family_t addr_family;
+ sa_family_t tunnel_addr_family;
+
+ starter_end_t left, right;
+
+ unsigned long id;
+
+ char *esp;
+ char *ike;
+ char *pfsgroup;
+
+ time_t dpd_delay;
+ time_t dpd_timeout;
+ dpd_action_t dpd_action;
+ int dpd_count;
+
+ starter_conn_t *next;
+};
+
+typedef struct starter_ca starter_ca_t;
+
+struct starter_ca {
+ lset_t seen;
+ char *name;
+ also_t *also;
+ kw_list_t *kw;
+ u_int visit;
+ startup_t startup;
+ starter_state_t state;
+
+ char *cacert;
+ char *ldaphost;
+ char *ldapbase;
+ char *crluri;
+ char *crluri2;
+ char *ocspuri;
+ char *ocspuri2;
+
+ bool strict;
+
+ starter_ca_t *next;
+};
+
+typedef struct starter_config starter_config_t;
+
+struct starter_config {
+ struct {
+ lset_t seen;
+ char **interfaces;
+ char *dumpdir;
+ bool charonstart;
+ bool plutostart;
+
+ /* pluto/charon keywords */
+ char **plutodebug;
+ char *charondebug;
+ char *prepluto;
+ char *postpluto;
+ bool uniqueids;
+ u_int overridemtu;
+ u_int crlcheckinterval;
+ bool cachecrls;
+ bool strictcrlpolicy;
+ bool nocrsend;
+ bool nat_traversal;
+ u_int keep_alive;
+ char *virtual_private;
+ char *eapdir;
+ char *pkcs11module;
+ bool pkcs11keepstate;
+ bool pkcs11proxy;
+
+ /* KLIPS keywords */
+ char **klipsdebug;
+ bool fragicmp;
+ char *packetdefault;
+ bool hidetos;
+ } setup;
+
+ /* information about the default route */
+ defaultroute_t defaultroute;
+
+ /* number of encountered parsing errors */
+ u_int err;
+
+ /* do we parse also statements */
+ bool parse_also;
+
+ /* ca %default */
+ starter_ca_t ca_default;
+
+ /* connections list (without %default) */
+ starter_ca_t *ca_first, *ca_last;
+
+ /* conn %default */
+ starter_conn_t conn_default;
+
+ /* connections list (without %default) */
+ starter_conn_t *conn_first, *conn_last;
+};
+
+extern starter_config_t *confread_load(const char *file);
+extern void confread_free(starter_config_t *cfg);
+
+#endif /* _IPSEC_CONFREAD_H_ */
+
diff --git a/src/starter/exec.c b/src/starter/exec.c
new file mode 100644
index 000000000..98541db75
--- /dev/null
+++ b/src/starter/exec.c
@@ -0,0 +1,54 @@
+/* strongSwan IPsec exec helper function
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: exec.c,v 1.4 2006/01/04 23:30:24 as Exp $
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <freeswan.h>
+
+#include "../pluto/constants.h"
+#include "../pluto/defs.h"
+#include "../pluto/log.h"
+
+#include "exec.h"
+
+#define BUF_SIZE 2048
+
+/**
+ * TODO:
+ * o log stdout with LOG_LEVEL_INFO and stderr with LOG_LEVEL_ERR
+ */
+
+int
+starter_exec(const char *fmt, ...)
+{
+ va_list args;
+ static char buf[BUF_SIZE];
+ int r;
+
+ va_start (args, fmt);
+ vsnprintf(buf, BUF_SIZE-1, fmt, args);
+ buf[BUF_SIZE - 1] = '\0';
+ va_end(args);
+ r = system(buf);
+ DBG(DBG_CONTROL,
+ DBG_log("starter_exec(%s) = %d", buf, r)
+ )
+ return r;
+}
+
diff --git a/src/starter/exec.h b/src/starter/exec.h
new file mode 100644
index 000000000..d4be931dd
--- /dev/null
+++ b/src/starter/exec.h
@@ -0,0 +1,23 @@
+/* strongSwan IPsec starter exec helper function
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: exec.h,v 1.2 2005/12/28 10:20:32 as Exp $
+ */
+
+#ifndef _STARTER_EXEC_H_
+#define _STARTER_EXEC_H_
+
+extern int starter_exec (const char *fmt, ...);
+
+#endif /* _STARTER_EXEC_H_ */
+
diff --git a/src/starter/files.h b/src/starter/files.h
new file mode 100644
index 000000000..88b670d94
--- /dev/null
+++ b/src/starter/files.h
@@ -0,0 +1,40 @@
+/* strongSwan file locations
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: files.h,v 1.5 2006/02/04 18:52:58 as Exp $
+ */
+
+#ifndef _STARTER_FILES_H_
+#define _STARTER_FILES_H_
+
+#define STARTER_PID_FILE IPSEC_PIDDIR "/starter.pid"
+
+#define PROC_NETKEY "/proc/net/pfkey"
+#define PROC_MODULES "/proc/modules"
+
+#define CONFIG_FILE IPSEC_CONFDIR "/ipsec.conf"
+#define SECRETS_FILE IPSEC_CONFDIR "/ipsec.secrets"
+
+#define PLUTO_CMD IPSEC_DIR "/pluto"
+#define PLUTO_CTL_FILE IPSEC_PIDDIR "/pluto.ctl"
+#define PLUTO_PID_FILE IPSEC_PIDDIR "/pluto.pid"
+
+#define CHARON_CMD IPSEC_DIR "/charon"
+#define CHARON_CTL_FILE IPSEC_PIDDIR "/charon.ctl"
+#define CHARON_PID_FILE IPSEC_PIDDIR "/charon.pid"
+
+#define DYNIP_DIR IPSEC_PIDDIR "/dynip"
+#define INFO_FILE IPSEC_PIDDIR "/ipsec.info"
+
+#endif /* _STARTER_FILES_H_ */
+
diff --git a/src/starter/interfaces.c b/src/starter/interfaces.c
new file mode 100644
index 000000000..a7c8efd44
--- /dev/null
+++ b/src/starter/interfaces.c
@@ -0,0 +1,595 @@
+/* strongSwan IPsec interfaces management
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: interfaces.c,v 1.15 2006/02/05 10:51:55 as Exp $
+ */
+
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <linux/if.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <freeswan.h>
+#include <ipsec_tunnel.h>
+
+#include <constants.h>
+#include <defs.h>
+#include <log.h>
+
+#include "interfaces.h"
+#include "exec.h"
+#include "files.h"
+
+#define MIN(a,b) ( ((a)>(b)) ? (b) : (a) )
+
+#define N_IPSEC_IF 4
+
+struct st_ipsec_if {
+ char name[IFNAMSIZ];
+ char phys[IFNAMSIZ];
+ int up;
+};
+
+static struct st_ipsec_if _ipsec_if[N_IPSEC_IF];
+
+static char *
+_find_physical_iface(int sock, char *iface)
+{
+ static char _if[IFNAMSIZ];
+ char *b;
+ struct ifreq req;
+ FILE *fd;
+ char line[BUF_LEN];
+
+ strncpy(req.ifr_name, iface, IFNAMSIZ);
+ if (ioctl(sock, SIOCGIFFLAGS, &req)==0)
+ {
+ if (req.ifr_flags & IFF_UP)
+ {
+ strncpy(_if, iface, IFNAMSIZ);
+ return _if;
+ }
+ }
+ else
+ {
+ /* If there is a file named /var/run/dynip/<iface>, look if we
+ * can get interface name from there (IP_PHYS)
+ */
+ b = (char *)alloc_bytes(strlen(DYNIP_DIR) + strlen(iface) + 10, "iface");
+ if (b)
+ {
+ sprintf(b, "%s/%s", DYNIP_DIR, iface);
+ fd = fopen(b, "r");
+ pfree(b);
+ if (fd)
+ {
+ memset(_if, 0, sizeof(_if));
+ memset(line, 0, sizeof(line));
+ while (fgets(line, sizeof(line), fd) != 0)
+ {
+ if ((strncmp(line,"IP_PHYS=\"", 9) == 0)
+ && (line[strlen(line) - 2] == '"')
+ && (line[strlen(line) - 1] == '\n'))
+ {
+ strncpy(_if, line + 9, MIN(strlen(line) - 11, IFNAMSIZ));
+ break;
+ }
+ else if ((strncmp(line,"IP_PHYS=", 8) == 0)
+ && (line[8] != '"')
+ && (line[strlen(line) - 1] == '\n'))
+ {
+ strncpy(_if, line + 8, MIN(strlen(line) - 9, IFNAMSIZ));
+ break;
+ }
+ }
+ fclose(fd);
+
+ if (*_if)
+ {
+ strncpy(req.ifr_name, _if, IFNAMSIZ);
+ if (ioctl(sock, SIOCGIFFLAGS, &req) == 0)
+ {
+ if (req.ifr_flags & IFF_UP)
+ return _if;
+ }
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+int
+starter_iface_find(char *iface, int af, ip_address *dst, ip_address *nh)
+{
+ char *phys;
+ struct ifreq req;
+ struct sockaddr_in *sa = (struct sockaddr_in *)(&req.ifr_addr);
+ int sock;
+
+ if (!iface)
+ return -1;
+
+ sock = socket(af, SOCK_DGRAM, 0);
+ if (sock < 0)
+ return -1;
+
+ phys = _find_physical_iface(sock, iface);
+ if (!phys)
+ goto failed;
+
+ strncpy(req.ifr_name, phys, IFNAMSIZ);
+ if (ioctl(sock, SIOCGIFFLAGS, &req)!=0)
+ goto failed;
+ if (!(req.ifr_flags & IFF_UP))
+ goto failed;
+
+ if ((req.ifr_flags & IFF_POINTOPOINT)
+ && nh
+ && ioctl(sock, SIOCGIFDSTADDR, &req) == 0)
+ {
+ if (sa->sin_family == af)
+ initaddr((const void *)&sa->sin_addr, sizeof(struct in_addr), af, nh);
+ }
+ if ((dst) && (ioctl(sock, SIOCGIFADDR, &req) == 0))
+ {
+ if (sa->sin_family == af)
+ initaddr((const void *)&sa->sin_addr, sizeof(struct in_addr), af, dst);
+ }
+ close(sock);
+ return 0;
+
+failed:
+ close(sock);
+ return -1;
+}
+
+static int
+valid_str(char *str, unsigned int *pn, char **pphys
+, defaultroute_t *defaultroute)
+{
+ if (streq(str, "%defaultroute"))
+ {
+ if (!defaultroute->defined)
+ {
+ return 0;
+ }
+ *pn = 0;
+ *pphys = defaultroute->iface;
+ }
+ else
+ {
+ if (strlen(str) < 8
+ || str[0] != 'i' || str[1] != 'p' || str[2] !='s' || str[3] != 'e'
+ || str[4] != 'c' || str[5] < '0' || str[5] > '9' || str[6] != '=')
+ {
+ return 0;
+ }
+ *pn = str[5] - '0';
+ *pphys = &(str[7]);
+ }
+ return 1;
+}
+
+static int
+_iface_up (int sock, struct st_ipsec_if *iface, char *phys
+, unsigned int mtu, bool nat_t)
+{
+ struct ifreq req;
+ struct ipsectunnelconf *shc=(struct ipsectunnelconf *)&req.ifr_data;
+ short phys_flags;
+ int ret = 0;
+ /* sscholz@astaro.com: for network mask 32 bit
+ struct sockaddr_in *inp;
+ */
+
+ strncpy(req.ifr_name, phys, IFNAMSIZ);
+ if (ioctl(sock, SIOCGIFFLAGS, &req) !=0 )
+ return ret;
+ phys_flags = req.ifr_flags;
+
+ strncpy(req.ifr_name, iface->name, IFNAMSIZ);
+ if (ioctl(sock, SIOCGIFFLAGS, &req) != 0)
+ return ret;
+
+ if ((!(req.ifr_flags & IFF_UP)) || (!iface->up))
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("attaching interface %s to %s", iface->name, phys)
+ )
+ ret = 1;
+ }
+
+ if ((*iface->phys) && (strcmp(iface->phys, phys) != 0 ))
+ {
+ /* tncfg --detach if phys has changed */
+ strncpy(req.ifr_name, iface->name, IFNAMSIZ);
+ ioctl(sock, IPSEC_DEL_DEV, &req);
+ ret = 1;
+ }
+
+ /* tncfg --attach */
+ strncpy(req.ifr_name, iface->name, IFNAMSIZ);
+ strncpy(shc->cf_name, phys, sizeof(shc->cf_name));
+ ioctl(sock, IPSEC_SET_DEV, &req);
+
+ /* set ipsec addr = phys addr */
+ strncpy(req.ifr_name, phys, IFNAMSIZ);
+ if (ioctl(sock, SIOCGIFADDR, &req) == 0)
+ {
+ strncpy(req.ifr_name, iface->name, IFNAMSIZ);
+ ioctl(sock, SIOCSIFADDR, &req);
+ }
+
+ /* set ipsec mask = phys mask */
+ strncpy(req.ifr_name, phys, IFNAMSIZ);
+ if (ioctl(sock, SIOCGIFNETMASK, &req) == 0)
+ {
+ strncpy(req.ifr_name, iface->name, IFNAMSIZ);
+ /* sscholz@astaro.com: changed netmask to 32 bit
+ * in order to prevent network routes from being created
+
+ inp = (struct sockaddr_in *)&req.ifr_addr;
+ inp->sin_addr.s_addr = 0xFFFFFFFFL;
+
+ */
+ ioctl(sock, SIOCSIFNETMASK, &req);
+ }
+
+ /* set other flags & addr */
+ strncpy(req.ifr_name, iface->name, IFNAMSIZ);
+ if (ioctl(sock, SIOCGIFFLAGS, &req)==0)
+ {
+/* removed by sscholz@astaro.com (caused trouble with DSL/ppp0) */
+/* if (phys_flags & IFF_POINTOPOINT)
+ {
+ req.ifr_flags |= IFF_POINTOPOINT;
+ req.ifr_flags &= ~IFF_BROADCAST;
+ ioctl(sock, SIOCSIFFLAGS, &req);
+ strncpy(req.ifr_name, phys, IFNAMSIZ);
+ if (ioctl(sock, SIOCGIFDSTADDR, &req) == 0)
+ {
+ strncpy(req.ifr_name, iface->name, IFNAMSIZ);
+ ioctl(sock, SIOCSIFDSTADDR, &req);
+ }
+ }
+ else
+ */
+ if (phys_flags & IFF_BROADCAST)
+ {
+ req.ifr_flags &= ~IFF_POINTOPOINT;
+ req.ifr_flags |= IFF_BROADCAST;
+ ioctl(sock, SIOCSIFFLAGS, &req);
+ strncpy(req.ifr_name, phys, IFNAMSIZ);
+ if (ioctl(sock, SIOCGIFBRDADDR, &req) == 0)
+ {
+ strncpy(req.ifr_name, iface->name, IFNAMSIZ);
+ ioctl(sock, SIOCSIFBRDADDR, &req);
+ }
+ }
+ else
+ {
+ req.ifr_flags &= ~IFF_POINTOPOINT;
+ req.ifr_flags &= ~IFF_BROADCAST;
+ ioctl(sock, SIOCSIFFLAGS, &req);
+ }
+ }
+
+ /*
+ * guess MTU = phys interface MTU - ESP Overhead
+ *
+ * ESP overhead : 10+16+7+2+12=57 -> 60 by security
+ * NAT-T overhead : 20
+ */
+ if (mtu == 0)
+ {
+ strncpy(req.ifr_name, phys, IFNAMSIZ);
+ ioctl(sock, SIOCGIFMTU, &req);
+ mtu = req.ifr_mtu - 60;
+ if (nat_t)
+ mtu -= 20;
+ }
+ /* set MTU */
+ if (mtu)
+ {
+ strncpy(req.ifr_name, iface->name, IFNAMSIZ);
+ req.ifr_mtu = mtu;
+ ioctl(sock, SIOCSIFMTU, &req);
+ }
+
+ /* ipsec interface UP */
+ strncpy(req.ifr_name, iface->name, IFNAMSIZ);
+ if (ioctl(sock, SIOCGIFFLAGS, &req) == 0)
+ {
+ req.ifr_flags |= IFF_UP;
+ ioctl(sock, SIOCSIFFLAGS, &req);
+ }
+
+ iface->up = 1;
+ strncpy(iface->phys, phys, IFNAMSIZ);
+ return ret;
+}
+
+static int
+_iface_down(int sock, struct st_ipsec_if *iface)
+{
+ struct ifreq req;
+ int ret = 0;
+
+ iface->up = 0;
+
+ strncpy(req.ifr_name, iface->name, IFNAMSIZ);
+ if (ioctl(sock, SIOCGIFFLAGS, &req)!=0)
+ return ret;
+
+ if (req.ifr_flags & IFF_UP)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("shutting down interface %s/%s", iface->name, iface->phys)
+ )
+ req.ifr_flags &= ~IFF_UP;
+ ioctl(sock, SIOCSIFFLAGS, &req);
+ ret = 1;
+ }
+
+ /* unset addr */
+ memset(&req.ifr_addr, 0, sizeof(req.ifr_addr));
+ req.ifr_addr.sa_family = AF_INET;
+ ioctl(sock, SIOCSIFADDR, &req);
+
+ /* tncfg --detach */
+ ioctl(sock, IPSEC_DEL_DEV, &req);
+
+ memset(iface->phys, 0, sizeof(iface->phys));
+
+ return ret;
+}
+
+void
+starter_ifaces_init(void)
+{
+ int i;
+
+ memset(_ipsec_if, 0, sizeof(_ipsec_if));
+ for (i = 0; i < N_IPSEC_IF; i++)
+ snprintf(_ipsec_if[i].name, IFNAMSIZ, "ipsec%d", i);
+}
+
+void
+starter_ifaces_clear (void)
+{
+ int sock;
+ unsigned int i;
+
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0)
+ return;
+
+ for (i = 0; i < N_IPSEC_IF; i++)
+ _iface_down (sock, &(_ipsec_if[i]));
+}
+
+int
+starter_ifaces_load(char **ifaces, unsigned int omtu, bool nat_t
+, defaultroute_t *defaultroute)
+{
+ char *tmp_phys, *phys;
+ int n;
+ char **i;
+ int sock;
+ int j, found;
+ int ret = 0;
+ struct ifreq physreq, ipsecreq; // re-attach interface
+ struct sockaddr_in *inp1, *inp2; // re-attach interface
+
+ DBG(DBG_CONTROL,
+ DBG_log("starter_ifaces_load()")
+ )
+
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0)
+ return -1;
+
+ for (j = 0; j < N_IPSEC_IF; j++)
+ {
+ found = 0;
+
+ for (i = ifaces; i && *i; i++)
+ {
+ if (valid_str(*i, &n, &tmp_phys, defaultroute)
+ && tmp_phys
+ && n >= 0
+ && n < N_IPSEC_IF)
+ {
+ if (n==j)
+ {
+ if (found)
+ {
+ plog( "ignoring duplicate entry for interface ipsec%d", j);
+ }
+ else
+ {
+ found++;
+ phys = _find_physical_iface(sock, tmp_phys);
+
+ /* Re-attach ipsec interface if IP address changes
+ * sscholz@astaro.com
+ */
+ if (phys)
+ {
+ memset ((void*)&physreq, 0, sizeof(physreq));
+ memset ((void*)&ipsecreq, 0, sizeof(ipsecreq));
+ strncpy(physreq.ifr_name, phys, IFNAMSIZ);
+ sprintf(ipsecreq.ifr_name, "ipsec%d", j);
+ ioctl(sock, SIOCGIFADDR, &physreq);
+ ioctl(sock, SIOCGIFADDR, &ipsecreq);
+ inp1 = (struct sockaddr_in *)&physreq.ifr_addr;
+ inp2 = (struct sockaddr_in *)&ipsecreq.ifr_addr;
+ if (inp1->sin_addr.s_addr != inp2->sin_addr.s_addr)
+ {
+ plog("IP address of physical interface changed "
+ "-> reinit of ipsec interface");
+ _iface_down (sock, &(_ipsec_if[n]));
+ }
+ ret += _iface_up (sock, &(_ipsec_if[n]), phys, omtu, nat_t);
+ }
+ else
+ {
+ ret += _iface_down (sock, &(_ipsec_if[n]));
+ }
+ }
+ }
+ }
+ else if (j == 0)
+ {
+ /* Only log in the first loop */
+ plog("ignoring invalid interface '%s'", *i);
+ }
+ }
+ if (!found)
+ ret += _iface_down (sock, &(_ipsec_if[j]));
+ }
+
+ close(sock);
+ return ret; /* = number of changes - 'whack --listen' if > 0 */
+}
+
+/*
+ * initialize a defaultroute_t struct
+ */
+static void
+init_defaultroute(defaultroute_t *defaultroute)
+{
+ memset(defaultroute, 0, sizeof(defaultroute_t));
+}
+
+/*
+ * discover the default route via /proc/net/route
+ */
+void
+get_defaultroute(defaultroute_t *defaultroute)
+{
+ FILE *fd;
+ char line[BUF_LEN];
+ bool first = TRUE;
+
+ init_defaultroute(defaultroute);
+
+ fd = fopen("/proc/net/route", "r");
+
+ if (!fd)
+ {
+ plog("could not open 'proc/net/route'");
+ return;
+ }
+
+ while (fgets(line, sizeof(line), fd) != 0)
+ {
+ char iface[11];
+ char destination[9];
+ char gateway[11];
+ char flags[5];
+ char mask[9];
+
+ int refcnt;
+ int use;
+ int metric;
+ int items;
+
+ /* proc/net/route returns IP addresses in host order */
+ strcpy(gateway, "0h");
+
+ /* skip the header line */
+ if (first)
+ {
+ first = FALSE;
+ continue;
+ }
+
+ /* parsing a single line of proc/net/route */
+ items = sscanf(line, "%10s\t%8s\t%8s\t%5s\t%d\t%d\t%d\t%8s\t"
+ , iface, destination, gateway+2, flags, &refcnt, &use, &metric, mask);
+ if (items < 8)
+ {
+ plog("parsing error while scanning /proc/net/route");
+ continue;
+ }
+
+ /* check for defaultroute (destination 0.0.0.0 and mask 0.0.0.0) */
+ if (streq(destination, "00000000") && streq(mask, "00000000"))
+ {
+ if (defaultroute->defined)
+ {
+ plog("multiple default routes - cannot cope with %%defaultroute!!!");
+ defaultroute->defined = FALSE;
+ fclose(fd);
+ return;
+ }
+ ttoaddr(gateway, strlen(gateway), AF_INET, &defaultroute->nexthop);
+ strncpy(defaultroute->iface, iface, IFNAMSIZ);
+ defaultroute->defined = TRUE;
+ }
+ }
+ fclose(fd);
+
+ if (!defaultroute->defined)
+ {
+ plog("no default route - cannot cope with %%defaultroute!!!");
+ }
+ else
+ {
+ char addr_buf[20], nexthop_buf[20];
+ struct ifreq physreq;
+
+ int sock = socket(AF_INET, SOCK_DGRAM, 0);
+
+ /* determine IP address of iface */
+ if (sock < 0)
+ {
+ plog("could not open SOCK_DGRAM socket");
+ defaultroute->defined = FALSE;
+ return;
+ }
+ memset ((void*)&physreq, 0, sizeof(physreq));
+ strncpy(physreq.ifr_name, defaultroute->iface, IFNAMSIZ);
+ ioctl(sock, SIOCGIFADDR, &physreq);
+ close(sock);
+ defaultroute->addr.u.v4 = *((struct sockaddr_in *)&physreq.ifr_addr);
+
+ addrtot(&defaultroute->addr, 0, addr_buf, sizeof(addr_buf));
+ addrtot(&defaultroute->nexthop, 0, nexthop_buf, sizeof(nexthop_buf));
+
+ DBG(DBG_CONTROL,
+ DBG_log("Default route found: iface=%s, addr=%s, nexthop=%s"
+ , defaultroute->iface, addr_buf, nexthop_buf)
+ )
+
+ /* for backwards-compatibility with the awk shell scripts
+ * store the defaultroute in /var/run/ipsec.info
+ */
+ fd = fopen(INFO_FILE, "w");
+
+ if (fd)
+ {
+ fprintf(fd, "defaultroutephys=%s\n", defaultroute->iface );
+ fprintf(fd, "defaultroutevirt=ipsec0\n");
+ fprintf(fd, "defaultrouteaddr=%s\n", addr_buf);
+ fprintf(fd, "defaultroutenexthop=%s\n", nexthop_buf);
+ fclose(fd);
+ }
+ }
+ return;
+}
diff --git a/src/starter/interfaces.h b/src/starter/interfaces.h
new file mode 100644
index 000000000..9898c0516
--- /dev/null
+++ b/src/starter/interfaces.h
@@ -0,0 +1,41 @@
+/* strongSwan IPsec interfaces management
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: interfaces.h,v 1.6 2006/01/06 20:24:07 as Exp $
+ */
+
+#ifndef _STARTER_INTERFACES_H_
+#define _STARTER_INTERFACES_H_
+
+#include <linux/if.h>
+
+#include "../pluto/constants.h"
+
+typedef struct {
+ bool defined;
+ char iface[IFNAMSIZ];
+ ip_address addr;
+ ip_address nexthop;
+} defaultroute_t;
+
+extern void starter_ifaces_init (void);
+extern int starter_iface_find(char *iface, int af, ip_address *dst
+ , ip_address *nh);
+extern int starter_ifaces_load (char **ifaces, unsigned int omtu, bool nat_t
+ , defaultroute_t *defaultroute);
+extern void starter_ifaces_clear (void);
+extern void get_defaultroute(defaultroute_t *defaultroute);
+
+
+#endif /* _STARTER_INTERFACES_H_ */
+
diff --git a/src/starter/invokecharon.c b/src/starter/invokecharon.c
new file mode 100644
index 000000000..e97c8388b
--- /dev/null
+++ b/src/starter/invokecharon.c
@@ -0,0 +1,251 @@
+/* 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, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+ };
+
+ if (!debug)
+ {
+ arg[argc++] = "--use-syslog";
+ }
+ if (cfg->setup.strictcrlpolicy)
+ {
+ arg[argc++] = "--strictcrlpolicy";
+ }
+ if (cfg->setup.cachecrls)
+ {
+ arg[argc++] = "--cachecrls";
+ }
+ if (cfg->setup.crlcheckinterval > 0)
+ {
+ char buffer[BUF_LEN];
+
+ snprintf(buffer, BUF_LEN, "%u", cfg->setup.crlcheckinterval);
+ arg[argc++] = "--crlcheckinterval";
+ arg[argc++] = buffer;
+ }
+ if (cfg->setup.eapdir)
+ {
+ arg[argc++] = "--eapdir";
+ arg[argc++] = cfg->setup.eapdir;
+ }
+
+ { /* parse debug string */
+ char *pos, *level, *buf_pos, type[4], buffer[BUF_LEN];
+ pos = cfg->setup.charondebug;
+ buf_pos = buffer;
+ while (pos && sscanf(pos, "%4s %d,", type, &level) == 2)
+ {
+ snprintf(buf_pos, buffer + sizeof(buffer) - buf_pos, "--debug-%s", type);
+ arg[argc++] = buf_pos;
+ buf_pos += strlen(buf_pos) + 1;
+ if (buf_pos >= buffer + sizeof(buffer))
+ {
+ break;
+ }
+ snprintf(buf_pos, buffer + sizeof(buffer) - buf_pos, "%d", level);
+ arg[argc++] = buf_pos;
+ buf_pos += strlen(buf_pos) + 1;
+ if (buf_pos >= buffer + sizeof(buffer))
+ {
+ break;
+ }
+
+ /* get next */
+ pos = strchr(pos, ',');
+ if (pos)
+ {
+ pos++;
+ }
+ }
+ }
+
+ if (_charon_pid)
+ {
+ plog("starter_start_charon(): charon already started...");
+ return -1;
+ }
+ else
+ {
+ unlink(CHARON_CTL_FILE);
+ _stop_requested = 0;
+
+ /* if ipsec.secrets file is missing then generate RSA default key pair */
+ if (stat(SECRETS_FILE, &stb) != 0)
+ {
+ mode_t oldmask;
+ FILE *f;
+
+ plog("no %s file, generating RSA key", SECRETS_FILE);
+ system("ipsec scepclient --out pkcs1 --out cert-self --quiet");
+
+ /* ipsec.secrets is root readable only */
+ oldmask = umask(0066);
+
+ f = fopen(SECRETS_FILE, "w");
+ if (f)
+ {
+ fprintf(f, "# /etc/ipsec.secrets - strongSwan IPsec secrets file\n");
+ fprintf(f, "\n");
+ fprintf(f, ": RSA myKey.der\n");
+ fclose(f);
+ }
+ umask(oldmask);
+ }
+
+ 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 --git a/src/starter/invokecharon.h b/src/starter/invokecharon.h
new file mode 100644
index 000000000..b18dba362
--- /dev/null
+++ b/src/starter/invokecharon.h
@@ -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 --git a/src/starter/invokepluto.c b/src/starter/invokepluto.c
new file mode 100644
index 000000000..1b11b4a10
--- /dev/null
+++ b/src/starter/invokepluto.c
@@ -0,0 +1,286 @@
+/* strongSwan Pluto launcher
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: invokepluto.c,v 1.12 2006/02/17 21:41:50 as Exp $
+ */
+
+#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 "invokepluto.h"
+#include "files.h"
+#include "starterwhack.h"
+#
+static int _pluto_pid = 0;
+static int _stop_requested;
+
+pid_t
+starter_pluto_pid(void)
+{
+ return _pluto_pid;
+}
+
+void
+starter_pluto_sigchild(pid_t pid)
+{
+ if (pid == _pluto_pid)
+ {
+ _pluto_pid = 0;
+ if (!_stop_requested)
+ {
+ plog("pluto has died -- restart scheduled (%dsec)"
+ , PLUTO_RESTART_DELAY);
+ alarm(PLUTO_RESTART_DELAY); // restart in 5 sec
+ }
+ unlink(PLUTO_PID_FILE);
+ }
+}
+
+int
+starter_stop_pluto (void)
+{
+ pid_t pid;
+ int i;
+
+ pid = _pluto_pid;
+ if (pid)
+ {
+ _stop_requested = 1;
+ if (starter_whack_shutdown() == 0)
+ {
+ for (i = 0; i < 20; i++)
+ {
+ usleep(20000);
+ if (_pluto_pid == 0)
+ return 0;
+ }
+ }
+ /* be more and more aggressive */
+ for (i = 0; i < 20 && (pid = _pluto_pid) != 0; i++)
+ {
+ if (i < 10)
+ kill(pid, SIGTERM);
+ else
+ kill(pid, SIGKILL);
+ usleep(20000);
+ }
+ if (_pluto_pid == 0)
+ return 0;
+ plog("starter_stop_pluto(): can't stop pluto !!!");
+ return -1;
+ }
+ else
+ {
+ plog("stater_stop_pluto(): pluto is not started...");
+ }
+ return -1;
+}
+
+#define ADD_DEBUG(v) { \
+ for (l = cfg->setup.plutodebug; l && *l; l++) if (streq(*l, v)) \
+ arg[argc++] = "--debug-" v; \
+ }
+
+int
+starter_start_pluto (starter_config_t *cfg, bool debug)
+{
+ int i;
+ struct stat stb;
+ pid_t pid;
+ char **l;
+ int argc = 2;
+ char *arg[] = {
+ PLUTO_CMD, "--nofork"
+ , NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+ , NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+ , NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+ , NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+ };
+
+ printf ("starter_start_pluto entered\n");
+
+ if (debug)
+ {
+ arg[argc++] = "--stderrlog";
+ }
+ if (cfg->setup.uniqueids)
+ {
+ arg[argc++] = "--uniqueids";
+ }
+ ADD_DEBUG("none")
+ ADD_DEBUG("all")
+ ADD_DEBUG("raw")
+ ADD_DEBUG("crypt")
+ ADD_DEBUG("parsing")
+ ADD_DEBUG("emitting")
+ ADD_DEBUG("control")
+ ADD_DEBUG("lifecycle")
+ ADD_DEBUG("klips")
+ ADD_DEBUG("dns")
+ ADD_DEBUG("natt")
+ ADD_DEBUG("oppo")
+ ADD_DEBUG("controlmore")
+ ADD_DEBUG("private")
+ if (cfg->setup.crlcheckinterval > 0)
+ {
+ static char buf1[15];
+
+ arg[argc++] = "--crlcheckinterval";
+ snprintf(buf1, sizeof(buf1), "%u", cfg->setup.crlcheckinterval);
+ arg[argc++] = buf1;
+ }
+ if (cfg->setup.cachecrls)
+ {
+ arg[argc++] = "--cachecrls";
+ }
+ if (cfg->setup.strictcrlpolicy)
+ {
+ arg[argc++] = "--strictcrlpolicy";
+ }
+ if (cfg->setup.nocrsend)
+ {
+ arg[argc++] = "--nocrsend";
+ }
+ if (cfg->setup.nat_traversal)
+ {
+ arg[argc++] = "--nat_traversal";
+ }
+ if (cfg->setup.keep_alive)
+ {
+ static char buf2[15];
+
+ arg[argc++] = "--keep_alive";
+ snprintf(buf2, sizeof(buf2), "%u", cfg->setup.keep_alive);
+ arg[argc++] = buf2;
+ }
+#ifdef VIRTUAL_IP
+ if (cfg->setup.virtual_private)
+ {
+ arg[argc++] = "--virtual_private";
+ arg[argc++] = cfg->setup.virtual_private;
+ }
+#endif
+ if (cfg->setup.pkcs11module)
+ {
+ arg[argc++] = "--pkcs11module";
+ arg[argc++] = cfg->setup.pkcs11module;
+ }
+ if (cfg->setup.pkcs11keepstate)
+ {
+ arg[argc++] = "--pkcs11keepstate";
+ }
+ if (cfg->setup.pkcs11proxy)
+ {
+ arg[argc++] = "--pkcs11proxy";
+ }
+
+ if (_pluto_pid)
+ {
+ plog("starter_start_pluto(): pluto already started...");
+ return -1;
+ }
+ else
+ {
+ unlink(PLUTO_CTL_FILE);
+ _stop_requested = 0;
+
+ if (cfg->setup.prepluto)
+ system(cfg->setup.prepluto);
+
+ /* if ipsec.secrets file is missing then generate RSA default key pair */
+ if (stat(SECRETS_FILE, &stb) != 0)
+ {
+ mode_t oldmask;
+ FILE *f;
+
+ plog("no %s file, generating RSA key", SECRETS_FILE);
+ system("ipsec scepclient --out pkcs1 --out cert-self --quiet");
+
+ /* ipsec.secrets is root readable only */
+ oldmask = umask(0066);
+
+ f = fopen(SECRETS_FILE, "w");
+ if (f)
+ {
+ fprintf(f, "# /etc/ipsec.secrets - strongSwan IPsec secrets file\n");
+ fprintf(f, "\n");
+ fprintf(f, ": RSA myKey.der\n");
+ fclose(f);
+ }
+ umask(oldmask);
+ }
+
+ 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 */
+ _pluto_pid = pid;
+ for (i = 0; i < 50 && _pluto_pid; i++)
+ {
+ /* wait for pluto */
+ usleep(20000);
+ if (stat(PLUTO_CTL_FILE, &stb) == 0)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("pluto (%d) started", _pluto_pid)
+ )
+ if (cfg->setup.postpluto)
+ system(cfg->setup.postpluto);
+ return 0;
+ }
+ }
+ if (_pluto_pid)
+ {
+ /* If pluto is started but with no ctl file, stop it */
+ plog("pluto too long to start... - kill kill");
+ for (i = 0; i < 20 && (pid = _pluto_pid) != 0; i++)
+ {
+ if (i < 10)
+ kill(pid, SIGTERM);
+ else
+ kill(pid, SIGKILL);
+ usleep(20000);
+ }
+ }
+ else
+ {
+ plog("pluto refused to be started");
+ }
+ return -1;
+ }
+ }
+ return -1;
+}
diff --git a/src/starter/invokepluto.h b/src/starter/invokepluto.h
new file mode 100644
index 000000000..26858f9b2
--- /dev/null
+++ b/src/starter/invokepluto.h
@@ -0,0 +1,28 @@
+/* strongSwan pluto launcher
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: invokepluto.h,v 1.3 2006/01/04 23:30:24 as Exp $
+ */
+
+#ifndef _STARTER_PLUTO_H_
+#define _STARTER_PLUTO_H_
+
+#define PLUTO_RESTART_DELAY 5
+
+extern void starter_pluto_sigchild (pid_t pid);
+extern pid_t starter_pluto_pid (void);
+extern int starter_stop_pluto (void);
+extern int starter_start_pluto (struct starter_config *cfg, bool debug);
+
+#endif /* _STARTER_PLUTO_H_ */
+
diff --git a/src/starter/ipsec.conf b/src/starter/ipsec.conf
new file mode 100644
index 000000000..76b85b23a
--- /dev/null
+++ b/src/starter/ipsec.conf
@@ -0,0 +1,42 @@
+# ipsec.conf - strongSwan IPsec configuration file
+
+# Manual: man 5 ipsec.conf
+# Help: http://www.strongswan.org/docs/readme.htm
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+# basic configuration
+
+config setup
+ # Debug-logging controls: "none" for (almost) none, "all" for lots.
+ # plutodebug=all
+ # crlcheckinterval=600
+ # strictcrlpolicy=yes
+ # cachecrls=yes
+ # nat_traversal=yes
+ # charonstart=no
+ # plutostart=no
+
+# Add connections here.
+
+# Sample VPN connections
+
+#conn sample-self-signed
+# left=%defaultroute
+# leftsubnet=10.1.0.0/16
+# leftcert=selfCert.der
+# leftsendcert=never
+# right=192.168.0.2
+# rightsubnet=10.2.0.0/16
+# rightcert=peerCert.der
+# auto=start
+
+#conn sample-with-ca-cert
+# left=%defaultroute
+# leftsubnet=10.1.0.0/16
+# leftcert=myCert.pem
+# right=192.168.0.2
+# rightsubnet=10.2.0.0/16
+# rightid="C=CH, O=Linux strongSwan CN=peer name"
+# keyexchange=ikev2
+# auto=start
diff --git a/src/starter/ipsec.conf.5 b/src/starter/ipsec.conf.5
new file mode 100644
index 000000000..3e59190e3
--- /dev/null
+++ b/src/starter/ipsec.conf.5
@@ -0,0 +1,1062 @@
+.TH IPSEC.CONF 5 "20 Jan 2006"
+.\" RCSID $Id: ipsec.conf.5,v 1.2 2006/01/22 15:33:46 as Exp $
+.SH NAME
+ipsec.conf \- IPsec configuration and connections
+.SH DESCRIPTION
+The optional
+.I ipsec.conf
+file
+specifies most configuration and control information for the
+strongSwan IPsec subsystem.
+(The major exception is secrets for authentication;
+see
+.IR ipsec.secrets (5).)
+Its contents are not security-sensitive.
+.PP
+The file is a text file, consisting of one or more
+.IR sections .
+White space followed by
+.B #
+followed by anything to the end of the line
+is a comment and is ignored,
+as are empty lines which are not within a section.
+.PP
+A line which contains
+.B include
+and a file name, separated by white space,
+is replaced by the contents of that file,
+preceded and followed by empty lines.
+If the file name is not a full pathname,
+it is considered to be relative to the directory containing the
+including file.
+Such inclusions can be nested.
+Only a single filename may be supplied, and it may not contain white space,
+but it may include shell wildcards (see
+.IR sh (1));
+for example:
+.PP
+.B include
+.B "ipsec.*.conf"
+.PP
+The intention of the include facility is mostly to permit keeping
+information on connections, or sets of connections,
+separate from the main configuration file.
+This permits such connection descriptions to be changed,
+copied to the other security gateways involved, etc.,
+without having to constantly extract them from the configuration
+file and then insert them back into it.
+Note also the
+.B also
+parameter (described below) which permits splitting a single logical
+section (e.g. a connection description) into several actual sections.
+.PP
+A section
+begins with a line of the form:
+.PP
+.I type
+.I name
+.PP
+where
+.I type
+indicates what type of section follows, and
+.I name
+is an arbitrary name which distinguishes the section from others
+of the same type.
+(Names must start with a letter and may contain only
+letters, digits, periods, underscores, and hyphens.)
+All subsequent non-empty lines
+which begin with white space are part of the section;
+comments within a section must begin with white space too.
+There may be only one section of a given type with a given name.
+.PP
+Lines within the section are generally of the form
+.PP
+\ \ \ \ \ \fIparameter\fB=\fIvalue\fR
+.PP
+(note the mandatory preceding white space).
+There can be white space on either side of the
+.BR = .
+Parameter names follow the same syntax as section names,
+and are specific to a section type.
+Unless otherwise explicitly specified,
+no parameter name may appear more than once in a section.
+.PP
+An empty
+.I value
+stands for the system default value (if any) of the parameter,
+i.e. it is roughly equivalent to omitting the parameter line entirely.
+A
+.I value
+may contain white space only if the entire
+.I value
+is enclosed in double quotes (\fB"\fR);
+a
+.I value
+cannot itself contain a double quote,
+nor may it be continued across more than one line.
+.PP
+Numeric values are specified to be either an ``integer''
+(a sequence of digits) or a ``decimal number''
+(sequence of digits optionally followed by `.' and another sequence of digits).
+.PP
+There is currently one parameter which is available in any type of
+section:
+.TP
+.B also
+the value is a section name;
+the parameters of that section are appended to this section,
+as if they had been written as part of it.
+The specified section must exist, must follow the current one,
+and must have the same section type.
+(Nesting is permitted,
+and there may be more than one
+.B also
+in a single section,
+although it is forbidden to append the same section more than once.)
+.PP
+A section with name
+.B %default
+specifies defaults for sections of the same type.
+For each parameter in it,
+any section of that type which does not have a parameter of the same name
+gets a copy of the one from the
+.B %default
+section.
+There may be multiple
+.B %default
+sections of a given type,
+but only one default may be supplied for any specific parameter name,
+and all
+.B %default
+sections of a given type must precede all non-\c
+.B %default
+sections of that type.
+.B %default
+sections may not contain the
+.B also
+parameter.
+.PP
+Currently there are three types of sections:
+a
+.B config
+section specifies general configuration information for IPsec, a
+.B conn
+section specifies an IPsec connection, while a
+.B ca
+section specifies special properties a certification authority.
+.SH "CONN SECTIONS"
+A
+.B conn
+section contains a
+.IR "connection specification" ,
+defining a network connection to be made using IPsec.
+The name given is arbitrary, and is used to identify the connection.
+Here's a simple example:
+.PP
+.ne 10
+.nf
+.ft B
+.ta 1c
+conn snt
+ left=10.11.11.1
+ leftsubnet=10.0.1.0/24
+ leftnexthop=172.16.55.66
+ right=192.168.22.1
+ rightsubnet=10.0.2.0/24
+ rightnexthop=172.16.88.99
+ keyingtries=%forever
+.ft
+.fi
+.PP
+A note on terminology: There are two kinds of communications going on:
+transmission of user IP packets, and gateway-to-gateway negotiations for
+keying, rekeying, and general control.
+The path to control the connection is called 'ISAKMP SA' in IKEv1 and
+'IKE SA' in the IKEv2 protocol. That what is beeing negotiated, the kernel
+level data path, is called 'IPsec SA'.
+strongSwan currently uses two separate keying daemons. Pluto handles
+all IKEv1 connections, Charon is the new daemon supporting the IKEv2 protocol.
+Charon does not support all keywords yet.
+.PP
+To avoid trivial editing of the configuration file to suit it to each system
+involved in a connection,
+connection specifications are written in terms of
+.I left
+and
+.I right
+participants,
+rather than in terms of local and remote.
+Which participant is considered
+.I left
+or
+.I right
+is arbitrary;
+IPsec figures out which one it is being run on based on internal information.
+This permits using identical connection specifications on both ends.
+There are cases where there is no symmetry; a good convention is to
+use
+.I left
+for the local side and
+.I right
+for the remote side (the first letters are a good mnemonic).
+.PP
+Many of the parameters relate to one participant or the other;
+only the ones for
+.I left
+are listed here, but every parameter whose name begins with
+.B left
+has a
+.B right
+counterpart,
+whose description is the same but with
+.B left
+and
+.B right
+reversed.
+.PP
+Parameters are optional unless marked '(required)'.
+.SS "CONN PARAMETERS"
+Unless otherwise noted, for a connection to work,
+in general it is necessary for the two ends to agree exactly
+on the values of these parameters.
+.TP 14
+.B type
+the type of the connection; currently the accepted values
+are
+.B tunnel
+(the default)
+signifying a host-to-host, host-to-subnet, or subnet-to-subnet tunnel;
+.BR transport ,
+signifying host-to-host transport mode;
+.BR passthrough ,
+signifying that no IPsec processing should be done at all;
+.BR drop ,
+signifying that packets should be discarded; and
+.BR reject ,
+signifying that packets should be discarded and a diagnostic ICMP returned.
+Charon currently supports only
+.BR tunnel
+and
+.BR transport
+connection types.
+.TP
+.B left
+(required)
+the IP address of the left participant's public-network interface,
+in any form accepted by
+.IR ipsec_ttoaddr (3)
+or one of several magic values.
+If it is
+.BR %defaultroute ,
+and
+the
+.B config
+.B setup
+section's,
+.B interfaces
+specification contains
+.BR %defaultroute,
+.B left
+will be filled in automatically with the local address
+of the default-route interface (as determined at IPsec startup time);
+this also overrides any value supplied for
+.BR leftnexthop .
+(Either
+.B left
+or
+.B right
+may be
+.BR %defaultroute ,
+but not both.)
+The value
+.B %any
+signifies an address to be filled in (by automatic keying) during
+negotiation.
+.TP
+.B leftsubnet
+private subnet behind the left participant, expressed as
+\fInetwork\fB/\fInetmask\fR
+(actually, any form acceptable to
+.IR ipsec_ttosubnet (3));
+if omitted, essentially assumed to be \fIleft\fB/32\fR,
+signifying that the left end of the connection goes to the left participant
+only. When using IKEv2, the configured subnet of the peers may differ, the
+protocol narrows it to the greates common subnet.
+.TP
+.B leftnexthop
+next-hop gateway IP address for the left participant's connection
+to the public network;
+defaults to
+.B %direct
+(meaning
+.IR right ).
+If the value is to be overridden by the
+.B left=%defaultroute
+method (see above),
+an explicit value must
+.I not
+be given.
+If that method is not being used,
+but
+.B leftnexthop
+is
+.BR %defaultroute ,
+and
+.B interfaces=%defaultroute
+is used in the
+.B config
+.B setup
+section,
+the next-hop gateway address of the default-route interface
+will be used.
+The magic value
+.B %direct
+signifies a value to be filled in (by automatic keying)
+with the peer's address.
+Relevant only locally, other end need not agree on it. Currently not supported
+in IKEv2.
+.TP
+.B leftupdown
+what ``updown'' script to run to adjust routing and/or firewalling
+when the status of the connection
+changes (default
+.BR "ipsec _updown" ).
+May include positional parameters separated by white space
+(although this requires enclosing the whole string in quotes);
+including shell metacharacters is unwise.
+See
+.IR ipsec_pluto (8)
+for details.
+Relevant only locally, other end need not agree on it. IKEv2 uses the updown
+script to insert firewall rules only. Routing is not support and will be
+implemented directly into Charon.
+.TP
+.B leftfirewall
+whether the left participant is doing forwarding-firewalling
+(including masquerading) for traffic from \fIleftsubnet\fR,
+which should be turned off (for traffic to the other subnet)
+once the connection is established;
+acceptable values are
+.B yes
+and (the default)
+.BR no .
+May not be used in the same connection description with
+.BR leftupdown .
+Implemented as a parameter to the default
+.I updown
+script.
+See notes below.
+Relevant only locally, other end need not agree on it.
+
+If one or both security gateways are doing forwarding firewalling
+(possibly including masquerading),
+and this is specified using the firewall parameters,
+tunnels established with IPsec are exempted from it
+so that packets can flow unchanged through the tunnels.
+(This means that all subnets connected in this manner must have
+distinct, non-overlapping subnet address blocks.)
+This is done by the default
+.I updown
+script (see
+.IR ipsec_pluto (8)).
+
+In situations calling for more control,
+it may be preferable for the user to supply his own
+.I updown
+script,
+which makes the appropriate adjustments for his system.
+.TP
+.B auto
+what operation, if any, should be done automatically at IPsec startup;
+currently-accepted values are
+.B add
+,
+.B route
+,
+.B start
+and
+.B ignore
+.
+.B add
+loads a connection without starting it.
+.B route
+loads a connection and installs kernel traps. If traffic is detected between
+.B leftsubnet
+and
+.B rightsubnet
+, a connection is established.
+.B start
+loads a connection and brings it up immediatly.
+.B ignore
+ignores the connection. This is equal to delete a connection from the config
+file.
+Relevant only locally, other end need not agree on it
+(but in general, for an intended-to-be-permanent connection,
+both ends should use
+.B auto=start
+to ensure that any reboot causes immediate renegotiation).
+.TP
+.B auth
+whether authentication should be done as part of
+ESP encryption, or separately using the AH protocol;
+acceptable values are
+.B esp
+(the default) and
+.BR ah .
+The IKEv2 daemon currently supports only ESP.
+.TP
+.B authby
+how the two security gateways should authenticate each other;
+acceptable values are
+.B secret
+for shared secrets,
+.B rsasig
+for RSA digital signatures (the default),
+.B secret|rsasig
+for either, and
+.B never
+if negotiation is never to be attempted or accepted (useful for shunt-only conns).
+Digital signatures are superior in every way to shared secrets. In IKEv2, the
+two ends must not agree on this parameter, it is relevant for the own
+authentication method only. IKEv2 additionally supports the value
+.B eap,
+which indicates an initiator to request EAP authentication. The EAP method to
+use is selected by the server (see
+.B eap).
+.TP
+.B compress
+whether IPComp compression of content is proposed on the connection
+(link-level compression does not work on encrypted data,
+so to be effective, compression must be done \fIbefore\fR encryption);
+acceptable values are
+.B yes
+and
+.B no
+(the default). A value of
+.B yes
+causes IPsec to propose both compressed and uncompressed,
+and prefer compressed.
+A value of
+.B no
+prevents IPsec from proposing compression;
+a proposal to compress will still be accepted.
+IKEv2 does not support IP compression yet.
+.TP
+.B dpdaction
+controls the use of the Dead Peer Detection protocol (DPD, RFC 3706) where
+R_U_THERE notification messages (IKEv1) or empty INFORMATIONAL messages (IKEv2)
+are periodically sent in order to check the
+liveliness of the IPsec peer. The values
+.B clear
+and
+.B hold
+both activate DPD. If no activity is detected, all connections with a dead peer
+are stopped and unrouted (
+.B clear
+) or put in the hold state (
+.B hold
+). For
+.B IKEv1
+, the default is
+.B none
+which disables the active sending of R_U_THERE notifications.
+Nevertheless pluto will always send the DPD Vendor ID during connection set up
+in order to signal the readiness to act passively as a responder if the peer
+wants to use DPD. For
+.B IKEv2, none
+does't make sense, as all messages are used to detect dead peers. If specified,
+it has the same meaning as the default (
+.B clear
+).
+.TP
+.B dpddelay
+defines the period time interval with which R_U_THERE messages/INFORMATIONAL
+exchanges are sent to the peer. These are only sent if no other traffic is
+received. In IKEv2, a value of 0 sends no additional INFORMATIONAL
+messages and uses only standard messages (such as those to rekey) to detect
+dead peers.
+.TP
+.B dpdtimeout
+defines the timeout interval, after which all connections to a peer are deleted
+in case of inactivity. This only applies to IKEv1, in IKEv2 the default
+retransmission timeout applies, as every exchange is used to detect dead peers.
+.TP
+.B failureshunt
+what to do with packets when negotiation fails.
+The default is
+.BR none :
+no shunt;
+.BR passthrough ,
+.BR drop ,
+and
+.B reject
+have the obvious meanings. Has no effect in IKEv2 yet.
+.TP
+.B ikelifetime
+how long the keying channel of a connection ('ISAKMP/IKE SA')
+should last before being renegotiated.
+.TP
+.B keyexchange
+method of key exchange;
+which protocol should be used to initialize the connection. Connections marked with
+.B ikev1
+are initiated with pluto, those marked with
+.B ikev2
+with charon. An incoming request from the remote peer is handled by the correct
+daemon, unaffected from the
+.B keyexchange
+setting. The default value
+.B ike
+currently behaves exactly as
+.B ikev1.
+.TP
+.B keyingtries
+how many attempts (a whole number or \fB%forever\fP) should be made to
+negotiate a connection, or a replacement for one, before giving up
+(default
+.BR %forever ).
+The value \fB%forever\fP
+means 'never give up'.
+Relevant only locally, other end need not agree on it.
+.TP
+.B keylife
+how long a particular instance of a connection
+(a set of encryption/authentication keys for user packets) should last,
+from successful negotiation to expiry;
+acceptable values are an integer optionally followed by
+.BR s
+(a time in seconds)
+or a decimal number followed by
+.BR m ,
+.BR h ,
+or
+.B d
+(a time
+in minutes, hours, or days respectively)
+(default
+.BR 1h ,
+maximum
+.BR 24h ).
+Normally, the connection is renegotiated (via the keying channel)
+before it expires.
+The two ends need not exactly agree on
+.BR keylife ,
+although if they do not,
+there will be some clutter of superseded connections on the end
+which thinks the lifetime is longer.
+.TP
+.B leftca
+the distinguished name of a certificate authority which is required to
+lie in the trust path going from the left participant's certificate up
+to the root certification authority.
+.TP
+.B leftcert
+the path to the left participant's X.509 certificate. The file can be coded either in
+PEM or DER format. OpenPGP certificates are supported as well.
+Both absolute paths or paths relative to
+.B /etc/ipsec.d/certs
+are accepted. By default
+.B leftcert
+sets
+.B leftid
+to the distinguished name of the certificate's subject and
+.B leftca
+to the distinguished name of the certificate's issuer.
+The left participant's ID can be overriden by specifying a
+.B leftid
+value which must be certified by the certificate, though.
+.TP
+.B leftgroups
+a comma separated list of group names. If the
+.B leftgroups
+parameter is present then the peer must be a member of at least one
+of the groups defined by the parameter. Group membership must be certified
+by a valid attribute certificate stored in \fI/etc/ipsec.d/acerts\fP thas has been
+issued to the peer by a trusted Authorization Authority stored in
+\fI/etc/ipsec.d/aacerts\fP. Attribute certificates are not supported in IKEv2 yet.
+.TP
+.B leftid
+how
+the left participant
+should be identified for authentication;
+defaults to
+.BR left .
+Can be an IP address (in any
+.IR ipsec_ttoaddr (3)
+syntax)
+or a fully-qualified domain name preceded by
+.B @
+(which is used as a literal string and not resolved).
+The magic value
+.B %myid
+stands for the current setting of \fImyid\fP.
+This is set in \fBconfig setup\fP or by \fIipsec_whack\fP(8)), or, if not set,
+it is the IP address in \fB%defaultroute\fP (if that is supported by a TXT record in its reverse domain), or otherwise
+it is the system's hostname (if that is supported by a TXT record in its forward domain), or otherwise it is undefined.
+.TP
+.B leftsourceip
+The internal source IP to use in a tunnel, also known as virtual IP. If the
+value is
+.B %modeconfig
+or
+.B %config,
+an address is requested from the peer.
+.TP
+.B leftsubnetwithin
+Not relevant for IKEv2, as subnets are narrowed.
+.TP
+.B pfs
+whether Perfect Forward Secrecy of keys is desired on the connection's
+keying channel
+(with PFS, penetration of the key-exchange protocol
+does not compromise keys negotiated earlier);
+acceptable values are
+.B yes
+(the default)
+and
+.BR no
+. IKEv2 always uses PFS for IKE_SA rekeying. PFS for rekeying IPsec SAs is
+currently not supported.
+.TP
+.B rekey
+whether a connection should be renegotiated when it is about to expire;
+acceptable values are
+.B yes
+(the default)
+and
+.BR no .
+The two ends need not agree,
+but while a value of
+.B no
+prevents Pluto/Charon from requesting renegotiation,
+it does not prevent responding to renegotiation requested from the other end,
+so
+.B no
+will be largely ineffective unless both ends agree on it.
+.TP
+.B reauth
+whether rekeying of an IKE_SA should also reauthenticate the peer. In IKEv1,
+reauthentication is always done. In IKEv2, a value of
+.B no
+rekeys without uninstalling the IPsec SAs, a value of
+.B yes
+(the default) creates a new IKE_SA from scratch and tries to recreate
+all IPsec SAs.
+.TP
+.B rekeyfuzz
+maximum percentage by which
+.B rekeymargin
+should be randomly increased to randomize rekeying intervals
+(important for hosts with many connections);
+acceptable values are an integer,
+which may exceed 100,
+followed by a `%'
+(default set by
+.IR ipsec_pluto (8),
+currently
+.BR 100% ).
+The value of
+.BR rekeymargin ,
+after this random increase,
+must not exceed
+.BR keylife .
+The value
+.B 0%
+will suppress time randomization.
+Relevant only locally, other end need not agree on it.
+.TP
+.B rekeymargin
+how long before connection expiry or keying-channel expiry
+should attempts to
+negotiate a replacement
+begin; acceptable values as for
+.B keylife
+(default
+.BR 9m ).
+Relevant only locally, other end need not agree on it.
+.TP
+.B ike
+IKE/ISAKMP SA encryption/authentication algorithm to be used, e.g.
+.B aes128-sha1-modp2048
+(encryption-integrity-dhgroup).
+.TP
+.B esp
+ESP encryption/authentication algorithm to be used
+for the connection, e.g.
+.B 3des-md5
+(encryption-integrity).
+.TP
+.B ah
+AH authentication algorithm to be used
+for the connection, e.g.
+.B hmac-md5.
+.SH "CA SECTIONS"
+This are optional sections that can be used to assign special
+parameters to a Certification Authority (CA). These parameters are not
+supported in IKEv2 yet.
+.TP 10
+.B auto
+currently can have either the value
+.B ignore
+or
+.B add
+.
+.TP
+.B cacert
+defines a path to the CA certificate either relative to
+\fI/etc/ipsec.d/cacerts\fP or as an absolute path.
+.TP
+.B crluri
+defines a CRL distribution point (ldap, http, or file URI)
+.TP
+.B crluri2
+defines an alternative CRL distribution point (ldap, http, or file URI)
+.TP
+.B ldaphost
+defines an ldap host.
+.TP
+.B ocspuri
+defines an OCSP URI.
+.SH "CONFIG SECTIONS"
+At present, the only
+.B config
+section known to the IPsec software is the one named
+.BR setup ,
+which contains information used when the software is being started
+(see
+.IR ipsec_setup (8)).
+Here's an example:
+.PP
+.ne 8
+.nf
+.ft B
+.ta 1c
+config setup
+ interfaces="ipsec0=eth1 ipsec1=ppp0"
+ klipsdebug=none
+ plutodebug=all
+ manualstart=
+.ft
+.fi
+.PP
+Parameters are optional unless marked ``(required)''.
+The currently-accepted
+.I parameter
+names in a
+.B config
+.B setup
+section are:
+.TP 14
+.B myid
+the identity to be used for
+.BR %myid .
+.B %myid
+is used in the implicit policy group conns and can be used as
+an identity in explicit conns.
+If unspecified,
+.B %myid
+is set to the IP address in \fB%defaultroute\fP (if that is supported by a TXT record in its reverse domain), or otherwise
+the system's hostname (if that is supported by a TXT record in its forward domain), or otherwise it is undefined.
+An explicit value generally starts with ``\fB@\fP''.
+.TP
+.B interfaces
+virtual and physical interfaces for IPsec to use:
+a single
+\fIvirtual\fB=\fIphysical\fR pair, a (quoted!) list of pairs separated
+by white space, or
+.BR %none .
+One of the pairs may be written as
+.BR %defaultroute ,
+which means: find the interface \fId\fR that the default route points to,
+and then act as if the value was ``\fBipsec0=\fId\fR''.
+.B %defaultroute
+is the default;
+.B %none
+must be used to denote no interfaces.
+If
+.B %defaultroute
+is used (implicitly or explicitly)
+information about the default route and its interface is noted for
+use by
+.IR ipsec_manual (8)
+and
+.IR ipsec_auto (8).)
+.TP
+.B forwardcontrol
+whether
+.I setup
+should turn IP forwarding on
+(if it's not already on) as IPsec is started,
+and turn it off again (if it was off) as IPsec is stopped;
+acceptable values are
+.B yes
+and (the default)
+.BR no .
+For this to have full effect, forwarding must be
+disabled before the hardware interfaces are brought
+up (e.g.,
+.B "net.ipv4.ip_forward\ =\ 0"
+in Red Hat 6.x
+.IR /etc/sysctl.conf ),
+because IPsec doesn't get control early enough to do that.
+.TP
+.B rp_filter
+whether and how
+.I setup
+should adjust the reverse path filtering mechanism for the
+physical devices to be used.
+Values are \fB%unchanged\fP (to leave it alone)
+or \fB0\fP, \fB1\fP, \fB2\fP (values to set it to).
+\fI/proc/sys/net/ipv4/conf/PHYS/rp_filter\fP
+is badly documented; it must be \fB0\fP in many cases
+for ipsec to function.
+The default value for the parameter is \fB0\fP.
+.TP
+.B syslog
+the
+.IR syslog (2)
+``facility'' name and priority to use for
+startup/shutdown log messages,
+default
+.BR daemon.error .
+.TP
+.B plutodebug
+how much Pluto debugging output should be logged.
+An empty value,
+or the magic value
+.BR none ,
+means no debugging output (the default).
+The magic value
+.B all
+means full output.
+Otherwise only the specified types of output
+(a quoted list, names without the
+.B \-\-debug\-
+prefix,
+separated by white space) are enabled;
+for details on available debugging types, see
+.IR ipsec_pluto (8).
+.TP
+.B charondebug
+how much Charon debugging output should be logged.
+A comma separated list containing type level/pairs may
+be specified, e.g:
+.B dmn 3, ike 1, net -1.
+Acceptable values for types are
+.B dmn, mgr, ike, chd, job, cfg, knl, net, enc, lib
+and the level is one of
+.B -1, 0, 1, 2, 3, 4
+(for silent, audit, control, controlmore, raw, private)
+.TP
+.B plutoopts
+additional options to pass to pluto upon startup. See
+.IR ipsec_pluto (8).
+.TP
+.B plutostderrlog
+do not use syslog, but rather log to stderr, and direct stderr to the
+argument file.
+.TP
+.B dumpdir
+in what directory should things started by
+.I setup
+(notably the Pluto daemon) be allowed to
+dump core?
+The empty value (the default) means they are not
+allowed to.
+.TP
+.B pluto
+whether to start Pluto or not;
+Values are
+.B yes
+(the default)
+or
+.B no
+(useful only in special circumstances).
+.TP
+.B plutowait
+should Pluto wait for each
+negotiation attempt that is part of startup to
+finish before proceeding with the next?
+Values are
+.B yes
+or
+.BR no
+(the default).
+.TP
+.B prepluto
+shell command to run before starting Pluto
+(e.g., to decrypt an encrypted copy of the
+.I ipsec.secrets
+file).
+It's run in a very simple way;
+complexities like I/O redirection are best hidden within a script.
+Any output is redirected for logging,
+so running interactive commands is difficult unless they use
+.I /dev/tty
+or equivalent for their interaction.
+Default is none.
+.TP
+.B postpluto
+shell command to run after starting Pluto
+(e.g., to remove a decrypted copy of the
+.I ipsec.secrets
+file).
+It's run in a very simple way;
+complexities like I/O redirection are best hidden within a script.
+Any output is redirected for logging,
+so running interactive commands is difficult unless they use
+.I /dev/tty
+or equivalent for their interaction.
+Default is none.
+.TP
+.B fragicmp
+whether a tunnel's need to fragment a packet should be reported
+back with an ICMP message,
+in an attempt to make the sender lower his PMTU estimate;
+acceptable values are
+.B yes
+(the default)
+and
+.BR no .
+.TP
+.B hidetos
+whether a tunnel packet's TOS field should be set to
+.B 0
+rather than copied from the user packet inside;
+acceptable values are
+.B yes
+(the default)
+and
+.BR no .
+.TP
+.B uniqueids
+whether a particular participant ID should be kept unique,
+with any new (automatically keyed)
+connection using an ID from a different IP address
+deemed to replace all old ones using that ID;
+acceptable values are
+.B yes
+(the default)
+and
+.BR no .
+Participant IDs normally \fIare\fR unique,
+so a new (automatically-keyed) connection using the same ID is
+almost invariably intended to replace an old one.
+.TP
+.B overridemtu
+value that the MTU of the ipsec\fIn\fR interface(s) should be set to,
+overriding IPsec's (large) default.
+This parameter is needed only in special situations.
+.TP
+.B nat_traversal
+.TP
+.B crlcheckinterval
+.TP
+.B strictcrlpolicy
+.TP
+.B pkcs11module
+.TP
+.B pkcs11keepstate
+
+.SH CHOOSING A CONNECTION
+.PP
+When choosing a connection to apply to an outbound packet caught with a
+.BR %trap,
+the system prefers the one with the most specific eroute that
+includes the packet's source and destination IP addresses.
+Source subnets are examined before destination subnets.
+For initiating, only routed connections are considered. For responding,
+unrouted but added connections are considered.
+.PP
+When choosing a connection to use to respond to a negotiation which
+doesn't match an ordinary conn, an opportunistic connection
+may be instantiated. Eventually, its instance will be /32 -> /32, but
+for earlier stages of the negotiation, there will not be enough
+information about the client subnets to complete the instantiation.
+.SH FILES
+.nf
+/etc/ipsec.conf
+/etc/ipsec.d/cacerts
+/etc/ipsec.d/certs
+/etc/ipsec.d/crls
+/etc/ipsec.d/aacerts
+/etc/ipsec.d/acerts
+
+.SH SEE ALSO
+ipsec(8), ipsec_ttoaddr(8), ipsec_auto(8), ipsec_manual(8), ipsec_rsasigkey(8)
+.SH HISTORY
+Written for the FreeS/WAN project
+<http://www.freeswan.org>
+by Henry Spencer. Extended for the strongSwan project
+<http://www.strongswan.org>
+by Andreas Steffen. Updated to respect IKEv2 specific configuration
+by Martin Willi.
+.SH BUGS
+.PP
+When
+.B type
+or
+.B failureshunt
+is set to
+.B drop
+or
+.BR reject,
+strongSwan blocks outbound packets using eroutes, but assumes inbound
+blocking is handled by the firewall. strongSwan offers firewall hooks
+via an ``updown'' script. However, the default
+.B ipsec _updown
+provides no help in controlling a modern firewall.
+.PP
+Including attributes of the keying channel
+(authentication methods,
+.BR ikelifetime ,
+etc.)
+as an attribute of a connection,
+rather than of a participant pair, is dubious and incurs limitations.
+.PP
+.IR Ipsec_manual
+is not nearly as generous about the syntax of subnets,
+addresses, etc. as the usual strongSwan user interfaces.
+Four-component dotted-decimal must be used for all addresses.
+It
+.I is
+smart enough to translate bit-count netmasks to dotted-decimal form.
+.PP
+It would be good to have a line-continuation syntax,
+especially for the very long lines involved in
+RSA signature keys.
+.PP
+The ability to specify different identities,
+.BR authby ,
+and public keys for different automatic-keyed connections
+between the same participants is misleading;
+this doesn't work dependably because the identity of the participants
+is not known early enough.
+This is especially awkward for the ``Road Warrior'' case,
+where the remote IP address is specified as
+.BR 0.0.0.0 ,
+and that is considered to be the ``participant'' for such connections.
+.PP
+In principle it might be necessary to control MTU on an
+interface-by-interface basis,
+rather than with the single global override that
+.B overridemtu
+provides.
+.PP
+A number of features which \fIcould\fR be implemented in
+both manual and automatic keying
+actually are not yet implemented for manual keying.
+This is unlikely to be fixed any time soon.
+.PP
+If conns are to be added before DNS is available,
+\fBleft=\fP\fIFQDN\fP,
+\fBleftnextop=\fP\fIFQDN\fP,
+and
+.B leftrsasigkey=%dnsonload
+will fail.
+.IR ipsec_pluto (8)
+does not actually use the public key for our side of a conn but it
+isn't generally known at a add-time which side is ours (Road Warrior
+and Opportunistic conns are currently exceptions).
+.PP
+The \fBmyid\fP option does not affect explicit \fB ipsec auto \-\-add\fP or \fBipsec auto \-\-replace\fP commands for implicit conns.
diff --git a/src/starter/keywords.c b/src/starter/keywords.c
new file mode 100644
index 000000000..215b95ad6
--- /dev/null
+++ b/src/starter/keywords.c
@@ -0,0 +1,261 @@
+/* C code produced by gperf version 3.0.1 */
+/* Command-line: /usr/bin/gperf -C -G -t */
+/* Computed positions: -k'1-2,$' */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646. */
+error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
+#endif
+
+
+/* strongSwan keywords
+ * Copyright (C) 2005 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil, Switzerland
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: keywords.txt,v 1.6 2006/04/17 10:30:27 as Exp $
+ */
+
+#include <string.h>
+
+#include "keywords.h"
+
+struct kw_entry {
+ char *name;
+ kw_token_t token;
+};
+
+#define TOTAL_KEYWORDS 90
+#define MIN_WORD_LENGTH 3
+#define MAX_WORD_LENGTH 17
+#define MIN_HASH_VALUE 15
+#define MAX_HASH_VALUE 188
+/* maximum key range = 174, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static unsigned int
+hash (str, len)
+ register const char *str;
+ register unsigned int len;
+{
+ static const unsigned char asso_values[] =
+ {
+ 189, 189, 189, 189, 189, 189, 189, 189, 189, 189,
+ 189, 189, 189, 189, 189, 189, 189, 189, 189, 189,
+ 189, 189, 189, 189, 189, 189, 189, 189, 189, 189,
+ 189, 189, 189, 189, 189, 189, 189, 189, 189, 189,
+ 189, 189, 189, 189, 189, 189, 189, 189, 189, 40,
+ 10, 189, 189, 189, 189, 189, 189, 189, 189, 189,
+ 189, 189, 189, 189, 189, 189, 189, 189, 189, 189,
+ 189, 189, 189, 189, 189, 189, 189, 189, 189, 189,
+ 189, 189, 189, 189, 189, 189, 189, 189, 189, 189,
+ 189, 189, 189, 189, 189, 189, 189, 80, 189, 20,
+ 75, 5, 95, 0, 30, 0, 189, 55, 0, 45,
+ 0, 35, 20, 189, 15, 70, 40, 15, 20, 189,
+ 0, 25, 0, 189, 189, 189, 189, 189, 189, 189,
+ 189, 189, 189, 189, 189, 189, 189, 189, 189, 189,
+ 189, 189, 189, 189, 189, 189, 189, 189, 189, 189,
+ 189, 189, 189, 189, 189, 189, 189, 189, 189, 189,
+ 189, 189, 189, 189, 189, 189, 189, 189, 189, 189,
+ 189, 189, 189, 189, 189, 189, 189, 189, 189, 189,
+ 189, 189, 189, 189, 189, 189, 189, 189, 189, 189,
+ 189, 189, 189, 189, 189, 189, 189, 189, 189, 189,
+ 189, 189, 189, 189, 189, 189, 189, 189, 189, 189,
+ 189, 189, 189, 189, 189, 189, 189, 189, 189, 189,
+ 189, 189, 189, 189, 189, 189, 189, 189, 189, 189,
+ 189, 189, 189, 189, 189, 189, 189, 189, 189, 189,
+ 189, 189, 189, 189, 189, 189, 189, 189, 189, 189,
+ 189, 189, 189, 189, 189, 189
+ };
+ return len + asso_values[(unsigned char)str[1]] + asso_values[(unsigned char)str[0]] + asso_values[(unsigned char)str[len - 1]];
+}
+
+static const struct kw_entry wordlist[] =
+ {
+ {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+ {""}, {""}, {""}, {""}, {""}, {""},
+ {"leftupdown", KW_LEFTUPDOWN},
+ {""},
+ {"leftfirewall", KW_LEFTFIREWALL},
+ {""}, {""}, {""},
+ {"leftsubnetwithin", KW_LEFTSUBNETWITHIN},
+ {""}, {""}, {""}, {""},
+ {"rightupdown", KW_RIGHTUPDOWN},
+ {""},
+ {"rightfirewall", KW_RIGHTFIREWALL},
+ {"rekeyfuzz", KW_REKEYFUZZ},
+ {"plutodebug", KW_PLUTODEBUG},
+ {"rekeymargin", KW_REKEYMARGIN},
+ {"rightsubnetwithin", KW_RIGHTSUBNETWITHIN},
+ {""},
+ {"leftnatip", KW_LEFTNATIP},
+ {""},
+ {"leftnexthop", KW_LEFTNEXTHOP},
+ {"leftsourceip", KW_LEFTSOURCEIP},
+ {""}, {""},
+ {"virtual_private", KW_VIRTUAL_PRIVATE},
+ {"crluri", KW_CRLURI},
+ {""},
+ {"leftrsasigkey", KW_LEFTRSASIGKEY},
+ {""},
+ {"rightnatip", KW_RIGHTNATIP},
+ {""},
+ {"rightnexthop", KW_RIGHTNEXTHOP},
+ {"rightsourceip", KW_RIGHTSOURCEIP},
+ {"left", KW_LEFT},
+ {"rekey", KW_REKEY},
+ {"crlcheckinterval", KW_CRLCHECKINTERVAL},
+ {"crluri2", KW_CRLURI2},
+ {"leftcert", KW_LEFTCERT,},
+ {"rightrsasigkey", KW_RIGHTRSASIGKEY},
+ {"leftsubnet", KW_LEFTSUBNET},
+ {"reauth", KW_REAUTH},
+ {"leftsendcert", KW_LEFTSENDCERT},
+ {"leftprotoport", KW_LEFTPROTOPORT},
+ {""},
+ {"right", KW_RIGHT},
+ {"charondebug", KW_CHARONDEBUG},
+ {"ocspuri", KW_OCSPURI},
+ {"ike", KW_IKE},
+ {"rightcert", KW_RIGHTCERT},
+ {"klipsdebug", KW_KLIPSDEBUG},
+ {"rightsubnet", KW_RIGHTSUBNET},
+ {""},
+ {"rightsendcert", KW_RIGHTSENDCERT},
+ {"rightprotoport", KW_RIGHTPROTOPORT},
+ {"plutostart", KW_PLUTOSTART},
+ {"ikelifetime", KW_IKELIFETIME},
+ {"keylife", KW_KEYLIFE},
+ {"ocspuri2", KW_OCSPURI2},
+ {"type", KW_TYPE},
+ {"keep_alive", KW_KEEP_ALIVE},
+ {"keyexchange", KW_KEYEXCHANGE},
+ {""},
+ {"prepluto", KW_PREPLUTO},
+ {""},
+ {"interfaces", KW_INTERFACES},
+ {"overridemtu", KW_OVERRIDEMTU},
+ {"crluri1", KW_CRLURI},
+ {""}, {""},
+ {"leftgroups", KW_LEFTGROUPS},
+ {"leftid", KW_LEFTID},
+ {""},
+ {"ldapbase", KW_LDAPBASE},
+ {"lefthostaccess", KW_LEFTHOSTACCESS},
+ {"modeconfig", KW_MODECONFIG},
+ {"leftca", KW_LEFTCA},
+ {"pkcs11module", KW_PKCS11MODULE},
+ {"nat_traversal", KW_NAT_TRAVERSAL},
+ {"uniqueids", KW_UNIQUEIDS},
+ {"pkcs11keepstate", KW_PKCS11KEEPSTATE},
+ {"rightgroups", KW_RIGHTGROUPS},
+ {"rightid", KW_RIGHTID},
+ {"esp", KW_ESP},
+ {"postpluto", KW_POSTPLUTO},
+ {"righthostaccess", KW_RIGHTHOSTACCESS},
+ {"charonstart", KW_CHARONSTART},
+ {"rightca", KW_RIGHTCA},
+ {"ocspuri1", KW_OCSPURI},
+ {"dpdaction", KW_DPDACTION},
+ {""},
+ {"eapdir", KW_EAPDIR},
+ {"hidetos", KW_HIDETOS},
+ {"eap", KW_EAP},
+ {""}, {""},
+ {"pkcs11proxy", KW_PKCS11PROXY},
+ {"dumpdir", KW_DUMPDIR},
+ {""}, {""},
+ {"xauth", KW_XAUTH},
+ {""}, {""},
+ {"nocrsend", KW_NOCRSEND},
+ {"also", KW_ALSO},
+ {""}, {""}, {""},
+ {"ldaphost", KW_LDAPHOST},
+ {""}, {""},
+ {"authby", KW_AUTHBY},
+ {""},
+ {"dpddelay", KW_DPDDELAY},
+ {"auth", KW_AUTH},
+ {""}, {""}, {""},
+ {"compress", KW_COMPRESS},
+ {"auto", KW_AUTO},
+ {""}, {""}, {""},
+ {"fragicmp", KW_FRAGICMP},
+ {""}, {""},
+ {"keyingtries", KW_KEYINGTRIES},
+ {""},
+ {"pfsgroup", KW_PFSGROUP},
+ {""},
+ {"dpdtimeout", KW_DPDTIMEOUT},
+ {"cacert", KW_CACERT},
+ {""}, {""}, {""},
+ {"strictcrlpolicy", KW_STRICTCRLPOLICY},
+ {""}, {""},
+ {"packetdefault", KW_PACKETDEFAULT},
+ {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+ {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+ {""}, {""}, {""}, {""}, {""}, {""}, {""},
+ {"cachecrls", KW_CACHECRLS},
+ {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+ {"pfs", KW_PFS}
+ };
+
+#ifdef __GNUC__
+__inline
+#endif
+const struct kw_entry *
+in_word_set (str, len)
+ register const char *str;
+ register unsigned int len;
+{
+ if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+ {
+ register int key = hash (str, len);
+
+ if (key <= MAX_HASH_VALUE && key >= 0)
+ {
+ register const char *s = wordlist[key].name;
+
+ if (*str == *s && !strcmp (str + 1, s + 1))
+ return &wordlist[key];
+ }
+ }
+ return 0;
+}
diff --git a/src/starter/keywords.h b/src/starter/keywords.h
new file mode 100644
index 000000000..08d50fea0
--- /dev/null
+++ b/src/starter/keywords.h
@@ -0,0 +1,176 @@
+/* strongSwan keywords
+ * Copyright (C) 2005 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil, Switzerland
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: keywords.h,v 1.8 2006/04/17 10:30:27 as Exp $
+ */
+
+#ifndef _KEYWORDS_H_
+#define _KEYWORDS_H_
+
+typedef enum {
+ /* config setup keywords */
+ KW_INTERFACES,
+ KW_DUMPDIR,
+ KW_CHARONSTART,
+ KW_PLUTOSTART,
+
+ /* pluto/charon keywords */
+ KW_PLUTODEBUG,
+ KW_CHARONDEBUG,
+ KW_PREPLUTO,
+ KW_POSTPLUTO,
+ KW_UNIQUEIDS,
+ KW_OVERRIDEMTU,
+ KW_CRLCHECKINTERVAL,
+ KW_CACHECRLS,
+ KW_STRICTCRLPOLICY,
+ KW_NOCRSEND,
+ KW_NAT_TRAVERSAL,
+ KW_KEEP_ALIVE,
+ KW_VIRTUAL_PRIVATE,
+ KW_EAPDIR,
+ KW_PKCS11MODULE,
+ KW_PKCS11KEEPSTATE,
+ KW_PKCS11PROXY,
+
+#define KW_PLUTO_FIRST KW_PLUTODEBUG
+#define KW_PLUTO_LAST KW_PKCS11PROXY
+
+ /* KLIPS keywords */
+ KW_KLIPSDEBUG,
+ KW_FRAGICMP,
+ KW_PACKETDEFAULT,
+ KW_HIDETOS,
+
+#define KW_KLIPS_FIRST KW_KLIPSDEBUG
+#define KW_KLIPS_LAST KW_HIDETOS
+
+#define KW_SETUP_FIRST KW_INTERFACES
+#define KW_SETUP_LAST KW_HIDETOS
+
+ /* conn section keywords */
+ KW_CONN_NAME,
+ KW_CONN_SETUP,
+ KW_KEYEXCHANGE,
+ KW_TYPE,
+ KW_PFS,
+ KW_COMPRESS,
+ KW_AUTH,
+ KW_AUTHBY,
+ KW_EAP,
+ KW_IKELIFETIME,
+ KW_KEYLIFE,
+ KW_REKEYMARGIN,
+ KW_KEYINGTRIES,
+ KW_REKEYFUZZ,
+ KW_REKEY,
+ KW_REAUTH,
+ KW_IKE,
+ KW_ESP,
+ KW_PFSGROUP,
+ KW_DPDDELAY,
+ KW_DPDTIMEOUT,
+ KW_DPDACTION,
+ KW_MODECONFIG,
+ KW_XAUTH,
+
+#define KW_CONN_FIRST KW_CONN_SETUP
+#define KW_CONN_LAST KW_XAUTH
+
+ /* ca section keywords */
+ KW_CA_NAME,
+ KW_CA_SETUP,
+ KW_CACERT,
+ KW_LDAPHOST,
+ KW_LDAPBASE,
+ KW_CRLURI,
+ KW_CRLURI2,
+ KW_OCSPURI,
+ KW_OCSPURI2,
+
+#define KW_CA_FIRST KW_CA_SETUP
+#define KW_CA_LAST KW_OCSPURI2
+
+ /* end keywords */
+ KW_HOST,
+ KW_NEXTHOP,
+ KW_SUBNET,
+ KW_SUBNETWITHIN,
+ KW_PROTOPORT,
+ KW_SOURCEIP,
+ KW_NATIP,
+ KW_FIREWALL,
+ KW_HOSTACCESS,
+ KW_UPDOWN,
+ KW_ID,
+ KW_RSASIGKEY,
+ KW_CERT,
+ KW_SENDCERT,
+ KW_CA,
+ KW_GROUPS,
+ KW_IFACE,
+
+#define KW_END_FIRST KW_HOST
+#define KW_END_LAST KW_IFACE
+
+ /* left end keywords */
+ KW_LEFT,
+ KW_LEFTNEXTHOP,
+ KW_LEFTSUBNET,
+ KW_LEFTSUBNETWITHIN,
+ KW_LEFTPROTOPORT,
+ KW_LEFTSOURCEIP,
+ KW_LEFTNATIP,
+ KW_LEFTFIREWALL,
+ KW_LEFTHOSTACCESS,
+ KW_LEFTUPDOWN,
+ KW_LEFTID,
+ KW_LEFTRSASIGKEY,
+ KW_LEFTCERT,
+ KW_LEFTSENDCERT,
+ KW_LEFTCA,
+ KW_LEFTGROUPS,
+
+#define KW_LEFT_FIRST KW_LEFT
+#define KW_LEFT_LAST KW_LEFTGROUPS
+
+ /* right end keywords */
+ KW_RIGHT,
+ KW_RIGHTNEXTHOP,
+ KW_RIGHTSUBNET,
+ KW_RIGHTSUBNETWITHIN,
+ KW_RIGHTPROTOPORT,
+ KW_RIGHTSOURCEIP,
+ KW_RIGHTNATIP,
+ KW_RIGHTFIREWALL,
+ KW_RIGHTHOSTACCESS,
+ KW_RIGHTUPDOWN,
+ KW_RIGHTID,
+ KW_RIGHTRSASIGKEY,
+ KW_RIGHTCERT,
+ KW_RIGHTSENDCERT,
+ KW_RIGHTCA,
+ KW_RIGHTGROUPS,
+
+#define KW_RIGHT_FIRST KW_RIGHT
+#define KW_RIGHT_LAST KW_RIGHTGROUPS
+
+ /* general section keywords */
+ KW_ALSO,
+ KW_AUTO
+
+} kw_token_t;
+
+#endif /* _KEYWORDS_H_ */
+
diff --git a/src/starter/keywords.txt b/src/starter/keywords.txt
new file mode 100644
index 000000000..0f943fc3c
--- /dev/null
+++ b/src/starter/keywords.txt
@@ -0,0 +1,118 @@
+%{
+/* strongSwan keywords
+ * Copyright (C) 2005 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil, Switzerland
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: keywords.txt,v 1.6 2006/04/17 10:30:27 as Exp $
+ */
+
+#include <string.h>
+
+#include "keywords.h"
+
+%}
+struct kw_entry {
+ char *name;
+ kw_token_t token;
+};
+%%
+interfaces, KW_INTERFACES
+dumpdir, KW_DUMPDIR
+charonstart, KW_CHARONSTART
+plutostart, KW_PLUTOSTART
+klipsdebug, KW_KLIPSDEBUG
+plutodebug, KW_PLUTODEBUG
+charondebug, KW_CHARONDEBUG
+prepluto, KW_PREPLUTO
+postpluto, KW_POSTPLUTO
+fragicmp, KW_FRAGICMP
+packetdefault, KW_PACKETDEFAULT
+hidetos, KW_HIDETOS
+uniqueids, KW_UNIQUEIDS
+overridemtu, KW_OVERRIDEMTU
+crlcheckinterval, KW_CRLCHECKINTERVAL
+cachecrls, KW_CACHECRLS
+strictcrlpolicy, KW_STRICTCRLPOLICY
+nocrsend, KW_NOCRSEND
+nat_traversal, KW_NAT_TRAVERSAL
+keep_alive, KW_KEEP_ALIVE
+virtual_private, KW_VIRTUAL_PRIVATE
+eap, KW_EAP
+eapdir, KW_EAPDIR
+pkcs11module, KW_PKCS11MODULE
+pkcs11keepstate, KW_PKCS11KEEPSTATE
+pkcs11proxy, KW_PKCS11PROXY
+keyexchange, KW_KEYEXCHANGE
+type, KW_TYPE
+pfs, KW_PFS
+compress, KW_COMPRESS
+auth, KW_AUTH
+authby, KW_AUTHBY
+keylife, KW_KEYLIFE
+rekeymargin, KW_REKEYMARGIN
+ikelifetime, KW_IKELIFETIME
+keyingtries, KW_KEYINGTRIES
+rekeyfuzz, KW_REKEYFUZZ
+rekey, KW_REKEY
+reauth, KW_REAUTH
+esp, KW_ESP
+ike, KW_IKE
+pfsgroup, KW_PFSGROUP
+dpddelay, KW_DPDDELAY
+dpdtimeout, KW_DPDTIMEOUT
+dpdaction, KW_DPDACTION
+modeconfig, KW_MODECONFIG
+xauth, KW_XAUTH
+cacert, KW_CACERT
+ldaphost, KW_LDAPHOST
+ldapbase, KW_LDAPBASE
+crluri, KW_CRLURI
+crluri1, KW_CRLURI
+crluri2, KW_CRLURI2
+ocspuri, KW_OCSPURI
+ocspuri1, KW_OCSPURI
+ocspuri2, KW_OCSPURI2
+left, KW_LEFT
+leftnexthop, KW_LEFTNEXTHOP
+leftsubnet, KW_LEFTSUBNET
+leftsubnetwithin, KW_LEFTSUBNETWITHIN
+leftprotoport, KW_LEFTPROTOPORT
+leftsourceip, KW_LEFTSOURCEIP
+leftnatip, KW_LEFTNATIP
+leftfirewall, KW_LEFTFIREWALL
+lefthostaccess, KW_LEFTHOSTACCESS
+leftupdown, KW_LEFTUPDOWN
+leftid, KW_LEFTID
+leftrsasigkey, KW_LEFTRSASIGKEY
+leftcert, KW_LEFTCERT,
+leftsendcert, KW_LEFTSENDCERT
+leftca, KW_LEFTCA
+leftgroups, KW_LEFTGROUPS
+right, KW_RIGHT
+rightnexthop, KW_RIGHTNEXTHOP
+rightsubnet, KW_RIGHTSUBNET
+rightsubnetwithin, KW_RIGHTSUBNETWITHIN
+rightprotoport, KW_RIGHTPROTOPORT
+rightsourceip, KW_RIGHTSOURCEIP
+rightnatip, KW_RIGHTNATIP
+rightfirewall, KW_RIGHTFIREWALL
+righthostaccess, KW_RIGHTHOSTACCESS
+rightupdown, KW_RIGHTUPDOWN
+rightid, KW_RIGHTID
+rightrsasigkey, KW_RIGHTRSASIGKEY
+rightcert, KW_RIGHTCERT
+rightsendcert, KW_RIGHTSENDCERT
+rightca, KW_RIGHTCA
+rightgroups, KW_RIGHTGROUPS
+also, KW_ALSO
+auto, KW_AUTO
diff --git a/src/starter/lex.yy.c b/src/starter/lex.yy.c
new file mode 100644
index 000000000..f8e6569f1
--- /dev/null
+++ b/src/starter/lex.yy.c
@@ -0,0 +1,1966 @@
+
+#line 3 "lex.yy.c"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 33
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart(yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+extern int yyleng;
+
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ #define YY_LESS_LINENO(n)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = (yy_hold_char); \
+ YY_RESTORE_YY_MORE_OFFSET \
+ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr) )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef unsigned int yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+ : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+static int yy_n_chars; /* number of characters read into yy_ch_buf */
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0; /* whether we need to initialize */
+static int yy_start = 0; /* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart (FILE *input_file );
+void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer );
+YY_BUFFER_STATE yy_create_buffer (FILE *file,int size );
+void yy_delete_buffer (YY_BUFFER_STATE b );
+void yy_flush_buffer (YY_BUFFER_STATE b );
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer );
+void yypop_buffer_state (void );
+
+static void yyensure_buffer_stack (void );
+static void yy_load_buffer_state (void );
+static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file );
+
+#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size );
+YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str );
+YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len );
+
+void *yyalloc (yy_size_t );
+void *yyrealloc (void *,yy_size_t );
+void yyfree (void * );
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ yyensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer(yyin,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ yyensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer(yyin,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+typedef unsigned char YY_CHAR;
+
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int yylineno;
+
+int yylineno = 1;
+
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[] );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ (yytext_ptr) = yy_bp; \
+ yyleng = (size_t) (yy_cp - yy_bp); \
+ (yy_hold_char) = *yy_cp; \
+ *yy_cp = '\0'; \
+ (yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 14
+#define YY_END_OF_BUFFER 15
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static yyconst flex_int16_t yy_accept[47] =
+ { 0,
+ 0, 0, 15, 11, 2, 4, 13, 11, 3, 11,
+ 11, 11, 11, 1, 11, 2, 0, 12, 11, 0,
+ 4, 8, 11, 11, 11, 11, 1, 11, 11, 11,
+ 11, 11, 7, 11, 11, 11, 11, 11, 6, 11,
+ 5, 11, 11, 9, 10, 0
+ } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 1, 4, 5, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 6, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 7, 1, 8, 9,
+
+ 10, 11, 12, 1, 13, 1, 1, 14, 1, 15,
+ 16, 17, 1, 18, 19, 20, 21, 22, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int32_t yy_meta[23] =
+ { 0,
+ 1, 2, 3, 2, 1, 2, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1
+ } ;
+
+static yyconst flex_int16_t yy_base[51] =
+ { 0,
+ 0, 69, 70, 0, 67, 72, 64, 21, 72, 19,
+ 52, 56, 55, 62, 0, 61, 58, 72, 34, 58,
+ 72, 0, 45, 51, 38, 39, 54, 17, 41, 33,
+ 34, 39, 0, 30, 33, 36, 27, 25, 0, 17,
+ 0, 21, 15, 0, 0, 72, 28, 40, 42, 45
+ } ;
+
+static yyconst flex_int16_t yy_def[51] =
+ { 0,
+ 46, 1, 46, 47, 46, 46, 48, 49, 46, 47,
+ 47, 47, 47, 46, 47, 46, 48, 46, 49, 50,
+ 46, 47, 47, 47, 47, 47, 46, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 0, 46, 46, 46, 46
+ } ;
+
+static yyconst flex_int16_t yy_nxt[95] =
+ { 0,
+ 4, 5, 6, 7, 8, 9, 4, 10, 4, 4,
+ 4, 4, 11, 4, 4, 4, 4, 4, 12, 4,
+ 4, 13, 20, 21, 20, 22, 20, 32, 15, 45,
+ 44, 33, 43, 42, 23, 20, 21, 20, 41, 20,
+ 17, 17, 19, 19, 19, 20, 20, 20, 40, 39,
+ 38, 37, 36, 35, 34, 27, 31, 30, 29, 28,
+ 21, 18, 16, 27, 26, 25, 24, 18, 16, 46,
+ 14, 3, 46, 46, 46, 46, 46, 46, 46, 46,
+ 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
+ 46, 46, 46, 46
+
+ } ;
+
+static yyconst flex_int16_t yy_chk[95] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 8, 8, 8, 10, 8, 28, 47, 43,
+ 42, 28, 40, 38, 10, 19, 19, 19, 37, 19,
+ 48, 48, 49, 49, 49, 50, 50, 50, 36, 35,
+ 34, 32, 31, 30, 29, 27, 26, 25, 24, 23,
+ 20, 17, 16, 14, 13, 12, 11, 7, 5, 3,
+ 2, 46, 46, 46, 46, 46, 46, 46, 46, 46,
+ 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
+ 46, 46, 46, 46
+
+ } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+extern int yy_flex_debug;
+int yy_flex_debug = 0;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "parser.l"
+#line 2 "parser.l"
+/* FreeS/WAN config file parser (parser.l)
+ * Copyright (C) 2001 Mathieu Lafon - Arkoon Network Security
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: parser.l,v 1.5 2006/03/28 22:32:33 as Exp $
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <glob.h>
+
+#include "y.tab.h"
+
+#define MAX_INCLUDE_DEPTH 20
+
+#define YY_NO_UNPUT
+extern void yyerror(const char *);
+extern int yylex (void);
+
+static struct {
+ int stack_ptr;
+ YY_BUFFER_STATE stack[MAX_INCLUDE_DEPTH];
+ FILE *file[MAX_INCLUDE_DEPTH];
+ unsigned int line[MAX_INCLUDE_DEPTH];
+ char *filename[MAX_INCLUDE_DEPTH];
+} __parser_y_private;
+
+void _parser_y_error(char *b, int size, const char *s);
+void _parser_y_init (const char *f);
+void _parser_y_fini (void);
+int _parser_y_include (const char *filename);
+
+void _parser_y_error(char *b, int size, const char *s)
+{
+ extern char *yytext; // was: char yytext[];
+
+ snprintf(b, size, "%s:%d: %s [%s]",
+ __parser_y_private.filename[__parser_y_private.stack_ptr],
+ __parser_y_private.line[__parser_y_private.stack_ptr],
+ s, yytext);
+}
+
+void _parser_y_init (const char *f)
+{
+ memset(&__parser_y_private, 0, sizeof(__parser_y_private));
+ __parser_y_private.line[0] = 1;
+ __parser_y_private.filename[0] = strdup(f);
+}
+
+void _parser_y_fini (void)
+{
+ unsigned int i;
+
+ for (i = 0; i < MAX_INCLUDE_DEPTH; i++)
+ {
+ if (__parser_y_private.filename[i])
+ free(__parser_y_private.filename[i]);
+ if (__parser_y_private.file[i])
+ fclose(__parser_y_private.file[i]);
+ }
+ memset(&__parser_y_private, 0, sizeof(__parser_y_private));
+}
+
+int _parser_y_include (const char *filename)
+{
+ glob_t files;
+ int i, ret;
+
+ ret = glob(filename, GLOB_ERR, NULL, &files);
+ if (ret)
+ {
+ const char *err;
+
+ switch (ret)
+ {
+ case GLOB_NOSPACE:
+ err = "include files ran out of memory";
+ break;
+ case GLOB_ABORTED:
+ err = "include files aborted due to read error";
+ break;
+ case GLOB_NOMATCH:
+ err = "include files found no matches";
+ break;
+ default:
+ err = "unknown include files error";
+ }
+ yyerror(err);
+ return 1;
+ }
+
+ for (i = 0; i < files.gl_pathc; i++)
+ {
+ FILE *f;
+ unsigned int p = __parser_y_private.stack_ptr + 1;
+
+ if (p >= MAX_INCLUDE_DEPTH)
+ {
+ yyerror("max inclusion depth reached");
+ return 1;
+ }
+
+ f = fopen(files.gl_pathv[i], "r");
+ if (!f)
+ {
+ yyerror("can't open include filename");
+ continue;
+ }
+
+ __parser_y_private.stack_ptr++;
+ __parser_y_private.file[p] = f;
+ __parser_y_private.stack[p] = YY_CURRENT_BUFFER;
+ __parser_y_private.line[p] = 1;
+ __parser_y_private.filename[p] = strdup(files.gl_pathv[i]);
+
+ yy_switch_to_buffer(yy_create_buffer(f,YY_BUF_SIZE));
+ }
+ globfree(&files);
+ return 0;
+}
+
+#line 618 "lex.yy.c"
+
+#define INITIAL 0
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap (void );
+#else
+extern int yywrap (void );
+#endif
+#endif
+
+ static void yyunput (int c,char *buf_ptr );
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ size_t n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yyin); \
+ } \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (void);
+
+#define YY_DECL int yylex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ if ( yyleng > 0 ) \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \
+ (yytext[yyleng - 1] == '\n'); \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
+#line 134 "parser.l"
+
+
+#line 777 "lex.yy.c"
+
+ if ( !(yy_init) )
+ {
+ (yy_init) = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! (yy_start) )
+ (yy_start) = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ yyensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer(yyin,YY_BUF_SIZE );
+ }
+
+ yy_load_buffer_state( );
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = (yy_c_buf_p);
+
+ /* Support of yytext. */
+ *yy_cp = (yy_hold_char);
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = (yy_start);
+ yy_current_state += YY_AT_BOL();
+yy_match:
+ do
+ {
+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 47 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 72 );
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+ if ( yy_act == 0 )
+ { /* have to back up */
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+ yy_act = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = (yy_hold_char);
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+ goto yy_find_action;
+
+case YY_STATE_EOF(INITIAL):
+#line 136 "parser.l"
+{
+ if (__parser_y_private.filename[__parser_y_private.stack_ptr]) {
+ free(__parser_y_private.filename[__parser_y_private.stack_ptr]);
+ __parser_y_private.filename[__parser_y_private.stack_ptr] = NULL;
+ }
+ if (__parser_y_private.file[__parser_y_private.stack_ptr]) {
+ fclose(__parser_y_private.file[__parser_y_private.stack_ptr]);
+ __parser_y_private.file[__parser_y_private.stack_ptr] = NULL;
+ yy_delete_buffer (YY_CURRENT_BUFFER);
+ yy_switch_to_buffer
+ (__parser_y_private.stack[__parser_y_private.stack_ptr]);
+ }
+ if (--__parser_y_private.stack_ptr < 0) {
+ yyterminate();
+ }
+}
+ YY_BREAK
+case 1:
+YY_RULE_SETUP
+#line 153 "parser.l"
+return FIRST_SPACES;
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 155 "parser.l"
+/* ignore spaces in line */ ;
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 157 "parser.l"
+return EQUAL;
+ YY_BREAK
+case 4:
+/* rule 4 can match eol */
+YY_RULE_SETUP
+#line 159 "parser.l"
+{
+ __parser_y_private.line[__parser_y_private.stack_ptr]++;
+ return EOL;
+ }
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 164 "parser.l"
+return CONFIG;
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 165 "parser.l"
+return SETUP;
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 166 "parser.l"
+return CONN;
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 167 "parser.l"
+return CA;
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 168 "parser.l"
+return INCLUDE;
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 169 "parser.l"
+return FILE_VERSION;
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 171 "parser.l"
+{
+ yylval.s = strdup(yytext);
+ return STRING;
+ }
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 176 "parser.l"
+{
+ yylval.s = strdup(yytext+1);
+ if (yylval.s) yylval.s[strlen(yylval.s)-1]='\0';
+ return STRING;
+ }
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 182 "parser.l"
+yyerror(yytext);
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 184 "parser.l"
+ECHO;
+ YY_BREAK
+#line 961 "lex.yy.c"
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = (yy_hold_char);
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++(yy_c_buf_p);
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = (yy_c_buf_p);
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ (yy_did_buffer_switch_on_eof) = 0;
+
+ if ( yywrap( ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) =
+ (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ (yy_c_buf_p) =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+} /* end of yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+ register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ register char *source = (yytext_ptr);
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+ else
+ {
+ int num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+ int yy_c_buf_p_offset =
+ (int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ (yy_n_chars), num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ if ( (yy_n_chars) == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart(yyin );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ (yy_n_chars) += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+ (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (void)
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+
+ yy_current_state = (yy_start);
+ yy_current_state += YY_AT_BOL();
+
+ for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+ {
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 47 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
+{
+ register int yy_is_jam;
+ register char *yy_cp = (yy_c_buf_p);
+
+ register YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 47 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 46);
+
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+ static void yyunput (int c, register char * yy_bp )
+{
+ register char *yy_cp;
+
+ yy_cp = (yy_c_buf_p);
+
+ /* undo effects of setting up yytext */
+ *yy_cp = (yy_hold_char);
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ register int number_to_move = (yy_n_chars) + 2;
+ register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+ register char *source =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+ while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += (int) (dest - source);
+ yy_bp += (int) (dest - source);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ YY_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ *--yy_cp = (char) c;
+
+ (yytext_ptr) = yy_bp;
+ (yy_hold_char) = *yy_cp;
+ (yy_c_buf_p) = yy_cp;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (void)
+#else
+ static int input (void)
+#endif
+
+{
+ int c;
+
+ *(yy_c_buf_p) = (yy_hold_char);
+
+ if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ /* This was really a NUL. */
+ *(yy_c_buf_p) = '\0';
+
+ else
+ { /* need more input */
+ int offset = (yy_c_buf_p) - (yytext_ptr);
+ ++(yy_c_buf_p);
+
+ switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart(yyin );
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap( ) )
+ return EOF;
+
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) = (yytext_ptr) + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */
+ *(yy_c_buf_p) = '\0'; /* preserve yytext */
+ (yy_hold_char) = *++(yy_c_buf_p);
+
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n');
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ *
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void yyrestart (FILE * input_file )
+{
+
+ if ( ! YY_CURRENT_BUFFER ){
+ yyensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer(yyin,YY_BUF_SIZE );
+ }
+
+ yy_init_buffer(YY_CURRENT_BUFFER,input_file );
+ yy_load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ *
+ */
+ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer )
+{
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * yypop_buffer_state();
+ * yypush_buffer_state(new_buffer);
+ */
+ yyensure_buffer_stack ();
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ yy_load_buffer_state( );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void yy_load_buffer_state (void)
+{
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ (yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ *
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size )
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer(b,file );
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ *
+ */
+ void yy_delete_buffer (YY_BUFFER_STATE b )
+{
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yyfree((void *) b->yy_ch_buf );
+
+ yyfree((void *) b );
+}
+
+#ifndef _UNISTD_H /* assume unistd.h has isatty() for us */
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __THROW /* this is a gnuism */
+extern int isatty (int ) __THROW;
+#else
+extern int isatty (int );
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file )
+
+{
+ int oerrno = errno;
+
+ yy_flush_buffer(b );
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then yy_init_buffer was _probably_
+ * called from yyrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ *
+ */
+ void yy_flush_buffer (YY_BUFFER_STATE b )
+{
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ yy_load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ *
+ */
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+ if (new_buffer == NULL)
+ return;
+
+ yyensure_buffer_stack();
+
+ /* This block is copied from yy_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ (yy_buffer_stack_top)++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from yy_switch_to_buffer. */
+ yy_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ *
+ */
+void yypop_buffer_state (void)
+{
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ yy_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if ((yy_buffer_stack_top) > 0)
+ --(yy_buffer_stack_top);
+
+ if (YY_CURRENT_BUFFER) {
+ yy_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void yyensure_buffer_stack (void)
+{
+ int num_to_alloc;
+
+ if (!(yy_buffer_stack)) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1;
+ (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+
+ memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ (yy_buffer_stack_max) = num_to_alloc;
+ (yy_buffer_stack_top) = 0;
+ return;
+ }
+
+ if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ int grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = (yy_buffer_stack_max) + grow_size;
+ (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
+ ((yy_buffer_stack),
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+
+ /* zero only the new slots.*/
+ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+ (yy_buffer_stack_max) = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size )
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ yy_switch_to_buffer(b );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to yylex() will
+ * scan from a @e copy of @a str.
+ * @param str a NUL-terminated string to scan
+ *
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE yy_scan_string (yyconst char * yystr )
+{
+
+ return yy_scan_bytes(yystr,strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param bytes the byte buffer to scan
+ * @param len the number of bytes in the buffer pointed to by @a bytes.
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len )
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _yybytes_len + 2;
+ buf = (char *) yyalloc(n );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = yy_scan_buffer(buf,n );
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yytext[yyleng] = (yy_hold_char); \
+ (yy_c_buf_p) = yytext + yyless_macro_arg; \
+ (yy_hold_char) = *(yy_c_buf_p); \
+ *(yy_c_buf_p) = '\0'; \
+ yyleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ *
+ */
+int yyget_lineno (void)
+{
+
+ return yylineno;
+}
+
+/** Get the input stream.
+ *
+ */
+FILE *yyget_in (void)
+{
+ return yyin;
+}
+
+/** Get the output stream.
+ *
+ */
+FILE *yyget_out (void)
+{
+ return yyout;
+}
+
+/** Get the length of the current token.
+ *
+ */
+int yyget_leng (void)
+{
+ return yyleng;
+}
+
+/** Get the current token.
+ *
+ */
+
+char *yyget_text (void)
+{
+ return yytext;
+}
+
+/** Set the current line number.
+ * @param line_number
+ *
+ */
+void yyset_lineno (int line_number )
+{
+
+ yylineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ *
+ * @see yy_switch_to_buffer
+ */
+void yyset_in (FILE * in_str )
+{
+ yyin = in_str ;
+}
+
+void yyset_out (FILE * out_str )
+{
+ yyout = out_str ;
+}
+
+int yyget_debug (void)
+{
+ return yy_flex_debug;
+}
+
+void yyset_debug (int bdebug )
+{
+ yy_flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from yylex_destroy(), so don't allocate here.
+ */
+
+ (yy_buffer_stack) = 0;
+ (yy_buffer_stack_top) = 0;
+ (yy_buffer_stack_max) = 0;
+ (yy_c_buf_p) = (char *) 0;
+ (yy_init) = 0;
+ (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ yyin = stdin;
+ yyout = stdout;
+#else
+ yyin = (FILE *) 0;
+ yyout = (FILE *) 0;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * yylex_init()
+ */
+ return 0;
+}
+
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy (void)
+{
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ yy_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ yypop_buffer_state();
+ }
+
+ /* Destroy the stack itself. */
+ yyfree((yy_buffer_stack) );
+ (yy_buffer_stack) = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * yylex() is called, initialization will occur. */
+ yy_init_globals( );
+
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *yyalloc (yy_size_t size )
+{
+ return (void *) malloc( size );
+}
+
+void *yyrealloc (void * ptr, yy_size_t size )
+{
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+}
+
+void yyfree (void * ptr )
+{
+ free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 184 "parser.l"
+
+
+
+int yywrap(void)
+{
+ return 1;
+}
+
+
diff --git a/src/starter/netkey.c b/src/starter/netkey.c
new file mode 100644
index 000000000..d0b8e0a2c
--- /dev/null
+++ b/src/starter/netkey.c
@@ -0,0 +1,85 @@
+/* strongSwan netkey starter
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: netkey.c,v 1.4 2006/02/15 18:33:57 as Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+
+#include <freeswan.h>
+
+#include "../pluto/constants.h"
+#include "../pluto/defs.h"
+#include "../pluto/log.h"
+
+#include "files.h"
+
+bool
+starter_netkey_init(void)
+{
+ struct stat stb;
+
+ if (stat(PROC_NETKEY, &stb) != 0)
+ {
+ /* af_key module makes the netkey proc interface visible */
+ if (stat(PROC_MODULES, &stb) == 0)
+ {
+ system("modprobe -qv af_key");
+ }
+
+ /* now test again */
+ if (stat(PROC_NETKEY, &stb) != 0)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("kernel appears to lack the native netkey IPsec stack")
+ )
+ return FALSE;
+ }
+ }
+
+ /* make sure that all required IPsec modules are loaded */
+ if (stat(PROC_MODULES, &stb) == 0)
+ {
+ system("modprobe -qv ah4");
+ system("modprobe -qv esp4");
+ system("modprobe -qv ipcomp");
+ system("modprobe -qv xfrm4_tunnel");
+ system("modprobe -qv xfrm_user");
+ }
+
+ DBG(DBG_CONTROL,
+ DBG_log("Found netkey IPsec stack")
+ )
+ return TRUE;
+}
+
+void
+starter_netkey_cleanup(void)
+{
+ if (system("ip xfrm state > /dev/null 2>&1") == 0)
+ {
+ system("ip xfrm state flush");
+ system("ip xfrm policy flush");
+ }
+ else if (system("type setkey > /dev/null 2>&1") == 0)
+ {
+ system("setkey -F");
+ system("setkey -FP");
+ }
+ else
+ {
+ plog("WARNING: cannot flush IPsec state/policy database");
+ }
+}
diff --git a/src/starter/netkey.h b/src/starter/netkey.h
new file mode 100644
index 000000000..ff8989d34
--- /dev/null
+++ b/src/starter/netkey.h
@@ -0,0 +1,24 @@
+/* strongSwan netkey initialization and cleanup
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: netkey.h,v 1.1 2005/12/30 19:03:15 as Exp $
+ */
+
+#ifndef _STARTER_NETKEY_H_
+#define _STARTER_NETKEY_H_
+
+extern bool starter_netkey_init (void);
+extern void starter_netkey_cleanup (void);
+
+#endif /* _STARTER_NETKEY_H_ */
+
diff --git a/src/starter/parser.h b/src/starter/parser.h
new file mode 100644
index 000000000..61bdea974
--- /dev/null
+++ b/src/starter/parser.h
@@ -0,0 +1,57 @@
+/* strongSwan config file parser
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: parser.h,v 1.5 2006/01/17 23:43:36 as Exp $
+ */
+
+#ifndef _IPSEC_PARSER_H_
+#define _IPSEC_PARSER_H_
+
+#include "keywords.h"
+
+typedef struct kw_entry kw_entry_t;
+
+struct kw_entry {
+ char *name;
+ kw_token_t token;
+};
+
+typedef struct kw_list kw_list_t;
+
+struct kw_list {
+ kw_entry_t *entry;
+ char *value;
+ kw_list_t *next;
+};
+
+typedef struct section_list section_list_t;
+
+struct section_list {
+ char *name;
+ kw_list_t *kw;
+ section_list_t *next;
+};
+
+typedef struct config_parsed config_parsed_t;
+
+struct config_parsed {
+ kw_list_t *config_setup;
+ section_list_t *conn_first, *conn_last;
+ section_list_t *ca_first, *ca_last;
+};
+
+config_parsed_t *parser_load_conf (const char *file);
+void parser_free_conf (config_parsed_t *cfg);
+
+#endif /* _IPSEC_PARSER_H_ */
+
diff --git a/src/starter/parser.l b/src/starter/parser.l
new file mode 100644
index 000000000..1469f94bc
--- /dev/null
+++ b/src/starter/parser.l
@@ -0,0 +1,190 @@
+%{
+/* FreeS/WAN config file parser (parser.l)
+ * Copyright (C) 2001 Mathieu Lafon - Arkoon Network Security
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: parser.l,v 1.5 2006/03/28 22:32:33 as Exp $
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <glob.h>
+
+#include "y.tab.h"
+
+#define MAX_INCLUDE_DEPTH 20
+
+#define YY_NO_UNPUT
+extern void yyerror(const char *);
+extern int yylex (void);
+
+static struct {
+ int stack_ptr;
+ YY_BUFFER_STATE stack[MAX_INCLUDE_DEPTH];
+ FILE *file[MAX_INCLUDE_DEPTH];
+ unsigned int line[MAX_INCLUDE_DEPTH];
+ char *filename[MAX_INCLUDE_DEPTH];
+} __parser_y_private;
+
+void _parser_y_error(char *b, int size, const char *s);
+void _parser_y_init (const char *f);
+void _parser_y_fini (void);
+int _parser_y_include (const char *filename);
+
+void _parser_y_error(char *b, int size, const char *s)
+{
+ extern char *yytext; // was: char yytext[];
+
+ snprintf(b, size, "%s:%d: %s [%s]",
+ __parser_y_private.filename[__parser_y_private.stack_ptr],
+ __parser_y_private.line[__parser_y_private.stack_ptr],
+ s, yytext);
+}
+
+void _parser_y_init (const char *f)
+{
+ memset(&__parser_y_private, 0, sizeof(__parser_y_private));
+ __parser_y_private.line[0] = 1;
+ __parser_y_private.filename[0] = strdup(f);
+}
+
+void _parser_y_fini (void)
+{
+ unsigned int i;
+
+ for (i = 0; i < MAX_INCLUDE_DEPTH; i++)
+ {
+ if (__parser_y_private.filename[i])
+ free(__parser_y_private.filename[i]);
+ if (__parser_y_private.file[i])
+ fclose(__parser_y_private.file[i]);
+ }
+ memset(&__parser_y_private, 0, sizeof(__parser_y_private));
+}
+
+int _parser_y_include (const char *filename)
+{
+ glob_t files;
+ int i, ret;
+
+ ret = glob(filename, GLOB_ERR, NULL, &files);
+ if (ret)
+ {
+ const char *err;
+
+ switch (ret)
+ {
+ case GLOB_NOSPACE:
+ err = "include files ran out of memory";
+ break;
+ case GLOB_ABORTED:
+ err = "include files aborted due to read error";
+ break;
+ case GLOB_NOMATCH:
+ err = "include files found no matches";
+ break;
+ default:
+ err = "unknown include files error";
+ }
+ yyerror(err);
+ return 1;
+ }
+
+ for (i = 0; i < files.gl_pathc; i++)
+ {
+ FILE *f;
+ unsigned int p = __parser_y_private.stack_ptr + 1;
+
+ if (p >= MAX_INCLUDE_DEPTH)
+ {
+ yyerror("max inclusion depth reached");
+ return 1;
+ }
+
+ f = fopen(files.gl_pathv[i], "r");
+ if (!f)
+ {
+ yyerror("can't open include filename");
+ continue;
+ }
+
+ __parser_y_private.stack_ptr++;
+ __parser_y_private.file[p] = f;
+ __parser_y_private.stack[p] = YY_CURRENT_BUFFER;
+ __parser_y_private.line[p] = 1;
+ __parser_y_private.filename[p] = strdup(files.gl_pathv[i]);
+
+ yy_switch_to_buffer(yy_create_buffer(f, YY_BUF_SIZE));
+ }
+ globfree(&files);
+ return 0;
+}
+
+%}
+
+%%
+
+<<EOF>> {
+ if (__parser_y_private.filename[__parser_y_private.stack_ptr]) {
+ free(__parser_y_private.filename[__parser_y_private.stack_ptr]);
+ __parser_y_private.filename[__parser_y_private.stack_ptr] = NULL;
+ }
+ if (__parser_y_private.file[__parser_y_private.stack_ptr]) {
+ fclose(__parser_y_private.file[__parser_y_private.stack_ptr]);
+ __parser_y_private.file[__parser_y_private.stack_ptr] = NULL;
+ yy_delete_buffer (YY_CURRENT_BUFFER);
+ yy_switch_to_buffer
+ (__parser_y_private.stack[__parser_y_private.stack_ptr]);
+ }
+ if (--__parser_y_private.stack_ptr < 0) {
+ yyterminate();
+ }
+}
+
+^[\t ]+ return FIRST_SPACES;
+
+[\t ]+ /* ignore spaces in line */ ;
+
+= return EQUAL;
+
+\n|#.*\n {
+ __parser_y_private.line[__parser_y_private.stack_ptr]++;
+ return EOL;
+ }
+
+config return CONFIG;
+setup return SETUP;
+conn return CONN;
+ca return CA;
+include return INCLUDE;
+version return FILE_VERSION;
+
+[^\"= \t\n]+ {
+ yylval.s = strdup(yytext);
+ return STRING;
+ }
+
+\"[^\"\n]*\" {
+ yylval.s = strdup(yytext+1);
+ if (yylval.s) yylval.s[strlen(yylval.s)-1]='\0';
+ return STRING;
+ }
+
+. yyerror(yytext);
+
+%%
+
+int yywrap(void)
+{
+ return 1;
+}
+
diff --git a/src/starter/parser.y b/src/starter/parser.y
new file mode 100644
index 000000000..db984fae3
--- /dev/null
+++ b/src/starter/parser.y
@@ -0,0 +1,283 @@
+%{
+/* strongSwan config file parser (parser.y)
+ * Copyright (C) 2001 Mathieu Lafon - Arkoon Network Security
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: parser.y,v 1.6 2006/01/17 23:43:36 as Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <freeswan.h>
+
+#include "../pluto/constants.h"
+#include "../pluto/defs.h"
+#include "../pluto/log.h"
+#include "parser.h"
+
+#define YYERROR_VERBOSE
+#define ERRSTRING_LEN 256
+
+/**
+ * Bison
+ */
+static char parser_errstring[ERRSTRING_LEN+1];
+
+extern void yyerror(const char *s);
+extern int yylex (void);
+extern void _parser_y_error(char *b, int size, const char *s);
+
+/**
+ * Static Globals
+ */
+static int _save_errors_;
+static config_parsed_t *_parser_cfg;
+static kw_list_t **_parser_kw, *_parser_kw_last;
+static char errbuf[ERRSTRING_LEN+1];
+
+/**
+ * Gperf
+ */
+extern kw_entry_t *in_word_set (char *str, unsigned int len);
+
+%}
+
+%union { char *s; };
+%token EQUAL FIRST_SPACES EOL CONFIG SETUP CONN CA INCLUDE FILE_VERSION
+%token <s> STRING
+
+%%
+
+/*
+ * Config file
+ */
+
+config_file:
+ config_file section_or_include
+ | /* NULL */
+ ;
+
+section_or_include:
+ FILE_VERSION STRING EOL
+ {
+ free($2);
+ }
+ | CONFIG SETUP EOL
+ {
+ _parser_kw = &(_parser_cfg->config_setup);
+ _parser_kw_last = NULL;
+ } kw_section
+ | CONN STRING EOL
+ {
+ section_list_t *section = (section_list_t *)alloc_thing(section_list_t
+ , "section_list_t");
+
+ section->name = clone_str($2, "conn section name");
+ section->kw = NULL;
+ section->next = NULL;
+ _parser_kw = &(section->kw);
+ if (!_parser_cfg->conn_first)
+ _parser_cfg->conn_first = section;
+ if (_parser_cfg->conn_last)
+ _parser_cfg->conn_last->next = section;
+ _parser_cfg->conn_last = section;
+ _parser_kw_last = NULL;
+ free($2);
+ } kw_section
+ | CA STRING EOL
+ {
+ section_list_t *section = (section_list_t *)alloc_thing(section_list_t
+ , "section_list_t");
+ section->name = clone_str($2, "ca section name");
+ section->kw = NULL;
+ section->next = NULL;
+ _parser_kw = &(section->kw);
+ if (!_parser_cfg->ca_first)
+ _parser_cfg->ca_first = section;
+ if (_parser_cfg->ca_last)
+ _parser_cfg->ca_last->next = section;
+ _parser_cfg->ca_last = section;
+ _parser_kw_last = NULL;
+ free($2);
+ } kw_section
+ | INCLUDE STRING
+ {
+ extern void _parser_y_include (const char *f);
+ _parser_y_include($2);
+ free($2);
+ } EOL
+ | EOL
+ ;
+
+kw_section:
+ FIRST_SPACES statement_kw EOL kw_section
+ |
+ ;
+
+statement_kw:
+ STRING EQUAL STRING
+ {
+ kw_list_t *new;
+ kw_entry_t *entry = in_word_set($1, strlen($1));
+
+ if (entry == NULL)
+ {
+ snprintf(errbuf, ERRSTRING_LEN, "unknown keyword '%s'", $1);
+ yyerror(errbuf);
+ }
+ else if (_parser_kw)
+ {
+ new = (kw_list_t *)alloc_thing(kw_list_t, "kw_list_t");
+ new->entry = entry;
+ new->value = clone_str($3, "kw_list value");
+ new->next = NULL;
+ if (_parser_kw_last)
+ _parser_kw_last->next = new;
+ _parser_kw_last = new;
+ if (!*_parser_kw)
+ *_parser_kw = new;
+ }
+ free($1);
+ free($3);
+ }
+ | STRING EQUAL
+ {
+ free($1);
+ }
+ |
+ ;
+
+%%
+
+void
+yyerror(const char *s)
+{
+ if (_save_errors_)
+ _parser_y_error(parser_errstring, ERRSTRING_LEN, s);
+}
+
+config_parsed_t *
+parser_load_conf(const char *file)
+{
+ config_parsed_t *cfg = NULL;
+ int err = 0;
+ FILE *f;
+
+ extern void _parser_y_init (const char *f);
+ extern FILE *yyin;
+
+ memset(parser_errstring, 0, ERRSTRING_LEN+1);
+
+ cfg = (config_parsed_t *)alloc_thing(config_parsed_t, "config_parsed_t");
+ if (cfg)
+ {
+ memset(cfg, 0, sizeof(config_parsed_t));
+ f = fopen(file, "r");
+ if (f)
+ {
+ yyin = f;
+ _parser_y_init(file);
+ _save_errors_ = 1;
+ _parser_cfg = cfg;
+
+ if (yyparse() !=0 )
+ {
+ if (parser_errstring[0] == '\0')
+ {
+ snprintf(parser_errstring, ERRSTRING_LEN, "Unknown error...");
+ }
+ _save_errors_ = 0;
+ while (yyparse() != 0);
+ err++;
+ }
+ else if (parser_errstring[0] != '\0')
+ {
+ err++;
+ }
+ else
+ {
+ /**
+ * Config valid
+ */
+ }
+
+ fclose(f);
+ }
+ else
+ {
+ snprintf(parser_errstring, ERRSTRING_LEN, "can't load file '%s'", file);
+ err++;
+ }
+ }
+ else
+ {
+ snprintf(parser_errstring, ERRSTRING_LEN, "can't allocate memory");
+ err++;
+ }
+
+ if (err)
+ {
+ plog("%s", parser_errstring);
+
+ if (cfg)
+ parser_free_conf(cfg);
+ cfg = NULL;
+ }
+
+ return cfg;
+}
+
+static void
+parser_free_kwlist(kw_list_t *list)
+{
+ kw_list_t *elt;
+
+ while (list)
+ {
+ elt = list;
+ list = list->next;
+ if (elt->value)
+ pfree(elt->value);
+ pfree(elt);
+ }
+}
+
+void
+parser_free_conf(config_parsed_t *cfg)
+{
+ section_list_t *sec;
+ if (cfg)
+ {
+ parser_free_kwlist(cfg->config_setup);
+ while (cfg->conn_first)
+ {
+ sec = cfg->conn_first;
+ cfg->conn_first = cfg->conn_first->next;
+ if (sec->name)
+ pfree(sec->name);
+ parser_free_kwlist(sec->kw);
+ pfree(sec);
+ }
+ while (cfg->ca_first)
+ {
+ sec = cfg->ca_first;
+ cfg->ca_first = cfg->ca_first->next;
+ if (sec->name)
+ pfree(sec->name);
+ parser_free_kwlist(sec->kw);
+ pfree(sec);
+ }
+ pfree(cfg);
+ }
+}
diff --git a/src/starter/starter.c b/src/starter/starter.c
new file mode 100644
index 000000000..0bf1d7a71
--- /dev/null
+++ b/src/starter/starter.c
@@ -0,0 +1,643 @@
+/* strongSwan IPsec starter
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: starter.c,v 1.23 2006/02/15 18:37:46 as Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <time.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <freeswan.h>
+
+#include "../pluto/constants.h"
+#include "../pluto/defs.h"
+#include "../pluto/log.h"
+
+#include "confread.h"
+#include "files.h"
+#include "starterwhack.h"
+#include "starterstroke.h"
+#include "invokepluto.h"
+#include "invokecharon.h"
+#include "netkey.h"
+#include "cmp.h"
+#include "interfaces.h"
+
+#define FLAG_ACTION_START_PLUTO 0x01
+#define FLAG_ACTION_UPDATE 0x02
+#define FLAG_ACTION_RELOAD 0x04
+#define FLAG_ACTION_QUIT 0x08
+#define FLAG_ACTION_LISTEN 0x10
+#define FLAG_ACTION_START_CHARON 0x20
+
+static unsigned int _action_ = 0;
+
+static void
+fsig(int signal)
+{
+ switch (signal)
+ {
+ case SIGCHLD:
+ {
+ int status;
+ pid_t pid;
+ char *name = NULL;
+
+ while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
+ {
+ if (pid == starter_pluto_pid())
+ name = " (Pluto)";
+ if (pid == starter_charon_pid())
+ name = " (Charon)";
+ if (WIFSIGNALED(status))
+ DBG(DBG_CONTROL,
+ DBG_log("child %d%s has been killed by sig %d\n",
+ pid, name?name:"", WTERMSIG(status))
+ )
+ else if (WIFSTOPPED(status))
+ DBG(DBG_CONTROL,
+ DBG_log("child %d%s has been stopped by sig %d\n",
+ pid, name?name:"", WSTOPSIG(status))
+ )
+ else if (WIFEXITED(status))
+ DBG(DBG_CONTROL,
+ DBG_log("child %d%s has quit (exit code %d)\n",
+ pid, name?name:"", WEXITSTATUS(status))
+ )
+ else
+ DBG(DBG_CONTROL,
+ DBG_log("child %d%s has quit", pid, name?name:"")
+ )
+ if (pid == starter_pluto_pid())
+ starter_pluto_sigchild(pid);
+ if (pid == starter_charon_pid())
+ starter_charon_sigchild(pid);
+ }
+ }
+ break;
+
+ case SIGPIPE:
+ /** ignore **/
+ break;
+
+ case SIGALRM:
+ _action_ |= FLAG_ACTION_START_PLUTO;
+ _action_ |= FLAG_ACTION_START_CHARON;
+ break;
+
+ case SIGHUP:
+ _action_ |= FLAG_ACTION_UPDATE;
+ break;
+
+ case SIGTERM:
+ case SIGQUIT:
+ case SIGINT:
+ _action_ |= FLAG_ACTION_QUIT;
+ break;
+
+ case SIGUSR1:
+ _action_ |= FLAG_ACTION_RELOAD;
+ _action_ |= FLAG_ACTION_UPDATE;
+ break;
+
+ default:
+ plog("fsig(): unknown signal %d -- investigate", signal);
+ break;
+ }
+}
+
+static void
+usage(char *name)
+{
+ fprintf(stderr, "Usage: starter [--nofork] [--auto-update <sec>] "
+ "[--debug|--debug-more|--debug-all]\n");
+ exit(1);
+}
+
+int main (int argc, char **argv)
+{
+ starter_config_t *cfg = NULL;
+ starter_config_t *new_cfg;
+ starter_conn_t *conn, *conn2;
+ starter_ca_t *ca, *ca2;
+
+ struct stat stb;
+
+ char *err = NULL;
+ int i;
+ int id = 1;
+ struct timeval tv;
+ unsigned long auto_update = 0;
+ time_t last_reload;
+ bool no_fork = FALSE;
+
+ /* global variables defined in log.h */
+ log_to_stderr = TRUE;
+ base_debugging = DBG_NONE;
+
+ /* parse command line */
+ for (i = 1; i < argc; i++)
+ {
+ if (streq(argv[i], "--debug"))
+ {
+ base_debugging |= DBG_CONTROL;
+ }
+ else if (streq(argv[i], "--debug-more"))
+ {
+ base_debugging |= DBG_CONTROLMORE;
+ }
+ else if (streq(argv[i], "--debug-all"))
+ {
+ base_debugging |= DBG_ALL;
+ }
+ else if (streq(argv[i], "--nofork"))
+ {
+ no_fork = TRUE;
+ }
+ else if (streq(argv[i], "--auto-update") && i+1 < argc)
+ {
+ auto_update = atoi(argv[++i]);
+ if (!auto_update)
+ usage(argv[0]);
+ }
+ else
+ {
+ usage(argv[0]);
+ }
+ }
+
+ /* Init */
+ init_log("ipsec_starter");
+ cur_debugging = base_debugging;
+
+ signal(SIGHUP, fsig);
+ signal(SIGCHLD, fsig);
+ signal(SIGPIPE, fsig);
+ signal(SIGINT, fsig);
+ signal(SIGTERM, fsig);
+ signal(SIGQUIT, fsig);
+ signal(SIGALRM, fsig);
+ signal(SIGUSR1, fsig);
+
+ plog("Starting strongSwan %s IPsec [starter]...", ipsec_version_code());
+
+ /* verify that we can start */
+ if (getuid() != 0)
+ {
+ plog("permission denied (must be superuser)");
+ exit(1);
+ }
+
+ if (stat(PLUTO_PID_FILE, &stb) == 0)
+ {
+ plog("pluto is already running (%s exists) -- skipping pluto start", PLUTO_PID_FILE);
+ }
+ else
+ {
+ _action_ |= FLAG_ACTION_START_PLUTO;
+ }
+ 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;
+ }
+ if (stat(DEV_RANDOM, &stb) != 0)
+ {
+ plog("unable to start strongSwan IPsec -- no %s!", DEV_RANDOM);
+ exit(1);
+ }
+
+ if (stat(DEV_URANDOM, &stb)!= 0)
+ {
+ plog("unable to start strongSwan IPsec -- no %s!", DEV_URANDOM);
+ exit(1);
+ }
+
+ cfg = confread_load(CONFIG_FILE);
+ if (!cfg)
+ {
+ plog("unable to start strongSwan -- errors in config");
+ exit(1);
+ }
+
+ /* determine if we have a native netkey IPsec stack */
+ if (!starter_netkey_init())
+ {
+ plog("no netkey IPSec stack detected");
+ exit(1);
+ }
+
+ last_reload = time(NULL);
+
+ if (stat(STARTER_PID_FILE, &stb) == 0)
+ {
+ plog("starter is already running (%s exists) -- no fork done", STARTER_PID_FILE);
+ exit(0);
+ }
+
+ /* fork if we're not debugging stuff */
+ if (!no_fork)
+ {
+ log_to_stderr = FALSE;
+
+ switch (fork())
+ {
+ case 0:
+ {
+ int fnull = open("/dev/null", O_RDWR);
+
+ if (fnull >= 0)
+ {
+ dup2(fnull, STDIN_FILENO);
+ dup2(fnull, STDOUT_FILENO);
+ dup2(fnull, STDERR_FILENO);
+ close(fnull);
+ }
+ }
+ break;
+ case -1:
+ plog("can't fork: %s", strerror(errno));
+ break;
+ default:
+ exit(0);
+ }
+ }
+
+ /* save pid file in /var/run/starter.pid */
+ {
+ FILE *fd = fopen(STARTER_PID_FILE, "w");
+
+ if (fd)
+ {
+ fprintf(fd, "%u\n", getpid());
+ fclose(fd);
+ }
+ }
+
+ for (;;)
+ {
+ /*
+ * Stop pluto/charon (if started) and exit
+ */
+ if (_action_ & FLAG_ACTION_QUIT)
+ {
+ if (starter_pluto_pid())
+ starter_stop_pluto();
+ if (starter_charon_pid())
+ starter_stop_charon();
+ starter_netkey_cleanup();
+ confread_free(cfg);
+ unlink(STARTER_PID_FILE);
+ unlink(INFO_FILE);
+#ifdef LEAK_DETECTIVE
+ report_leaks();
+#endif /* LEAK_DETECTIVE */
+ close_log();
+ plog("ipsec starter stopped");
+ exit(0);
+ }
+
+ /*
+ * Delete all connections. Will be added below
+ */
+ if (_action_ & FLAG_ACTION_RELOAD)
+ {
+ if (starter_pluto_pid() || starter_charon_pid())
+ {
+ for (conn = cfg->conn_first; conn; conn = conn->next)
+ {
+ if (conn->state == STATE_ADDED)
+ {
+ if (starter_charon_pid())
+ {
+ starter_stroke_del_conn(conn);
+ }
+ if (starter_pluto_pid())
+ {
+ starter_whack_del_conn(conn);
+ }
+ conn->state = STATE_TO_ADD;
+ }
+ }
+ for (ca = cfg->ca_first; ca; ca = ca->next)
+ {
+ if (ca->state == STATE_ADDED)
+ {
+ if (starter_charon_pid())
+ {
+ starter_stroke_del_ca(ca);
+ }
+ if (starter_pluto_pid())
+ {
+ starter_whack_del_ca(ca);
+ }
+ ca->state = STATE_TO_ADD;
+ }
+ }
+ }
+ _action_ &= ~FLAG_ACTION_RELOAD;
+ }
+
+ /*
+ * Update configuration
+ */
+ if (_action_ & FLAG_ACTION_UPDATE)
+ {
+ err = NULL;
+ DBG(DBG_CONTROL,
+ DBG_log("Reloading config...")
+ );
+ new_cfg = confread_load(CONFIG_FILE);
+
+ if (new_cfg)
+ {
+ /* Switch to new config. New conn will be loaded below */
+ if (!starter_cmp_defaultroute(&new_cfg->defaultroute
+ , &cfg->defaultroute))
+ {
+ _action_ |= FLAG_ACTION_LISTEN;
+ }
+
+ if (!starter_cmp_pluto(cfg, new_cfg))
+ {
+ plog("Pluto has changed");
+ if (starter_pluto_pid())
+ starter_stop_pluto();
+ _action_ &= ~FLAG_ACTION_LISTEN;
+ _action_ |= FLAG_ACTION_START_PLUTO;
+ }
+ else
+ {
+ /* Only reload conn and ca sections if pluto is not killed */
+
+ /* Look for new connections that are already loaded */
+ for (conn = cfg->conn_first; conn; conn = conn->next)
+ {
+ if (conn->state == STATE_ADDED)
+ {
+ for (conn2 = new_cfg->conn_first; conn2; conn2 = conn2->next)
+ {
+ if (conn2->state == STATE_TO_ADD && starter_cmp_conn(conn, conn2))
+ {
+ conn->state = STATE_REPLACED;
+ conn2->state = STATE_ADDED;
+ conn2->id = conn->id;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Remove conn sections that have become unused */
+ for (conn = cfg->conn_first; conn; conn = conn->next)
+ {
+ if (conn->state == STATE_ADDED)
+ {
+ if (starter_charon_pid())
+ {
+ starter_stroke_del_conn(conn);
+ }
+ if (starter_pluto_pid())
+ {
+ starter_whack_del_conn(conn);
+ }
+ }
+ }
+
+ /* Look for new ca sections that are already loaded */
+ for (ca = cfg->ca_first; ca; ca = ca->next)
+ {
+ if (ca->state == STATE_ADDED)
+ {
+ for (ca2 = new_cfg->ca_first; ca2; ca2 = ca2->next)
+ {
+ if (ca2->state == STATE_TO_ADD && starter_cmp_ca(ca, ca2))
+ {
+ ca->state = STATE_REPLACED;
+ ca2->state = STATE_ADDED;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Remove ca sections that have become unused */
+ for (ca = cfg->ca_first; ca; ca = ca->next)
+ {
+ if (ca->state == STATE_ADDED)
+ {
+ if (starter_charon_pid())
+ {
+ starter_stroke_del_ca(ca);
+ }
+ if (starter_pluto_pid())
+ {
+ starter_whack_del_ca(ca);
+ }
+ }
+ }
+ }
+ confread_free(cfg);
+ cfg = new_cfg;
+ }
+ else
+ {
+ plog("can't reload config file: %s -- keeping old one");
+ }
+ _action_ &= ~FLAG_ACTION_UPDATE;
+ last_reload = time(NULL);
+ }
+
+ /*
+ * Start pluto
+ */
+ if (_action_ & FLAG_ACTION_START_PLUTO)
+ {
+ if (cfg->setup.plutostart && !starter_pluto_pid())
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("Attempting to start pluto...")
+ );
+
+ if (starter_start_pluto(cfg, no_fork) == 0)
+ {
+ starter_whack_listen();
+ }
+ else
+ {
+ /* schedule next try */
+ alarm(PLUTO_RESTART_DELAY);
+ }
+ }
+ _action_ &= ~FLAG_ACTION_START_PLUTO;
+
+ for (ca = cfg->ca_first; ca; ca = ca->next)
+ {
+ if (ca->state == STATE_ADDED)
+ ca->state = STATE_TO_ADD;
+ }
+
+ for (conn = cfg->conn_first; conn; conn = conn->next)
+ {
+ if (conn->state == STATE_ADDED)
+ conn->state = STATE_TO_ADD;
+ }
+ }
+
+ /*
+ * Start charon
+ */
+ if (_action_ & FLAG_ACTION_START_CHARON)
+ {
+ if (cfg->setup.charonstart && !starter_charon_pid())
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("Attempting to start charon...")
+ );
+ if (starter_start_charon(cfg, no_fork))
+ {
+ /* schedule next try */
+ alarm(PLUTO_RESTART_DELAY);
+ }
+ }
+ _action_ &= ~FLAG_ACTION_START_CHARON;
+ }
+
+ /*
+ * Tell pluto to reread its interfaces
+ */
+ if (_action_ & FLAG_ACTION_LISTEN)
+ {
+ if (starter_pluto_pid())
+ {
+ starter_whack_listen();
+ _action_ &= ~FLAG_ACTION_LISTEN;
+ }
+ }
+
+ /*
+ * Add stale conn and ca sections
+ */
+ if (starter_pluto_pid() || starter_charon_pid())
+ {
+ for (ca = cfg->ca_first; ca; ca = ca->next)
+ {
+ if (ca->state == STATE_TO_ADD)
+ {
+ if (starter_charon_pid())
+ {
+ starter_stroke_add_ca(ca);
+ }
+ if (starter_pluto_pid())
+ {
+ starter_whack_add_ca(ca);
+ }
+ ca->state = STATE_ADDED;
+ }
+ }
+
+ for (conn = cfg->conn_first; conn; conn = conn->next)
+ {
+ if (conn->state == STATE_TO_ADD)
+ {
+ if (conn->id == 0)
+ {
+ /* affect new unique id */
+ conn->id = id++;
+ }
+ if (starter_charon_pid())
+ {
+ starter_stroke_add_conn(conn);
+ }
+ if (starter_pluto_pid())
+ {
+ starter_whack_add_conn(conn);
+ }
+ conn->state = STATE_ADDED;
+
+ if (conn->startup == STARTUP_START)
+ {
+ if (conn->keyexchange == KEY_EXCHANGE_IKEV2)
+ {
+ if (starter_charon_pid())
+ {
+ starter_stroke_initiate_conn(conn);
+ }
+ }
+ else
+ {
+ if (starter_pluto_pid())
+ {
+ starter_whack_initiate_conn(conn);
+ }
+ }
+ }
+ else if (conn->startup == STARTUP_ROUTE)
+ {
+ if (conn->keyexchange == KEY_EXCHANGE_IKEV2)
+ {
+ if (starter_charon_pid())
+ {
+ starter_stroke_route_conn(conn);
+ }
+ }
+ else
+ {
+ if (starter_pluto_pid())
+ {
+ starter_whack_route_conn(conn);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * If auto_update activated, when to stop select
+ */
+ if (auto_update)
+ {
+ time_t now = time(NULL);
+
+ tv.tv_sec = (now < last_reload + auto_update)
+ ? (last_reload + auto_update-now) : 0;
+ tv.tv_usec = 0;
+ }
+
+ /*
+ * Wait for something to happen
+ */
+ if (select(0, NULL, NULL, NULL, auto_update ? &tv : NULL) == 0)
+ {
+ /* timeout -> auto_update */
+ _action_ |= FLAG_ACTION_UPDATE;
+ }
+ }
+
+ return 0;
+}
+
diff --git a/src/starter/starterstroke.c b/src/starter/starterstroke.c
new file mode 100644
index 000000000..fb8e74b8c
--- /dev/null
+++ b/src/starter/starterstroke.c
@@ -0,0 +1,295 @@
+/* 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 <stddef.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <freeswan.h>
+
+#include <constants.h>
+#include <defs.h>
+#include <log.h>
+
+#include <stroke.h>
+
+#include "starterstroke.h"
+#include "confread.h"
+#include "files.h"
+
+/**
+ * Authentication mehtods, must be the same values as in charon
+ */
+enum auth_method_t {
+ AUTH_RSA = 1,
+ AUTH_PSK = 2,
+ AUTH_DSS = 3,
+ AUTH_EAP = 201,
+};
+
+static char* push_string(stroke_msg_t *msg, char *string)
+{
+ unsigned long string_start = msg->length;
+
+ if (string == NULL || msg->length + strlen(string) >= sizeof(stroke_msg_t))
+ {
+ return NULL;
+ }
+ else
+ {
+ msg->length += strlen(string) + 1;
+ strcpy((char*)msg + string_start, string);
+ return (char*)string_start;
+ }
+}
+
+static int send_stroke_msg (stroke_msg_t *msg)
+{
+ struct sockaddr_un ctl_addr = { AF_UNIX, CHARON_CTL_FILE };
+ int byte_count;
+ char buffer[64];
+
+ /* starter is not called from commandline, and therefore absolutely silent */
+ msg->output_verbosity = -1;
+
+ int 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;
+ }
+ while ((byte_count = read(sock, buffer, sizeof(buffer)-1)) > 0)
+ {
+ buffer[byte_count] = '\0';
+ plog("%s", buffer);
+ }
+ if (byte_count < 0)
+ {
+ plog("read() failed: %s", strerror(errno));
+ }
+
+ 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;
+}
+
+static void ip_address2string(ip_address *addr, char *buffer, size_t len)
+{
+ switch (((struct sockaddr*)addr)->sa_family)
+ {
+ case AF_INET:
+ {
+ struct sockaddr_in* sin = (struct sockaddr_in*)addr;
+ if (inet_ntop(AF_INET, &sin->sin_addr, buffer, len))
+ {
+ return;
+ }
+ break;
+ }
+ case AF_INET6:
+ {
+ struct sockaddr_in6* sin6 = (struct sockaddr_in6*)addr;
+ if (inet_ntop(AF_INET6, &sin6->sin6_addr, buffer, len))
+ {
+ return;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ /* failed */
+ snprintf(buffer, len, "0.0.0.0");
+}
+
+
+static void starter_stroke_add_end(stroke_msg_t *msg, stroke_end_t *msg_end, starter_end_t *conn_end)
+{
+ char buffer[INET6_ADDRSTRLEN];
+
+ msg_end->id = push_string(msg, conn_end->id);
+ msg_end->cert = push_string(msg, conn_end->cert);
+ msg_end->ca = push_string(msg, conn_end->ca);
+ msg_end->updown = push_string(msg, conn_end->updown);
+ ip_address2string(&conn_end->addr, buffer, sizeof(buffer));
+ msg_end->address = push_string(msg, buffer);
+ ip_address2string(&conn_end->subnet.addr, buffer, sizeof(buffer));
+ msg_end->subnet = push_string(msg, buffer);
+ msg_end->subnet_mask = conn_end->subnet.maskbits;
+ msg_end->sendcert = conn_end->sendcert;
+ msg_end->hostaccess = conn_end->hostaccess;
+ msg_end->tohost = !conn_end->has_client;
+ msg_end->protocol = conn_end->protocol;
+ msg_end->port = conn_end->port;
+ msg_end->virtual_ip = conn_end->modecfg;
+ ip_address2string(&conn_end->srcip, buffer, sizeof(buffer));
+ msg_end->sourceip = push_string(msg, buffer);
+}
+
+int starter_stroke_add_conn(starter_conn_t *conn)
+{
+ stroke_msg_t msg;
+
+ msg.type = STR_ADD_CONN;
+ msg.length = offsetof(stroke_msg_t, buffer);
+ msg.add_conn.ikev2 = conn->keyexchange == KEY_EXCHANGE_IKEV2;
+ msg.add_conn.name = push_string(&msg, connection_name(conn));
+
+ /* RSA is preferred before PSK and EAP */
+ if (conn->policy & POLICY_RSASIG)
+ {
+ msg.add_conn.auth_method = AUTH_RSA;
+ }
+ else if (conn->policy & POLICY_PSK)
+ {
+ msg.add_conn.auth_method = AUTH_PSK;
+ }
+ else
+ {
+ msg.add_conn.auth_method = AUTH_EAP;
+ }
+ msg.add_conn.eap_type = conn->eap;
+
+ if (conn->policy & POLICY_TUNNEL)
+ {
+ msg.add_conn.mode = 1; /* XFRM_MODE_TRANSPORT */
+ }
+ else if (conn->policy & POLICY_BEET)
+ {
+ msg.add_conn.mode = 4; /* XFRM_MODE_BEET */
+ }
+ else
+ {
+ msg.add_conn.mode = 0; /* XFRM_MODE_TUNNEL */
+ }
+
+ if (conn->policy & POLICY_DONT_REKEY)
+ {
+ msg.add_conn.rekey.ipsec_lifetime = 0;
+ msg.add_conn.rekey.ike_lifetime = 0;
+ msg.add_conn.rekey.margin = 0;
+ msg.add_conn.rekey.tries = 0;
+ msg.add_conn.rekey.fuzz = 0;
+ }
+ else
+ {
+ msg.add_conn.rekey.reauth = (conn->policy & POLICY_DONT_REAUTH) == LEMPTY;
+ msg.add_conn.rekey.ipsec_lifetime = conn->sa_ipsec_life_seconds;
+ msg.add_conn.rekey.ike_lifetime = conn->sa_ike_life_seconds;
+ msg.add_conn.rekey.margin = conn->sa_rekey_margin;
+ msg.add_conn.rekey.tries = conn->sa_keying_tries;
+ msg.add_conn.rekey.fuzz = conn->sa_rekey_fuzz;
+ }
+ msg.add_conn.algorithms.ike = push_string(&msg, conn->ike);
+ msg.add_conn.algorithms.esp = push_string(&msg, conn->esp);
+ msg.add_conn.dpd.delay = conn->dpd_delay;
+ msg.add_conn.dpd.action = conn->dpd_action;
+
+ starter_stroke_add_end(&msg, &msg.add_conn.me, &conn->left);
+ starter_stroke_add_end(&msg, &msg.add_conn.other, &conn->right);
+
+ return send_stroke_msg(&msg);
+}
+
+int starter_stroke_del_conn(starter_conn_t *conn)
+{
+ stroke_msg_t msg;
+
+ msg.type = STR_DEL_CONN;
+ msg.length = offsetof(stroke_msg_t, buffer);
+ msg.del_conn.name = push_string(&msg, connection_name(conn));
+ return send_stroke_msg(&msg);
+}
+
+int starter_stroke_route_conn(starter_conn_t *conn)
+{
+ stroke_msg_t msg;
+
+ msg.type = STR_ROUTE;
+ msg.length = offsetof(stroke_msg_t, buffer);
+ msg.route.name = push_string(&msg, connection_name(conn));
+ return send_stroke_msg(&msg);
+}
+
+int starter_stroke_initiate_conn(starter_conn_t *conn)
+{
+ stroke_msg_t msg;
+
+ msg.type = STR_INITIATE;
+ msg.length = offsetof(stroke_msg_t, buffer);
+ msg.initiate.name = push_string(&msg, connection_name(conn));
+ return send_stroke_msg(&msg);
+}
+
+int starter_stroke_add_ca(starter_ca_t *ca)
+{
+ stroke_msg_t msg;
+
+ msg.type = STR_ADD_CA;
+ msg.length = offsetof(stroke_msg_t, buffer);
+ msg.add_ca.name = push_string(&msg, ca->name);
+ msg.add_ca.cacert = push_string(&msg, ca->cacert);
+ msg.add_ca.crluri = push_string(&msg, ca->crluri);
+ msg.add_ca.crluri2 = push_string(&msg, ca->crluri2);
+ msg.add_ca.ocspuri = push_string(&msg, ca->ocspuri);
+ msg.add_ca.ocspuri2 = push_string(&msg, ca->ocspuri2);
+ return send_stroke_msg(&msg);
+}
+
+int starter_stroke_del_ca(starter_ca_t *ca)
+{
+ stroke_msg_t msg;
+
+ msg.type = STR_DEL_CA;
+ msg.length = offsetof(stroke_msg_t, buffer);
+ msg.del_ca.name = push_string(&msg, ca->name);
+ return send_stroke_msg(&msg);
+}
+
+
diff --git a/src/starter/starterstroke.h b/src/starter/starterstroke.h
new file mode 100644
index 000000000..95c37094e
--- /dev/null
+++ b/src/starter/starterstroke.h
@@ -0,0 +1,29 @@
+/* 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);
+extern int starter_stroke_add_ca(starter_ca_t *ca);
+extern int starter_stroke_del_ca(starter_ca_t *ca);
+
+#endif /* _STARTER_STROKE_H_ */
diff --git a/src/starter/starterwhack.c b/src/starter/starterwhack.c
new file mode 100644
index 000000000..42328849a
--- /dev/null
+++ b/src/starter/starterwhack.c
@@ -0,0 +1,369 @@
+/* strongSwan whack functions to communicate with pluto (whack.c)
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: starterwhack.c,v 1.17 2006/04/17 10:32:36 as Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <freeswan.h>
+
+#include <constants.h>
+#include <defs.h>
+#include <log.h>
+#include <whack.h>
+
+#include "starterwhack.h"
+#include "confread.h"
+#include "files.h"
+
+static int
+pack_str (char **p, char **next, char **roof)
+{
+ const char *s = (*p==NULL) ? "" : *p; /* note: NULL becomes ""! */
+ size_t len = strlen(s) + 1;
+
+ if ((*roof - *next) < len)
+ {
+ return 0; /* not enough space */
+ }
+ else
+ {
+ strcpy(*next, s);
+ *next += len;
+ *p = NULL; /* don't send pointers on the wire! */
+ return 1;
+ }
+}
+
+static int
+send_whack_msg (whack_message_t *msg)
+{
+ struct sockaddr_un ctl_addr = { AF_UNIX, PLUTO_CTL_FILE };
+ int sock;
+ ssize_t len;
+ char *str_next, *str_roof;
+
+ /* pack strings */
+ str_next = (char *)msg->string;
+ str_roof = (char *)&msg->string[sizeof(msg->string)];
+
+ if (!pack_str(&msg->name, &str_next, &str_roof)
+ || !pack_str(&msg->left.id, &str_next, &str_roof)
+ || !pack_str(&msg->left.cert, &str_next, &str_roof)
+ || !pack_str(&msg->left.ca, &str_next, &str_roof)
+ || !pack_str(&msg->left.groups, &str_next, &str_roof)
+ || !pack_str(&msg->left.updown, &str_next, &str_roof)
+ || !pack_str(&msg->left.virt, &str_next, &str_roof)
+ || !pack_str(&msg->right.id, &str_next, &str_roof)
+ || !pack_str(&msg->right.cert, &str_next, &str_roof)
+ || !pack_str(&msg->right.ca, &str_next, &str_roof)
+ || !pack_str(&msg->right.groups, &str_next, &str_roof)
+ || !pack_str(&msg->right.updown, &str_next, &str_roof)
+ || !pack_str(&msg->right.virt, &str_next, &str_roof)
+ || !pack_str(&msg->keyid, &str_next, &str_roof)
+ || !pack_str(&msg->myid, &str_next, &str_roof)
+ || !pack_str(&msg->cacert, &str_next, &str_roof)
+ || !pack_str(&msg->ldaphost, &str_next, &str_roof)
+ || !pack_str(&msg->ldapbase, &str_next, &str_roof)
+ || !pack_str(&msg->crluri, &str_next, &str_roof)
+ || !pack_str(&msg->crluri2, &str_next, &str_roof)
+ || !pack_str(&msg->ocspuri, &str_next, &str_roof)
+ || !pack_str(&msg->ike, &str_next, &str_roof)
+ || !pack_str(&msg->esp, &str_next, &str_roof)
+ || !pack_str(&msg->sc_data, &str_next, &str_roof)
+ || (str_roof - str_next < msg->keyval.len))
+ {
+ plog("send_wack_msg(): can't pack strings");
+ return -1;
+ }
+ if (msg->keyval.ptr)
+ memcpy(str_next, msg->keyval.ptr, msg->keyval.len);
+ msg->keyval.ptr = NULL;
+ str_next += msg->keyval.len;
+ len = str_next - (char *)msg;
+
+ /* connect to pluto ctl */
+ 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(pluto_ctl) failed: %s", strerror(errno));
+ close(sock);
+ return -1;
+ }
+
+ /* send message */
+ if (write(sock, msg, len) != len)
+ {
+ plog("write(pluto_ctl) failed: %s", strerror(errno));
+ close(sock);
+ return -1;
+ }
+
+ /* TODO: read reply */
+ close(sock);
+ return 0;
+}
+
+static void
+init_whack_msg(whack_message_t *msg)
+{
+ memset(msg, 0, sizeof(whack_message_t));
+ msg->magic = WHACK_MAGIC;
+}
+
+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;
+}
+
+static void
+set_whack_end(whack_end_t *w, starter_end_t *end)
+{
+ w->id = end->id;
+ w->cert = end->cert;
+ w->ca = end->ca;
+ w->groups = end->groups;
+ w->host_addr = end->addr;
+ w->host_nexthop = end->nexthop;
+ w->host_srcip = end->srcip;
+ w->has_client = end->has_client;
+
+ if (w->has_client)
+ w->client = end->subnet;
+ else
+ w->client.addr.u.v4.sin_family = addrtypeof(&w->host_addr);
+
+ w->has_client_wildcard = end->has_client_wildcard;
+ w->has_port_wildcard = end->has_port_wildcard;
+ w->has_srcip = end->has_srcip;
+ w->has_natip = end->has_natip;
+ w->modecfg = end->modecfg;
+ w->hostaccess = end->hostaccess;
+ w->sendcert = end->sendcert;
+ w->updown = end->updown;
+ w->host_port = IKE_UDP_PORT;
+ w->port = end->port;
+ w->protocol = end->protocol;
+ w->virt = end->virt;
+
+ if (w->port != 0)
+ {
+ int port = htons(w->port);
+
+ setportof(port, &w->host_addr);
+ setportof(port, &w->client.addr);
+ }
+}
+
+static int
+starter_whack_add_pubkey (starter_conn_t *conn, starter_end_t *end
+, const char *lr)
+{
+ const char *err;
+ static char keyspace[1024 + 4];
+ whack_message_t msg;
+
+ init_whack_msg(&msg);
+
+ msg.whack_key = TRUE;
+ msg.pubkey_alg = PUBKEY_ALG_RSA;
+ if (end->id && end->rsakey)
+ {
+ /* special values to ignore */
+ if (streq(end->rsakey, "")
+ || streq(end->rsakey, "%none")
+ || streq(end->rsakey, "%cert")
+ || streq(end->rsakey, "0x00"))
+ {
+ return 0;
+ }
+ msg.keyid = end->id;
+ err = atobytes(end->rsakey, 0, keyspace, sizeof(keyspace), &msg.keyval.len);
+ if (err)
+ {
+ plog("conn %s/%s: rsakey malformed [%s]", connection_name(conn), lr, err);
+ return 1;
+ }
+ else
+ {
+ msg.keyval.ptr = keyspace;
+ return send_whack_msg(&msg);
+ }
+ }
+ return 0;
+}
+
+int
+starter_whack_add_conn(starter_conn_t *conn)
+{
+ whack_message_t msg;
+ int r;
+
+ init_whack_msg(&msg);
+
+ msg.whack_connection = TRUE;
+ msg.name = connection_name(conn);
+
+ msg.ikev1 = conn->keyexchange != KEY_EXCHANGE_IKEV2;
+ msg.addr_family = conn->addr_family;
+ msg.tunnel_addr_family = conn->tunnel_addr_family;
+ msg.sa_ike_life_seconds = conn->sa_ike_life_seconds;
+ msg.sa_ipsec_life_seconds = conn->sa_ipsec_life_seconds;
+ msg.sa_rekey_margin = conn->sa_rekey_margin;
+ msg.sa_rekey_fuzz = conn->sa_rekey_fuzz;
+ msg.sa_keying_tries = conn->sa_keying_tries;
+ msg.policy = conn->policy;
+
+ set_whack_end(&msg.left, &conn->left);
+ set_whack_end(&msg.right, &conn->right);
+
+ msg.esp = conn->esp;
+ msg.ike = conn->ike;
+ msg.pfsgroup = conn->pfsgroup;
+
+ /* taken from pluto/whack.c */
+ if (msg.pfsgroup)
+ {
+ char esp_buf[256];
+
+ snprintf(esp_buf, sizeof (esp_buf), "%s;%s"
+ , msg.esp ? msg.esp : ""
+ , msg.pfsgroup ? msg.pfsgroup : "");
+ msg.esp = esp_buf;
+
+ DBG(DBG_CONTROL,
+ DBG_log("Setting --esp=%s", msg.esp)
+ )
+ }
+ msg.dpd_delay = conn->dpd_delay;
+ msg.dpd_timeout = conn->dpd_timeout;
+ msg.dpd_action = conn->dpd_action;
+/* msg.dpd_count = conn->dpd_count; not supported yet by strongSwan */
+
+ r = send_whack_msg(&msg);
+
+ if (r == 0 && (conn->policy & POLICY_RSASIG))
+ {
+ r += starter_whack_add_pubkey (conn, &conn->left, "left");
+ r += starter_whack_add_pubkey (conn, &conn->right, "right");
+ }
+
+ return r;
+}
+
+int
+starter_whack_del_conn(starter_conn_t *conn)
+{
+ whack_message_t msg;
+
+ init_whack_msg(&msg);
+ msg.whack_delete = TRUE;
+ msg.name = connection_name(conn);
+ return send_whack_msg(&msg);
+}
+
+int
+starter_whack_route_conn(starter_conn_t *conn)
+{
+ whack_message_t msg;
+
+ init_whack_msg(&msg);
+ msg.whack_route = TRUE;
+ msg.name = connection_name(conn);
+ return send_whack_msg(&msg);
+}
+
+int
+starter_whack_initiate_conn(starter_conn_t *conn)
+{
+ whack_message_t msg;
+
+ init_whack_msg(&msg);
+ msg.whack_initiate = TRUE;
+ msg.whack_async = TRUE;
+ msg.name = connection_name(conn);
+ return send_whack_msg(&msg);
+}
+
+int
+starter_whack_listen(void)
+{
+ whack_message_t msg;
+ init_whack_msg(&msg);
+ msg.whack_listen = TRUE;
+ return send_whack_msg(&msg);
+}
+
+int starter_whack_shutdown(void)
+{
+ whack_message_t msg;
+
+ init_whack_msg(&msg);
+ msg.whack_shutdown = TRUE;
+ return send_whack_msg(&msg);
+}
+
+int
+starter_whack_add_ca(starter_ca_t *ca)
+{
+ whack_message_t msg;
+
+ init_whack_msg(&msg);
+
+ msg.whack_ca = TRUE;
+ msg.name = ca->name;
+ msg.cacert = ca->cacert;
+ msg.ldaphost = ca->ldaphost;
+ msg.ldapbase = ca->ldapbase;
+ msg.crluri = ca->crluri;
+ msg.crluri2 = ca->crluri2;
+ msg.ocspuri = ca->ocspuri;
+ msg.whack_strict = ca->strict;
+
+ return send_whack_msg(&msg);
+}
+
+int
+starter_whack_del_ca(starter_ca_t *ca)
+{
+ whack_message_t msg;
+
+ init_whack_msg(&msg);
+
+ msg.whack_delete = TRUE;
+ msg.whack_ca = TRUE;
+ msg.name = ca->name;
+
+ return send_whack_msg(&msg);
+}
diff --git a/src/starter/starterwhack.h b/src/starter/starterwhack.h
new file mode 100644
index 000000000..2e79c0715
--- /dev/null
+++ b/src/starter/starterwhack.h
@@ -0,0 +1,32 @@
+/* FreeS/WAN whack functions to communicate with pluto (whack.h)
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: starterwhack.h,v 1.6 2006/01/03 18:37:03 as Exp $
+ */
+
+#ifndef _STARTER_WHACK_H_
+#define _STARTER_WHACK_H_
+
+#include "confread.h"
+
+extern int starter_whack_add_conn(starter_conn_t *conn);
+extern int starter_whack_del_conn(starter_conn_t *conn);
+extern int starter_whack_route_conn(starter_conn_t *conn);
+extern int starter_whack_initiate_conn(starter_conn_t *conn);
+extern int starter_whack_listen(void);
+extern int starter_whack_shutdown(void);
+extern int starter_whack_add_ca(starter_ca_t *ca);
+extern int starter_whack_del_ca(starter_ca_t *ca);
+
+#endif /* _STARTER_WHACK_H_ */
+
diff --git a/src/starter/y.tab.c b/src/starter/y.tab.c
new file mode 100644
index 000000000..11a0373e9
--- /dev/null
+++ b/src/starter/y.tab.c
@@ -0,0 +1,1832 @@
+/* A Bison parser, made by GNU Bison 2.2. */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.2"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ EQUAL = 258,
+ FIRST_SPACES = 259,
+ EOL = 260,
+ CONFIG = 261,
+ SETUP = 262,
+ CONN = 263,
+ CA = 264,
+ INCLUDE = 265,
+ FILE_VERSION = 266,
+ STRING = 267
+ };
+#endif
+/* Tokens. */
+#define EQUAL 258
+#define FIRST_SPACES 259
+#define EOL 260
+#define CONFIG 261
+#define SETUP 262
+#define CONN 263
+#define CA 264
+#define INCLUDE 265
+#define FILE_VERSION 266
+#define STRING 267
+
+
+
+
+/* Copy the first part of user declarations. */
+#line 1 "parser.y"
+
+/* strongSwan config file parser (parser.y)
+ * Copyright (C) 2001 Mathieu Lafon - Arkoon Network Security
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: parser.y,v 1.6 2006/01/17 23:43:36 as Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <freeswan.h>
+
+#include "../pluto/constants.h"
+#include "../pluto/defs.h"
+#include "../pluto/log.h"
+#include "parser.h"
+
+#define YYERROR_VERBOSE
+#define ERRSTRING_LEN 256
+
+/**
+ * Bison
+ */
+static char parser_errstring[ERRSTRING_LEN+1];
+
+extern void yyerror(const char *s);
+extern int yylex (void);
+extern void _parser_y_error(char *b, int size, const char *s);
+
+/**
+ * Static Globals
+ */
+static int _save_errors_;
+static config_parsed_t *_parser_cfg;
+static kw_list_t **_parser_kw, *_parser_kw_last;
+static char errbuf[ERRSTRING_LEN+1];
+
+/**
+ * Gperf
+ */
+extern kw_entry_t *in_word_set (char *str, unsigned int len);
+
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 56 "parser.y"
+{ char *s; }
+/* Line 193 of yacc.c. */
+#line 177 "y.tab.c"
+ YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations. */
+
+
+/* Line 216 of yacc.c. */
+#line 190 "y.tab.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int i)
+#else
+static int
+YYID (i)
+ int i;
+#endif
+{
+ return i;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined _STDLIB_H \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss;
+ YYSTYPE yyvs;
+ };
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 2
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 27
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 13
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 9
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 18
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 34
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 267
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const yytype_uint8 yyprhs[] =
+{
+ 0, 0, 3, 6, 7, 11, 12, 18, 19, 25,
+ 26, 32, 33, 38, 40, 45, 46, 50, 53
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int8 yyrhs[] =
+{
+ 14, 0, -1, 14, 15, -1, -1, 11, 12, 5,
+ -1, -1, 6, 7, 5, 16, 20, -1, -1, 8,
+ 12, 5, 17, 20, -1, -1, 9, 12, 5, 18,
+ 20, -1, -1, 10, 12, 19, 5, -1, 5, -1,
+ 4, 21, 5, 20, -1, -1, 12, 3, 12, -1,
+ 12, 3, -1, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const yytype_uint8 yyrline[] =
+{
+ 0, 67, 67, 68, 72, 77, 76, 82, 81, 99,
+ 98, 115, 114, 120, 124, 125, 129, 154, 158
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "EQUAL", "FIRST_SPACES", "EOL", "CONFIG",
+ "SETUP", "CONN", "CA", "INCLUDE", "FILE_VERSION", "STRING", "$accept",
+ "config_file", "section_or_include", "@1", "@2", "@3", "@4",
+ "kw_section", "statement_kw", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 13, 14, 14, 15, 16, 15, 17, 15, 18,
+ 15, 19, 15, 15, 20, 20, 21, 21, 21
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 2, 0, 3, 0, 5, 0, 5, 0,
+ 5, 0, 4, 1, 4, 0, 3, 2, 0
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint8 yydefact[] =
+{
+ 3, 0, 1, 13, 0, 0, 0, 0, 0, 2,
+ 0, 0, 0, 11, 0, 5, 7, 9, 0, 4,
+ 15, 15, 15, 12, 18, 6, 8, 10, 0, 0,
+ 17, 15, 16, 14
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int8 yydefgoto[] =
+{
+ -1, 1, 9, 20, 21, 22, 18, 25, 29
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -20
+static const yytype_int8 yypact[] =
+{
+ -20, 0, -20, -20, -6, -8, -5, 1, 2, -20,
+ 10, 11, 12, -20, 13, -20, -20, -20, 14, -20,
+ 16, 16, 16, -20, 9, -20, -20, -20, 19, 18,
+ 15, 16, -20, -20
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int8 yypgoto[] =
+{
+ -20, -20, -20, -20, -20, -20, -20, -19, -20
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -1
+static const yytype_uint8 yytable[] =
+{
+ 2, 10, 26, 27, 11, 3, 4, 12, 5, 6,
+ 7, 8, 33, 13, 14, 15, 16, 17, 19, 23,
+ 24, 28, 30, 31, 0, 0, 0, 32
+};
+
+static const yytype_int8 yycheck[] =
+{
+ 0, 7, 21, 22, 12, 5, 6, 12, 8, 9,
+ 10, 11, 31, 12, 12, 5, 5, 5, 5, 5,
+ 4, 12, 3, 5, -1, -1, -1, 12
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
+{
+ 0, 14, 0, 5, 6, 8, 9, 10, 11, 15,
+ 7, 12, 12, 12, 12, 5, 5, 5, 19, 5,
+ 16, 17, 18, 5, 4, 20, 20, 20, 12, 21,
+ 3, 5, 12, 20
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+
+#define YYFAIL goto yyerrlab
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK (1); \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (YYID (0))
+
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
+#ifndef YY_LOCATION_PRINT
+# if YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, const YYSTYPE * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ const YYSTYPE * const yyvaluep;
+#endif
+{
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, const YYSTYPE * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ const YYSTYPE * const yyvaluep;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
+#else
+static void
+yy_stack_print (bottom, top)
+ yytype_int16 *bottom;
+ yytype_int16 *top;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp,
+ int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule
+ )
+ YYSTYPE *yyvsp;
+
+ int yyrule;
+#endif
+{
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ fprintf (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
+ fprintf (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+ YYCHAR while in state YYSTATE. Return the number of bytes copied,
+ including the terminating null byte. If YYRESULT is null, do not
+ copy anything; just return the number of bytes that would be
+ copied. As a special case, return 0 if an ordinary "syntax error"
+ message will do. Return YYSIZE_MAXIMUM if overflow occurs during
+ size calculation. */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+ int yyn = yypact[yystate];
+
+ if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+ return 0;
+ else
+ {
+ int yytype = YYTRANSLATE (yychar);
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ int yysize_overflow = 0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ int yyx;
+
+# if 0
+ /* This is so xgettext sees the translatable formats that are
+ constructed on the fly. */
+ YY_("syntax error, unexpected %s");
+ YY_("syntax error, unexpected %s, expecting %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+ char *yyfmt;
+ char const *yyf;
+ static char const yyunexpected[] = "syntax error, unexpected %s";
+ static char const yyexpecting[] = ", expecting %s";
+ static char const yyor[] = " or %s";
+ char yyformat[sizeof yyunexpected
+ + sizeof yyexpecting - 1
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+ * (sizeof yyor - 1))];
+ char const *yyprefix = yyexpecting;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 1;
+
+ yyarg[0] = yytname[yytype];
+ yyfmt = yystpcpy (yyformat, yyunexpected);
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ yyformat[sizeof yyunexpected - 1] = '\0';
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+ yyfmt = yystpcpy (yyfmt, yyprefix);
+ yyprefix = yyor;
+ }
+
+ yyf = YY_(yyformat);
+ yysize1 = yysize + yystrlen (yyf);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+
+ if (yysize_overflow)
+ return YYSIZE_MAXIMUM;
+
+ if (yyresult)
+ {
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ char *yyp = yyresult;
+ int yyi = 0;
+ while ((*yyp = *yyf) != '\0')
+ {
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyf += 2;
+ }
+ else
+ {
+ yyp++;
+ yyf++;
+ }
+ }
+ }
+ return yysize;
+ }
+}
+#endif /* YYERROR_VERBOSE */
+
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ YYUSE (yyvaluep);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes. */
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+/* The look-ahead symbol. */
+int yychar;
+
+/* The semantic value of the look-ahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+
+ int yystate;
+ int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Look-ahead token as an internal (translated) token number. */
+ int yytoken = 0;
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss = yyssa;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ look-ahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to look-ahead token. */
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a look-ahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the look-ahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ *++yyvsp = yylval;
+
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 4:
+#line 73 "parser.y"
+ {
+ free((yyvsp[(2) - (3)].s));
+ }
+ break;
+
+ case 5:
+#line 77 "parser.y"
+ {
+ _parser_kw = &(_parser_cfg->config_setup);
+ _parser_kw_last = NULL;
+ }
+ break;
+
+ case 7:
+#line 82 "parser.y"
+ {
+ section_list_t *section = (section_list_t *)alloc_thing(section_list_t
+ , "section_list_t");
+
+ section->name = clone_str((yyvsp[(2) - (3)].s), "conn section name");
+ section->kw = NULL;
+ section->next = NULL;
+ _parser_kw = &(section->kw);
+ if (!_parser_cfg->conn_first)
+ _parser_cfg->conn_first = section;
+ if (_parser_cfg->conn_last)
+ _parser_cfg->conn_last->next = section;
+ _parser_cfg->conn_last = section;
+ _parser_kw_last = NULL;
+ free((yyvsp[(2) - (3)].s));
+ }
+ break;
+
+ case 9:
+#line 99 "parser.y"
+ {
+ section_list_t *section = (section_list_t *)alloc_thing(section_list_t
+ , "section_list_t");
+ section->name = clone_str((yyvsp[(2) - (3)].s), "ca section name");
+ section->kw = NULL;
+ section->next = NULL;
+ _parser_kw = &(section->kw);
+ if (!_parser_cfg->ca_first)
+ _parser_cfg->ca_first = section;
+ if (_parser_cfg->ca_last)
+ _parser_cfg->ca_last->next = section;
+ _parser_cfg->ca_last = section;
+ _parser_kw_last = NULL;
+ free((yyvsp[(2) - (3)].s));
+ }
+ break;
+
+ case 11:
+#line 115 "parser.y"
+ {
+ extern void _parser_y_include (const char *f);
+ _parser_y_include((yyvsp[(2) - (2)].s));
+ free((yyvsp[(2) - (2)].s));
+ }
+ break;
+
+ case 16:
+#line 130 "parser.y"
+ {
+ kw_list_t *new;
+ kw_entry_t *entry = in_word_set((yyvsp[(1) - (3)].s), strlen((yyvsp[(1) - (3)].s)));
+
+ if (entry == NULL)
+ {
+ snprintf(errbuf, ERRSTRING_LEN, "unknown keyword '%s'", (yyvsp[(1) - (3)].s));
+ yyerror(errbuf);
+ }
+ else if (_parser_kw)
+ {
+ new = (kw_list_t *)alloc_thing(kw_list_t, "kw_list_t");
+ new->entry = entry;
+ new->value = clone_str((yyvsp[(3) - (3)].s), "kw_list value");
+ new->next = NULL;
+ if (_parser_kw_last)
+ _parser_kw_last->next = new;
+ _parser_kw_last = new;
+ if (!*_parser_kw)
+ *_parser_kw = new;
+ }
+ free((yyvsp[(1) - (3)].s));
+ free((yyvsp[(3) - (3)].s));
+ }
+ break;
+
+ case 17:
+#line 155 "parser.y"
+ {
+ free((yyvsp[(1) - (2)].s));
+ }
+ break;
+
+
+/* Line 1267 of yacc.c. */
+#line 1496 "y.tab.c"
+ default: break;
+ }
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (YY_("syntax error"));
+#else
+ {
+ YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+ if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+ {
+ YYSIZE_T yyalloc = 2 * yysize;
+ if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+ yyalloc = YYSTACK_ALLOC_MAXIMUM;
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+ if (yymsg)
+ yymsg_alloc = yyalloc;
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ }
+ }
+
+ if (0 < yysize && yysize <= yymsg_alloc)
+ {
+ (void) yysyntax_error (yymsg, yystate, yychar);
+ yyerror (yymsg);
+ }
+ else
+ {
+ yyerror (YY_("syntax error"));
+ if (yysize != 0)
+ goto yyexhaustedlab;
+ }
+ }
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse look-ahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse look-ahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ *++yyvsp = yylval;
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEOF && yychar != YYEMPTY)
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ return yyresult;
+}
+
+
+#line 161 "parser.y"
+
+
+void
+yyerror(const char *s)
+{
+ if (_save_errors_)
+ _parser_y_error(parser_errstring, ERRSTRING_LEN, s);
+}
+
+config_parsed_t *
+parser_load_conf(const char *file)
+{
+ config_parsed_t *cfg = NULL;
+ int err = 0;
+ FILE *f;
+
+ extern void _parser_y_init (const char *f);
+ extern FILE *yyin;
+
+ memset(parser_errstring, 0, ERRSTRING_LEN+1);
+
+ cfg = (config_parsed_t *)alloc_thing(config_parsed_t, "config_parsed_t");
+ if (cfg)
+ {
+ memset(cfg, 0, sizeof(config_parsed_t));
+ f = fopen(file, "r");
+ if (f)
+ {
+ yyin = f;
+ _parser_y_init(file);
+ _save_errors_ = 1;
+ _parser_cfg = cfg;
+
+ if (yyparse() !=0 )
+ {
+ if (parser_errstring[0] == '\0')
+ {
+ snprintf(parser_errstring, ERRSTRING_LEN, "Unknown error...");
+ }
+ _save_errors_ = 0;
+ while (yyparse() != 0);
+ err++;
+ }
+ else if (parser_errstring[0] != '\0')
+ {
+ err++;
+ }
+ else
+ {
+ /**
+ * Config valid
+ */
+ }
+
+ fclose(f);
+ }
+ else
+ {
+ snprintf(parser_errstring, ERRSTRING_LEN, "can't load file '%s'", file);
+ err++;
+ }
+ }
+ else
+ {
+ snprintf(parser_errstring, ERRSTRING_LEN, "can't allocate memory");
+ err++;
+ }
+
+ if (err)
+ {
+ plog("%s", parser_errstring);
+
+ if (cfg)
+ parser_free_conf(cfg);
+ cfg = NULL;
+ }
+
+ return cfg;
+}
+
+static void
+parser_free_kwlist(kw_list_t *list)
+{
+ kw_list_t *elt;
+
+ while (list)
+ {
+ elt = list;
+ list = list->next;
+ if (elt->value)
+ pfree(elt->value);
+ pfree(elt);
+ }
+}
+
+void
+parser_free_conf(config_parsed_t *cfg)
+{
+ section_list_t *sec;
+ if (cfg)
+ {
+ parser_free_kwlist(cfg->config_setup);
+ while (cfg->conn_first)
+ {
+ sec = cfg->conn_first;
+ cfg->conn_first = cfg->conn_first->next;
+ if (sec->name)
+ pfree(sec->name);
+ parser_free_kwlist(sec->kw);
+ pfree(sec);
+ }
+ while (cfg->ca_first)
+ {
+ sec = cfg->ca_first;
+ cfg->ca_first = cfg->ca_first->next;
+ if (sec->name)
+ pfree(sec->name);
+ parser_free_kwlist(sec->kw);
+ pfree(sec);
+ }
+ pfree(cfg);
+ }
+}
+
diff --git a/src/starter/y.tab.h b/src/starter/y.tab.h
new file mode 100644
index 000000000..4b55cb005
--- /dev/null
+++ b/src/starter/y.tab.h
@@ -0,0 +1,82 @@
+/* A Bison parser, made by GNU Bison 2.2. */
+
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ EQUAL = 258,
+ FIRST_SPACES = 259,
+ EOL = 260,
+ CONFIG = 261,
+ SETUP = 262,
+ CONN = 263,
+ CA = 264,
+ INCLUDE = 265,
+ FILE_VERSION = 266,
+ STRING = 267
+ };
+#endif
+/* Tokens. */
+#define EQUAL 258
+#define FIRST_SPACES 259
+#define EOL 260
+#define CONFIG 261
+#define SETUP 262
+#define CONN 263
+#define CA 264
+#define INCLUDE 265
+#define FILE_VERSION 266
+#define STRING 267
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 56 "parser.y"
+{ char *s; }
+/* Line 1528 of yacc.c. */
+#line 75 "y.tab.h"
+ YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+extern YYSTYPE yylval;
+
diff --git a/src/stroke/Makefile.am b/src/stroke/Makefile.am
new file mode 100644
index 000000000..6ea64753c
--- /dev/null
+++ b/src/stroke/Makefile.am
@@ -0,0 +1,9 @@
+ipsec_PROGRAMS = stroke
+
+stroke_SOURCES = stroke.c stroke.h stroke_keywords.c stroke_keywords.h
+INCLUDES = -I$(top_srcdir)/src/libstrongswan
+EXTRA_DIST = stroke_keywords.txt
+MAINTAINERCLEANFILES = stroke_keywords.c
+
+stroke_keywords.c: stroke_keywords.txt stroke_keywords.h
+ $(GPERF) -C -G -t < stroke_keywords.txt > stroke_keywords.c
diff --git a/src/stroke/Makefile.in b/src/stroke/Makefile.in
new file mode 100644
index 000000000..179bca750
--- /dev/null
+++ b/src/stroke/Makefile.in
@@ -0,0 +1,483 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+ipsec_PROGRAMS = stroke$(EXEEXT)
+subdir = src/stroke
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_CLEAN_FILES =
+am__installdirs = "$(DESTDIR)$(ipsecdir)"
+ipsecPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(ipsec_PROGRAMS)
+am_stroke_OBJECTS = stroke.$(OBJEXT) stroke_keywords.$(OBJEXT)
+stroke_OBJECTS = $(am_stroke_OBJECTS)
+stroke_LDADD = $(LDADD)
+DEFAULT_INCLUDES = -I. -I$(srcdir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(stroke_SOURCES)
+DIST_SOURCES = $(stroke_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_EAP_SIM_FALSE = @BUILD_EAP_SIM_FALSE@
+BUILD_EAP_SIM_TRUE = @BUILD_EAP_SIM_TRUE@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GPERF = @GPERF@
+GREP = @GREP@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+USE_CISCO_QUIRKS_FALSE = @USE_CISCO_QUIRKS_FALSE@
+USE_CISCO_QUIRKS_TRUE = @USE_CISCO_QUIRKS_TRUE@
+USE_LEAK_DETECTIVE_FALSE = @USE_LEAK_DETECTIVE_FALSE@
+USE_LEAK_DETECTIVE_TRUE = @USE_LEAK_DETECTIVE_TRUE@
+USE_LIBCURL_FALSE = @USE_LIBCURL_FALSE@
+USE_LIBCURL_TRUE = @USE_LIBCURL_TRUE@
+USE_LIBLDAP_FALSE = @USE_LIBLDAP_FALSE@
+USE_LIBLDAP_TRUE = @USE_LIBLDAP_TRUE@
+USE_NAT_TRANSPORT_FALSE = @USE_NAT_TRANSPORT_FALSE@
+USE_NAT_TRANSPORT_TRUE = @USE_NAT_TRANSPORT_TRUE@
+USE_SMARTCARD_FALSE = @USE_SMARTCARD_FALSE@
+USE_SMARTCARD_TRUE = @USE_SMARTCARD_TRUE@
+USE_VENDORID_FALSE = @USE_VENDORID_FALSE@
+USE_VENDORID_TRUE = @USE_VENDORID_TRUE@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+confdir = @confdir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+eapdir = @eapdir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+ipsecdir = @ipsecdir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+piddir = @piddir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+stroke_SOURCES = stroke.c stroke.h stroke_keywords.c stroke_keywords.h
+INCLUDES = -I$(top_srcdir)/src/libstrongswan
+EXTRA_DIST = stroke_keywords.txt
+MAINTAINERCLEANFILES = stroke_keywords.c
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/stroke/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/stroke/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-ipsecPROGRAMS: $(ipsec_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(ipsecdir)" || $(mkdir_p) "$(DESTDIR)$(ipsecdir)"
+ @list='$(ipsec_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ || test -f $$p1 \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(ipsecPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(ipsecdir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(ipsecPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(ipsecdir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-ipsecPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(ipsec_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(ipsecdir)/$$f'"; \
+ rm -f "$(DESTDIR)$(ipsecdir)/$$f"; \
+ done
+
+clean-ipsecPROGRAMS:
+ @list='$(ipsec_PROGRAMS)'; for p in $$list; do \
+ f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f $$p $$f"; \
+ rm -f $$p $$f ; \
+ done
+stroke$(EXEEXT): $(stroke_OBJECTS) $(stroke_DEPENDENCIES)
+ @rm -f stroke$(EXEEXT)
+ $(LINK) $(stroke_LDFLAGS) $(stroke_OBJECTS) $(stroke_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stroke.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stroke_keywords.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS)
+installdirs:
+ for dir in "$(DESTDIR)$(ipsecdir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic clean-ipsecPROGRAMS clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-ipsecPROGRAMS
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-ipsecPROGRAMS
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-ipsecPROGRAMS clean-libtool ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am \
+ install-ipsecPROGRAMS install-man install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-info-am \
+ uninstall-ipsecPROGRAMS
+
+
+stroke_keywords.c: stroke_keywords.txt stroke_keywords.h
+ $(GPERF) -C -G -t < stroke_keywords.txt > stroke_keywords.c
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/stroke/stroke.c b/src/stroke/stroke.c
new file mode 100644
index 000000000..5d3fd6e77
--- /dev/null
+++ b/src/stroke/stroke.c
@@ -0,0 +1,421 @@
+/* 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 <stddef.h>
+
+#include "stroke.h"
+#include "stroke_keywords.h"
+
+struct stroke_token {
+ char *name;
+ stroke_keyword_t kw;
+};
+
+static char* push_string(stroke_msg_t *msg, char *string)
+{
+ unsigned long string_start = msg->length;
+
+ if (string == NULL || msg->length + strlen(string) >= sizeof(stroke_msg_t))
+ {
+ return NULL;
+ }
+ else
+ {
+ msg->length += strlen(string) + 1;
+ strcpy((char*)msg + string_start, string);
+ return (char*)string_start;
+ }
+}
+
+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;
+
+ msg->output_verbosity = 1; /* CONTROL */
+
+ 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;
+
+ msg.length = offsetof(stroke_msg_t, buffer);
+ msg.type = STR_ADD_CONN;
+
+ msg.add_conn.name = push_string(&msg, name);
+ msg.add_conn.ikev2 = 1;
+ msg.add_conn.auth_method = 2;
+ msg.add_conn.eap_type = 0;
+ msg.add_conn.mode = 1;
+
+ msg.add_conn.rekey.reauth = 0;
+ msg.add_conn.rekey.ipsec_lifetime = 0;
+ msg.add_conn.rekey.ike_lifetime = 0;
+ msg.add_conn.rekey.margin = 0;
+ msg.add_conn.rekey.tries = 0;
+ msg.add_conn.rekey.fuzz = 0;
+
+ msg.add_conn.algorithms.ike = NULL;
+ msg.add_conn.algorithms.esp = NULL;
+
+ msg.add_conn.dpd.delay = 0;
+ msg.add_conn.dpd.action = 1;
+
+ 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.sourceip = NULL;
+ msg.add_conn.me.virtual_ip = 0;
+ msg.add_conn.me.cert = NULL;
+ msg.add_conn.me.ca = NULL;
+ msg.add_conn.me.sendcert = 1;
+ msg.add_conn.me.hostaccess = 0;
+ msg.add_conn.me.tohost = 0;
+ msg.add_conn.me.protocol = 0;
+ msg.add_conn.me.port = 0;
+
+ 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.sourceip = NULL;
+ msg.add_conn.other.virtual_ip = 0;
+ msg.add_conn.other.cert = NULL;
+ msg.add_conn.other.ca = NULL;
+ msg.add_conn.other.sendcert = 1;
+ msg.add_conn.other.hostaccess = 0;
+ msg.add_conn.other.tohost = 0;
+ msg.add_conn.other.protocol = 0;
+ msg.add_conn.other.port = 0;
+
+ return send_stroke_msg(&msg);
+}
+
+static int del_connection(char *name)
+{
+ stroke_msg_t msg;
+
+ msg.length = offsetof(stroke_msg_t, buffer);
+ msg.type = STR_DEL_CONN;
+ msg.initiate.name = push_string(&msg, name);
+ return send_stroke_msg(&msg);
+}
+
+static int initiate_connection(char *name)
+{
+ stroke_msg_t msg;
+
+ msg.length = offsetof(stroke_msg_t, buffer);
+ msg.type = STR_INITIATE;
+ msg.initiate.name = push_string(&msg, name);
+ return send_stroke_msg(&msg);
+}
+
+static int terminate_connection(char *name)
+{
+ stroke_msg_t msg;
+
+ msg.type = STR_TERMINATE;
+ msg.length = offsetof(stroke_msg_t, buffer);
+ msg.initiate.name = push_string(&msg, name);
+ return send_stroke_msg(&msg);
+}
+
+static int route_connection(char *name)
+{
+ stroke_msg_t msg;
+
+ msg.type = STR_ROUTE;
+ msg.length = offsetof(stroke_msg_t, buffer);
+ msg.route.name = push_string(&msg, name);
+ return send_stroke_msg(&msg);
+}
+
+static int unroute_connection(char *name)
+{
+ stroke_msg_t msg;
+
+ msg.type = STR_UNROUTE;
+ msg.length = offsetof(stroke_msg_t, buffer);
+ msg.unroute.name = push_string(&msg, name);
+ return send_stroke_msg(&msg);
+}
+
+static int show_status(stroke_keyword_t kw, char *connection)
+{
+ stroke_msg_t msg;
+
+ msg.type = (kw == STROKE_STATUS)? STR_STATUS:STR_STATUS_ALL;
+ msg.length = offsetof(stroke_msg_t, buffer);
+ msg.status.name = push_string(&msg, connection);
+ return send_stroke_msg(&msg);
+}
+
+static int list_flags[] = {
+ LIST_CERTS,
+ LIST_CACERTS,
+ LIST_OCSPCERTS,
+ LIST_CAINFOS,
+ LIST_CRLS,
+ LIST_OCSP,
+ LIST_ALL
+};
+
+static int list(stroke_keyword_t kw, int utc)
+{
+ stroke_msg_t msg;
+
+ msg.type = STR_LIST;
+ msg.length = offsetof(stroke_msg_t, buffer);
+ msg.list.utc = utc;
+ msg.list.flags = list_flags[kw - STROKE_LIST_FIRST];
+ return send_stroke_msg(&msg);
+}
+
+static int reread_flags[] = {
+ REREAD_CACERTS,
+ REREAD_OCSPCERTS,
+ REREAD_CRLS,
+ REREAD_ALL
+};
+
+static int reread(stroke_keyword_t kw)
+{
+ stroke_msg_t msg;
+
+ msg.type = STR_REREAD;
+ msg.length = offsetof(stroke_msg_t, buffer);
+ msg.reread.flags = reread_flags[kw - STROKE_REREAD_FIRST];
+ return send_stroke_msg(&msg);
+}
+
+static int purge_flags[] = {
+ PURGE_OCSP
+};
+
+static int purge(stroke_keyword_t kw)
+{
+ stroke_msg_t msg;
+
+ msg.type = STR_PURGE;
+ msg.length = offsetof(stroke_msg_t, buffer);
+ msg.purge.flags = purge_flags[kw - STROKE_PURGE_FIRST];
+ return send_stroke_msg(&msg);
+}
+
+static int set_loglevel(char *type, u_int level)
+{
+ stroke_msg_t msg;
+
+ msg.type = STR_LOGLEVEL;
+ msg.length = offsetof(stroke_msg_t, buffer);
+ msg.loglevel.type = push_string(&msg, type);
+ msg.loglevel.level = level;
+ return send_stroke_msg(&msg);
+}
+
+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(" Delete a connection:\n");
+ printf(" stroke delete NAME\n");
+ printf(" where: NAME is a connection name added with \"stroke add\"\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 loglevel for a logging type:\n");
+ printf(" stroke loglevel TYPE LEVEL\n");
+ printf(" where: TYPE is any|dmn|mgr|ike|chd|job|cfg|knl|net|enc|lib\n");
+ printf(" LEVEL is -1|0|1|2|3|4\n");
+ printf(" Show connection status:\n");
+ printf(" stroke status\n");
+ printf(" Show list of locally loaded certificates and crls:\n");
+ printf(" stroke listcerts|listcacerts|listocspcerts|listcainfos|listcrls|listocsp|listall\n");
+ printf(" Reload ca certificates and crls:\n");
+ printf(" stroke rereadcacerts|rereadcrls|rereadall\n");
+ printf(" Purge ocsp cache entries:\n");
+ printf(" stroke purgeocsp\n");
+ exit_error(error);
+}
+
+int main(int argc, char *argv[])
+{
+ const stroke_token_t *token;
+ int res = 0;
+
+ if (argc < 2)
+ {
+ exit_usage(NULL);
+ }
+
+ token = in_word_set(argv[1], strlen(argv[1]));
+
+ if (token == NULL)
+ {
+ exit_usage("unknown keyword");
+ }
+
+ switch (token->kw)
+ {
+ case STROKE_ADD:
+ 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]));
+ break;
+ case STROKE_DELETE:
+ case STROKE_DEL:
+ if (argc < 3)
+ {
+ exit_usage("\"delete\" needs a connection name");
+ }
+ res = del_connection(argv[2]);
+ break;
+ case STROKE_UP:
+ if (argc < 3)
+ {
+ exit_usage("\"up\" needs a connection name");
+ }
+ res = initiate_connection(argv[2]);
+ break;
+ case STROKE_DOWN:
+ if (argc < 3)
+ {
+ exit_usage("\"down\" needs a connection name");
+ }
+ res = terminate_connection(argv[2]);
+ break;
+ case STROKE_ROUTE:
+ if (argc < 3)
+ {
+ exit_usage("\"route\" needs a connection name");
+ }
+ res = route_connection(argv[2]);
+ break;
+ case STROKE_UNROUTE:
+ if (argc < 3)
+ {
+ exit_usage("\"unroute\" needs a connection name");
+ }
+ res = unroute_connection(argv[2]);
+ break;
+ case STROKE_LOGLEVEL:
+ if (argc < 4)
+ {
+ exit_usage("\"logtype\" needs more parameters...");
+ }
+ res = set_loglevel(argv[2], atoi(argv[3]));
+ break;
+ case STROKE_STATUS:
+ case STROKE_STATUSALL:
+ res = show_status(token->kw, argc > 2 ? argv[2] : NULL);
+ break;
+ case STROKE_LIST_CERTS:
+ case STROKE_LIST_CACERTS:
+ case STROKE_LIST_OCSPCERTS:
+ case STROKE_LIST_CAINFOS:
+ case STROKE_LIST_CRLS:
+ case STROKE_LIST_OCSP:
+ case STROKE_LIST_ALL:
+ res = list(token->kw, argc > 2 && strcmp(argv[2], "--utc") == 0);
+ break;
+ case STROKE_REREAD_CACERTS:
+ case STROKE_REREAD_CRLS:
+ case STROKE_REREAD_ALL:
+ res = reread(token->kw);
+ break;
+ case STROKE_PURGE_OCSP:
+ res = purge(token->kw);
+ break;
+ default:
+ exit_usage(NULL);
+ }
+ return res;
+}
diff --git a/src/stroke/stroke.h b/src/stroke/stroke.h
new file mode 100644
index 000000000..2eefb36c4
--- /dev/null
+++ b/src/stroke/stroke.h
@@ -0,0 +1,226 @@
+/**
+ * @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_
+
+#include <sys/types.h>
+
+/**
+ * Socket which is used to communicate between charon and stroke
+ */
+#define STROKE_SOCKET "/var/run/charon.ctl"
+
+#define STROKE_BUF_LEN 2048
+
+typedef enum list_flag_t list_flag_t;
+
+/**
+ * Definition of the LIST flags, used for
+ * the various stroke list* commands.
+ */
+enum list_flag_t {
+ /** don't list anything */
+ LIST_NONE = 0x0000,
+ /** list all host/user certs */
+ LIST_CERTS = 0x0001,
+ /** list all ca certs */
+ LIST_CACERTS = 0x0002,
+ /** list all ocsp signer certs */
+ LIST_OCSPCERTS = 0x0004,
+ /** list all ca information records */
+ LIST_CAINFOS = 0x0008,
+ /** list all crls */
+ LIST_CRLS = 0x0010,
+ /** list all ocsp cache entries */
+ LIST_OCSP = 0x0020,
+ /** all list options */
+ LIST_ALL = 0x003F,
+};
+
+typedef enum reread_flag_t reread_flag_t;
+
+/**
+ * Definition of the REREAD flags, used for
+ * the various stroke reread* commands.
+ */
+enum reread_flag_t {
+ /** don't reread anything */
+ REREAD_NONE = 0x0000,
+ /** reread all ca certs */
+ REREAD_CACERTS = 0x0001,
+ /** reread all ocsp signer certs */
+ REREAD_OCSPCERTS = 0x0002,
+ /** reread all crls */
+ REREAD_CRLS = 0x0004,
+ /** all reread options */
+ REREAD_ALL = 0x0007,
+};
+
+typedef enum purge_flag_t purge_flag_t;
+
+/**
+ * Definition of the PURGE flags, currently used for
+ * the stroke purgeocsp command.
+ */
+enum purge_flag_t {
+ /** don't purge anything */
+ PURGE_NONE = 0x0000,
+ /** purge ocsp cache entries */
+ PURGE_OCSP = 0x0001,
+};
+
+typedef struct stroke_end_t stroke_end_t;
+
+/**
+ * definition of a peer in a stroke message
+ */
+struct stroke_end_t {
+ char *id;
+ char *cert;
+ char *ca;
+ char *updown;
+ char *address;
+ char *sourceip;
+ u_int8_t virtual_ip;
+ char *subnet;
+ int subnet_mask;
+ int sendcert;
+ int hostaccess;
+ int tohost;
+ u_int8_t protocol;
+ u_int16_t port;
+};
+
+typedef struct stroke_msg_t stroke_msg_t;
+
+/**
+ * @brief A stroke message sent over the unix socket.
+ */
+struct stroke_msg_t {
+ /* length of this message with all strings */
+ u_int16_t length;
+
+ /* type of the message */
+ enum {
+ /* initiate a connection */
+ STR_INITIATE,
+ /* install SPD entries for a policy */
+ STR_ROUTE,
+ /* uninstall SPD entries for a policy */
+ STR_UNROUTE,
+ /* add a connection */
+ STR_ADD_CONN,
+ /* delete a connection */
+ STR_DEL_CONN,
+ /* terminate connection */
+ STR_TERMINATE,
+ /* show connection status */
+ STR_STATUS,
+ /* show verbose connection status */
+ STR_STATUS_ALL,
+ /* add a ca information record */
+ STR_ADD_CA,
+ /* delete ca information record */
+ STR_DEL_CA,
+ /* set a log type to log/not log */
+ STR_LOGLEVEL,
+ /* list various objects */
+ STR_LIST,
+ /* reread various objects */
+ STR_REREAD,
+ /* purge various objects */
+ STR_PURGE
+ /* more to come */
+ } type;
+
+ /* verbosity of output returned from charon (-from -1=silent to 4=private)*/
+ int output_verbosity;
+
+ union {
+ /* data for STR_INITIATE, STR_ROUTE, STR_UP, STR_DOWN, ... */
+ struct {
+ char *name;
+ } initiate, route, unroute, terminate, status, del_conn, del_ca;
+
+ /* data for STR_ADD_CONN */
+ struct {
+ char *name;
+ int ikev2;
+ int auth_method;
+ int eap_type;
+ int mode;
+ struct {
+ char *ike;
+ char *esp;
+ } algorithms;
+ struct {
+ int reauth;
+ time_t ipsec_lifetime;
+ time_t ike_lifetime;
+ time_t margin;
+ unsigned long tries;
+ unsigned long fuzz;
+ } rekey;
+ struct {
+ time_t delay;
+ int action;
+ } dpd;
+ stroke_end_t me, other;
+ } add_conn;
+
+ /* data for STR_ADD_CA */
+ struct {
+ char *name;
+ char *cacert;
+ char *crluri;
+ char *crluri2;
+ char *ocspuri;
+ char *ocspuri2;
+ } add_ca;
+
+ /* data for STR_LOGLEVEL */
+ struct {
+ char *type;
+ int level;
+ } loglevel;
+
+ /* data for STR_LIST */
+ struct {
+ list_flag_t flags;
+ int utc;
+ } list;
+
+ /* data for STR_REREAD */
+ struct {
+ reread_flag_t flags;
+ } reread;
+
+ /* data for STR_PURGE */
+ struct {
+ purge_flag_t flags;
+ } purge;
+ };
+ char buffer[STROKE_BUF_LEN];
+};
+
+#endif /* STROKE_H_ */
diff --git a/src/stroke/stroke_keywords.c b/src/stroke/stroke_keywords.c
new file mode 100644
index 000000000..71d99ecad
--- /dev/null
+++ b/src/stroke/stroke_keywords.c
@@ -0,0 +1,179 @@
+/* C code produced by gperf version 3.0.1 */
+/* Command-line: /usr/bin/gperf -C -G -t */
+/* Computed positions: -k'2,7' */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646. */
+error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
+#endif
+
+
+/* stroke keywords
+ * Copyright (C) 2006 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil, Switzerland
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: keywords.txt,v 1.6 2006/04/17 10:30:27 as Exp $
+ */
+
+#include <string.h>
+
+#include "stroke_keywords.h"
+
+struct stroke_token {
+ char *name;
+ stroke_keyword_t kw;
+};
+
+#define TOTAL_KEYWORDS 22
+#define MIN_WORD_LENGTH 2
+#define MAX_WORD_LENGTH 15
+#define MIN_HASH_VALUE 2
+#define MAX_HASH_VALUE 33
+/* maximum key range = 32, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static unsigned int
+hash (str, len)
+ register const char *str;
+ register unsigned int len;
+{
+ static const unsigned char asso_values[] =
+ {
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 0, 34, 0,
+ 30, 0, 34, 34, 34, 5, 34, 34, 15, 34,
+ 0, 0, 0, 34, 10, 5, 5, 10, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34
+ };
+ register int hval = len;
+
+ switch (hval)
+ {
+ default:
+ hval += asso_values[(unsigned char)str[6]];
+ /*FALLTHROUGH*/
+ case 6:
+ case 5:
+ case 4:
+ case 3:
+ case 2:
+ hval += asso_values[(unsigned char)str[1]];
+ break;
+ }
+ return hval;
+}
+
+static const struct stroke_token wordlist[] =
+ {
+ {""}, {""},
+ {"up", STROKE_UP},
+ {"del", STROKE_DEL},
+ {"down", STROKE_DOWN},
+ {"route", STROKE_ROUTE},
+ {"delete", STROKE_DELETE},
+ {"unroute", STROKE_UNROUTE},
+ {"loglevel", STROKE_LOGLEVEL},
+ {"rereadall", STROKE_REREAD_ALL},
+ {"rereadcrls", STROKE_REREAD_CRLS},
+ {"status", STROKE_STATUS},
+ {""},
+ {"rereadcacerts", STROKE_REREAD_CACERTS},
+ {"statusall", STROKE_STATUSALL},
+ {"rereadocspcerts", STROKE_REREAD_OCSPCERTS},
+ {"listcacerts", STROKE_LIST_CACERTS},
+ {""},
+ {"listocsp", STROKE_LIST_OCSP},
+ {"purgeocsp", STROKE_PURGE_OCSP},
+ {""},
+ {"listcainfos", STROKE_LIST_CAINFOS},
+ {""},
+ {"listocspcerts", STROKE_LIST_OCSPCERTS},
+ {"listcerts", STROKE_LIST_CERTS},
+ {""}, {""},
+ {"listall", STROKE_LIST_ALL},
+ {"listcrls", STROKE_LIST_CRLS},
+ {""}, {""}, {""}, {""},
+ {"add", STROKE_ADD}
+ };
+
+#ifdef __GNUC__
+__inline
+#endif
+const struct stroke_token *
+in_word_set (str, len)
+ register const char *str;
+ register unsigned int len;
+{
+ if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+ {
+ register int key = hash (str, len);
+
+ if (key <= MAX_HASH_VALUE && key >= 0)
+ {
+ register const char *s = wordlist[key].name;
+
+ if (*str == *s && !strcmp (str + 1, s + 1))
+ return &wordlist[key];
+ }
+ }
+ return 0;
+}
diff --git a/src/stroke/stroke_keywords.h b/src/stroke/stroke_keywords.h
new file mode 100644
index 000000000..2e7d7c385
--- /dev/null
+++ b/src/stroke/stroke_keywords.h
@@ -0,0 +1,55 @@
+/* stroke keywords
+ * Copyright (C) 2006 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil, Switzerland
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: keywords.h,v 1.8 2006/04/17 10:30:27 as Exp $
+ */
+
+#ifndef _STROKE_KEYWORDS_H_
+#define _STROKE_KEYWORDS_H_
+
+typedef enum {
+ STROKE_ADD,
+ STROKE_DEL,
+ STROKE_DELETE,
+ STROKE_ROUTE,
+ STROKE_UNROUTE,
+ STROKE_UP,
+ STROKE_DOWN,
+ STROKE_LOGLEVEL,
+ STROKE_STATUS,
+ STROKE_STATUSALL,
+ STROKE_LIST_CERTS,
+ STROKE_LIST_CACERTS,
+ STROKE_LIST_OCSPCERTS,
+ STROKE_LIST_CAINFOS,
+ STROKE_LIST_CRLS,
+ STROKE_LIST_OCSP,
+ STROKE_LIST_ALL,
+ STROKE_REREAD_CACERTS,
+ STROKE_REREAD_OCSPCERTS,
+ STROKE_REREAD_CRLS,
+ STROKE_REREAD_ALL,
+ STROKE_PURGE_OCSP
+} stroke_keyword_t;
+
+#define STROKE_LIST_FIRST STROKE_LIST_CERTS
+#define STROKE_REREAD_FIRST STROKE_REREAD_CACERTS
+#define STROKE_PURGE_FIRST STROKE_PURGE_OCSP
+
+typedef struct stroke_token stroke_token_t;
+
+extern const stroke_token_t* in_word_set(register const char *str, register unsigned int len);
+
+#endif /* _STROKE_KEYWORDS_H_ */
+
diff --git a/src/stroke/stroke_keywords.txt b/src/stroke/stroke_keywords.txt
new file mode 100644
index 000000000..1e8afe19e
--- /dev/null
+++ b/src/stroke/stroke_keywords.txt
@@ -0,0 +1,50 @@
+%{
+/* stroke keywords
+ * Copyright (C) 2006 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil, Switzerland
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: keywords.txt,v 1.6 2006/04/17 10:30:27 as Exp $
+ */
+
+#include <string.h>
+
+#include "stroke_keywords.h"
+
+%}
+struct stroke_token {
+ char *name;
+ stroke_keyword_t kw;
+};
+%%
+add, STROKE_ADD
+del, STROKE_DEL
+delete, STROKE_DELETE
+route, STROKE_ROUTE
+unroute, STROKE_UNROUTE
+up, STROKE_UP
+down, STROKE_DOWN
+loglevel, STROKE_LOGLEVEL
+status, STROKE_STATUS
+statusall, STROKE_STATUSALL
+listcerts, STROKE_LIST_CERTS
+listcacerts, STROKE_LIST_CACERTS
+listocspcerts, STROKE_LIST_OCSPCERTS
+listcainfos, STROKE_LIST_CAINFOS
+listcrls, STROKE_LIST_CRLS
+listocsp, STROKE_LIST_OCSP
+listall, STROKE_LIST_ALL
+rereadcacerts, STROKE_REREAD_CACERTS
+rereadocspcerts, STROKE_REREAD_OCSPCERTS
+rereadcrls, STROKE_REREAD_CRLS
+rereadall, STROKE_REREAD_ALL
+purgeocsp, STROKE_PURGE_OCSP
diff --git a/src/whack/Makefile.am b/src/whack/Makefile.am
new file mode 100644
index 000000000..985245026
--- /dev/null
+++ b/src/whack/Makefile.am
@@ -0,0 +1,8 @@
+ipsec_PROGRAMS = whack
+
+whack_SOURCES = whack.c whack.h
+INCLUDES = -I$(top_srcdir)/src/libfreeswan -I$(top_srcdir)/src/pluto
+whack_LDADD = $(top_builddir)/src/libfreeswan/libfreeswan.a
+
+AM_CFLAGS = -DDEBUG
+
diff --git a/src/whack/Makefile.in b/src/whack/Makefile.in
new file mode 100644
index 000000000..d14f5e8ed
--- /dev/null
+++ b/src/whack/Makefile.in
@@ -0,0 +1,478 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+ipsec_PROGRAMS = whack$(EXEEXT)
+subdir = src/whack
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_CLEAN_FILES =
+am__installdirs = "$(DESTDIR)$(ipsecdir)"
+ipsecPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(ipsec_PROGRAMS)
+am_whack_OBJECTS = whack.$(OBJEXT)
+whack_OBJECTS = $(am_whack_OBJECTS)
+whack_DEPENDENCIES = $(top_builddir)/src/libfreeswan/libfreeswan.a
+DEFAULT_INCLUDES = -I. -I$(srcdir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(whack_SOURCES)
+DIST_SOURCES = $(whack_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_EAP_SIM_FALSE = @BUILD_EAP_SIM_FALSE@
+BUILD_EAP_SIM_TRUE = @BUILD_EAP_SIM_TRUE@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GPERF = @GPERF@
+GREP = @GREP@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+USE_CISCO_QUIRKS_FALSE = @USE_CISCO_QUIRKS_FALSE@
+USE_CISCO_QUIRKS_TRUE = @USE_CISCO_QUIRKS_TRUE@
+USE_LEAK_DETECTIVE_FALSE = @USE_LEAK_DETECTIVE_FALSE@
+USE_LEAK_DETECTIVE_TRUE = @USE_LEAK_DETECTIVE_TRUE@
+USE_LIBCURL_FALSE = @USE_LIBCURL_FALSE@
+USE_LIBCURL_TRUE = @USE_LIBCURL_TRUE@
+USE_LIBLDAP_FALSE = @USE_LIBLDAP_FALSE@
+USE_LIBLDAP_TRUE = @USE_LIBLDAP_TRUE@
+USE_NAT_TRANSPORT_FALSE = @USE_NAT_TRANSPORT_FALSE@
+USE_NAT_TRANSPORT_TRUE = @USE_NAT_TRANSPORT_TRUE@
+USE_SMARTCARD_FALSE = @USE_SMARTCARD_FALSE@
+USE_SMARTCARD_TRUE = @USE_SMARTCARD_TRUE@
+USE_VENDORID_FALSE = @USE_VENDORID_FALSE@
+USE_VENDORID_TRUE = @USE_VENDORID_TRUE@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+confdir = @confdir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+eapdir = @eapdir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+ipsecdir = @ipsecdir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+piddir = @piddir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+whack_SOURCES = whack.c whack.h
+INCLUDES = -I$(top_srcdir)/src/libfreeswan -I$(top_srcdir)/src/pluto
+whack_LDADD = $(top_builddir)/src/libfreeswan/libfreeswan.a
+AM_CFLAGS = -DDEBUG
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/whack/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/whack/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-ipsecPROGRAMS: $(ipsec_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(ipsecdir)" || $(mkdir_p) "$(DESTDIR)$(ipsecdir)"
+ @list='$(ipsec_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ || test -f $$p1 \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(ipsecPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(ipsecdir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(ipsecPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(ipsecdir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-ipsecPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(ipsec_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(ipsecdir)/$$f'"; \
+ rm -f "$(DESTDIR)$(ipsecdir)/$$f"; \
+ done
+
+clean-ipsecPROGRAMS:
+ @list='$(ipsec_PROGRAMS)'; for p in $$list; do \
+ f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f $$p $$f"; \
+ rm -f $$p $$f ; \
+ done
+whack$(EXEEXT): $(whack_OBJECTS) $(whack_DEPENDENCIES)
+ @rm -f whack$(EXEEXT)
+ $(LINK) $(whack_LDFLAGS) $(whack_OBJECTS) $(whack_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/whack.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS)
+installdirs:
+ for dir in "$(DESTDIR)$(ipsecdir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-ipsecPROGRAMS clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-ipsecPROGRAMS
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-ipsecPROGRAMS
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-ipsecPROGRAMS clean-libtool ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am \
+ install-ipsecPROGRAMS install-man install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-info-am \
+ uninstall-ipsecPROGRAMS
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/whack/whack.c b/src/whack/whack.c
new file mode 100644
index 000000000..92ebd01ef
--- /dev/null
+++ b/src/whack/whack.c
@@ -0,0 +1,1905 @@
+/* command interface to Pluto
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: whack.c,v 1.21 2006/04/20 04:42:12 as Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <getopt.h>
+#include <assert.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "whack.h"
+
+static void
+help(void)
+{
+ fprintf(stderr
+ , "Usage:\n\n"
+ "all forms:"
+ " [--optionsfrom <filename>]"
+ " [--ctlbase <path>]"
+ " [--label <string>]"
+ "\n\n"
+ "help: whack"
+ " [--help]"
+ " [--version]"
+ "\n\n"
+ "connection: whack"
+ " --name <connection_name>"
+ " \\\n "
+ " [--ipv4 | --ipv6]"
+ " [--tunnelipv4 | --tunnelipv6]"
+ " \\\n "
+ " (--host <ip-address> | --id <identity>)"
+ " \\\n "
+ " [--cert <path>]"
+ " [--ca <distinguished name>]"
+ " [--sendcert <policy>]"
+ " \\\n "
+ " [--groups <access control groups>]"
+ " \\\n "
+ " [--ikeport <port-number>]"
+ " [--nexthop <ip-address>]"
+ " [--srcip <ip-address>]"
+ " \\\n "
+ " [--client <subnet> | --clientwithin <address range>]"
+ " [--clientprotoport <protocol>/<port>]"
+ " \\\n "
+ " [--dnskeyondemand]"
+ " [--updown <updown>]"
+ " \\\n "
+ " --to"
+ " (--host <ip-address> | --id <identity>)"
+ " \\\n "
+ " [--cert <path>]"
+ " [--ca <distinguished name>]"
+ " [--sendcert <policy>]"
+ " \\\n "
+ " [--ikeport <port-number>]"
+ " [--nexthop <ip-address>]"
+ " [--srcip <ip-address>]"
+ " \\\n "
+ " [--client <subnet> | --clientwithin <address range>]"
+ " [--clientprotoport <protocol>/<port>]"
+ " \\\n "
+ " [--dnskeyondemand]"
+ " [--updown <updown>]"
+ " [--psk]"
+ " [--rsasig]"
+ " \\\n "
+ " [--encrypt]"
+ " [--authenticate]"
+ " [--compress]"
+ " [--tunnel]"
+ " [--pfs]"
+ " \\\n "
+ " [--ikelifetime <seconds>]"
+ " [--ipseclifetime <seconds>]"
+ " \\\n "
+ " [--reykeymargin <seconds>]"
+ " [--reykeyfuzz <percentage>]"
+ " \\\n "
+ " [--keyingtries <count>]"
+ " \\\n "
+ " [--esp <esp-algos>]"
+ " \\\n "
+ " [--dontrekey]"
+
+ " [--dpdaction (none|clear|hold|restart)]"
+ " \\\n "
+ " [--dpddelay <seconds> --dpdtimeout <seconds>]"
+ " \\\n "
+ " [--initiateontraffic|--pass|--drop|--reject]"
+ " \\\n "
+ " [--failnone|--failpass|--faildrop|--failreject]"
+ "\n\n"
+ "routing: whack"
+ " (--route | --unroute)"
+ " --name <connection_name>"
+ "\n\n"
+ "initiation:"
+ "\n "
+ " whack"
+ " (--initiate | --terminate)"
+ " --name <connection_name>"
+ " [--asynchronous]"
+ "\n\n"
+ "opportunistic initiation: whack"
+ " [--tunnelipv4 | --tunnelipv6]"
+ " \\\n "
+ " --oppohere <ip-address>"
+ " --oppothere <ip-address>"
+ "\n\n"
+ "delete: whack"
+ " --delete"
+ " (--name <connection_name> | --caname <ca name>)"
+ "\n\n"
+ "deletestate: whack"
+ " --deletestate <state_object_number>"
+ " --crash <ip-address>"
+ "\n\n"
+ "pubkey: whack"
+ " --keyid <id>"
+ " [--addkey]"
+ " [--pubkeyrsa <key>]"
+ "\n\n"
+ "myid: whack"
+ " --myid <id>"
+ "\n\n"
+ "ca: whack"
+ " --caname <name>"
+ " --cacert <path>"
+ " \\\n "
+ " [--ldaphost <hostname>]"
+ " [--ldapbase <base>]"
+ " \\\n "
+ " [--crluri <uri>]"
+ " [--crluri2 <uri>]"
+ " [--ocspuri <uri>]"
+ " [--strictcrlpolicy]"
+ "\n\n"
+#ifdef DEBUG
+ "debug: whack [--name <connection_name>]"
+ " \\\n "
+ " [--debug-none]"
+ " [--debug-all]"
+ " \\\n "
+ " [--debug-raw]"
+ " [--debug-crypt]"
+ " [--debug-parsing]"
+ " [--debug-emitting]"
+ " \\\n "
+ " [--debug-control]"
+ " [--debug-lifecycle]"
+ " [--debug-klips]"
+ " [--debug-dns]"
+ " \\\n "
+ " [--debug-natt]"
+ " [--debug-oppo]"
+ " [--debug-controlmore]"
+ " [--debug-private]"
+ "\n\n"
+#endif
+ "listen: whack"
+ " (--listen | --unlisten)"
+ "\n\n"
+ "list: whack [--utc]"
+ " [--listalgs]"
+ " [--listpubkeys]"
+ " [--listcerts]"
+ " [--listcacerts]"
+ " \\\n "
+ " [--listacerts]"
+ " [--listaacerts]"
+ " [--listocspcerts]"
+ " [--listgroups]"
+ " \\\n "
+ " [--listcainfos]"
+ " [--listcrls]"
+ " [--listocsp]"
+ " [--listcards]"
+ " [--listall]"
+ "\n\n"
+ "purge: whack"
+ " [--purgeocsp]"
+ "\n\n"
+ "reread: whack"
+ " [--rereadsecrets]"
+ " [--rereadcacerts]"
+ " [--rereadaacerts]"
+ " \\\n "
+ " [--rereadocspcerts]"
+ " [--rereadacerts]"
+ " [--rereadcrls]"
+ " [--rereadall]"
+ "\n\n"
+ "status: whack"
+ " [--name <connection_name>] --status|--statusall"
+ "\n\n"
+ "scdecrypt: whack"
+ " --scencrypt|scdecrypt <value>"
+ " [--inbase <base>]"
+ " [--outbase <base>]"
+ " [--keyid <id>]"
+ "\n\n"
+ "shutdown: whack"
+ " --shutdown"
+ "\n\n"
+ "strongSwan %s\n"
+ , ipsec_version_code());
+}
+
+static const char *label = NULL; /* --label operand, saved for diagnostics */
+
+static const char *name = NULL; /* --name operand, saved for diagnostics */
+
+/* print a string as a diagnostic, then exit whack unhappily */
+static void
+diag(const char *mess)
+{
+ if (mess != NULL)
+ {
+ fprintf(stderr, "whack error: ");
+ if (label != NULL)
+ fprintf(stderr, "%s ", label);
+ if (name != NULL)
+ fprintf(stderr, "\"%s\" ", name);
+ fprintf(stderr, "%s\n", mess);
+ }
+
+ exit(RC_WHACK_PROBLEM);
+}
+
+/* conditially calls diag; prints second arg, if non-NULL, as quoted string */
+static void
+diagq(err_t ugh, const char *this)
+{
+ if (ugh != NULL)
+ {
+ if (this == NULL)
+ {
+ diag(ugh);
+ }
+ else
+ {
+ char buf[120]; /* arbitrary limit */
+
+ snprintf(buf, sizeof(buf), "%s \"%s\"", ugh, this);
+ diag(buf);
+ }
+ }
+}
+
+/* complex combined operands return one of these enumerated values
+ * Note: these become flags in an lset_t. Since there are more than
+ * 32, we partition them into:
+ * - OPT_* options (most random options)
+ * - LST_* options (list various internal data)
+ * - DBGOPT_* option (DEBUG options)
+ * - END_* options (End description options)
+ * - CD_* options (Connection Description options)
+ * - CA_* options (CA description options)
+ */
+enum {
+# define OPT_FIRST OPT_CTLBASE
+ OPT_CTLBASE,
+ OPT_NAME,
+
+ OPT_CD,
+
+ OPT_KEYID,
+ OPT_ADDKEY,
+ OPT_PUBKEYRSA,
+
+ OPT_MYID,
+
+ OPT_ROUTE,
+ OPT_UNROUTE,
+
+ OPT_INITIATE,
+ OPT_TERMINATE,
+ OPT_DELETE,
+ OPT_DELETESTATE,
+ OPT_LISTEN,
+ OPT_UNLISTEN,
+
+ OPT_PURGEOCSP,
+
+ OPT_REREADSECRETS,
+ OPT_REREADCACERTS,
+ OPT_REREADAACERTS,
+ OPT_REREADOCSPCERTS,
+ OPT_REREADACERTS,
+ OPT_REREADCRLS,
+ OPT_REREADALL,
+
+ OPT_STATUS,
+ OPT_STATUSALL,
+ OPT_SHUTDOWN,
+
+ OPT_OPPO_HERE,
+ OPT_OPPO_THERE,
+
+ OPT_ASYNC,
+ OPT_DELETECRASH,
+
+# define OPT_LAST OPT_ASYNC /* last "normal" option */
+
+/* Smartcard options */
+
+# define SC_FIRST SC_ENCRYPT /* first smartcard option */
+
+ SC_ENCRYPT,
+ SC_DECRYPT,
+ SC_INBASE,
+ SC_OUTBASE,
+
+# define SC_LAST SC_OUTBASE /* last "smartcard" option */
+
+/* List options */
+
+# define LST_FIRST LST_UTC /* first list option */
+ LST_UTC,
+ LST_ALGS,
+ LST_PUBKEYS,
+ LST_CERTS,
+ LST_CACERTS,
+ LST_ACERTS,
+ LST_AACERTS,
+ LST_OCSPCERTS,
+ LST_GROUPS,
+ LST_CAINFOS,
+ LST_CRLS,
+ LST_OCSP,
+ LST_CARDS,
+ LST_ALL,
+
+# define LST_LAST LST_ALL /* last list option */
+
+/* Connection End Description options */
+
+# define END_FIRST END_HOST /* first end description */
+ END_HOST,
+ END_ID,
+ END_CERT,
+ END_CA,
+ END_SENDCERT,
+ END_GROUPS,
+ END_IKEPORT,
+ END_NEXTHOP,
+ END_CLIENT,
+ END_CLIENTWITHIN,
+ END_CLIENTPROTOPORT,
+ END_DNSKEYONDEMAND,
+ END_SRCIP,
+ END_HOSTACCESS,
+ END_UPDOWN,
+
+#define END_LAST END_UPDOWN /* last end description*/
+
+/* Connection Description options -- segregated */
+
+# define CD_FIRST CD_TO /* first connection description */
+ CD_TO,
+
+# define CD_POLICY_FIRST CD_PSK
+ CD_PSK, /* same order as POLICY_* */
+ CD_RSASIG, /* same order as POLICY_* */
+ CD_ENCRYPT, /* same order as POLICY_* */
+ CD_AUTHENTICATE, /* same order as POLICY_* */
+ CD_COMPRESS, /* same order as POLICY_* */
+ CD_TUNNEL, /* same order as POLICY_* */
+ CD_PFS, /* same order as POLICY_* */
+ CD_DISABLEARRIVALCHECK, /* same order as POLICY_* */
+ CD_SHUNT0, /* same order as POLICY_* */
+ CD_SHUNT1, /* same order as POLICY_* */
+ CD_FAIL0, /* same order as POLICY_* */
+ CD_FAIL1, /* same order as POLICY_* */
+ CD_DONT_REKEY, /* same order as POLICY_* */
+
+ CD_TUNNELIPV4,
+ CD_TUNNELIPV6,
+ CD_CONNIPV4,
+ CD_CONNIPV6,
+
+ CD_IKELIFETIME,
+ CD_IPSECLIFETIME,
+ CD_RKMARGIN,
+ CD_RKFUZZ,
+ CD_KTRIES,
+ CD_DPDACTION,
+ CD_DPDDELAY,
+ CD_DPDTIMEOUT,
+ CD_IKE,
+ CD_PFSGROUP,
+ CD_ESP,
+
+# define CD_LAST CD_ESP /* last connection description */
+
+/* Certificate Authority (CA) description options */
+
+# define CA_FIRST CA_NAME /* first ca description */
+
+ CA_NAME,
+ CA_CERT,
+ CA_LDAPHOST,
+ CA_LDAPBASE,
+ CA_CRLURI,
+ CA_CRLURI2,
+ CA_OCSPURI,
+ CA_STRICT
+
+# define CA_LAST CA_STRICT /* last ca description */
+
+#ifdef DEBUG /* must be last so others are less than 32 to fit in lset_t */
+# define DBGOPT_FIRST DBGOPT_NONE
+ ,
+ /* NOTE: these definitions must match DBG_* and IMPAIR_* in constants.h */
+ DBGOPT_NONE,
+ DBGOPT_ALL,
+
+ DBGOPT_RAW, /* same order as DBG_* */
+ DBGOPT_CRYPT, /* same order as DBG_* */
+ DBGOPT_PARSING, /* same order as DBG_* */
+ DBGOPT_EMITTING, /* same order as DBG_* */
+ DBGOPT_CONTROL, /* same order as DBG_* */
+ DBGOPT_LIFECYCLE, /* same order as DBG_* */
+ DBGOPT_KLIPS, /* same order as DBG_* */
+ DBGOPT_DNS, /* same order as DBG_* */
+ DBGOPT_NATT, /* same order as DBG_* */
+ DBGOPT_OPPO, /* same order as DBG_* */
+ DBGOPT_CONTROLMORE, /* same order as DBG_* */
+
+ DBGOPT_PRIVATE, /* same order as DBG_* */
+
+ DBGOPT_IMPAIR_DELAY_ADNS_KEY_ANSWER, /* same order as IMPAIR_* */
+ DBGOPT_IMPAIR_DELAY_ADNS_TXT_ANSWER, /* same order as IMPAIR_* */
+ DBGOPT_IMPAIR_BUST_MI2, /* same order as IMPAIR_* */
+ DBGOPT_IMPAIR_BUST_MR2 /* same order as IMPAIR_* */
+
+# define DBGOPT_LAST DBGOPT_IMPAIR_BUST_MR2
+#endif
+
+};
+
+/* Carve up space for result from getop_long.
+ * Stupidly, the only result is an int.
+ * Numeric arg is bit immediately left of basic value.
+ *
+ */
+#define OPTION_OFFSET 256 /* to get out of the way of letter options */
+#define NUMERIC_ARG (1 << 9) /* expect a numeric argument */
+#define AUX_SHIFT 10 /* amount to shift for aux information */
+
+static const struct option long_opts[] = {
+# define OO OPTION_OFFSET
+ /* name, has_arg, flag, val */
+
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'v' },
+ { "optionsfrom", required_argument, NULL, '+' },
+ { "label", required_argument, NULL, 'l' },
+
+ { "ctlbase", required_argument, NULL, OPT_CTLBASE + OO },
+ { "name", required_argument, NULL, OPT_NAME + OO },
+
+ { "keyid", required_argument, NULL, OPT_KEYID + OO },
+ { "addkey", no_argument, NULL, OPT_ADDKEY + OO },
+ { "pubkeyrsa", required_argument, NULL, OPT_PUBKEYRSA + OO },
+
+ { "myid", required_argument, NULL, OPT_MYID + OO },
+
+ { "route", no_argument, NULL, OPT_ROUTE + OO },
+ { "unroute", no_argument, NULL, OPT_UNROUTE + OO },
+
+ { "initiate", no_argument, NULL, OPT_INITIATE + OO },
+ { "terminate", no_argument, NULL, OPT_TERMINATE + OO },
+ { "delete", no_argument, NULL, OPT_DELETE + OO },
+ { "deletestate", required_argument, NULL, OPT_DELETESTATE + OO + NUMERIC_ARG },
+ { "crash", required_argument, NULL, OPT_DELETECRASH + OO },
+ { "listen", no_argument, NULL, OPT_LISTEN + OO },
+ { "unlisten", no_argument, NULL, OPT_UNLISTEN + OO },
+
+ { "purgeocsp", no_argument, NULL, OPT_PURGEOCSP + OO },
+
+ { "rereadsecrets", no_argument, NULL, OPT_REREADSECRETS + OO },
+ { "rereadcacerts", no_argument, NULL, OPT_REREADCACERTS + OO },
+ { "rereadaacerts", no_argument, NULL, OPT_REREADAACERTS + OO },
+ { "rereadocspcerts", no_argument, NULL, OPT_REREADOCSPCERTS + OO },
+ { "rereadacerts", no_argument, NULL, OPT_REREADACERTS + OO },
+ { "rereadcrls", no_argument, NULL, OPT_REREADCRLS + OO },
+ { "rereadall", no_argument, NULL, OPT_REREADALL + OO },
+ { "status", no_argument, NULL, OPT_STATUS + OO },
+ { "statusall", no_argument, NULL, OPT_STATUSALL + OO },
+ { "shutdown", no_argument, NULL, OPT_SHUTDOWN + OO },
+
+ { "oppohere", required_argument, NULL, OPT_OPPO_HERE + OO },
+ { "oppothere", required_argument, NULL, OPT_OPPO_THERE + OO },
+
+ { "asynchronous", no_argument, NULL, OPT_ASYNC + OO },
+
+ /* smartcard options */
+
+ { "scencrypt", required_argument, NULL, SC_ENCRYPT + OO },
+ { "scdecrypt", required_argument, NULL, SC_DECRYPT + OO },
+ { "inbase", required_argument, NULL, SC_INBASE + OO },
+ { "outbase", required_argument, NULL, SC_OUTBASE + OO },
+
+ /* list options */
+
+ { "utc", no_argument, NULL, LST_UTC + OO },
+ { "listalgs", no_argument, NULL, LST_ALGS + OO },
+ { "listpubkeys", no_argument, NULL, LST_PUBKEYS + OO },
+ { "listcerts", no_argument, NULL, LST_CERTS + OO },
+ { "listcacerts", no_argument, NULL, LST_CACERTS + OO },
+ { "listacerts", no_argument, NULL, LST_ACERTS + OO },
+ { "listaacerts", no_argument, NULL, LST_AACERTS + OO },
+ { "listocspcerts", no_argument, NULL, LST_OCSPCERTS + OO },
+ { "listgroups", no_argument, NULL, LST_GROUPS + OO },
+ { "listcainfos", no_argument, NULL, LST_CAINFOS + OO },
+ { "listcrls", no_argument, NULL, LST_CRLS + OO },
+ { "listocsp", no_argument, NULL, LST_OCSP + OO },
+ { "listcards", no_argument, NULL, LST_CARDS + OO },
+ { "listall", no_argument, NULL, LST_ALL + OO },
+
+ /* options for an end description */
+
+ { "host", required_argument, NULL, END_HOST + OO },
+ { "id", required_argument, NULL, END_ID + OO },
+ { "cert", required_argument, NULL, END_CERT + OO },
+ { "ca", required_argument, NULL, END_CA + OO },
+ { "sendcert", required_argument, NULL, END_SENDCERT + OO },
+ { "groups", required_argument, NULL, END_GROUPS + OO },
+ { "ikeport", required_argument, NULL, END_IKEPORT + OO + NUMERIC_ARG },
+ { "nexthop", required_argument, NULL, END_NEXTHOP + OO },
+ { "client", required_argument, NULL, END_CLIENT + OO },
+ { "clientwithin", required_argument, NULL, END_CLIENTWITHIN + OO },
+ { "clientprotoport", required_argument, NULL, END_CLIENTPROTOPORT + OO },
+ { "dnskeyondemand", no_argument, NULL, END_DNSKEYONDEMAND + OO },
+ { "srcip", required_argument, NULL, END_SRCIP + OO },
+ { "hostaccess", no_argument, NULL, END_HOSTACCESS + OO },
+ { "updown", required_argument, NULL, END_UPDOWN + OO },
+
+ /* options for a connection description */
+
+ { "to", no_argument, NULL, CD_TO + OO },
+
+ { "psk", no_argument, NULL, CD_PSK + OO },
+ { "rsasig", no_argument, NULL, CD_RSASIG + OO },
+
+ { "encrypt", no_argument, NULL, CD_ENCRYPT + OO },
+ { "authenticate", no_argument, NULL, CD_AUTHENTICATE + OO },
+ { "compress", no_argument, NULL, CD_COMPRESS + OO },
+ { "tunnel", no_argument, NULL, CD_TUNNEL + OO },
+ { "tunnelipv4", no_argument, NULL, CD_TUNNELIPV4 + OO },
+ { "tunnelipv6", no_argument, NULL, CD_TUNNELIPV6 + OO },
+ { "pfs", no_argument, NULL, CD_PFS + OO },
+ { "disablearrivalcheck", no_argument, NULL, CD_DISABLEARRIVALCHECK + OO },
+ { "initiateontraffic", no_argument, NULL
+ , CD_SHUNT0 + (POLICY_SHUNT_TRAP >> POLICY_SHUNT_SHIFT << AUX_SHIFT) + OO },
+ { "pass", no_argument, NULL
+ , CD_SHUNT0 + (POLICY_SHUNT_PASS >> POLICY_SHUNT_SHIFT << AUX_SHIFT) + OO },
+ { "drop", no_argument, NULL
+ , CD_SHUNT0 + (POLICY_SHUNT_DROP >> POLICY_SHUNT_SHIFT << AUX_SHIFT) + OO },
+ { "reject", no_argument, NULL
+ , CD_SHUNT0 + (POLICY_SHUNT_REJECT >> POLICY_SHUNT_SHIFT << AUX_SHIFT) + OO },
+ { "failnone", no_argument, NULL
+ , CD_FAIL0 + (POLICY_FAIL_NONE >> POLICY_FAIL_SHIFT << AUX_SHIFT) + OO },
+ { "failpass", no_argument, NULL
+ , CD_FAIL0 + (POLICY_FAIL_PASS >> POLICY_FAIL_SHIFT << AUX_SHIFT) + OO },
+ { "faildrop", no_argument, NULL
+ , CD_FAIL0 + (POLICY_FAIL_DROP >> POLICY_FAIL_SHIFT << AUX_SHIFT) + OO },
+ { "failreject", no_argument, NULL
+ , CD_FAIL0 + (POLICY_FAIL_REJECT >> POLICY_FAIL_SHIFT << AUX_SHIFT) + OO },
+ { "dontrekey", no_argument, NULL, CD_DONT_REKEY + OO },
+ { "ipv4", no_argument, NULL, CD_CONNIPV4 + OO },
+ { "ipv6", no_argument, NULL, CD_CONNIPV6 + OO },
+
+ { "ikelifetime", required_argument, NULL, CD_IKELIFETIME + OO + NUMERIC_ARG },
+ { "ipseclifetime", required_argument, NULL, CD_IPSECLIFETIME + OO + NUMERIC_ARG },
+ { "rekeymargin", required_argument, NULL, CD_RKMARGIN + OO + NUMERIC_ARG },
+ { "rekeywindow", required_argument, NULL, CD_RKMARGIN + OO + NUMERIC_ARG }, /* OBSOLETE */
+ { "rekeyfuzz", required_argument, NULL, CD_RKFUZZ + OO + NUMERIC_ARG },
+ { "keyingtries", required_argument, NULL, CD_KTRIES + OO + NUMERIC_ARG },
+ { "dpdaction", required_argument, NULL, CD_DPDACTION + OO },
+ { "dpddelay", required_argument, NULL, CD_DPDDELAY + OO + NUMERIC_ARG },
+ { "dpdtimeout", required_argument, NULL, CD_DPDTIMEOUT + OO + NUMERIC_ARG },
+ { "ike", required_argument, NULL, CD_IKE + OO },
+ { "pfsgroup", required_argument, NULL, CD_PFSGROUP + OO },
+ { "esp", required_argument, NULL, CD_ESP + OO },
+
+ /* options for a ca description */
+
+ { "caname", required_argument, NULL, CA_NAME + OO },
+ { "cacert", required_argument, NULL, CA_CERT + OO },
+ { "ldaphost", required_argument, NULL, CA_LDAPHOST + OO },
+ { "ldapbase", required_argument, NULL, CA_LDAPBASE + OO },
+ { "crluri", required_argument, NULL, CA_CRLURI + OO },
+ { "crluri2", required_argument, NULL, CA_CRLURI2 + OO },
+ { "ocspuri", required_argument, NULL, CA_OCSPURI + OO },
+ { "strictcrlpolicy", no_argument, NULL, CA_STRICT + OO },
+
+#ifdef DEBUG
+ { "debug-none", no_argument, NULL, DBGOPT_NONE + OO },
+ { "debug-all]", no_argument, NULL, DBGOPT_ALL + OO },
+ { "debug-raw", no_argument, NULL, DBGOPT_RAW + OO },
+ { "debug-crypt", no_argument, NULL, DBGOPT_CRYPT + OO },
+ { "debug-parsing", no_argument, NULL, DBGOPT_PARSING + OO },
+ { "debug-emitting", no_argument, NULL, DBGOPT_EMITTING + OO },
+ { "debug-control", no_argument, NULL, DBGOPT_CONTROL + OO },
+ { "debug-lifecycle", no_argument, NULL, DBGOPT_LIFECYCLE + OO },
+ { "debug-klips", no_argument, NULL, DBGOPT_KLIPS + OO },
+ { "debug-dns", no_argument, NULL, DBGOPT_DNS + OO },
+ { "debug-natt", no_argument, NULL, DBGOPT_NATT + OO },
+ { "debug-oppo", no_argument, NULL, DBGOPT_OPPO + OO },
+ { "debug-controlmore", no_argument, NULL, DBGOPT_CONTROLMORE + OO },
+ { "debug-private", no_argument, NULL, DBGOPT_PRIVATE + OO },
+
+ { "impair-delay-adns-key-answer", no_argument, NULL, DBGOPT_IMPAIR_DELAY_ADNS_KEY_ANSWER + OO },
+ { "impair-delay-adns-txt-answer", no_argument, NULL, DBGOPT_IMPAIR_DELAY_ADNS_TXT_ANSWER + OO },
+ { "impair-bust-mi2", no_argument, NULL, DBGOPT_IMPAIR_BUST_MI2 + OO },
+ { "impair-bust-mr2", no_argument, NULL, DBGOPT_IMPAIR_BUST_MR2 + OO },
+#endif
+# undef OO
+ { 0,0,0,0 }
+};
+
+struct sockaddr_un ctl_addr = { AF_UNIX, DEFAULT_CTLBASE CTL_SUFFIX };
+
+/* helper variables and function to encode strings from whack message */
+
+static char
+ *next_str,
+ *str_roof;
+
+static bool
+pack_str(char **p)
+{
+ const char *s = *p == NULL? "" : *p; /* note: NULL becomes ""! */
+ size_t len = strlen(s) + 1;
+
+ if (str_roof - next_str < (ptrdiff_t)len)
+ {
+ return FALSE; /* fishy: no end found */
+ }
+ else
+ {
+ strcpy(next_str, s);
+ next_str += len;
+ *p = NULL; /* don't send pointers on the wire! */
+ return TRUE;
+ }
+}
+
+static void
+check_life_time(time_t life, time_t limit, const char *which
+, const whack_message_t *msg)
+{
+ time_t mint = msg->sa_rekey_margin * (100 + msg->sa_rekey_fuzz) / 100;
+
+ if (life > limit)
+ {
+ char buf[200]; /* arbitrary limit */
+
+ snprintf(buf, sizeof(buf)
+ , "%s [%lu seconds] must be less than %lu seconds"
+ , which, (unsigned long)life, (unsigned long)limit);
+ diag(buf);
+ }
+ if ((msg->policy & POLICY_DONT_REKEY) == LEMPTY && life <= mint)
+ {
+ char buf[200]; /* arbitrary limit */
+
+ snprintf(buf, sizeof(buf)
+ , "%s [%lu] must be greater than"
+ " rekeymargin*(100+rekeyfuzz)/100 [%lu*(100+%lu)/100 = %lu]"
+ , which
+ , (unsigned long)life
+ , (unsigned long)msg->sa_rekey_margin
+ , (unsigned long)msg->sa_rekey_fuzz
+ , (unsigned long)mint);
+ diag(buf);
+ }
+}
+
+static void
+clear_end(whack_end_t *e)
+{
+ zero(e);
+ e->id = NULL;
+ e->cert = NULL;
+ e->ca = NULL;
+ e->updown = NULL;
+ e->host_port = IKE_UDP_PORT;
+}
+
+static void
+update_ports(whack_message_t *m)
+{
+ int port;
+
+ if (m->left.port != 0) {
+ port = htons(m->left.port);
+ setportof(port, &m->left.host_addr);
+ setportof(port, &m->left.client.addr);
+ }
+ if (m->right.port != 0) {
+ port = htons(m->right.port);
+ setportof(port, &m->right.host_addr);
+ setportof(port, &m->right.client.addr);
+ }
+}
+
+static void
+check_end(whack_end_t *this, whack_end_t *that
+, bool default_nexthop, sa_family_t caf, sa_family_t taf)
+{
+ if (caf != addrtypeof(&this->host_addr))
+ diag("address family of host inconsistent");
+
+ if (default_nexthop)
+ {
+ if (isanyaddr(&that->host_addr))
+ diag("our nexthop must be specified when other host is a %any or %opportunistic");
+ this->host_nexthop = that->host_addr;
+ }
+
+ if (caf != addrtypeof(&this->host_nexthop))
+ diag("address family of nexthop inconsistent");
+
+ if (this->has_client)
+ {
+ if (taf != subnettypeof(&this->client))
+ diag("address family of client subnet inconsistent");
+ }
+ else
+ {
+ /* fill in anyaddr-anyaddr as (missing) client subnet */
+ ip_address cn;
+
+ diagq(anyaddr(caf, &cn), NULL);
+ diagq(rangetosubnet(&cn, &cn, &this->client), NULL);
+ }
+
+ /* fill in anyaddr if source IP is not defined */
+ if (!this->has_srcip)
+ diagq(anyaddr(caf, &this->host_srcip), optarg);
+
+ /* check protocol */
+ if (this->protocol != that->protocol)
+ diag("the protocol for leftprotoport and rightprotoport must be the same");
+}
+
+static void
+get_secret(int sock)
+{
+ const char *buf, *secret;
+ int len;
+
+ fflush(stdout);
+ usleep(20000); /* give fflush time for flushing */
+ buf = getpass("Enter: ");
+ secret = (buf == NULL)? "" : buf;
+
+ /* send the secret to pluto */
+ len = strlen(secret) + 1;
+ if (write(sock, secret, len) != len)
+ {
+ int e = errno;
+
+ fprintf(stderr, "whack: write() failed (%d %s)\n", e, strerror(e));
+ exit(RC_WHACK_PROBLEM);
+ }
+}
+
+/* This is a hack for initiating ISAKMP exchanges. */
+
+int
+main(int argc, char **argv)
+{
+ whack_message_t msg;
+ char esp_buf[256]; /* uses snprintf */
+ lset_t
+ opts_seen = LEMPTY,
+ sc_seen = LEMPTY,
+ lst_seen = LEMPTY,
+ cd_seen = LEMPTY,
+ ca_seen = LEMPTY,
+ end_seen = LEMPTY,
+ end_seen_before_to = LEMPTY;
+ const char
+ *af_used_by = NULL,
+ *tunnel_af_used_by = NULL;
+
+ /* check division of numbering space */
+#ifdef DEBUG
+ assert(OPTION_OFFSET + DBGOPT_LAST < NUMERIC_ARG);
+#else
+ assert(OPTION_OFFSET + CA_LAST < NUMERIC_ARG);
+#endif
+ assert(OPT_LAST - OPT_FIRST < (sizeof opts_seen * BITS_PER_BYTE));
+ assert(SC_LAST - SC_FIRST < (sizeof sc_seen * BITS_PER_BYTE));
+ assert(LST_LAST - LST_FIRST < (sizeof lst_seen * BITS_PER_BYTE));
+ assert(END_LAST - END_FIRST < (sizeof end_seen * BITS_PER_BYTE));
+ assert(CD_LAST - CD_FIRST < (sizeof cd_seen * BITS_PER_BYTE));
+ assert(CA_LAST - CA_FIRST < (sizeof ca_seen * BITS_PER_BYTE));
+#ifdef DEBUG /* must be last so others are less than (sizeof cd_seen * BITS_PER_BYTE) to fit in lset_t */
+ assert(DBGOPT_LAST - DBGOPT_FIRST < (sizeof cd_seen * BITS_PER_BYTE));
+#endif
+ /* check that POLICY bit assignment matches with CD_ */
+ assert(LELEM(CD_DONT_REKEY - CD_POLICY_FIRST) == POLICY_DONT_REKEY);
+
+ zero(&msg);
+
+ clear_end(&msg.right); /* left set from this after --to */
+
+ msg.name = NULL;
+ msg.keyid = NULL;
+ msg.keyval.ptr = NULL;
+ msg.esp = NULL;
+ msg.ike = NULL;
+ msg.pfsgroup = NULL;
+
+ /* if a connection is added via whack then we assume IKEv1 */
+ msg.ikev1 = TRUE;
+
+ msg.sa_ike_life_seconds = OAKLEY_ISAKMP_SA_LIFETIME_DEFAULT;
+ msg.sa_ipsec_life_seconds = PLUTO_SA_LIFE_DURATION_DEFAULT;
+ msg.sa_rekey_margin = SA_REPLACEMENT_MARGIN_DEFAULT;
+ msg.sa_rekey_fuzz = SA_REPLACEMENT_FUZZ_DEFAULT;
+ msg.sa_keying_tries = SA_REPLACEMENT_RETRIES_DEFAULT;
+
+ msg.addr_family = AF_INET;
+ msg.tunnel_addr_family = AF_INET;
+
+ msg.cacert = NULL;
+ msg.ldaphost = NULL;
+ msg.ldapbase = NULL;
+ msg.crluri = NULL;
+ msg.crluri2 = NULL;
+ msg.ocspuri = NULL;
+
+ for (;;)
+ {
+ int long_index;
+ unsigned long opt_whole = 0; /* numeric argument for some flags */
+
+ /* Note: we don't like the way short options get parsed
+ * by getopt_long, so we simply pass an empty string as
+ * the list. It could be "hp:d:c:o:eatfs" "NARXPECK".
+ */
+ int c = getopt_long(argc, argv, "", long_opts, &long_index) - OPTION_OFFSET;
+ int aux = 0;
+
+ /* decode a numeric argument, if expected */
+ if (0 <= c)
+ {
+ if (c & NUMERIC_ARG)
+ {
+ char *endptr;
+
+ c -= NUMERIC_ARG;
+ opt_whole = strtoul(optarg, &endptr, 0);
+
+ if (*endptr != '\0' || endptr == optarg)
+ diagq("badly formed numeric argument", optarg);
+ }
+ if (c >= (1 << AUX_SHIFT))
+ {
+ aux = c >> AUX_SHIFT;
+ c -= aux << AUX_SHIFT;
+ }
+ }
+
+ /* per-class option processing */
+ if (0 <= c && c <= OPT_LAST)
+ {
+ /* OPT_* options get added to opts_seen.
+ * Reject repeated options (unless later code intervenes).
+ */
+ lset_t f = LELEM(c);
+
+ if (opts_seen & f)
+ diagq("duplicated flag", long_opts[long_index].name);
+ opts_seen |= f;
+ }
+ else if (SC_FIRST <= c && c <= SC_LAST)
+ {
+ /* SC_* options get added to sc_seen.
+ * Reject repeated options (unless later code intervenes).
+ */
+ lset_t f = LELEM(c - SC_FIRST);
+
+ if (sc_seen & f)
+ diagq("duplicated flag", long_opts[long_index].name);
+ sc_seen |= f;
+ }
+ else if (LST_FIRST <= c && c <= LST_LAST)
+ {
+ /* LST_* options get added to lst_seen.
+ * Reject repeated options (unless later code intervenes).
+ */
+ lset_t f = LELEM(c - LST_FIRST);
+
+ if (lst_seen & f)
+ diagq("duplicated flag", long_opts[long_index].name);
+ lst_seen |= f;
+ }
+#ifdef DEBUG
+ else if (DBGOPT_FIRST <= c && c <= DBGOPT_LAST)
+ {
+ msg.whack_options = TRUE;
+ }
+#endif
+ else if (END_FIRST <= c && c <= END_LAST)
+ {
+ /* END_* options are added to end_seen.
+ * Reject repeated options (unless later code intervenes).
+ */
+ lset_t f = LELEM(c - END_FIRST);
+
+ if (end_seen & f)
+ diagq("duplicated flag", long_opts[long_index].name);
+ end_seen |= f;
+ opts_seen |= LELEM(OPT_CD);
+ }
+ else if (CD_FIRST <= c && c <= CD_LAST)
+ {
+ /* CD_* options are added to cd_seen.
+ * Reject repeated options (unless later code intervenes).
+ */
+ lset_t f = LELEM(c - CD_FIRST);
+
+ if (cd_seen & f)
+ diagq("duplicated flag", long_opts[long_index].name);
+ cd_seen |= f;
+ opts_seen |= LELEM(OPT_CD);
+ }
+ else if (CA_FIRST <= c && c <= CA_LAST)
+ {
+ /* CA_* options are added to ca_seen.
+ * Reject repeated options (unless later code intervenes).
+ */
+ lset_t f = LELEM(c - CA_FIRST);
+
+ if (ca_seen & f)
+ diagq("duplicated flag", long_opts[long_index].name);
+ ca_seen |= f;
+ }
+
+ /* Note: "break"ing from switch terminates loop.
+ * most cases should end with "continue".
+ */
+ switch (c)
+ {
+ case EOF - OPTION_OFFSET: /* end of flags */
+ break;
+
+ case 0 - OPTION_OFFSET: /* long option already handled */
+ continue;
+
+ case ':' - OPTION_OFFSET: /* diagnostic already printed by getopt_long */
+ case '?' - OPTION_OFFSET: /* diagnostic already printed by getopt_long */
+ diag(NULL); /* print no additional diagnostic, but exit sadly */
+ break; /* not actually reached */
+
+ case 'h' - OPTION_OFFSET: /* --help */
+ help();
+ return 0; /* GNU coding standards say to stop here */
+
+ case 'v' - OPTION_OFFSET: /* --version */
+ {
+ const char **sp = ipsec_copyright_notice();
+
+ printf("%s\n", ipsec_version_string());
+ for (; *sp != NULL; sp++)
+ puts(*sp);
+ }
+ return 0; /* GNU coding standards say to stop here */
+
+ case 'l' - OPTION_OFFSET: /* --label <string> */
+ label = optarg; /* remember for diagnostics */
+ continue;
+
+ case '+' - OPTION_OFFSET: /* --optionsfrom <filename> */
+ optionsfrom(optarg, &argc, &argv, optind, stderr);
+ /* does not return on error */
+ continue;
+
+ /* the rest of the options combine in complex ways */
+
+ case OPT_CTLBASE: /* --port <ctlbase> */
+ if (snprintf(ctl_addr.sun_path, sizeof(ctl_addr.sun_path)
+ , "%s%s", optarg, CTL_SUFFIX) == -1)
+ diag("<ctlbase>" CTL_SUFFIX " must be fit in a sun_addr");
+ continue;
+
+ case OPT_NAME: /* --name <connection-name> */
+ name = optarg;
+ msg.name = optarg;
+ continue;
+
+ case OPT_KEYID: /* --keyid <identity> */
+ msg.whack_key = !msg.whack_sc_op;
+ msg.keyid = optarg; /* decoded by Pluto */
+ continue;
+
+ case OPT_MYID: /* --myid <identity> */
+ msg.whack_myid = TRUE;
+ msg.myid = optarg; /* decoded by Pluto */
+ continue;
+
+ case OPT_ADDKEY: /* --addkey */
+ msg.whack_addkey = TRUE;
+ continue;
+
+ case OPT_PUBKEYRSA: /* --pubkeyrsa <key> */
+ {
+ static char keyspace[RSA_MAX_ENCODING_BYTES]; /* room for 8K bit key */
+ char diag_space[TTODATAV_BUF];
+ const char *ugh = ttodatav(optarg, 0, 0
+ , keyspace, sizeof(keyspace)
+ , &msg.keyval.len, diag_space, sizeof(diag_space)
+ , TTODATAV_SPACECOUNTS);
+
+ if (ugh != NULL)
+ {
+ char ugh_space[80]; /* perhaps enough space */
+
+ snprintf(ugh_space, sizeof(ugh_space)
+ , "RSA public-key data malformed (%s)", ugh);
+ diagq(ugh_space, optarg);
+ }
+ msg.pubkey_alg = PUBKEY_ALG_RSA;
+ msg.keyval.ptr = keyspace;
+ }
+ continue;
+
+ case OPT_ROUTE: /* --route */
+ msg.whack_route = TRUE;
+ continue;
+
+ case OPT_UNROUTE: /* --unroute */
+ msg.whack_unroute = TRUE;
+ continue;
+
+ case OPT_INITIATE: /* --initiate */
+ msg.whack_initiate = TRUE;
+ continue;
+
+ case OPT_TERMINATE: /* --terminate */
+ msg.whack_terminate = TRUE;
+ continue;
+
+ case OPT_DELETE: /* --delete */
+ msg.whack_delete = TRUE;
+ continue;
+
+ case OPT_DELETESTATE: /* --deletestate <state_object_number> */
+ msg.whack_deletestate = TRUE;
+ msg.whack_deletestateno = opt_whole;
+ continue;
+
+ case OPT_DELETECRASH: /* --crash <ip-address> */
+ msg.whack_crash = TRUE;
+ tunnel_af_used_by = long_opts[long_index].name;
+ diagq(ttoaddr(optarg, 0, msg.tunnel_addr_family, &msg.whack_crash_peer), optarg);
+ if (isanyaddr(&msg.whack_crash_peer))
+ diagq("0.0.0.0 or 0::0 isn't a valid client address", optarg);
+ continue;
+
+ case OPT_LISTEN: /* --listen */
+ msg.whack_listen = TRUE;
+ continue;
+
+ case OPT_UNLISTEN: /* --unlisten */
+ msg.whack_unlisten = TRUE;
+ continue;
+
+ case OPT_PURGEOCSP: /* --purgeocsp */
+ msg.whack_purgeocsp = TRUE;
+ continue;
+
+ case OPT_REREADSECRETS: /* --rereadsecrets */
+ case OPT_REREADCACERTS: /* --rereadcacerts */
+ case OPT_REREADAACERTS: /* --rereadaacerts */
+ case OPT_REREADOCSPCERTS: /* --rereadocspcerts */
+ case OPT_REREADACERTS: /* --rereadacerts */
+ case OPT_REREADCRLS: /* --rereadcrls */
+ msg.whack_reread |= LELEM(c-OPT_REREADSECRETS);
+ continue;
+
+ case OPT_REREADALL: /* --rereadall */
+ msg.whack_reread = REREAD_ALL;
+ continue;
+
+ case OPT_STATUSALL: /* --statusall */
+ msg.whack_statusall = TRUE;
+
+ case OPT_STATUS: /* --status */
+ msg.whack_status = TRUE;
+ continue;
+
+ case OPT_SHUTDOWN: /* --shutdown */
+ msg.whack_shutdown = TRUE;
+ continue;
+
+ case OPT_OPPO_HERE: /* --oppohere <ip-address> */
+ tunnel_af_used_by = long_opts[long_index].name;
+ diagq(ttoaddr(optarg, 0, msg.tunnel_addr_family, &msg.oppo_my_client), optarg);
+ if (isanyaddr(&msg.oppo_my_client))
+ diagq("0.0.0.0 or 0::0 isn't a valid client address", optarg);
+ continue;
+
+ case OPT_OPPO_THERE: /* --oppohere <ip-address> */
+ tunnel_af_used_by = long_opts[long_index].name;
+ diagq(ttoaddr(optarg, 0, msg.tunnel_addr_family, &msg.oppo_peer_client), optarg);
+ if (isanyaddr(&msg.oppo_peer_client))
+ diagq("0.0.0.0 or 0::0 isn't a valid client address", optarg);
+ continue;
+
+ case OPT_ASYNC:
+ msg.whack_async = TRUE;
+ continue;
+
+ /* Smartcard options */
+
+ case SC_ENCRYPT: /* --scencrypt <plaintext data> */
+ case SC_DECRYPT: /* --scdecrypt <encrypted data> */
+ msg.whack_sc_op = 1 + c - SC_ENCRYPT;
+ msg.whack_key = FALSE;
+ msg.sc_data = optarg;
+ continue;
+
+ case SC_INBASE: /* --inform <format> */
+ case SC_OUTBASE: /* --outform <format> */
+ {
+ int base = 0;
+
+ if (streq(optarg, "16") || strcaseeq(optarg, "hex"))
+ base = 16;
+ else if (streq(optarg, "64") || strcaseeq(optarg, "base64"))
+ base = 64;
+ else if (streq(optarg, "256") || strcaseeq(optarg, "text")
+ || strcaseeq(optarg, "ascii"))
+ base = 256;
+ else
+ diagq("not a valid base", optarg);
+
+ if (c == SC_INBASE)
+ msg.inbase = base;
+ else
+ msg.outbase = base;
+ }
+ continue;
+
+ /* List options */
+
+ case LST_UTC: /* --utc */
+ msg.whack_utc = TRUE;
+ continue;
+
+ case LST_ALGS: /* --listalgs */
+ case LST_PUBKEYS: /* --listpubkeys */
+ case LST_CERTS: /* --listcerts */
+ case LST_CACERTS: /* --listcacerts */
+ case LST_ACERTS: /* --listacerts */
+ case LST_AACERTS: /* --listaacerts */
+ case LST_OCSPCERTS: /* --listocspcerts */
+ case LST_GROUPS: /* --listgroups */
+ case LST_CAINFOS: /* --listcainfos */
+ case LST_CRLS: /* --listcrls */
+ case LST_OCSP: /* --listocsp */
+ case LST_CARDS: /* --listcards */
+ msg.whack_list |= LELEM(c - LST_ALGS);
+ continue;
+
+ case LST_ALL: /* --listall */
+ msg.whack_list = LIST_ALL;
+ continue;
+
+ /* Connection Description options */
+
+ case END_HOST: /* --host <ip-address> */
+ {
+ lset_t new_policy = LEMPTY;
+
+ af_used_by = long_opts[long_index].name;
+ diagq(anyaddr(msg.addr_family, &msg.right.host_addr), optarg);
+ if (streq(optarg, "%any"))
+ {
+ }
+ else if (streq(optarg, "%opportunistic"))
+ {
+ /* always use tunnel mode; mark as opportunistic */
+ new_policy |= POLICY_TUNNEL | POLICY_OPPO;
+ }
+ else if (streq(optarg, "%group"))
+ {
+ /* always use tunnel mode; mark as group */
+ new_policy |= POLICY_TUNNEL | POLICY_GROUP;
+ }
+ else if (streq(optarg, "%opportunisticgroup"))
+ {
+ /* always use tunnel mode; mark as opportunistic */
+ new_policy |= POLICY_TUNNEL | POLICY_OPPO | POLICY_GROUP;
+ }
+ else
+ {
+ diagq(ttoaddr(optarg, 0, msg.addr_family
+ , &msg.right.host_addr), optarg);
+ }
+
+ msg.policy |= new_policy;
+
+ if (new_policy & (POLICY_OPPO | POLICY_GROUP))
+ {
+ if (!LHAS(end_seen, END_CLIENT - END_FIRST))
+ {
+ /* set host to 0.0.0 and --client to 0.0.0.0/0
+ * or IPV6 equivalent
+ */
+ ip_address any;
+
+ tunnel_af_used_by = optarg;
+ diagq(anyaddr(msg.tunnel_addr_family, &any), optarg);
+ diagq(initsubnet(&any, 0, '0', &msg.right.client), optarg);
+ }
+ msg.right.has_client = TRUE;
+ }
+ if (new_policy & POLICY_GROUP)
+ {
+ /* client subnet must not be specified by user:
+ * it will come from the group's file.
+ */
+ if (LHAS(end_seen, END_CLIENT - END_FIRST))
+ diag("--host %group clashes with --client");
+
+ end_seen |= LELEM(END_CLIENT - END_FIRST);
+ }
+ if (new_policy & POLICY_OPPO)
+ msg.right.key_from_DNS_on_demand = TRUE;
+ continue;
+ }
+ case END_ID: /* --id <identity> */
+ msg.right.id = optarg; /* decoded by Pluto */
+ continue;
+
+ case END_CERT: /* --cert <path> */
+ msg.right.cert = optarg; /* decoded by Pluto */
+ continue;
+
+ case END_CA: /* --ca <distinguished name> */
+ msg.right.ca = optarg; /* decoded by Pluto */
+ continue;
+
+ case END_SENDCERT:
+ if (streq(optarg, "yes") || streq(optarg, "always"))
+ {
+ msg.right.sendcert = CERT_ALWAYS_SEND;
+ }
+ else if (streq(optarg, "no") || streq(optarg, "never"))
+ {
+ msg.right.sendcert = CERT_NEVER_SEND;
+ }
+ else if (streq(optarg, "ifasked"))
+ {
+ msg.right.sendcert = CERT_SEND_IF_ASKED;
+ }
+ else
+ {
+ diagq("whack sendcert value is not legal", optarg);
+ }
+ continue;
+
+ case END_GROUPS:/* --groups <access control groups> */
+ msg.right.groups = optarg; /* decoded by Pluto */
+ continue;
+
+ case END_IKEPORT: /* --ikeport <port-number> */
+ if (opt_whole<=0 || opt_whole >= 0x10000)
+ diagq("<port-number> must be a number between 1 and 65535", optarg);
+ msg.right.host_port = opt_whole;
+ continue;
+
+ case END_NEXTHOP: /* --nexthop <ip-address> */
+ af_used_by = long_opts[long_index].name;
+ if (streq(optarg, "%direct"))
+ diagq(anyaddr(msg.addr_family
+ , &msg.right.host_nexthop), optarg);
+ else
+ diagq(ttoaddr(optarg, 0, msg.addr_family
+ , &msg.right.host_nexthop), optarg);
+ continue;
+
+ case END_SRCIP: /* --srcip <ip-address> */
+ af_used_by = long_opts[long_index].name;
+ if (streq(optarg, "%modeconfig") || streq(optarg, "%modecfg"))
+ {
+ msg.right.modecfg = TRUE;
+ }
+ else
+ {
+ diagq(ttoaddr(optarg, 0, msg.addr_family
+ , &msg.right.host_srcip), optarg);
+ msg.right.has_srcip = TRUE;
+ }
+ msg.policy |= POLICY_TUNNEL; /* srcip => tunnel */
+ continue;
+
+ case END_CLIENT: /* --client <subnet> */
+ if (end_seen & LELEM(END_CLIENTWITHIN - END_FIRST))
+ diag("--client conflicts with --clientwithin");
+ tunnel_af_used_by = long_opts[long_index].name;
+ if ((strlen(optarg) >= 6 && strncmp(optarg,"vhost:",6) == 0)
+ || (strlen(optarg) >= 5 && strncmp(optarg,"vnet:",5) == 0))
+ {
+ msg.right.virt = optarg;
+ }
+ else
+ {
+ diagq(ttosubnet(optarg, 0, msg.tunnel_addr_family, &msg.right.client), optarg);
+ msg.right.has_client = TRUE;
+ }
+ msg.policy |= POLICY_TUNNEL; /* client => tunnel */
+ continue;
+
+ case END_CLIENTWITHIN: /* --clienwithin <address range> */
+ if (end_seen & LELEM(END_CLIENT - END_FIRST))
+ diag("--clientwithin conflicts with --client");
+ tunnel_af_used_by = long_opts[long_index].name;
+ diagq(ttosubnet(optarg, 0, msg.tunnel_addr_family, &msg.right.client), optarg);
+ msg.right.has_client = TRUE;
+ msg.policy |= POLICY_TUNNEL; /* client => tunnel */
+ msg.right.has_client_wildcard = TRUE;
+ continue;
+
+ case END_CLIENTPROTOPORT: /* --clientprotoport <protocol>/<port> */
+ diagq(ttoprotoport(optarg, 0, &msg.right.protocol, &msg.right.port
+ , &msg.right.has_port_wildcard), optarg);
+ continue;
+
+ case END_DNSKEYONDEMAND: /* --dnskeyondemand */
+ msg.right.key_from_DNS_on_demand = TRUE;
+ continue;
+
+ case END_HOSTACCESS: /* --hostaccess */
+ msg.right.hostaccess = TRUE;
+ continue;
+
+ case END_UPDOWN: /* --updown <updown> */
+ msg.right.updown = optarg;
+ continue;
+
+ case CD_TO: /* --to */
+ /* process right end, move it to left, reset it */
+ if (!LHAS(end_seen, END_HOST - END_FIRST))
+ diag("connection missing --host before --to");
+ msg.left = msg.right;
+ clear_end(&msg.right);
+ end_seen_before_to = end_seen;
+ end_seen = LEMPTY;
+ continue;
+
+ case CD_PSK: /* --psk */
+ case CD_RSASIG: /* --rsasig */
+ case CD_ENCRYPT: /* --encrypt */
+ case CD_AUTHENTICATE: /* --authenticate */
+ case CD_COMPRESS: /* --compress */
+ case CD_TUNNEL: /* --tunnel */
+ case CD_PFS: /* --pfs */
+ case CD_DISABLEARRIVALCHECK: /* --disablearrivalcheck */
+ case CD_DONT_REKEY: /* --donotrekey */
+ msg.policy |= LELEM(c - CD_POLICY_FIRST);
+ continue;
+
+ /* --initiateontraffic
+ * --pass
+ * --drop
+ * --reject
+ */
+ case CD_SHUNT0:
+ msg.policy = (msg.policy & ~POLICY_SHUNT_MASK)
+ | ((lset_t)aux << POLICY_SHUNT_SHIFT);
+ continue;
+
+ /* --failnone
+ * --failpass
+ * --faildrop
+ * --failreject
+ */
+ case CD_FAIL0:
+ msg.policy = (msg.policy & ~POLICY_FAIL_MASK)
+ | ((lset_t)aux << POLICY_FAIL_SHIFT);
+ continue;
+
+ case CD_IKELIFETIME: /* --ikelifetime <seconds> */
+ msg.sa_ike_life_seconds = opt_whole;
+ continue;
+
+ case CD_IPSECLIFETIME: /* --ipseclifetime <seconds> */
+ msg.sa_ipsec_life_seconds = opt_whole;
+ continue;
+
+ case CD_RKMARGIN: /* --rekeymargin <seconds> */
+ msg.sa_rekey_margin = opt_whole;
+ continue;
+
+ case CD_RKFUZZ: /* --rekeyfuzz <percentage> */
+ msg.sa_rekey_fuzz = opt_whole;
+ continue;
+
+ case CD_KTRIES: /* --keyingtries <count> */
+ msg.sa_keying_tries = opt_whole;
+ continue;
+
+ case CD_DPDACTION:
+ if (streq(optarg, "none"))
+ msg.dpd_action = DPD_ACTION_NONE;
+ else if (streq(optarg, "clear"))
+ msg.dpd_action = DPD_ACTION_CLEAR;
+ else if (streq(optarg, "hold"))
+ msg.dpd_action = DPD_ACTION_HOLD;
+ else if (streq(optarg, "restart"))
+ msg.dpd_action = DPD_ACTION_RESTART;
+ else
+ msg.dpd_action = DPD_ACTION_UNKNOWN;
+ continue;
+
+ case CD_DPDDELAY:
+ msg.dpd_delay = opt_whole;
+ continue;
+
+ case CD_DPDTIMEOUT:
+ msg.dpd_timeout = opt_whole;
+ continue;
+
+ case CD_IKE: /* --ike <ike_alg1,ike_alg2,...> */
+ msg.ike = optarg;
+ continue;
+
+ case CD_PFSGROUP: /* --pfsgroup modpXXXX */
+ msg.pfsgroup = optarg;
+ continue;
+
+ case CD_ESP: /* --esp <esp_alg1,esp_alg2,...> */
+ msg.esp = optarg;
+ continue;
+
+ case CD_CONNIPV4:
+ if (LHAS(cd_seen, CD_CONNIPV6 - CD_FIRST))
+ diag("--ipv4 conflicts with --ipv6");
+
+ /* Since this is the default, the flag is redundant.
+ * So we don't need to set msg.addr_family
+ * and we don't need to check af_used_by
+ * and we don't have to consider defaulting tunnel_addr_family.
+ */
+ continue;
+
+ case CD_CONNIPV6:
+ if (LHAS(cd_seen, CD_CONNIPV4 - CD_FIRST))
+ diag("--ipv6 conflicts with --ipv4");
+
+ if (af_used_by != NULL)
+ diagq("--ipv6 must precede", af_used_by);
+
+ af_used_by = long_opts[long_index].name;
+ msg.addr_family = AF_INET6;
+
+ /* Consider defaulting tunnel_addr_family to AF_INET6.
+ * Do so only if it hasn't yet been specified or used.
+ */
+ if (LDISJOINT(cd_seen, LELEM(CD_TUNNELIPV4 - CD_FIRST) | LELEM(CD_TUNNELIPV6 - CD_FIRST))
+ && tunnel_af_used_by == NULL)
+ msg.tunnel_addr_family = AF_INET6;
+ continue;
+
+ case CD_TUNNELIPV4:
+ if (LHAS(cd_seen, CD_TUNNELIPV6 - CD_FIRST))
+ diag("--tunnelipv4 conflicts with --tunnelipv6");
+
+ if (tunnel_af_used_by != NULL)
+ diagq("--tunnelipv4 must precede", af_used_by);
+
+ msg.tunnel_addr_family = AF_INET;
+ continue;
+
+ case CD_TUNNELIPV6:
+ if (LHAS(cd_seen, CD_TUNNELIPV4 - CD_FIRST))
+ diag("--tunnelipv6 conflicts with --tunnelipv4");
+
+ if (tunnel_af_used_by != NULL)
+ diagq("--tunnelipv6 must precede", af_used_by);
+
+ msg.tunnel_addr_family = AF_INET6;
+ continue;
+
+ case CA_NAME: /* --caname <name> */
+ msg.name = optarg;
+ msg.whack_ca = TRUE;
+ continue;
+ case CA_CERT: /* --cacert <path> */
+ msg.cacert = optarg;
+ continue;
+ case CA_LDAPHOST: /* --ldaphost <hostname> */
+ msg.ldaphost = optarg;
+ continue;
+ case CA_LDAPBASE: /* --ldapbase <base> */
+ msg.ldapbase = optarg;
+ continue;
+ case CA_CRLURI: /* --crluri <uri> */
+ msg.crluri = optarg;
+ continue;
+ case CA_CRLURI2: /* --crluri2 <uri> */
+ msg.crluri2 = optarg;
+ continue;
+ case CA_OCSPURI: /* --ocspuri <uri> */
+ msg.ocspuri = optarg;
+ continue;
+ case CA_STRICT: /* --strictcrlpolicy */
+ msg.whack_strict = TRUE;
+ continue;
+
+#ifdef DEBUG
+ case DBGOPT_NONE: /* --debug-none */
+ msg.debugging = DBG_NONE;
+ continue;
+
+ case DBGOPT_ALL: /* --debug-all */
+ msg.debugging |= DBG_ALL; /* note: does not include PRIVATE */
+ continue;
+
+ case DBGOPT_RAW: /* --debug-raw */
+ case DBGOPT_CRYPT: /* --debug-crypt */
+ case DBGOPT_PARSING: /* --debug-parsing */
+ case DBGOPT_EMITTING: /* --debug-emitting */
+ case DBGOPT_CONTROL: /* --debug-control */
+ case DBGOPT_LIFECYCLE: /* --debug-lifecycle */
+ case DBGOPT_KLIPS: /* --debug-klips */
+ case DBGOPT_DNS: /* --debug-dns */
+ case DBGOPT_NATT: /* --debug-natt */
+ case DBGOPT_OPPO: /* --debug-oppo */
+ case DBGOPT_CONTROLMORE: /* --debug-controlmore */
+ case DBGOPT_PRIVATE: /* --debug-private */
+ case DBGOPT_IMPAIR_DELAY_ADNS_KEY_ANSWER: /* --impair-delay-adns-key-answer */
+ case DBGOPT_IMPAIR_DELAY_ADNS_TXT_ANSWER: /* --impair-delay-adns-txt-answer */
+ case DBGOPT_IMPAIR_BUST_MI2: /* --impair_bust_mi2 */
+ case DBGOPT_IMPAIR_BUST_MR2: /* --impair_bust_mr2 */
+ msg.debugging |= LELEM(c-DBGOPT_RAW);
+ continue;
+#endif
+ default:
+ assert(FALSE); /* unknown return value */
+ }
+ break;
+ }
+
+ if (optind != argc)
+ {
+ /* If you see this message unexpectedly, perhaps the
+ * case for the previous option ended with "break"
+ * instead of "continue"
+ */
+ diagq("unexpected argument", argv[optind]);
+ }
+
+ /* For each possible form of the command, figure out if an argument
+ * suggests whether that form was intended, and if so, whether all
+ * required information was supplied.
+ */
+
+ /* check opportunistic initiation simulation request */
+ switch (opts_seen & (LELEM(OPT_OPPO_HERE) | LELEM(OPT_OPPO_THERE)))
+ {
+ case LELEM(OPT_OPPO_HERE):
+ case LELEM(OPT_OPPO_THERE):
+ diag("--oppohere and --oppothere must be used together");
+ /*NOTREACHED*/
+ case LELEM(OPT_OPPO_HERE) | LELEM(OPT_OPPO_THERE):
+ msg.whack_oppo_initiate = TRUE;
+ if (LIN(cd_seen, LELEM(CD_TUNNELIPV4 - CD_FIRST) | LELEM(CD_TUNNELIPV6 - CD_FIRST)))
+ opts_seen &= ~LELEM(OPT_CD);
+ break;
+ }
+
+ /* check connection description */
+ if (LHAS(opts_seen, OPT_CD))
+ {
+ if (!LHAS(cd_seen, CD_TO-CD_FIRST))
+ diag("connection description option, but no --to");
+
+ if (!LHAS(end_seen, END_HOST-END_FIRST))
+ diag("connection missing --host after --to");
+
+ if (isanyaddr(&msg.left.host_addr)
+ && isanyaddr(&msg.right.host_addr))
+ diag("hosts cannot both be 0.0.0.0 or 0::0");
+
+ if (msg.policy & POLICY_OPPO)
+ {
+ if ((msg.policy & (POLICY_PSK | POLICY_RSASIG)) != POLICY_RSASIG)
+ diag("only RSASIG is supported for opportunism");
+ if ((msg.policy & POLICY_PFS) == 0)
+ diag("PFS required for opportunism");
+ if ((msg.policy & POLICY_ENCRYPT) == 0)
+ diag("encryption required for opportunism");
+ }
+
+ check_end(&msg.left, &msg.right, !LHAS(end_seen_before_to, END_NEXTHOP-END_FIRST)
+ , msg.addr_family, msg.tunnel_addr_family);
+
+ check_end(&msg.right, &msg.left, !LHAS(end_seen, END_NEXTHOP-END_FIRST)
+ , msg.addr_family, msg.tunnel_addr_family);
+
+ if (subnettypeof(&msg.left.client) != subnettypeof(&msg.right.client))
+ diag("endpoints clash: one is IPv4 and the other is IPv6");
+
+ if (NEVER_NEGOTIATE(msg.policy))
+ {
+ /* we think this is just a shunt (because he didn't specify
+ * a host authentication method). If he didn't specify a
+ * shunt type, he's probably gotten it wrong.
+ */
+ if ((msg.policy & POLICY_SHUNT_MASK) == POLICY_SHUNT_TRAP)
+ diag("non-shunt connection must have --psk or --rsasig or both");
+ }
+ else
+ {
+ /* not just a shunt: a real ipsec connection */
+ if ((msg.policy & POLICY_ID_AUTH_MASK) == LEMPTY)
+ diag("must specify --rsasig or --psk for a connection");
+
+ if (!HAS_IPSEC_POLICY(msg.policy)
+ && (msg.left.has_client || msg.right.has_client))
+ diag("must not specify clients for ISAKMP-only connection");
+ }
+
+ msg.whack_connection = TRUE;
+ }
+
+ /* decide whether --name is mandatory or forbidden */
+ if (!LDISJOINT(opts_seen
+ , LELEM(OPT_ROUTE) | LELEM(OPT_UNROUTE)
+ | LELEM(OPT_INITIATE) | LELEM(OPT_TERMINATE)
+ | LELEM(OPT_DELETE) | LELEM(OPT_CD)))
+ {
+ if (!LHAS(opts_seen, OPT_NAME) && !msg.whack_ca)
+ diag("missing --name <connection_name>");
+ }
+ else if (!msg.whack_options && !msg.whack_status)
+ {
+ if (LHAS(opts_seen, OPT_NAME))
+ diag("no reason for --name");
+ }
+
+ if (!LDISJOINT(opts_seen, LELEM(OPT_PUBKEYRSA) | LELEM(OPT_ADDKEY)))
+ {
+ if (!LHAS(opts_seen, OPT_KEYID))
+ diag("--addkey and --pubkeyrsa require --keyid");
+ }
+
+ if (!(msg.whack_connection || msg.whack_key || msg.whack_myid
+ || msg.whack_delete || msg.whack_deletestate
+ || msg.whack_initiate || msg.whack_oppo_initiate || msg.whack_terminate
+ || msg.whack_route || msg.whack_unroute || msg.whack_listen
+ || msg.whack_unlisten || msg.whack_list || msg.whack_purgeocsp || msg.whack_reread
+ || msg.whack_ca || msg.whack_status || msg.whack_options || msg.whack_shutdown
+ || msg.whack_sc_op))
+ {
+ diag("no action specified; try --help for hints");
+ }
+
+ update_ports(&msg);
+
+ /* tricky quick and dirty check for wild values */
+ if (msg.sa_rekey_margin != 0
+ && msg.sa_rekey_fuzz * msg.sa_rekey_margin * 4 / msg.sa_rekey_margin / 4
+ != msg.sa_rekey_fuzz)
+ diag("rekeymargin or rekeyfuzz values are so large that they cause oveflow");
+
+ check_life_time (msg.sa_ike_life_seconds, OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM
+ , "ikelifetime", &msg);
+
+ check_life_time(msg.sa_ipsec_life_seconds, SA_LIFE_DURATION_MAXIMUM
+ , "ipseclifetime", &msg);
+
+ if (msg.dpd_action == DPD_ACTION_UNKNOWN)
+ diag("dpdaction must be \"none\", \"clear\", \"hold\" or \"restart\"");
+
+ if (msg.dpd_action != DPD_ACTION_NONE)
+ {
+ if (msg.dpd_delay <= 0)
+ diag("dpddelay must be larger than zero");
+
+ if (msg.dpd_timeout <= 0)
+ diag("dpdtimeout must be larger than zero");
+
+ if (msg.dpd_timeout <= msg.dpd_delay)
+ diag("dpdtimeout must be larger than dpddelay");
+ }
+
+ /* pack strings for inclusion in message */
+ next_str = msg.string;
+ str_roof = &msg.string[sizeof(msg.string)];
+
+ /* build esp message as esp="<esp>;<pfsgroup>" */
+ if (msg.pfsgroup) {
+ snprintf(esp_buf, sizeof (esp_buf), "%s;%s",
+ msg.esp ? msg.esp : "",
+ msg.pfsgroup ? msg.pfsgroup : "");
+ msg.esp=esp_buf;
+ }
+ if (!pack_str(&msg.name) /* string 1 */
+ || !pack_str(&msg.left.id) /* string 2 */
+ || !pack_str(&msg.left.cert) /* string 3 */
+ || !pack_str(&msg.left.ca) /* string 4 */
+ || !pack_str(&msg.left.groups) /* string 5 */
+ || !pack_str(&msg.left.updown) /* string 6 */
+ || !pack_str(&msg.left.virt) /* string 7 */
+ || !pack_str(&msg.right.id) /* string 8 */
+ || !pack_str(&msg.right.cert) /* string 9 */
+ || !pack_str(&msg.right.ca) /* string 10 */
+ || !pack_str(&msg.right.groups) /* string 11 */
+ || !pack_str(&msg.right.updown) /* string 12 */
+ || !pack_str(&msg.right.virt) /* string 13 */
+ || !pack_str(&msg.keyid) /* string 14 */
+ || !pack_str(&msg.myid) /* string 15 */
+ || !pack_str(&msg.cacert) /* string 16 */
+ || !pack_str(&msg.ldaphost) /* string 17 */
+ || !pack_str(&msg.ldapbase) /* string 18 */
+ || !pack_str(&msg.crluri) /* string 19 */
+ || !pack_str(&msg.crluri2) /* string 20 */
+ || !pack_str(&msg.ocspuri) /* string 21 */
+ || !pack_str(&msg.ike) /* string 22 */
+ || !pack_str(&msg.esp) /* string 23 */
+ || !pack_str(&msg.sc_data) /* string 24 */
+ || str_roof - next_str < (ptrdiff_t)msg.keyval.len) /* chunk (sort of string 5) */
+ diag("too many bytes of strings to fit in message to pluto");
+
+ memcpy(next_str, msg.keyval.ptr, msg.keyval.len);
+ msg.keyval.ptr = NULL;
+ next_str += msg.keyval.len;
+
+ msg.magic = ((opts_seen & ~LELEM(OPT_SHUTDOWN))
+ | sc_seen | lst_seen | cd_seen | ca_seen) != LEMPTY
+ || msg.whack_options
+ ? WHACK_MAGIC : WHACK_BASIC_MAGIC;
+
+ /* send message to Pluto */
+ if (access(ctl_addr.sun_path, R_OK | W_OK) < 0)
+ {
+ int e = errno;
+
+ switch (e)
+ {
+ case EACCES:
+ fprintf(stderr, "whack: no right to communicate with pluto (access(\"%s\"))\n"
+ , ctl_addr.sun_path);
+ break;
+ case ENOENT:
+ fprintf(stderr, "whack: Pluto is not running (no \"%s\")\n"
+ , ctl_addr.sun_path);
+ break;
+ default:
+ fprintf(stderr, "whack: access(\"%s\") failed with %d %s\n"
+ , ctl_addr.sun_path, errno, strerror(e));
+ break;
+ }
+ exit(RC_WHACK_PROBLEM);
+ }
+ else
+ {
+ int sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ int exit_status = 0;
+ ssize_t len = next_str - (char *)&msg;
+
+ if (sock == -1)
+ {
+ int e = errno;
+
+ fprintf(stderr, "whack: socket() failed (%d %s)\n", e, strerror(e));
+ exit(RC_WHACK_PROBLEM);
+ }
+
+ if (connect(sock, (struct sockaddr *)&ctl_addr
+ , offsetof(struct sockaddr_un, sun_path) + strlen(ctl_addr.sun_path)) < 0)
+ {
+ int e = errno;
+
+ fprintf(stderr, "whack:%s connect() for \"%s\" failed (%d %s)\n"
+ , e == ECONNREFUSED? " is Pluto running? " : ""
+ , ctl_addr.sun_path, e, strerror(e));
+ exit(RC_WHACK_PROBLEM);
+ }
+
+ if (write(sock, &msg, len) != len)
+ {
+ int e = errno;
+
+ fprintf(stderr, "whack: write() failed (%d %s)\n", e, strerror(e));
+ exit(RC_WHACK_PROBLEM);
+ }
+
+ /* for now, just copy reply back to stdout */
+
+ {
+ char buf[4097]; /* arbitrary limit on log line length */
+ char *be = buf;
+
+ for (;;)
+ {
+ char *ls = buf;
+ ssize_t rl = read(sock, be, (buf + sizeof(buf)-1) - be);
+
+ if (rl < 0)
+ {
+ int e = errno;
+
+ fprintf(stderr, "whack: read() failed (%d %s)\n", e, strerror(e));
+ exit(RC_WHACK_PROBLEM);
+ }
+ if (rl == 0)
+ {
+ if (be != buf)
+ fprintf(stderr, "whack: last line from pluto too long or unterminated\n");
+ break;
+ }
+
+ be += rl;
+ *be = '\0';
+
+ for (;;)
+ {
+ char *le = strchr(ls, '\n');
+
+ if (le == NULL)
+ {
+ /* move last, partial line to start of buffer */
+ memmove(buf, ls, be-ls);
+ be -= ls - buf;
+ break;
+ }
+
+ le++; /* include NL in line */
+ write(1, ls, le - ls);
+
+ /* figure out prefix number
+ * and how it should affect our exit status
+ */
+ {
+ unsigned long s = strtoul(ls, NULL, 10);
+
+ switch (s)
+ {
+ case RC_COMMENT:
+ case RC_LOG:
+ /* ignore */
+ break;
+ case RC_SUCCESS:
+ /* be happy */
+ exit_status = 0;
+ break;
+ case RC_ENTERSECRET:
+ get_secret(sock);
+ break;
+ /* case RC_LOG_SERIOUS: */
+ default:
+ /* pass through */
+ exit_status = s;
+ break;
+ }
+ }
+ ls = le;
+ }
+ }
+ }
+ return exit_status;
+ }
+}
diff --git a/src/whack/whack.h b/src/whack/whack.h
new file mode 100644
index 000000000..49ef67995
--- /dev/null
+++ b/src/whack/whack.h
@@ -0,0 +1,318 @@
+/* Structure of messages from whack to Pluto proper.
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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: whack.h,v 1.16 2006/04/17 10:39:14 as Exp $
+ */
+
+#ifndef _WHACK_H
+#define _WHACK_H
+
+#include <freeswan.h>
+
+#include <smartcard.h>
+
+/* Since the message remains on one host, native representation is used.
+ * Think of this as horizontal microcode: all selected operations are
+ * to be done (in the order declared here).
+ *
+ * MAGIC is used to help detect version mismatches between whack and Pluto.
+ * Whenever the interface (i.e. this struct) changes in form or
+ * meaning, change this value (probably by changing the last number).
+ *
+ * If the command only requires basic actions (status or shutdown),
+ * it is likely that the relevant part of the message changes less frequently.
+ * Whack uses WHACK_BASIC_MAGIC in those cases.
+ *
+ * NOTE: no value of WHACK_BASIC_MAGIC may equal any value of WHACK_MAGIC.
+ * Otherwise certain version mismatches will not be detected.
+ */
+
+#define WHACK_BASIC_MAGIC (((((('w' << 8) + 'h') << 8) + 'k') << 8) + 24)
+#define WHACK_MAGIC (((((('w' << 8) + 'h') << 8) + 'k') << 8) + 26)
+
+typedef struct whack_end whack_end_t;
+
+/* struct whack_end is a lot like connection.h's struct end
+ * It differs because it is going to be shipped down a socket
+ * and because whack is a separate program from pluto.
+ */
+struct whack_end {
+ char *id; /* id string (if any) -- decoded by pluto */
+ char *cert; /* path string (if any) -- loaded by pluto */
+ char *ca; /* distinguished name string (if any) -- parsed by pluto */
+ char *groups; /* access control groups (if any) -- parsed by pluto */
+ ip_address
+ host_addr,
+ host_nexthop,
+ host_srcip;
+ ip_subnet client;
+
+ bool key_from_DNS_on_demand;
+ bool has_client;
+ bool has_client_wildcard;
+ bool has_port_wildcard;
+ bool has_srcip;
+ bool has_natip;
+ bool modecfg;
+ bool hostaccess;
+ certpolicy_t sendcert;
+ char *updown; /* string */
+ u_int16_t host_port; /* host order */
+ u_int16_t port; /* host order */
+ u_int8_t protocol;
+ char *virt;
+ };
+
+typedef struct whack_message whack_message_t;
+
+struct whack_message {
+ unsigned int magic;
+
+ /* for WHACK_STATUS: */
+ bool whack_status;
+ bool whack_statusall;
+
+
+ /* for WHACK_SHUTDOWN */
+ bool whack_shutdown;
+
+ /* END OF BASIC COMMANDS
+ * If you change anything earlier in this struct, update WHACK_BASIC_MAGIC.
+ */
+
+ /* name is used in connection, ca and initiate */
+ size_t name_len; /* string 1 */
+ char *name;
+
+ /* for WHACK_OPTIONS: */
+
+ bool whack_options;
+
+ lset_t debugging; /* only used #ifdef DEBUG, but don't want layout to change */
+
+ /* for WHACK_CONNECTION */
+
+ bool whack_connection;
+ bool whack_async;
+ bool ikev1;
+
+ lset_t policy;
+ time_t sa_ike_life_seconds;
+ time_t sa_ipsec_life_seconds;
+ time_t sa_rekey_margin;
+ unsigned long sa_rekey_fuzz;
+ unsigned long sa_keying_tries;
+
+ /* For DPD 3706 - Dead Peer Detection */
+ time_t dpd_delay;
+ time_t dpd_timeout;
+ dpd_action_t dpd_action;
+
+ /* note that each end contains string 2/5.id, string 3/6 cert,
+ * and string 4/7 updown
+ */
+ whack_end_t left;
+ whack_end_t right;
+
+ /* note: if the client is the gateway, the following must be equal */
+ sa_family_t addr_family; /* between gateways */
+ sa_family_t tunnel_addr_family; /* between clients */
+
+ char *ike; /* ike algo string (separated by commas) */
+ char *pfsgroup; /* pfsgroup will be "encapsulated" in esp string for pluto */
+ char *esp; /* esp algo string (separated by commas) */
+
+ /* for WHACK_KEY: */
+ bool whack_key;
+ bool whack_addkey;
+ char *keyid; /* string 8 */
+ enum pubkey_alg pubkey_alg;
+ chunk_t keyval; /* chunk */
+
+ /* for WHACK_MYID: */
+ bool whack_myid;
+ char *myid; /* string 7 */
+
+ /* for WHACK_ROUTE: */
+ bool whack_route;
+
+ /* for WHACK_UNROUTE: */
+ bool whack_unroute;
+
+ /* for WHACK_INITIATE: */
+ bool whack_initiate;
+
+ /* for WHACK_OPINITIATE */
+ bool whack_oppo_initiate;
+ ip_address oppo_my_client, oppo_peer_client;
+
+ /* for WHACK_TERMINATE: */
+ bool whack_terminate;
+
+ /* for WHACK_DELETE: */
+ bool whack_delete;
+
+ /* for WHACK_DELETESTATE: */
+ bool whack_deletestate;
+ so_serial_t whack_deletestateno;
+
+ /* for WHACK_LISTEN: */
+ bool whack_listen, whack_unlisten;
+
+ /* for WHACK_CRASH - note if a remote peer is known to have rebooted */
+ bool whack_crash;
+ ip_address whack_crash_peer;
+
+ /* for WHACK_LIST */
+ bool whack_utc;
+ lset_t whack_list;
+
+ /* for WHACK_PURGEOCSP */
+ bool whack_purgeocsp;
+
+ /* for WHACK_REREAD */
+ u_char whack_reread;
+
+ /* for WHACK_CA */
+ bool whack_ca;
+ bool whack_strict;
+
+ char *cacert;
+ char *ldaphost;
+ char *ldapbase;
+ char *crluri;
+ char *crluri2;
+ char *ocspuri;
+
+ /* for WHACK_SC_OP */
+ sc_op_t whack_sc_op;
+ int inbase, outbase;
+ char *sc_data;
+
+ /* space for strings (hope there is enough room):
+ * Note that pointers don't travel on wire.
+ * 1 connection name [name_len]
+ * 2 left's name [left.host.name.len]
+ * 3 left's cert
+ * 4 left's ca
+ * 5 left's groups
+ * 6 left's updown
+ * 7 right's name [left.host.name.len]
+ * 8 right's cert
+ * 9 right's ca
+ * 10 right's groups
+ * 11 right's updown
+ * 12 keyid
+ * 13 myid
+ * 14 cacert
+ * 15 ldaphost
+ * 16 ldapbase
+ * 17 crluri
+ * 18 crluri2
+ * 19 ocspuri
+ * 20 ike
+ " 21 esp
+ * 22 rsa_data
+ * plus keyval (limit: 8K bits + overhead), a chunk.
+ */
+ size_t str_size;
+ char string[2048];
+};
+
+/* Codes for status messages returned to whack.
+ * These are 3 digit decimal numerals. The structure
+ * is inspired by section 4.2 of RFC959 (FTP).
+ * Since these will end up as the exit status of whack, they
+ * must be less than 256.
+ * NOTE: ipsec_auto(8) knows about some of these numbers -- change carefully.
+ */
+enum rc_type {
+ RC_COMMENT, /* non-commital utterance (does not affect exit status) */
+ RC_WHACK_PROBLEM, /* whack-detected problem */
+ RC_LOG, /* message aimed at log (does not affect exit status) */
+ RC_LOG_SERIOUS, /* serious message aimed at log (does not affect exit status) */
+ RC_SUCCESS, /* success (exit status 0) */
+
+ /* failure, but not definitive */
+
+ RC_RETRANSMISSION = 10,
+
+ /* improper request */
+
+ RC_DUPNAME = 20, /* attempt to reuse a connection name */
+ RC_UNKNOWN_NAME, /* connection name unknown or state number */
+ RC_ORIENT, /* cannot orient connection: neither end is us */
+ RC_CLASH, /* clash between two Road Warrior connections OVERLOADED */
+ RC_DEAF, /* need --listen before --initiate */
+ RC_ROUTE, /* cannot route */
+ RC_RTBUSY, /* cannot unroute: route busy */
+ RC_BADID, /* malformed --id */
+ RC_NOKEY, /* no key found through DNS */
+ RC_NOPEERIP, /* cannot initiate when peer IP is unknown */
+ RC_INITSHUNT, /* cannot initiate a shunt-oly connection */
+ RC_WILDCARD, /* cannot initiate when ID has wildcards */
+ RC_NOVALIDPIN, /* cannot initiate without valid PIN */
+
+ /* permanent failure */
+
+ RC_BADWHACKMESSAGE = 30,
+ RC_NORETRANSMISSION,
+ RC_INTERNALERR,
+ RC_OPPOFAILURE, /* Opportunism failed */
+
+ /* entry of secrets */
+ RC_ENTERSECRET = 40,
+
+ /* progress: start of range for successful state transition.
+ * Actual value is RC_NEW_STATE plus the new state code.
+ */
+ RC_NEW_STATE = 100,
+
+ /* start of range for notification.
+ * Actual value is RC_NOTIFICATION plus code for notification
+ * that should be generated by this Pluto.
+ */
+ RC_NOTIFICATION = 200 /* as per IKE notification messages */
+};
+
+/* options of whack --list*** command */
+
+#define LIST_NONE 0x0000 /* don't list anything */
+#define LIST_ALGS 0x0001 /* list all registered IKE algorithms */
+#define LIST_PUBKEYS 0x0002 /* list all public keys */
+#define LIST_CERTS 0x0004 /* list all host/user certs */
+#define LIST_CACERTS 0x0008 /* list all ca certs */
+#define LIST_ACERTS 0x0010 /* list all attribute certs */
+#define LIST_AACERTS 0x0020 /* list all aa certs */
+#define LIST_OCSPCERTS 0x0040 /* list all ocsp certs */
+#define LIST_GROUPS 0x0080 /* list all access control groups */
+#define LIST_CAINFOS 0x0100 /* list all ca information records */
+#define LIST_CRLS 0x0200 /* list all crls */
+#define LIST_OCSP 0x0400 /* list all ocsp cache entries */
+#define LIST_CARDS 0x0800 /* list all smartcard records */
+
+#define LIST_ALL LRANGES(LIST_ALGS, LIST_CARDS) /* all list options */
+
+/* options of whack --reread*** command */
+
+#define REREAD_NONE 0x00 /* don't reread anything */
+#define REREAD_SECRETS 0x01 /* reread /etc/ipsec.secrets */
+#define REREAD_CACERTS 0x02 /* reread certs in /etc/ipsec.d/cacerts */
+#define REREAD_AACERTS 0x04 /* reread certs in /etc/ipsec.d/aacerts */
+#define REREAD_OCSPCERTS 0x08 /* reread certs in /etc/ipsec.d/ocspcerts */
+#define REREAD_ACERTS 0x10 /* reread certs in /etc/ipsec.d/acerts */
+#define REREAD_CRLS 0x20 /* reread crls in /etc/ipsec.d/crls */
+
+#define REREAD_ALL LRANGES(REREAD_SECRETS, REREAD_CRLS) /* all reread options */
+
+#endif /* _WHACK_H */